From 90320b179ee6a64249c1e830e9f40d9c29304d06 Mon Sep 17 00:00:00 2001 From: Paul Siedler Date: Thu, 25 Apr 2019 15:16:40 +0200 Subject: [PATCH 001/888] #339: allow direct execution of the bin/magento executable instead of calling custom endpoint --- .../Module/MagentoWebDriver.php | 178 ++++++++++++------ 1 file changed, 120 insertions(+), 58 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 93e6a5968..91c00c691 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -6,20 +6,21 @@ namespace Magento\FunctionalTestingFramework\Module; +use Codeception\Exception\ModuleConfigException; +use Codeception\Exception\ModuleException; use Codeception\Module\WebDriver; use Codeception\Test\Descriptor; use Codeception\TestInterface; -use Facebook\WebDriver\Interactions\WebDriverActions; -use Codeception\Exception\ModuleConfigException; -use Codeception\Exception\ModuleException; use Codeception\Util\Uri; +use Facebook\WebDriver\Interactions\WebDriverActions; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; use Magento\FunctionalTestingFramework\DataGenerator\Persist\Curl\WebapiExecutor; -use Magento\FunctionalTestingFramework\Util\Protocol\CurlTransport; -use Magento\FunctionalTestingFramework\Util\Protocol\CurlInterface; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Util\ConfigSanitizerUtil; +use Magento\FunctionalTestingFramework\Util\Protocol\CurlInterface; +use Magento\FunctionalTestingFramework\Util\Protocol\CurlTransport; +use Symfony\Component\Process\Process; use Yandex\Allure\Adapter\Support\AttachmentSupport; -use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; /** * MagentoWebDriver module provides common Magento web actions through Selenium WebDriver. @@ -47,6 +48,7 @@ class MagentoWebDriver extends WebDriver /** * List of known magento loading masks by selector + * * @var array */ public static $loadingMasksLocators = [ @@ -54,7 +56,7 @@ class MagentoWebDriver extends WebDriver '//div[contains(@class, "admin_data-grid-loading-mask")]', '//div[contains(@class, "admin__data-grid-loading-mask")]', '//div[contains(@class, "admin__form-loading-mask")]', - '//div[@data-role="spinner"]' + '//div[@data-role="spinner"]', ]; /** @@ -67,7 +69,7 @@ class MagentoWebDriver extends WebDriver 'backend_name', 'username', 'password', - 'browser' + 'browser', ]; /** @@ -114,6 +116,7 @@ class MagentoWebDriver extends WebDriver /** * Sanitizes config, then initializes using parent. + * * @return void */ public function _initialize() @@ -137,6 +140,7 @@ public function _resetConfig() /** * Remap parent::_after, called in TestContextExtension + * * @param TestInterface $test * @return void */ @@ -147,9 +151,10 @@ public function _runAfter(TestInterface $test) /** * Override parent::_after to do nothing. - * @return void + * * @param TestInterface $test * @SuppressWarnings(PHPMD) + * @return void */ public function _after(TestInterface $test) { @@ -159,9 +164,9 @@ public function _after(TestInterface $test) /** * Returns URL of a host. * - * @api * @return mixed * @throws ModuleConfigException + * @api */ public function _getUrl() { @@ -171,6 +176,7 @@ public function _getUrl() "Module connection failure. The URL for client can't bre retrieved" ); } + return $this->config['url']; } @@ -178,8 +184,8 @@ public function _getUrl() * Uri of currently opened page. * * @return string - * @api * @throws ModuleException + * @api */ public function _getCurrentUri() { @@ -187,6 +193,7 @@ public function _getCurrentUri() if ($url == 'about:blank') { throw new ModuleException($this, 'Current url is blank, no page was opened'); } + return Uri::retrieveUri($url); } @@ -243,6 +250,7 @@ public function grabFromCurrentUrl($regex = null) if (!isset($matches[1])) { $this->fail("Nothing to grab. A regex parameter with a capture group is required. Ex: '/(foo)(bar)/'"); } + return $matches[1]; } @@ -297,17 +305,17 @@ public function closeAdminNotification() * Search for and Select multiple options from a Magento Multi-Select drop down menu. * e.g. The drop down menu you use to assign Products to Categories. * - * @param string $select - * @param array $options + * @param string $select + * @param array $options * @param boolean $requireAction - * @throws \Exception * @return void + * @throws \Exception */ public function searchAndMultiSelectOption($select, array $options, $requireAction = false) { - $selectDropdown = $select . ' .action-select.admin__action-multiselect'; - $selectSearchText = $select - . ' .admin__action-multiselect-search-wrap>input[data-role="advanced-select-text"]'; + $selectDropdown = $select . ' .action-select.admin__action-multiselect'; + $selectSearchText = $select + . ' .admin__action-multiselect-search-wrap>input[data-role="advanced-select-text"]'; $selectSearchResult = $select . ' .admin__action-multiselect-label>span'; $this->waitForPageLoad(); @@ -326,11 +334,11 @@ public function searchAndMultiSelectOption($select, array $options, $requireActi /** * Select multiple options from a drop down using a filter and text field to narrow results. * - * @param string $selectSearchTextField - * @param string $selectSearchResult + * @param string $selectSearchTextField + * @param string $selectSearchResult * @param string[] $options - * @throws \Exception * @return void + * @throws \Exception */ public function selectMultipleOptions($selectSearchTextField, $selectSearchResult, array $options) { @@ -367,8 +375,8 @@ public function waitForAjaxLoad($timeout = null) * Wait for all JavaScript to finish executing. * * @param integer $timeout - * @throws \Exception * @return void + * @throws \Exception */ public function waitForPageLoad($timeout = null) { @@ -383,8 +391,8 @@ public function waitForPageLoad($timeout = null) * Wait for all visible loading masks to disappear. Gets all elements by mask selector, then loops over them. * * @param integer $timeout - * @throws \Exception * @return void + * @throws \Exception */ public function waitForLoadingMaskToDisappear($timeout = null) { @@ -401,7 +409,7 @@ public function waitForLoadingMaskToDisappear($timeout = null) } /** - * @param float $money + * @param float $money * @param string $locale * @return array */ @@ -412,6 +420,7 @@ public function formatMoney(float $money, $locale = 'en_US.UTF-8') $this->mResetLocale(); $prefix = substr($money, 0, 1); $number = substr($money, 1); + return ['prefix' => $prefix, 'number' => $number]; } @@ -424,12 +433,13 @@ public function formatMoney(float $money, $locale = 'en_US.UTF-8') public function parseFloat($floatString) { $floatString = str_replace(',', '', $floatString); + return floatval($floatString); } /** * @param integer $category - * @param string $locale + * @param string $locale * @return void */ public function mSetLocale(int $category, $locale) @@ -445,6 +455,7 @@ public function mSetLocale(int $category, $locale) /** * Reset Locale setting. + * * @return void */ public function mResetLocale() @@ -459,6 +470,7 @@ public function mResetLocale() /** * Scroll to the Top of the Page. + * * @return void */ public function scrollToTopOfPage() @@ -467,44 +479,28 @@ public function scrollToTopOfPage() } /** - * Takes given $command and executes it against exposed MTF CLI entry point. Returns response from server. + * Takes given $command and executes it against bin/magento or custom exposed entrypoint. Returns command output. + * * @param string $command * @param string $arguments - * @throws TestFrameworkException * @return string + * @throws TestFrameworkException */ public function magentoCLI($command, $arguments = null) { - // Remove index.php if it's present in url - $baseUrl = rtrim( - str_replace('index.php', '', rtrim($this->config['url'], '/')), - '/' - ); - $apiURL = $baseUrl . '/' . ltrim(getenv('MAGENTO_CLI_COMMAND_PATH'), '/'); - - $restExecutor = new WebapiExecutor(); - $executor = new CurlTransport(); - $executor->write( - $apiURL, - [ - 'token' => $restExecutor->getAuthToken(), - getenv('MAGENTO_CLI_COMMAND_PARAMETER') => $command, - 'arguments' => $arguments - ], - CurlInterface::POST, - [] - ); - $response = $executor->read(); - $restExecutor->close(); - $executor->close(); - return $response; + try { + return $this->shellExecMagentoCLI($command, $arguments); + } catch (\Exception $exception) { + return $this->curlExecMagentoCLI($command, $arguments); + } } /** * Runs DELETE request to delete a Magento entity against the url given. + * * @param string $url - * @throws TestFrameworkException * @return string + * @throws TestFrameworkException */ public function deleteEntityByUrl($url) { @@ -512,17 +508,18 @@ public function deleteEntityByUrl($url) $executor->write($url, [], CurlInterface::DELETE, []); $response = $executor->read(); $executor->close(); + return $response; } /** * Conditional click for an area that should be visible * - * @param string $selector - * @param string $dependentSelector + * @param string $selector + * @param string $dependentSelector * @param boolean $visible - * @throws \Exception * @return void + * @throws \Exception */ public function conditionalClick($selector, $dependentSelector, $visible) { @@ -577,6 +574,7 @@ public function assertElementContainsAttribute($selector, $attribute, $value) /** * Sets current test to the given test, and resets test failure artifacts to null + * * @param TestInterface $test * @return void */ @@ -591,8 +589,9 @@ public function _before(TestInterface $test) /** * Override for codeception's default dragAndDrop to include offset options. - * @param string $source - * @param string $target + * + * @param string $source + * @param string $target * @param integer $xOffset * @param integer $yOffset * @return void @@ -641,7 +640,7 @@ public function fillSecretField($field, $value) * following parent execution of test failure processing. * * @param TestInterface $test - * @param \Exception $fail + * @param \Exception $fail * @return void */ public function _failed(TestInterface $test, $fail) @@ -666,6 +665,7 @@ public function _failed(TestInterface $test, $fail) /** * Function which saves a screenshot of the current stat of the browser + * * @return void */ public function saveScreenshot() @@ -685,8 +685,8 @@ public function saveScreenshot() * Go to a page and wait for ajax requests to finish * * @param string $page - * @throws \Exception * @return void + * @throws \Exception */ public function amOnPage($page) { @@ -698,8 +698,8 @@ public function amOnPage($page) * Turn Readiness check on or off * * @param boolean $check - * @throws \Exception * @return void + * @throws \Exception */ public function skipReadinessCheck($check) { @@ -742,6 +742,7 @@ private function getJsErrors() $errors .= "\n" . $jsError; } } + return $errors; } @@ -754,4 +755,65 @@ public function dontSeeJsError() { $this->assertEmpty($this->jsErrors, $this->getJsErrors()); } + + /** + * Takes given $command and executes it against bin/magento executable. Returns stdout output from the command. + * + * @param string $command + * @param string $arguments + * + * @throws \RuntimeException + * @return string + */ + private function shellExecMagentoCLI($command, $arguments): string + { + $php = PHP_BINDIR ? PHP_BINDIR . DIRECTORY_SEPARATOR. 'php' : 'php'; + $binMagento = realpath(MAGENTO_BP . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'magento'); + $command = $php . ' -f ' . $binMagento . ' ' . $command . ' ' . $arguments; + $process = new Process(escapeshellcmd($command), MAGENTO_BP); + $process->setIdleTimeout(60); + $process->setTimeout(0); + $exitCode = $process->run(); + if ($exitCode !== 0) { + throw new \RuntimeException($process->getErrorOutput()); + } + + return $process->getOutput(); + } + + /** + * Takes given $command and executes it against exposed MTF CLI entry point. Returns response from server. + * + * @param string $command + * @param string $arguments + * @return string + * @throws TestFrameworkException + */ + private function curlExecMagentoCLI($command, $arguments): string + { + // Remove index.php if it's present in url + $baseUrl = rtrim( + str_replace('index.php', '', rtrim($this->config['url'], '/')), + '/' + ); + $apiURL = $baseUrl . '/' . ltrim(getenv('MAGENTO_CLI_COMMAND_PATH'), '/'); + + $restExecutor = new WebapiExecutor(); + $executor = new CurlTransport(); + $executor->write( + $apiURL, + [ + 'token' => $restExecutor->getAuthToken(), + getenv('MAGENTO_CLI_COMMAND_PARAMETER') => $command, + 'arguments' => $arguments, + ], + CurlInterface::POST, + [] + ); + $response = $executor->read(); + $restExecutor->close(); + $executor->close(); + + return $response; + } } From f1322810a1698c42fa35dd19b808741615d06f96 Mon Sep 17 00:00:00 2001 From: Paul Siedler Date: Tue, 30 Apr 2019 13:33:08 +0200 Subject: [PATCH 002/888] Fix phpcs issues --- .../Module/MagentoWebDriver.php | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 91c00c691..1632757a6 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -305,8 +305,8 @@ public function closeAdminNotification() * Search for and Select multiple options from a Magento Multi-Select drop down menu. * e.g. The drop down menu you use to assign Products to Categories. * - * @param string $select - * @param array $options + * @param string $select + * @param array $options * @param boolean $requireAction * @return void * @throws \Exception @@ -334,8 +334,8 @@ public function searchAndMultiSelectOption($select, array $options, $requireActi /** * Select multiple options from a drop down using a filter and text field to narrow results. * - * @param string $selectSearchTextField - * @param string $selectSearchResult + * @param string $selectSearchTextField + * @param string $selectSearchResult * @param string[] $options * @return void * @throws \Exception @@ -409,7 +409,7 @@ public function waitForLoadingMaskToDisappear($timeout = null) } /** - * @param float $money + * @param float $money * @param string $locale * @return array */ @@ -439,7 +439,7 @@ public function parseFloat($floatString) /** * @param integer $category - * @param string $locale + * @param string $locale * @return void */ public function mSetLocale(int $category, $locale) @@ -515,8 +515,8 @@ public function deleteEntityByUrl($url) /** * Conditional click for an area that should be visible * - * @param string $selector - * @param string $dependentSelector + * @param string $selector + * @param string $dependentSelector * @param boolean $visible * @return void * @throws \Exception @@ -590,8 +590,8 @@ public function _before(TestInterface $test) /** * Override for codeception's default dragAndDrop to include offset options. * - * @param string $source - * @param string $target + * @param string $source + * @param string $target * @param integer $xOffset * @param integer $yOffset * @return void @@ -640,7 +640,7 @@ public function fillSecretField($field, $value) * following parent execution of test failure processing. * * @param TestInterface $test - * @param \Exception $fail + * @param \Exception $fail * @return void */ public function _failed(TestInterface $test, $fail) From 26558bf8e7d5ddeab4a7ebf44d16ae50323aaf3f Mon Sep 17 00:00:00 2001 From: Laura Folco Date: Sun, 15 Sep 2019 11:38:43 -0400 Subject: [PATCH 003/888] Fixed example test cases to point to actual tests --- docs/commands/mftf.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 2301d6f44..2e4361367 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -39,7 +39,7 @@ vendor/bin/mftf generate:tests ### Generate tests by test name ```bash -vendor/bin/mftf generate:tests LoginAsAdminTest LoginAsCustomerTest +vendor/bin/mftf generate:tests AdminLoginTest StorefrontPersistedCustomerLoginTest ``` ### Generate and run the tests for a specified group @@ -53,7 +53,7 @@ This command cleans up the previously generated tests; generates and runs tests ### Generate and run particular tests ```bash -vendor/bin/mftf run:test LoginAsAdminTest LoginAsCustomerTest -r +vendor/bin/mftf run:test AdminLoginTest StorefrontPersistedCustomerLoginTest -r ``` This command cleans up the previously generated tests; generates and runs the `LoginAsAdminTest` and `LoginAsCustomerTest` tests. From 1039d79ca517e65a46c2cdbc24df0c16ce9316d0 Mon Sep 17 00:00:00 2001 From: Laura Folco Date: Sat, 21 Sep 2019 11:27:10 -0400 Subject: [PATCH 004/888] Fix reference to action groups The original text looks like it was copied from the Action Group extends article. --- docs/merge_points/extend-data.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/merge_points/extend-data.md b/docs/merge_points/extend-data.md index 344d11935..7896f66a9 100644 --- a/docs/merge_points/extend-data.md +++ b/docs/merge_points/extend-data.md @@ -1,8 +1,8 @@ # Extend data entities -Extending an action group doesn't affect the existing action group. +Extending a data entity doesn't affect the existing data entity. -In this example we add a `` command to check the checkbox that our extension added with a new action group for the simple product creation form. +In this example we update the quantity to 1001 and add a new piece of data relevant to our extension. Unlike merging, this will _not_ affect any other tests that use this data entity. ## Starting entity @@ -67,4 +67,4 @@ Note that there are now two data entities below. CustomAttributeCategoryIds dataHere -``` \ No newline at end of file +``` From 814a239c0896c904198917ed26bceff8a7eb9d5f Mon Sep 17 00:00:00 2001 From: Laura Folco Date: Sat, 21 Sep 2019 11:38:35 -0400 Subject: [PATCH 005/888] Fix reference to data objects The text should be about tests, not data objects --- docs/merge_points/extend-tests.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/merge_points/extend-tests.md b/docs/merge_points/extend-tests.md index 7398e273d..6aab50764 100644 --- a/docs/merge_points/extend-tests.md +++ b/docs/merge_points/extend-tests.md @@ -1,6 +1,6 @@ # Extend tests -Data objects can be merged to cover the needs of your extension. +Tests can be extended to cover the needs of your extension. In this example, we add an action group to a new copy of the original test for our extension. @@ -142,4 +142,4 @@ Note that there are now two tests below. -``` \ No newline at end of file +``` From 4379b7e1a619961b482cfe7f7f6c378ad66a40aa Mon Sep 17 00:00:00 2001 From: Laura Folco Date: Sat, 21 Sep 2019 12:07:07 -0400 Subject: [PATCH 006/888] Fix invalid line break tags The text had backwards line breaks: `
` --- docs/commands/mftf.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 58be6501e..7851f6ce2 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -126,12 +126,12 @@ vendor/bin/mftf generate:tests [option] [] [] [--remove] | Option | Description| | ---| --- | -| `--config=[ or or ]` | Creates a single manifest file with a list of all tests. The default location is `tests/functional/Magento/FunctionalTest/_generated/testManifest.txt`.
You can split the list into multiple groups using `--config=parallel`; the groups will be generated in `_generated/groups/` like `_generated/groups/group1.txt, group2.txt, ...`.
Available values: `default` (default), `singleRun`(same as `default`), and `parallel`.
Example: `generate:tests --config=parallel`. | +| `--config=[ or or ]` | Creates a single manifest file with a list of all tests. The default location is `tests/functional/Magento/FunctionalTest/_generated/testManifest.txt`.
You can split the list into multiple groups using `--config=parallel`; the groups will be generated in `_generated/groups/` like `_generated/groups/group1.txt, group2.txt, ...`.
Available values: `default` (default), `singleRun`(same as `default`), and `parallel`.
Example: `generate:tests --config=parallel`. | | `--force` | Forces test generation, regardless of the module merge order defined in the Magento instance. Example: `generate:tests --force`. | | `-i,--time` | Set time in minutes to determine the group size when `--config=parallel` is used. The __default value__ is `10`. Example: `generate:tests --config=parallel --time=15`| | `--tests` | Defines the test configuration as a JSON string.| | `--allow-skipped` | Allows MFTF to generate and run tests marked with `.`| -| `--debug or --debug=[]`| Performs schema validations on XML files.
DEFAULT: `generate:tests` implicitly performs schema validation on merged files. It does not indicate the file name where the error is encountered.
DEVELOPER: `--debug` performs per-file validation and returns additional debug information (such as the filename where an error occurred) when test generation fails because of an invalid XML schema. This option takes extra processing time. Use it after test generation has failed once.

NONE: `--debug=none` skips debugging during test generation. Added for backward compatibility, it will be removed in the next MAJOR release.
| +| `--debug or --debug=[]`| Performs schema validations on XML files.
DEFAULT: `generate:tests` implicitly performs schema validation on merged files. It does not indicate the file name where the error is encountered.
DEVELOPER: `--debug` performs per-file validation and returns additional debug information (such as the filename where an error occurred) when test generation fails because of an invalid XML schema. This option takes extra processing time. Use it after test generation has failed once.
NONE: `--debug=none` skips debugging during test generation. Added for backward compatibility, it will be removed in the next MAJOR release.
| | `-r,--remove`| Removes the existing generated suites and tests cleaning up the `_generated` directory before the actual run. For example, `generate:tests SampleTest --remove` cleans up the entire `_generated` directory and generates `SampleTest` only.| #### Examples of the JSON configuration From 09dd48726384a87faba57236ccc63b4f5cd48ebb Mon Sep 17 00:00:00 2001 From: Donald Booth Date: Tue, 1 Oct 2019 10:55:14 -0500 Subject: [PATCH 007/888] Removed contraction. --- docs/merge_points/extend-data.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/merge_points/extend-data.md b/docs/merge_points/extend-data.md index 7896f66a9..ebac16108 100644 --- a/docs/merge_points/extend-data.md +++ b/docs/merge_points/extend-data.md @@ -1,6 +1,6 @@ # Extend data entities -Extending a data entity doesn't affect the existing data entity. +Extending a data entity does not affect the existing data entity. In this example we update the quantity to 1001 and add a new piece of data relevant to our extension. Unlike merging, this will _not_ affect any other tests that use this data entity. From 7d37bb4d500372036ce8687354550c8b2b5f8ec6 Mon Sep 17 00:00:00 2001 From: Laura Folco Date: Sun, 6 Oct 2019 15:31:06 -0400 Subject: [PATCH 008/888] Grammatical and formatting fixes --- docs/suite.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/suite.md b/docs/suite.md index e49dd02ab..080795b6e 100644 --- a/docs/suite.md +++ b/docs/suite.md @@ -1,7 +1,7 @@ # Suites -Suites are essentially groups of tests that run in the specific conditions (preconditions and postconditions). -They enable you including, excluding, and grouping tests for a customized test run when you need it. +Suites are essentially groups of tests that run in specific conditions (preconditions and postconditions). +They enable including, excluding, and grouping tests for a customized test run when you need it. You can form suites using separate tests, groups, and modules. Each suite must be defined in the `/dev/tests/acceptance/tests/_suite/suite.xml` file. @@ -42,12 +42,12 @@ The format of a suite: ## Principles - A suite name: - - must not match any existing group value. + - must not match any existing group value. For example, the suite `` will fail during test run if any test contains in annotations ``. - - must not be `default` or `skip`. Tests that are not in any suite are generated under the `default` suite. + - must not be `default` or `skip`. Tests that are not in any suite are generated under the `default` suite. The suite name `skip` is synonymous to including a test in the ``, which will be deprecated in MFTF 3.0.0. - - can contain letters, numbers, and underscores. - - should be upper camel case. + - can contain letters, numbers, and underscores. + - should be upper camel case. - A suite must contain at least one ``, or one ``, or both. - Using `` in a suite, you must add the corresponding `` to restore the initial state of your testing instance. @@ -134,7 +134,7 @@ It performs the following steps: *After* the testing, the suite returns the Magento instance to the initial state disabling WYSIWYG: 1. Log back in. -2. Disable **WYSIWYG** so that +2. Disable **WYSIWYG** in the Magento instance. This suite includes all tests that contain the `` annotation. @@ -243,11 +243,11 @@ The element can contain [``], [``], and [``]. A set of filters that you can use to specify which tests to exclude in the test suite. -There two types of behavior: +There are two types of behavior: 1. Applying filters to the included tests when the suite contains [``] filters. The MFTF will exclude tests from the previously included set and generate the remaining tests in the suite. -2. Applying filter to all tests when the suite does not contain [``] filters. +2. Applying filters to all tests when the suite does not contain [``] filters. The MFTF will generate all existing tests except the excluded. In this case, the custom suite will contain all generated tests except excluded, and the _default_ suite will contain the excluded tests only. From 8c1c2c43bc0da6ffa8d45ea0f9d2ac83db959f8a Mon Sep 17 00:00:00 2001 From: Simon Sprankel Date: Fri, 11 Oct 2019 09:12:47 +0200 Subject: [PATCH 009/888] fixed static checks command name --- docs/commands/mftf.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 58be6501e..273e3567c 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -429,9 +429,9 @@ vendor/bin/mftf setup:env The example parameters are taken from the `etc/config/.env.example` file. -### `static:checks` +### `static-checks` -Runs all MFTF static:checks on the test codebase that MFTF is currently attached to. +Runs all MFTF static-checks on the test codebase that MFTF is currently attached to. #### Existing static checks @@ -440,7 +440,7 @@ Runs all MFTF static:checks on the test codebase that MFTF is currently attached #### Usage ```bash -vendor/bin/mftf static:checks +vendor/bin/mftf static-checks ``` ### `upgrade:tests` From 36a243a40b378d6d81022b41cb19cfefb74a0100 Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Wed, 16 Oct 2019 14:08:09 -0500 Subject: [PATCH 010/888] MQE-1644: Add ability to see JS log in Allure - Initial logging addition. --- .../Extension/ErrorLogger.php | 36 ++++++++++++++----- .../Extension/TestContextExtension.php | 8 +++++ 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Extension/ErrorLogger.php b/src/Magento/FunctionalTestingFramework/Extension/ErrorLogger.php index b0621df1b..07a6d2779 100644 --- a/src/Magento/FunctionalTestingFramework/Extension/ErrorLogger.php +++ b/src/Magento/FunctionalTestingFramework/Extension/ErrorLogger.php @@ -12,6 +12,9 @@ */ class ErrorLogger { + const LOG_TYPE_BROWSER = "browser"; + const ERROR_TYPE_JAVASCRIPT = "javascript"; + /** * Error Logger Instance * @var ErrorLogger @@ -49,16 +52,33 @@ private function __construct() public function logErrors($module, $stepEvent) { //Types available should be "server", "browser", "driver". Only care about browser at the moment. - if (in_array("browser", $module->webDriver->manage()->getAvailableLogTypes())) { - $browserLogEntries = $module->webDriver->manage()->getLog("browser"); - foreach ($browserLogEntries as $entry) { - if (array_key_exists("source", $entry) && $entry["source"] === "javascript") { - $this->logError("javascript", $stepEvent, $entry); - //Set javascript error in MagentoWebDriver internal array - $module->setJsError("ERROR({$entry["level"]}) - " . $entry["message"]); - } + if (in_array(self::LOG_TYPE_BROWSER, $module->webDriver->manage()->getAvailableLogTypes())) { + $browserLogEntries = $module->webDriver->manage()->getLog(self::LOG_TYPE_BROWSER); + $jsErrors = $this->getLogsOfType($browserLogEntries, self::ERROR_TYPE_JAVASCRIPT); + foreach ($jsErrors as $entry) { + $this->logError(self::ERROR_TYPE_JAVASCRIPT, $stepEvent, $entry); + //Set javascript error in MagentoWebDriver internal array + $module->setJsError("ERROR({$entry["level"]}) - " . $entry["message"]); + } + } + } + + /** + * Loops through given logs and returns entries of the given type. + * + * @param array $log + * @param string $type + * @return array + */ + public function getLogsOfType($log, $type) + { + $errors = []; + foreach ($log as $entry) { + if (array_key_exists("source", $entry) && $entry["source"] === $type) { + $errors[] = $entry; } } + return $errors; } /** diff --git a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php index 467074097..93faf9e82 100644 --- a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php +++ b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php @@ -7,6 +7,7 @@ namespace Magento\FunctionalTestingFramework\Extension; use Codeception\Events; +use Magento\FunctionalTestingFramework\Allure\AllureHelper; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; /** @@ -173,6 +174,13 @@ public function beforeStep(\Codeception\Event\StepEvent $e) */ public function afterStep(\Codeception\Event\StepEvent $e) { + if (getenv('ENABLE_JS_LOG')) { + $browserLogEntries = $this->getDriver()->webDriver->manage()->getLog("browser"); + $jsErrors = ErrorLogger::getInstance()->getLogsOfType($browserLogEntries, ErrorLogger::ERROR_TYPE_JAVASCRIPT); + if (!empty($jsErrors)) { + AllureHelper::addAttachmentToCurrentStep($jsErrors); + } + } ErrorLogger::getInstance()->logErrors($this->getDriver(), $e); } From 997a9ef190f696903d1ecb3206fd31185f5dc886 Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Thu, 17 Oct 2019 09:40:22 -0500 Subject: [PATCH 011/888] MQE-1644: Add ability to see JS log in Allure - Addec blacklist - Renamed variables --- etc/config/.env.example | 5 +++++ .../Extension/ErrorLogger.php | 20 ++++++++++++++++++- .../Extension/TestContextExtension.php | 13 +++++++----- 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/etc/config/.env.example b/etc/config/.env.example index f25cb3de7..bb1d1ad63 100644 --- a/etc/config/.env.example +++ b/etc/config/.env.example @@ -54,4 +54,9 @@ MODULE_WHITELIST=Magento_Framework,ConfigurableProductWishlist,ConfigurableProdu #*** Default timeout for wait actions #WAIT_TIMEOUT=10 + +#*** Uncomment and set to enable browser log entries on actions in Allure. Blacklist is used to filter logs of a specific "source" +#ENABLE_BROWSER_LOG=true +#BROWSER_LOG_BLACKLIST=other + #*** End of .env ***# diff --git a/src/Magento/FunctionalTestingFramework/Extension/ErrorLogger.php b/src/Magento/FunctionalTestingFramework/Extension/ErrorLogger.php index 07a6d2779..b76a9c1f4 100644 --- a/src/Magento/FunctionalTestingFramework/Extension/ErrorLogger.php +++ b/src/Magento/FunctionalTestingFramework/Extension/ErrorLogger.php @@ -64,7 +64,7 @@ public function logErrors($module, $stepEvent) } /** - * Loops through given logs and returns entries of the given type. + * Loops through given log and returns entries of the given type. * * @param array $log * @param string $type @@ -81,6 +81,24 @@ public function getLogsOfType($log, $type) return $errors; } + /** + * Loops through given log and filters entries of the given type. + * + * @param array $log + * @param string $type + * @return array + */ + public function filterLogsOfType($log, $type) + { + $errors = []; + foreach ($log as $entry) { + if (array_key_exists("source", $entry) && $entry["source"] !== $type) { + $errors[] = $entry; + } + } + return $errors; + } + /** * Logs errors to console/report. * @param string $type diff --git a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php index 93faf9e82..639d65133 100644 --- a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php +++ b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php @@ -174,11 +174,14 @@ public function beforeStep(\Codeception\Event\StepEvent $e) */ public function afterStep(\Codeception\Event\StepEvent $e) { - if (getenv('ENABLE_JS_LOG')) { - $browserLogEntries = $this->getDriver()->webDriver->manage()->getLog("browser"); - $jsErrors = ErrorLogger::getInstance()->getLogsOfType($browserLogEntries, ErrorLogger::ERROR_TYPE_JAVASCRIPT); - if (!empty($jsErrors)) { - AllureHelper::addAttachmentToCurrentStep($jsErrors); + if (getenv('ENABLE_BROWSER_LOG')) { + $browserLog = $this->getDriver()->webDriver->manage()->getLog("browser"); + foreach (explode(',', getenv('BROWSER_LOG_BLACKLIST')) as $source) { + $browserLog = ErrorLogger::getInstance()->filterLogsOfType($browserLog, $source); + } + + if (!empty($browserLog)) { + AllureHelper::addAttachmentToCurrentStep(json_encode($browserLog, JSON_PRETTY_PRINT), "Browser Log"); } } ErrorLogger::getInstance()->logErrors($this->getDriver(), $e); From 76ecba3b28ce2ec5af7428a71b1660e74ec80150 Mon Sep 17 00:00:00 2001 From: Donald Booth Date: Thu, 17 Oct 2019 10:11:25 -0500 Subject: [PATCH 012/888] formatting --- docs/suite.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/suite.md b/docs/suite.md index 080795b6e..6232d2201 100644 --- a/docs/suite.md +++ b/docs/suite.md @@ -1,7 +1,7 @@ # Suites Suites are essentially groups of tests that run in specific conditions (preconditions and postconditions). -They enable including, excluding, and grouping tests for a customized test run when you need it. +They enable including, excluding, and grouping tests for a customized test run. You can form suites using separate tests, groups, and modules. Each suite must be defined in the `/dev/tests/acceptance/tests/_suite/suite.xml` file. @@ -18,7 +18,6 @@ The format of a suite: ```xml - @@ -42,12 +41,14 @@ The format of a suite: ## Principles - A suite name: + - must not match any existing group value. For example, the suite `` will fail during test run if any test contains in annotations ``. - must not be `default` or `skip`. Tests that are not in any suite are generated under the `default` suite. - The suite name `skip` is synonymous to including a test in the ``, which will be deprecated in MFTF 3.0.0. + The suite name `skip` is synonymous to including a test in the ``, which will be deprecated in MFTF 3.0.0. - can contain letters, numbers, and underscores. - should be upper camel case. + - A suite must contain at least one ``, or one ``, or both. - Using `` in a suite, you must add the corresponding `` to restore the initial state of your testing instance. From dc0bf75cc902212b7eb1572c6757f55134881995 Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Thu, 17 Oct 2019 10:39:34 -0500 Subject: [PATCH 013/888] MQE-1644: Add ability to see JS log in Allure - Refactor ErrorLogger into BrowserLogUtil, no longer a singleton --- .../{ErrorLogger.php => BrowserLogUtil.php} | 43 ++++--------------- .../Extension/TestContextExtension.php | 4 +- 2 files changed, 10 insertions(+), 37 deletions(-) rename src/Magento/FunctionalTestingFramework/Extension/{ErrorLogger.php => BrowserLogUtil.php} (71%) diff --git a/src/Magento/FunctionalTestingFramework/Extension/ErrorLogger.php b/src/Magento/FunctionalTestingFramework/Extension/BrowserLogUtil.php similarity index 71% rename from src/Magento/FunctionalTestingFramework/Extension/ErrorLogger.php rename to src/Magento/FunctionalTestingFramework/Extension/BrowserLogUtil.php index b76a9c1f4..330c21ebf 100644 --- a/src/Magento/FunctionalTestingFramework/Extension/ErrorLogger.php +++ b/src/Magento/FunctionalTestingFramework/Extension/BrowserLogUtil.php @@ -7,41 +7,14 @@ namespace Magento\FunctionalTestingFramework\Extension; /** - * Class ErrorLogger + * Class BrowserLogUtil * @package Magento\FunctionalTestingFramework\Extension */ -class ErrorLogger +class BrowserLogUtil { const LOG_TYPE_BROWSER = "browser"; const ERROR_TYPE_JAVASCRIPT = "javascript"; - /** - * Error Logger Instance - * @var ErrorLogger - */ - private static $errorLogger; - - /** - * Singleton method to return ErrorLogger. - * @return ErrorLogger - */ - public static function getInstance() - { - if (!self::$errorLogger) { - self::$errorLogger = new ErrorLogger(); - } - - return self::$errorLogger; - } - - /** - * ErrorLogger constructor. - */ - private function __construct() - { - // private constructor - } - /** * Loops through stepEvent for browser log entries * @@ -49,14 +22,14 @@ private function __construct() * @param \Codeception\Event\StepEvent $stepEvent * @return void */ - public function logErrors($module, $stepEvent) + public static function logErrors($module, $stepEvent) { //Types available should be "server", "browser", "driver". Only care about browser at the moment. if (in_array(self::LOG_TYPE_BROWSER, $module->webDriver->manage()->getAvailableLogTypes())) { $browserLogEntries = $module->webDriver->manage()->getLog(self::LOG_TYPE_BROWSER); - $jsErrors = $this->getLogsOfType($browserLogEntries, self::ERROR_TYPE_JAVASCRIPT); + $jsErrors = self::getLogsOfType($browserLogEntries, self::ERROR_TYPE_JAVASCRIPT); foreach ($jsErrors as $entry) { - $this->logError(self::ERROR_TYPE_JAVASCRIPT, $stepEvent, $entry); + self::logError(self::ERROR_TYPE_JAVASCRIPT, $stepEvent, $entry); //Set javascript error in MagentoWebDriver internal array $module->setJsError("ERROR({$entry["level"]}) - " . $entry["message"]); } @@ -70,7 +43,7 @@ public function logErrors($module, $stepEvent) * @param string $type * @return array */ - public function getLogsOfType($log, $type) + public static function getLogsOfType($log, $type) { $errors = []; foreach ($log as $entry) { @@ -88,7 +61,7 @@ public function getLogsOfType($log, $type) * @param string $type * @return array */ - public function filterLogsOfType($log, $type) + public static function filterLogsOfType($log, $type) { $errors = []; foreach ($log as $entry) { @@ -106,7 +79,7 @@ public function filterLogsOfType($log, $type) * @param array $entry * @return void */ - private function logError($type, $stepEvent, $entry) + private static function logError($type, $stepEvent, $entry) { //TODO Add to overall log $stepEvent->getTest()->getScenario()->comment("{$type} ERROR({$entry["level"]}) - " . $entry["message"]); diff --git a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php index 639d65133..10b7621b4 100644 --- a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php +++ b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php @@ -177,14 +177,14 @@ public function afterStep(\Codeception\Event\StepEvent $e) if (getenv('ENABLE_BROWSER_LOG')) { $browserLog = $this->getDriver()->webDriver->manage()->getLog("browser"); foreach (explode(',', getenv('BROWSER_LOG_BLACKLIST')) as $source) { - $browserLog = ErrorLogger::getInstance()->filterLogsOfType($browserLog, $source); + $browserLog = BrowserLogUtil::filterLogsOfType($browserLog, $source); } if (!empty($browserLog)) { AllureHelper::addAttachmentToCurrentStep(json_encode($browserLog, JSON_PRETTY_PRINT), "Browser Log"); } } - ErrorLogger::getInstance()->logErrors($this->getDriver(), $e); + BrowserLogUtil::logErrors($this->getDriver(), $e); } /** From 31073a38efa5d6d47943004995c99539fdd71908 Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Thu, 17 Oct 2019 11:34:26 -0500 Subject: [PATCH 014/888] MQE-1644: Add ability to see JS log in Allure - Unit test + static check fixes --- .../Extension/BrowserLogUtilTest.php | 76 +++++++++++++++++++ .../Extension/BrowserLogUtil.php | 4 +- 2 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/Extension/BrowserLogUtilTest.php diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Extension/BrowserLogUtilTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Extension/BrowserLogUtilTest.php new file mode 100644 index 000000000..32cac698e --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Extension/BrowserLogUtilTest.php @@ -0,0 +1,76 @@ + "WARNING", + "message" => "warningMessage", + "source" => "console-api", + "timestamp" => 1234567890 + ]; + $entryTwo = [ + "level" => "ERROR", + "message" => "errorMessage", + "source" => "other", + "timestamp" => 1234567890 + ]; + $entryThree = [ + "level" => "LOG", + "message" => "logMessage", + "source" => "javascript", + "timestamp" => 1234567890 + ]; + $log = [ + $entryOne, + $entryTwo, + $entryThree + ]; + + $actual = BrowserLogUtil::getLogsOfType($log, 'console-api'); + + self::assertEquals($entryOne, $actual[0]); + } + + public function testFilterLogsOfType() + { + $entryOne = [ + "level" => "WARNING", + "message" => "warningMessage", + "source" => "console-api", + "timestamp" => 1234567890 + ]; + $entryTwo = [ + "level" => "ERROR", + "message" => "errorMessage", + "source" => "other", + "timestamp" => 1234567890 + ]; + $entryThree = [ + "level" => "LOG", + "message" => "logMessage", + "source" => "javascript", + "timestamp" => 1234567890 + ]; + $log = [ + $entryOne, + $entryTwo, + $entryThree + ]; + + $actual = BrowserLogUtil::filterLogsOfType($log, 'console-api'); + + self::assertEquals($entryTwo, $actual[0]); + self::assertEquals($entryThree, $actual[1]); + } +} diff --git a/src/Magento/FunctionalTestingFramework/Extension/BrowserLogUtil.php b/src/Magento/FunctionalTestingFramework/Extension/BrowserLogUtil.php index 330c21ebf..a4f5c6d4c 100644 --- a/src/Magento/FunctionalTestingFramework/Extension/BrowserLogUtil.php +++ b/src/Magento/FunctionalTestingFramework/Extension/BrowserLogUtil.php @@ -39,7 +39,7 @@ public static function logErrors($module, $stepEvent) /** * Loops through given log and returns entries of the given type. * - * @param array $log + * @param array $log * @param string $type * @return array */ @@ -57,7 +57,7 @@ public static function getLogsOfType($log, $type) /** * Loops through given log and filters entries of the given type. * - * @param array $log + * @param array $log * @param string $type * @return array */ From d7d14c333efbe97836cde7d2fefbec6f05651249 Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Thu, 17 Oct 2019 11:57:33 -0500 Subject: [PATCH 015/888] MQE-1644: Add ability to see JS log in Allure - Added documentation --- docs/configuration.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/configuration.md b/docs/configuration.md index c741e2f60..4af2c4e82 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -277,6 +277,24 @@ Example: CREDENTIAL_VAULT_SECRET_BASE_PATH=secret ``` +### ENABLE_BROWSER_LOG + +Enables addition of browser logs to Allure steps + +```conf +ENABLE_BROWSER_LOG=true +``` + +### BROWSER_LOG_BLACKLIST + +Blacklists types of browser log entries from appearing in Allure steps. + +Denoted in browser log entry as `"SOURCE": "type"`. + +```conf +BROWSER_LOG_BLACKLIST=other,console-api +``` + [`MAGENTO_CLI_COMMAND_PATH`]: #magento_cli_command_path From b7ee3f89eeb665e88a0c818f669944ff0f679bf2 Mon Sep 17 00:00:00 2001 From: Tom Reece Date: Fri, 18 Oct 2019 13:28:38 -0500 Subject: [PATCH 016/888] Work in progress before vacation --- .../Console/RunTestGroupCommand.php | 110 +++++++++++++++++- 1 file changed, 109 insertions(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php index 7f954c8fe..86b349f53 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php @@ -119,7 +119,7 @@ function ($type, $buffer) use ($output) { * @return string * @throws \Magento\FunctionalTestingFramework\Exceptions\XmlException */ - private function getGroupAndSuiteConfiguration(array $groups) + private function OLDgetGroupAndSuiteConfiguration(array $groups) { $testConfiguration['tests'] = []; $testConfiguration['suites'] = null; @@ -139,4 +139,112 @@ private function getGroupAndSuiteConfiguration(array $groups) $testConfigurationJson = json_encode($testConfiguration); return $testConfigurationJson; } + + /** first attempt at an implementation, needs tested */ + private function first_attempt_getGroupAndSuiteConfiguration(array $groups) + { + $testConfiguration['tests'] = []; + $testConfiguration['suites'] = null; + $availableSuites = SuiteObjectHandler::getInstance()->getAllObjects(); + + // iterate through all group names passed into the command + foreach ($groups as $group) { + if (array_key_exists($group, $availableSuites)) { + // group is actually a suite, so add it to the suites array + $testConfiguration['suites'][$group] = []; + } else { + // group is a group, so find and add all tests from that group to the tests array + $testConfiguration['tests'] = array_merge( + $testConfiguration['tests'], + array_keys(TestObjectHandler::getInstance()->getTestsByGroup($group)) + ); + } + } + + // find all tests that are in suites and build pairs + $testsInSuites = SuiteObjectHandler::getInstance()->getAllTestReferences(); + $suiteToTestPair = []; + foreach ($testConfiguration['tests'] as $test) { + if (array_key_exists($test, $testsInSuites)) { + $suites = $testsInSuites[$test]; + foreach ($suites as $suite) { + $suiteToTestPair[] = "$suite:$test"; + } + } + } + + // add tests to suites array + $diff = []; + foreach ($suiteToTestPair as $pair) { + list($suite, $test) = explode(":", $pair); + $testConfiguration['suites'][$suite][] = $test; + $diff[] = $test; + } + + // remove tests in suites from the tests array + $testConfiguration['tests'] = array_diff($testConfiguration['tests'], $diff); + + // encode and return the result + $testConfigurationJson = json_encode($testConfiguration); + return $testConfigurationJson; + } + + /** second attempt at a cleaner implementation, needs work */ + private function getGroupAndSuiteConfiguration(array $groupOrSuiteNames) + { + $result['tests'] = []; + $result['suites'] = null; + + $groups = []; + $suites = []; + + $allSuites = SuiteObjectHandler::getInstance()->getAllObjects(); + $testsInSuites = SuiteObjectHandler::getInstance()->getAllTestReferences(); + + foreach ($groupOrSuiteNames as $groupOrSuiteName) { + if (array_key_exists($groupOrSuiteName, $allSuites)) { + $suites[] = $groupOrSuiteName; + } else { + $groups[] = $groupOrSuiteName; + } + } + + foreach ($suites as $suite) { + $result['suites'][$suite] = []; + } + + foreach ($groups as $group) { + $testsInGroup = TestObjectHandler::getInstance()->getTestsByGroup($group); + + $testsInGroupAndNotInAnySuite = array_diff( + array_keys($testsInGroup), + array_keys($testsInSuites) + ); + + $testsInGroupAndInAnySuite = array_diff( + array_keys($testsInGroup), + $testsInGroupAndNotInAnySuite + ); + + foreach ($testsInGroupAndInAnySuite as $testInGroupAndInAnySuite) { + $cat = $testsInSuites[$testInGroupAndInAnySuite][0]; + $dog[$cat][] = $testInGroupAndInAnySuite; + + /* + * todo -- I left off here. Code works so far. + * I need to take this $dog array and put into the $result['suites'] array + * and then test it thoroughly + */ + + } + + $result['tests'] = array_merge( + $result['tests'], + $testsInGroupAndNotInAnySuite + ); + } + + $json = json_encode($result); + return $json; + } } From 6f9dc12d3a6436d815371551f88c2cd36d7dbd63 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Thu, 17 Oct 2019 10:41:28 -0500 Subject: [PATCH 017/888] MQE-1796: Magento Git vs Composer and MFTF --- docs/guides/git-vs-composer-install.md | 72 ++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 docs/guides/git-vs-composer-install.md diff --git a/docs/guides/git-vs-composer-install.md b/docs/guides/git-vs-composer-install.md new file mode 100644 index 000000000..a96085fd8 --- /dev/null +++ b/docs/guides/git-vs-composer-install.md @@ -0,0 +1,72 @@ +#Git vs Composer Installation of Magento with MFTF + + +###How to download Magento + MFTF from GitHub? + +If you are planning on contributing a PR to the Magento 2 codebase, you can download Magento 2 from GitHub. Contribution to the codebase is done using the 'fork and pull' model where contributors maintain their own fork of the repo. This repo is then used to submit a pull request to the base repo. + +Install guide: [GitHub Installation](https://devdocs.magento.com/mftf/docs/getting-started.html) + +###How to download Magento + MFTF via Composer? + +Composer install downloads released packages of Magento 2 from the composer repo [https://repo.magento.com](https://repo.magento.com). + +All Magento modules and their MFTF tests are put under `` directory for convenience of 3rd party developers. With this setup, you can keep your custom modules separate from the core. You can also develop modules in a separate VCS repository and add them to your `composer.json` which will allow them to be installed into the `vendor` directory. + +Install guide: [Composer based Installation](https://devdocs.magento.com/guides/v2.3/install-gde/composer.html) + + +###Managing MFTF test artifacts - Composer vs GitHub + +####Via GitHub: + +Cloning Magento 2 git repository is a way of installing when you don't have to worry frequently about matching the codebase with production. Your version control system generally holds and manages your `app/code` folder and you can do manual ad-hoc development here. + +####Via composer: + +Magento 2 advocates the use of composer for managing modules. When you install a module through composer, it is added to `vendor//` + +If you are developing your own module or adding MFTF tests to the module, you should not edit `vendor` because a composer update could clobber your changes. Instead, you can override a module under `vendor`, by adding files or cloning your module specific git repo to `app/code//`. + +If you want to distribute the module and its tests, you can initialize a git repo and create a [composer package](https://devdocs.magento.com/guides/v2.3/extension-dev-guide/package/package_module.html). In this way others will be able to download and install your module and access your tests as a composer package, in their `` folder. + + +###MFTF test artifacts location + +- For GitHub installation, MFTF test artifacts are located at `/app/code///Test/Mftf/`. This is the directory to create new tests or maintain existing ones. + +- For Composer based installation, MFTF test artifacts are located at `/vendor///Test/Mftf/`. This is the directory to run tests fetched by Composer. + +The file structure under both paths is the same as below: + +```tree + +├── ActionGroup +│   └── ... +├── Data +│   └── ... +├── Metadata +│   └── ... +├── Page +│   └── ... +├── Section +│   └── ... +└── Test + └── ... +``` + +###How ModuleResolver reads modules + +In either of the installations, all tests and test data are read and merged by MFTF's ModuleResolver in the order indicated the below: + +1. `/app/code///Test/Mftf/` +2. `/vendor///Test/Mftf/` + +###Conclusion + +There are no differences from MFTF's perspective between having the test artifacts in `app/code` or in `/vendor` as it reads artifacts from both paths. It works the same. Composer based install may benefit teams when there's a need to match file systems in dev and production. + +If you are a contributing developer with an understanding of Git and Composer commands, you can choose the GitHub installation method instead. + + + From e345f05f9ea9aef5031017ea0bfeeaf570d47d72 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Fri, 18 Oct 2019 11:28:24 -0500 Subject: [PATCH 018/888] MQE-1796: Magento Git vs Composer and MFTF Addressed review comments --- docs/guides/git-vs-composer-install.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/guides/git-vs-composer-install.md b/docs/guides/git-vs-composer-install.md index a96085fd8..93153c31d 100644 --- a/docs/guides/git-vs-composer-install.md +++ b/docs/guides/git-vs-composer-install.md @@ -1,13 +1,13 @@ #Git vs Composer Installation of Magento with MFTF -###How to download Magento + MFTF from GitHub? +###GitHub Installation If you are planning on contributing a PR to the Magento 2 codebase, you can download Magento 2 from GitHub. Contribution to the codebase is done using the 'fork and pull' model where contributors maintain their own fork of the repo. This repo is then used to submit a pull request to the base repo. Install guide: [GitHub Installation](https://devdocs.magento.com/mftf/docs/getting-started.html) -###How to download Magento + MFTF via Composer? +###Composer based Installation Composer install downloads released packages of Magento 2 from the composer repo [https://repo.magento.com](https://repo.magento.com). @@ -16,7 +16,7 @@ All Magento modules and their MFTF tests are put under `` directory for Install guide: [Composer based Installation](https://devdocs.magento.com/guides/v2.3/install-gde/composer.html) -###Managing MFTF test artifacts - Composer vs GitHub +###Managing modules - Composer vs GitHub ####Via GitHub: @@ -57,7 +57,7 @@ The file structure under both paths is the same as below: ###How ModuleResolver reads modules -In either of the installations, all tests and test data are read and merged by MFTF's ModuleResolver in the order indicated the below: +In either of the installations, all tests and test data are read and merged by MFTF's ModuleResolver in the order indicated below: 1. `/app/code///Test/Mftf/` 2. `/vendor///Test/Mftf/` From 57f2eaadefe803e052ed9fd0a5ee056ca6dd5e67 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Fri, 18 Oct 2019 12:33:48 -0500 Subject: [PATCH 019/888] MQE-1796: Magento Git vs Composer and MFTF Addressed review comments --- docs/guides/git-vs-composer-install.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/guides/git-vs-composer-install.md b/docs/guides/git-vs-composer-install.md index 93153c31d..8a98d9921 100644 --- a/docs/guides/git-vs-composer-install.md +++ b/docs/guides/git-vs-composer-install.md @@ -5,7 +5,8 @@ If you are planning on contributing a PR to the Magento 2 codebase, you can download Magento 2 from GitHub. Contribution to the codebase is done using the 'fork and pull' model where contributors maintain their own fork of the repo. This repo is then used to submit a pull request to the base repo. -Install guide: [GitHub Installation](https://devdocs.magento.com/mftf/docs/getting-started.html) +Install guide: [GitHub Installation](https://devdocs.magento.com/guides/v2.3/install-gde/prereq/dev_install.html) + ###Composer based Installation @@ -16,6 +17,13 @@ All Magento modules and their MFTF tests are put under `` directory for Install guide: [Composer based Installation](https://devdocs.magento.com/guides/v2.3/install-gde/composer.html) +### MFTF Installation + +After installing your Magento project in either of the above ways, the composer dependency `magento/magento2-functional-testing-framework` allows you to download and install MFTF. MFTF will be embedded in your Magento 2 installation and will cover your project with functional tests. + +If you want to contribute a PR into MFTF codebase, you will need to install MFTF in the [Standalone] mode. + + ###Managing modules - Composer vs GitHub ####Via GitHub: @@ -55,6 +63,7 @@ The file structure under both paths is the same as below: └── ... ``` + ###How ModuleResolver reads modules In either of the installations, all tests and test data are read and merged by MFTF's ModuleResolver in the order indicated below: @@ -62,6 +71,7 @@ In either of the installations, all tests and test data are read and merged by M 1. `/app/code///Test/Mftf/` 2. `/vendor///Test/Mftf/` + ###Conclusion There are no differences from MFTF's perspective between having the test artifacts in `app/code` or in `/vendor` as it reads artifacts from both paths. It works the same. Composer based install may benefit teams when there's a need to match file systems in dev and production. @@ -69,4 +79,6 @@ There are no differences from MFTF's perspective between having the test artifac If you are a contributing developer with an understanding of Git and Composer commands, you can choose the GitHub installation method instead. + +[Standalone]: ../getting-started.html#set-up-a-standalone-mftf From 6cfdc49b70145540d9dc177618aa32060240b8c8 Mon Sep 17 00:00:00 2001 From: DanieliMi <31039652+DanieliMi@users.noreply.github.com> Date: Tue, 15 Oct 2019 17:09:37 +0200 Subject: [PATCH 020/888] #339 Add information about web server configuration --- docs/getting-started.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 626cca31b..92c39b983 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -80,7 +80,10 @@ To enable the **Admin Account Sharing** setting, to avoid unpredictable logout d 3. Set **Add Secret Key to URLs** to **No**. 4. Click **Save Config**. -### Nginx settings {#nginx-settings} +### Webserver configuration {#web-server-configuration} +The MFTF doesn't support executing CLI commands if your web server points to `/pub` directory as recommended in the [Installation Guide][Installation Guide docroot]. For the MFTF to execute the CLI commands, the web server must point to the Magento root directory. + +#### Nginx settings {#nginx-settings} If Nginx Web server is used on your development environment then **Use Web Server Rewrites** setting in **Stores** > Settings > **Configuration** > **Web** > **Search Engine Optimization** must be set to **Yes**. @@ -323,3 +326,4 @@ allure serve dev/tests/_output/allure-results/ [Set up a standalone MFTF]: #set-up-a-standalone-mftf [test suite]: suite.html [Find your MFTF version]: introduction.html#find-your-mftf-version +[Installation Guide docroot]: https://devdocs.magento.com/guides/v2.3/install-gde/tutorials/change-docroot-to-pub.html From 4b8fd6026653f949b6605175946dc089d1670003 Mon Sep 17 00:00:00 2001 From: Donald Booth Date: Mon, 21 Oct 2019 10:10:41 -0500 Subject: [PATCH 021/888] Formatting and small edits --- docs/getting-started.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 92c39b983..754786811 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -2,8 +2,8 @@
[Find your MFTF version][] of the MFTF. -The latest Magento 2.3 release supports MFTF 2.3.13. -The latest Magento 2.2 release supports MFTF 2.3.8. +The latest Magento 2.3.x release supports MFTF 2.4.5. +The latest Magento 2.2.x release supports MFTF 2.4.5.
## Prepare environment {#prepare-environment} @@ -18,6 +18,7 @@ Make sure that you have the following software installed and configured on your
[PhpStorm] supports [Codeception test execution][], which is helpful when debugging.
+ ## Install Magento {#install-magento} Use instructions below to install Magento. @@ -81,7 +82,8 @@ To enable the **Admin Account Sharing** setting, to avoid unpredictable logout d 4. Click **Save Config**. ### Webserver configuration {#web-server-configuration} -The MFTF doesn't support executing CLI commands if your web server points to `/pub` directory as recommended in the [Installation Guide][Installation Guide docroot]. For the MFTF to execute the CLI commands, the web server must point to the Magento root directory. + +The MFTF does not support executing CLI commands if your web server points to `/pub` directory as recommended in the [Installation Guide][Installation Guide docroot]. For the MFTF to execute the CLI commands, the web server must point to the Magento root directory. #### Nginx settings {#nginx-settings} From c17c746536b82452ef98a45e3c624e112b85261b Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Mon, 21 Oct 2019 13:33:08 -0500 Subject: [PATCH 022/888] MQE-1650: update MFTF configuration to read Test entities from new location - Reduced requirements of composer.json to 1.4 (magento 2.2) --- composer.json | 2 +- composer.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index f980005c1..a50171dc1 100755 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ "ext-curl": "*", "allure-framework/allure-codeception": "~1.3.0", "codeception/codeception": "~2.3.4 || ~2.4.0 ", - "composer/composer": "^1.6", + "composer/composer": "^1.4", "consolidation/robo": "^1.0.0", "csharpru/vault-php": "~3.5.3", "csharpru/vault-php-guzzle6-transport": "^2.0", diff --git a/composer.lock b/composer.lock index 275ae9778..416ed077c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "beb8473a3c21b83da864289149fc03b4", + "content-hash": "06a363880f237913287952e19a7a8fd3", "packages": [ { "name": "allure-framework/allure-codeception", @@ -250,7 +250,7 @@ { "name": "Tobias Nyholm", "email": "tobias.nyholm@gmail.com", - "homepage": "https://github.com/nyholm" + "homepage": "https://github.com/Nyholm" } ], "description": "Library of all the php-cache adapters", From 39d987a4e08d393cb994c362672f50900aa0e385 Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Tue, 22 Oct 2019 09:00:30 -0500 Subject: [PATCH 023/888] MQE-1644: Add ability to see JS log in Allure - Moved redundant logic --- .../Extension/BrowserLogUtil.php | 23 ++++++++----------- .../Extension/TestContextExtension.php | 5 ++-- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Extension/BrowserLogUtil.php b/src/Magento/FunctionalTestingFramework/Extension/BrowserLogUtil.php index a4f5c6d4c..ca9d2be9e 100644 --- a/src/Magento/FunctionalTestingFramework/Extension/BrowserLogUtil.php +++ b/src/Magento/FunctionalTestingFramework/Extension/BrowserLogUtil.php @@ -16,23 +16,20 @@ class BrowserLogUtil const ERROR_TYPE_JAVASCRIPT = "javascript"; /** - * Loops through stepEvent for browser log entries + * Loops throw errors in log and logs them to allure. Uses Module to set the error itself * - * @param \Magento\FunctionalTestingFramework\Module\MagentoWebDriver $module - * @param \Codeception\Event\StepEvent $stepEvent + * @param array $log + * @param \Codeception\Module\WebDriver $module + * @param \Codeception\Event\StepEvent $stepEvent * @return void */ - public static function logErrors($module, $stepEvent) + public static function logErrors($log, $module, $stepEvent) { - //Types available should be "server", "browser", "driver". Only care about browser at the moment. - if (in_array(self::LOG_TYPE_BROWSER, $module->webDriver->manage()->getAvailableLogTypes())) { - $browserLogEntries = $module->webDriver->manage()->getLog(self::LOG_TYPE_BROWSER); - $jsErrors = self::getLogsOfType($browserLogEntries, self::ERROR_TYPE_JAVASCRIPT); - foreach ($jsErrors as $entry) { - self::logError(self::ERROR_TYPE_JAVASCRIPT, $stepEvent, $entry); - //Set javascript error in MagentoWebDriver internal array - $module->setJsError("ERROR({$entry["level"]}) - " . $entry["message"]); - } + $jsErrors = self::getLogsOfType($log, self::ERROR_TYPE_JAVASCRIPT); + foreach ($jsErrors as $entry) { + self::logError(self::ERROR_TYPE_JAVASCRIPT, $stepEvent, $entry); + //Set javascript error in MagentoWebDriver internal array + $module->setJsError("ERROR({$entry["level"]}) - " . $entry["message"]); } } diff --git a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php index 10b7621b4..9fe7adb7a 100644 --- a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php +++ b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php @@ -174,17 +174,16 @@ public function beforeStep(\Codeception\Event\StepEvent $e) */ public function afterStep(\Codeception\Event\StepEvent $e) { + $browserLog = $this->getDriver()->webDriver->manage()->getLog("browser"); if (getenv('ENABLE_BROWSER_LOG')) { - $browserLog = $this->getDriver()->webDriver->manage()->getLog("browser"); foreach (explode(',', getenv('BROWSER_LOG_BLACKLIST')) as $source) { $browserLog = BrowserLogUtil::filterLogsOfType($browserLog, $source); } - if (!empty($browserLog)) { AllureHelper::addAttachmentToCurrentStep(json_encode($browserLog, JSON_PRETTY_PRINT), "Browser Log"); } } - BrowserLogUtil::logErrors($this->getDriver(), $e); + BrowserLogUtil::logErrors($browserLog, $this->getDriver(), $e); } /** From 49d318e7f52962b8425c448871cde4b7ede9582e Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Tue, 22 Oct 2019 10:01:05 -0500 Subject: [PATCH 024/888] MQE-1796: Magento Git vs Composer and MFTF Addressed review comments --- docs/guides/git-vs-composer-install.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/guides/git-vs-composer-install.md b/docs/guides/git-vs-composer-install.md index 8a98d9921..baec08471 100644 --- a/docs/guides/git-vs-composer-install.md +++ b/docs/guides/git-vs-composer-install.md @@ -1,14 +1,14 @@ -#Git vs Composer Installation of Magento with MFTF +# Git vs Composer Installation of Magento with MFTF -###GitHub Installation +### GitHub Installation If you are planning on contributing a PR to the Magento 2 codebase, you can download Magento 2 from GitHub. Contribution to the codebase is done using the 'fork and pull' model where contributors maintain their own fork of the repo. This repo is then used to submit a pull request to the base repo. Install guide: [GitHub Installation](https://devdocs.magento.com/guides/v2.3/install-gde/prereq/dev_install.html) -###Composer based Installation +### Composer based Installation Composer install downloads released packages of Magento 2 from the composer repo [https://repo.magento.com](https://repo.magento.com). @@ -24,13 +24,13 @@ After installing your Magento project in either of the above ways, the composer If you want to contribute a PR into MFTF codebase, you will need to install MFTF in the [Standalone] mode. -###Managing modules - Composer vs GitHub +### Managing modules - Composer vs GitHub -####Via GitHub: +#### Via GitHub: Cloning Magento 2 git repository is a way of installing when you don't have to worry frequently about matching the codebase with production. Your version control system generally holds and manages your `app/code` folder and you can do manual ad-hoc development here. -####Via composer: +#### Via composer: Magento 2 advocates the use of composer for managing modules. When you install a module through composer, it is added to `vendor//` @@ -39,11 +39,11 @@ If you are developing your own module or adding MFTF tests to the module, you sh If you want to distribute the module and its tests, you can initialize a git repo and create a [composer package](https://devdocs.magento.com/guides/v2.3/extension-dev-guide/package/package_module.html). In this way others will be able to download and install your module and access your tests as a composer package, in their `` folder. -###MFTF test artifacts location +### MFTF test artifacts location -- For GitHub installation, MFTF test artifacts are located at `/app/code///Test/Mftf/`. This is the directory to create new tests or maintain existing ones. +- For GitHub installation, MFTF test materials are located at `/app/code///Test/Mftf/`. This is the directory to create new tests or maintain existing ones. -- For Composer based installation, MFTF test artifacts are located at `/vendor///Test/Mftf/`. This is the directory to run tests fetched by Composer. +- For Composer based installation, MFTF test materials are located at `/vendor///Test/Mftf/`. This is the directory to run tests fetched by Composer. The file structure under both paths is the same as below: @@ -64,7 +64,7 @@ The file structure under both paths is the same as below: ``` -###How ModuleResolver reads modules +### How ModuleResolver reads modules In either of the installations, all tests and test data are read and merged by MFTF's ModuleResolver in the order indicated below: @@ -72,9 +72,9 @@ In either of the installations, all tests and test data are read and merged by M 2. `/vendor///Test/Mftf/` -###Conclusion +### Conclusion -There are no differences from MFTF's perspective between having the test artifacts in `app/code` or in `/vendor` as it reads artifacts from both paths. It works the same. Composer based install may benefit teams when there's a need to match file systems in dev and production. +There are no differences from MFTF's perspective between having the test materials in `app/code` or in `/vendor` as it reads artifacts from both paths. It works the same. Composer based install may benefit teams when there's a need to match file systems in dev and production. If you are a contributing developer with an understanding of Git and Composer commands, you can choose the GitHub installation method instead. From 451430dff1aae64bffe4a28e9cd205fa3550cbe8 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Tue, 22 Oct 2019 10:13:27 -0500 Subject: [PATCH 025/888] MQE-1833: CHANGELOG.MD and Composer version bump --- CHANGELOG.md | 19 + bin/mftf | 2 +- composer.json | 2 +- composer.lock | 1699 ++++++++++++++++++++++++++++++------------------- 4 files changed, 1078 insertions(+), 644 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54189d745..e54636819 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ Magento Functional Testing Framework Changelog ================================================ +2.5.2 +----- + +* Traceability + * Added test's filepath to Allure reports for ease of debugging. + +* Modularity + * Refactored problem methods to reduce cyclomatic complexity. + +* Maintainability + * Added support to read MFTF test entities from path of MFTF test packages. + +### Fixes +* Added escaping for `magentoCLI` commands. +* Fixed issue with builds due to absence of AcceptanceTester class. +* Removed path deprecation warning from ModuleResolver. + +### GitHub Issues/Pull requests: +* [#348](https://github.com/magento/magento2-functional-testing-framework/pull/348) -- executeInSelenium command fixed to prevent escaping double quotes. 2.5.1 ----- diff --git a/bin/mftf b/bin/mftf index b978d99ee..355a851c8 100755 --- a/bin/mftf +++ b/bin/mftf @@ -29,7 +29,7 @@ try { try { $application = new Symfony\Component\Console\Application(); $application->setName('Magento Functional Testing Framework CLI'); - $application->setVersion('2.5.1'); + $application->setVersion('2.5.2'); /** @var \Magento\FunctionalTestingFramework\Console\CommandListInterface $commandList */ $commandList = new \Magento\FunctionalTestingFramework\Console\CommandList; foreach ($commandList->getCommands() as $command) { diff --git a/composer.json b/composer.json index a50171dc1..bc2592d97 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "2.5.1", + "version": "2.5.2", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index 416ed077c..fb8cb2056 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "06a363880f237913287952e19a7a8fd3", + "content-hash": "5d566c152481274493082bdabb128c70", "packages": [ { "name": "allure-framework/allure-codeception", @@ -59,25 +59,26 @@ }, { "name": "allure-framework/allure-php-api", - "version": "1.1.4", + "version": "1.1.5", "source": { "type": "git", - "url": "https://github.com/allure-framework/allure-php-adapter-api.git", - "reference": "a462a0da121681577033e13c123b6cc4e89cdc64" + "url": "https://github.com/allure-framework/allure-php-commons.git", + "reference": "c7a675823ad75b8e02ddc364baae21668e7c4e88" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/allure-framework/allure-php-adapter-api/zipball/a462a0da121681577033e13c123b6cc4e89cdc64", - "reference": "a462a0da121681577033e13c123b6cc4e89cdc64", + "url": "https://api.github.com/repos/allure-framework/allure-php-commons/zipball/c7a675823ad75b8e02ddc364baae21668e7c4e88", + "reference": "c7a675823ad75b8e02ddc364baae21668e7c4e88", "shasum": "" }, "require": { - "jms/serializer": ">=0.16.0", - "moontoast/math": ">=1.1.0", + "jms/serializer": "^0.16.0", "php": ">=5.4.0", - "phpunit/phpunit": ">=4.0.0", - "ramsey/uuid": ">=3.0.0", - "symfony/http-foundation": ">=2.0" + "ramsey/uuid": "^3.0.0", + "symfony/http-foundation": "^2.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0.0" }, "type": "library", "autoload": { @@ -107,20 +108,20 @@ "php", "report" ], - "time": "2016-12-07T12:15:46+00:00" + "time": "2018-05-25T14:02:11+00:00" }, { "name": "behat/gherkin", - "version": "v4.4.5", + "version": "v4.6.0", "source": { "type": "git", "url": "https://github.com/Behat/Gherkin.git", - "reference": "5c14cff4f955b17d20d088dec1bde61c0539ec74" + "reference": "ab0a02ea14893860bca00f225f5621d351a3ad07" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Behat/Gherkin/zipball/5c14cff4f955b17d20d088dec1bde61c0539ec74", - "reference": "5c14cff4f955b17d20d088dec1bde61c0539ec74", + "url": "https://api.github.com/repos/Behat/Gherkin/zipball/ab0a02ea14893860bca00f225f5621d351a3ad07", + "reference": "ab0a02ea14893860bca00f225f5621d351a3ad07", "shasum": "" }, "require": { @@ -128,8 +129,8 @@ }, "require-dev": { "phpunit/phpunit": "~4.5|~5", - "symfony/phpunit-bridge": "~2.7|~3", - "symfony/yaml": "~2.3|~3" + "symfony/phpunit-bridge": "~2.7|~3|~4", + "symfony/yaml": "~2.3|~3|~4" }, "suggest": { "symfony/yaml": "If you want to parse features, represented in YAML files" @@ -166,7 +167,7 @@ "gherkin", "parser" ], - "time": "2016-10-30T11:50:56+00:00" + "time": "2019-01-16T14:22:17+00:00" }, { "name": "cache/cache", @@ -250,7 +251,7 @@ { "name": "Tobias Nyholm", "email": "tobias.nyholm@gmail.com", - "homepage": "https://github.com/Nyholm" + "homepage": "https://github.com/nyholm" } ], "description": "Library of all the php-cache adapters", @@ -263,31 +264,28 @@ }, { "name": "codeception/codeception", - "version": "2.3.9", + "version": "2.4.5", "source": { "type": "git", "url": "https://github.com/Codeception/Codeception.git", - "reference": "104f46fa0bde339f1bcc3a375aac21eb36e65a1e" + "reference": "5fee32d5c82791548931cbc34806b4de6aa1abfc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/Codeception/zipball/104f46fa0bde339f1bcc3a375aac21eb36e65a1e", - "reference": "104f46fa0bde339f1bcc3a375aac21eb36e65a1e", + "url": "https://api.github.com/repos/Codeception/Codeception/zipball/5fee32d5c82791548931cbc34806b4de6aa1abfc", + "reference": "5fee32d5c82791548931cbc34806b4de6aa1abfc", "shasum": "" }, "require": { - "behat/gherkin": "~4.4.0", - "codeception/stub": "^1.0", + "behat/gherkin": "^4.4.0", + "codeception/phpunit-wrapper": "^6.0.9|^7.0.6", + "codeception/stub": "^2.0", "ext-json": "*", "ext-mbstring": "*", "facebook/webdriver": ">=1.1.3 <2.0", "guzzlehttp/guzzle": ">=4.1.4 <7.0", "guzzlehttp/psr7": "~1.0", - "php": ">=5.4.0 <8.0", - "phpunit/php-code-coverage": ">=2.2.4 <6.0", - "phpunit/phpunit": ">=4.8.28 <5.0.0 || >=5.6.3 <7.0", - "sebastian/comparator": ">1.1 <3.0", - "sebastian/diff": ">=1.4 <3.0", + "php": ">=5.6.0 <8.0", "symfony/browser-kit": ">=2.7 <5.0", "symfony/console": ">=2.7 <5.0", "symfony/css-selector": ">=2.7 <5.0", @@ -353,26 +351,66 @@ "functional testing", "unit testing" ], - "time": "2018-02-26T23:29:41+00:00" + "time": "2018-08-01T07:21:49+00:00" }, { - "name": "codeception/stub", - "version": "1.0.4", + "name": "codeception/phpunit-wrapper", + "version": "7.0.6", "source": { "type": "git", - "url": "https://github.com/Codeception/Stub.git", - "reference": "681b62348837a5ef07d10d8a226f5bc358cc8805" + "url": "https://github.com/Codeception/phpunit-wrapper.git", + "reference": "e8528cb777cf5a5ccea1cf57a3522b142625d1b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/Stub/zipball/681b62348837a5ef07d10d8a226f5bc358cc8805", - "reference": "681b62348837a5ef07d10d8a226f5bc358cc8805", + "url": "https://api.github.com/repos/Codeception/phpunit-wrapper/zipball/e8528cb777cf5a5ccea1cf57a3522b142625d1b5", + "reference": "e8528cb777cf5a5ccea1cf57a3522b142625d1b5", "shasum": "" }, "require": { - "phpunit/phpunit-mock-objects": ">2.3 <7.0" + "phpunit/php-code-coverage": "^6.0", + "phpunit/phpunit": "^7.0", + "sebastian/comparator": "^2.0", + "sebastian/diff": "^3.0" }, "require-dev": { + "codeception/specify": "*", + "vlucas/phpdotenv": "^2.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Codeception\\PHPUnit\\": "src\\" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Davert", + "email": "davert.php@resend.cc" + } + ], + "description": "PHPUnit classes used by Codeception", + "time": "2018-03-31T18:49:51+00:00" + }, + { + "name": "codeception/stub", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/Codeception/Stub.git", + "reference": "f50bc271f392a2836ff80690ce0c058efe1ae03e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/Stub/zipball/f50bc271f392a2836ff80690ce0c058efe1ae03e", + "reference": "f50bc271f392a2836ff80690ce0c058efe1ae03e", + "shasum": "" + }, + "require": { "phpunit/phpunit": ">=4.8 <8.0" }, "type": "library", @@ -386,7 +424,7 @@ "MIT" ], "description": "Flexible Stub wrapper for PHPUnit's Mock Builder", - "time": "2018-05-17T09:31:08+00:00" + "time": "2018-07-26T11:55:37+00:00" }, { "name": "composer/ca-bundle", @@ -692,34 +730,78 @@ }, { "name": "consolidation/annotated-command", - "version": "2.9.1", + "version": "2.12.0", "source": { "type": "git", "url": "https://github.com/consolidation/annotated-command.git", - "reference": "4bdbb8fa149e1cc1511bd77b0bc4729fd66bccac" + "reference": "512a2e54c98f3af377589de76c43b24652bcb789" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/annotated-command/zipball/4bdbb8fa149e1cc1511bd77b0bc4729fd66bccac", - "reference": "4bdbb8fa149e1cc1511bd77b0bc4729fd66bccac", + "url": "https://api.github.com/repos/consolidation/annotated-command/zipball/512a2e54c98f3af377589de76c43b24652bcb789", + "reference": "512a2e54c98f3af377589de76c43b24652bcb789", "shasum": "" }, "require": { - "consolidation/output-formatters": "^3.1.12", - "php": ">=5.4.0", + "consolidation/output-formatters": "^3.4", + "php": ">=5.4.5", "psr/log": "^1", "symfony/console": "^2.8|^3|^4", "symfony/event-dispatcher": "^2.5|^3|^4", "symfony/finder": "^2.5|^3|^4" }, "require-dev": { - "g1a/composer-test-scenarios": "^2", + "g1a/composer-test-scenarios": "^3", + "php-coveralls/php-coveralls": "^1", "phpunit/phpunit": "^6", - "satooshi/php-coveralls": "^2", "squizlabs/php_codesniffer": "^2.7" }, "type": "library", "extra": { + "scenarios": { + "symfony4": { + "require": { + "symfony/console": "^4.0" + }, + "config": { + "platform": { + "php": "7.1.3" + } + } + }, + "symfony2": { + "require": { + "symfony/console": "^2.8" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.36" + }, + "remove": [ + "php-coveralls/php-coveralls" + ], + "config": { + "platform": { + "php": "5.4.8" + } + }, + "scenario-options": { + "create-lockfile": "false" + } + }, + "phpunit4": { + "require-dev": { + "phpunit/phpunit": "^4.8.36" + }, + "remove": [ + "php-coveralls/php-coveralls" + ], + "config": { + "platform": { + "php": "5.4.8" + } + } + } + }, "branch-alias": { "dev-master": "2.x-dev" } @@ -740,20 +822,20 @@ } ], "description": "Initialize Symfony Console commands from annotated command class methods.", - "time": "2018-09-19T17:47:18+00:00" + "time": "2019-03-08T16:55:03+00:00" }, { "name": "consolidation/config", - "version": "1.1.1", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/consolidation/config.git", - "reference": "925231dfff32f05b787e1fddb265e789b939cf4c" + "reference": "cac1279bae7efb5c7fb2ca4c3ba4b8eb741a96c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/config/zipball/925231dfff32f05b787e1fddb265e789b939cf4c", - "reference": "925231dfff32f05b787e1fddb265e789b939cf4c", + "url": "https://api.github.com/repos/consolidation/config/zipball/cac1279bae7efb5c7fb2ca4c3ba4b8eb741a96c1", + "reference": "cac1279bae7efb5c7fb2ca4c3ba4b8eb741a96c1", "shasum": "" }, "require": { @@ -762,9 +844,9 @@ "php": ">=5.4.0" }, "require-dev": { - "g1a/composer-test-scenarios": "^1", + "g1a/composer-test-scenarios": "^3", + "php-coveralls/php-coveralls": "^1", "phpunit/phpunit": "^5", - "satooshi/php-coveralls": "^1.0", "squizlabs/php_codesniffer": "2.*", "symfony/console": "^2.5|^3|^4", "symfony/yaml": "^2.8.11|^3|^4" @@ -774,6 +856,33 @@ }, "type": "library", "extra": { + "scenarios": { + "symfony4": { + "require-dev": { + "symfony/console": "^4.0" + }, + "config": { + "platform": { + "php": "7.1.3" + } + } + }, + "symfony2": { + "require-dev": { + "symfony/console": "^2.8", + "symfony/event-dispatcher": "^2.8", + "phpunit/phpunit": "^4.8.36" + }, + "remove": [ + "php-coveralls/php-coveralls" + ], + "config": { + "platform": { + "php": "5.4.8" + } + } + } + }, "branch-alias": { "dev-master": "1.x-dev" } @@ -794,35 +903,76 @@ } ], "description": "Provide configuration services for a commandline tool.", - "time": "2018-10-24T17:55:35+00:00" + "time": "2019-03-03T19:37:04+00:00" }, { "name": "consolidation/log", - "version": "1.0.6", + "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/consolidation/log.git", - "reference": "dfd8189a771fe047bf3cd669111b2de5f1c79395" + "reference": "b2e887325ee90abc96b0a8b7b474cd9e7c896e3a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/log/zipball/dfd8189a771fe047bf3cd669111b2de5f1c79395", - "reference": "dfd8189a771fe047bf3cd669111b2de5f1c79395", + "url": "https://api.github.com/repos/consolidation/log/zipball/b2e887325ee90abc96b0a8b7b474cd9e7c896e3a", + "reference": "b2e887325ee90abc96b0a8b7b474cd9e7c896e3a", "shasum": "" }, "require": { - "php": ">=5.5.0", - "psr/log": "~1.0", + "php": ">=5.4.5", + "psr/log": "^1.0", "symfony/console": "^2.8|^3|^4" }, "require-dev": { - "g1a/composer-test-scenarios": "^1", - "phpunit/phpunit": "4.*", - "satooshi/php-coveralls": "^2", - "squizlabs/php_codesniffer": "2.*" + "g1a/composer-test-scenarios": "^3", + "php-coveralls/php-coveralls": "^1", + "phpunit/phpunit": "^6", + "squizlabs/php_codesniffer": "^2" }, "type": "library", "extra": { + "scenarios": { + "symfony4": { + "require": { + "symfony/console": "^4.0" + }, + "config": { + "platform": { + "php": "7.1.3" + } + } + }, + "symfony2": { + "require": { + "symfony/console": "^2.8" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.36" + }, + "remove": [ + "php-coveralls/php-coveralls" + ], + "config": { + "platform": { + "php": "5.4.8" + } + } + }, + "phpunit4": { + "require-dev": { + "phpunit/phpunit": "^4.8.36" + }, + "remove": [ + "php-coveralls/php-coveralls" + ], + "config": { + "platform": { + "php": "5.4.8" + } + } + } + }, "branch-alias": { "dev-master": "1.x-dev" } @@ -843,20 +993,20 @@ } ], "description": "Improved Psr-3 / Psr\\Log logger based on Symfony Console components.", - "time": "2018-05-25T18:14:39+00:00" + "time": "2019-01-01T17:30:51+00:00" }, { "name": "consolidation/output-formatters", - "version": "3.4.0", + "version": "3.5.0", "source": { "type": "git", "url": "https://github.com/consolidation/output-formatters.git", - "reference": "a942680232094c4a5b21c0b7e54c20cce623ae19" + "reference": "99ec998ffb697e0eada5aacf81feebfb13023605" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/output-formatters/zipball/a942680232094c4a5b21c0b7e54c20cce623ae19", - "reference": "a942680232094c4a5b21c0b7e54c20cce623ae19", + "url": "https://api.github.com/repos/consolidation/output-formatters/zipball/99ec998ffb697e0eada5aacf81feebfb13023605", + "reference": "99ec998ffb697e0eada5aacf81feebfb13023605", "shasum": "" }, "require": { @@ -866,11 +1016,10 @@ "symfony/finder": "^2.5|^3|^4" }, "require-dev": { - "g1a/composer-test-scenarios": "^2", + "g1a/composer-test-scenarios": "^3", + "php-coveralls/php-coveralls": "^1", "phpunit/phpunit": "^5.7.27", - "satooshi/php-coveralls": "^2", "squizlabs/php_codesniffer": "^2.7", - "symfony/console": "3.2.3", "symfony/var-dumper": "^2.8|^3|^4", "victorjonsson/markdowndocs": "^1.3" }, @@ -879,6 +1028,52 @@ }, "type": "library", "extra": { + "scenarios": { + "symfony4": { + "require": { + "symfony/console": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^6" + }, + "config": { + "platform": { + "php": "7.1.3" + } + } + }, + "symfony3": { + "require": { + "symfony/console": "^3.4", + "symfony/finder": "^3.4", + "symfony/var-dumper": "^3.4" + }, + "config": { + "platform": { + "php": "5.6.32" + } + } + }, + "symfony2": { + "require": { + "symfony/console": "^2.8" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.36" + }, + "remove": [ + "php-coveralls/php-coveralls" + ], + "config": { + "platform": { + "php": "5.4.8" + } + }, + "scenario-options": { + "create-lockfile": "false" + } + } + }, "branch-alias": { "dev-master": "3.x-dev" } @@ -899,29 +1094,28 @@ } ], "description": "Format text by applying transformations provided by plug-in formatters.", - "time": "2018-10-19T22:35:38+00:00" + "time": "2019-05-30T23:16:01+00:00" }, { "name": "consolidation/robo", - "version": "1.3.1", + "version": "1.4.10", "source": { "type": "git", "url": "https://github.com/consolidation/Robo.git", - "reference": "31f2d2562c4e1dcde70f2659eefd59aa9c7f5b2d" + "reference": "e5a6ca64cf1324151873672e484aceb21f365681" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/Robo/zipball/31f2d2562c4e1dcde70f2659eefd59aa9c7f5b2d", - "reference": "31f2d2562c4e1dcde70f2659eefd59aa9c7f5b2d", + "url": "https://api.github.com/repos/consolidation/Robo/zipball/e5a6ca64cf1324151873672e484aceb21f365681", + "reference": "e5a6ca64cf1324151873672e484aceb21f365681", "shasum": "" }, "require": { - "consolidation/annotated-command": "^2.8.2", - "consolidation/config": "^1.0.10", + "consolidation/annotated-command": "^2.10.2", + "consolidation/config": "^1.2", "consolidation/log": "~1", "consolidation/output-formatters": "^3.1.13", "consolidation/self-update": "^1", - "g1a/composer-test-scenarios": "^2", "grasmash/yaml-expander": "^1.3", "league/container": "^2.2", "php": ">=5.5.0", @@ -938,14 +1132,15 @@ "codeception/aspect-mock": "^1|^2.1.1", "codeception/base": "^2.3.7", "codeception/verify": "^0.3.2", + "g1a/composer-test-scenarios": "^3", "goaop/framework": "~2.1.2", "goaop/parser-reflection": "^1.1.0", "natxet/cssmin": "3.0.4", "nikic/php-parser": "^3.1.5", "patchwork/jsqueeze": "~2", - "pear/archive_tar": "^1.4.2", + "pear/archive_tar": "^1.4.4", + "php-coveralls/php-coveralls": "^1", "phpunit/php-code-coverage": "~2|~4", - "satooshi/php-coveralls": "^2", "squizlabs/php_codesniffer": "^2.8" }, "suggest": { @@ -959,9 +1154,36 @@ ], "type": "library", "extra": { + "scenarios": { + "symfony4": { + "require": { + "symfony/console": "^4" + }, + "config": { + "platform": { + "php": "7.1.3" + } + } + }, + "symfony2": { + "require": { + "symfony/console": "^2.8" + }, + "remove": [ + "goaop/framework" + ], + "config": { + "platform": { + "php": "5.5.9" + } + }, + "scenario-options": { + "create-lockfile": "false" + } + } + }, "branch-alias": { - "dev-master": "1.x-dev", - "dev-state": "1.x-dev" + "dev-master": "2.x-dev" } }, "autoload": { @@ -980,7 +1202,7 @@ } ], "description": "Modern task runner", - "time": "2018-08-17T18:44:18+00:00" + "time": "2019-07-29T15:40:50+00:00" }, { "name": "consolidation/self-update", @@ -1210,30 +1432,30 @@ }, { "name": "doctrine/annotations", - "version": "v1.4.0", + "version": "v1.8.0", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "54cacc9b81758b14e3ce750f205a393d52339e97" + "reference": "904dca4eb10715b92569fbcd79e201d5c349b6bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/54cacc9b81758b14e3ce750f205a393d52339e97", - "reference": "54cacc9b81758b14e3ce750f205a393d52339e97", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/904dca4eb10715b92569fbcd79e201d5c349b6bc", + "reference": "904dca4eb10715b92569fbcd79e201d5c349b6bc", "shasum": "" }, "require": { "doctrine/lexer": "1.*", - "php": "^5.6 || ^7.0" + "php": "^7.1" }, "require-dev": { "doctrine/cache": "1.*", - "phpunit/phpunit": "^5.7" + "phpunit/phpunit": "^7.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4.x-dev" + "dev-master": "1.7.x-dev" } }, "autoload": { @@ -1246,6 +1468,10 @@ "MIT" ], "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -1254,10 +1480,6 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -1274,7 +1496,7 @@ "docblock", "parser" ], - "time": "2017-02-24T16:22:25+00:00" + "time": "2019-10-01T18:55:10+00:00" }, { "name": "doctrine/cache", @@ -1415,32 +1637,34 @@ }, { "name": "doctrine/instantiator", - "version": "1.0.5", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + "reference": "a2c590166b2133a4633738648b6b064edae0814a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/a2c590166b2133a4633738648b6b064edae0814a", + "reference": "a2c590166b2133a4633738648b6b064edae0814a", "shasum": "" }, "require": { - "php": ">=5.3,<8.0-DEV" + "php": "^7.1" }, "require-dev": { - "athletic/athletic": "~0.1.8", + "doctrine/coding-standard": "^6.0", "ext-pdo": "*", "ext-phar": "*", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~2.0" + "phpbench/phpbench": "^0.13", + "phpstan/phpstan-phpunit": "^0.11", + "phpstan/phpstan-shim": "^0.11", + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { @@ -1460,12 +1684,12 @@ } ], "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://github.com/doctrine/instantiator", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", "keywords": [ "constructor", "instantiate" ], - "time": "2015-06-14T21:17:01+00:00" + "time": "2019-03-17T17:37:11+00:00" }, { "name": "doctrine/lexer", @@ -1529,16 +1753,16 @@ }, { "name": "facebook/webdriver", - "version": "1.6.0", + "version": "1.7.1", "source": { "type": "git", "url": "https://github.com/facebook/php-webdriver.git", - "reference": "bd8c740097eb9f2fc3735250fc1912bc811a954e" + "reference": "e43de70f3c7166169d0f14a374505392734160e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/bd8c740097eb9f2fc3735250fc1912bc811a954e", - "reference": "bd8c740097eb9f2fc3735250fc1912bc811a954e", + "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/e43de70f3c7166169d0f14a374505392734160e5", + "reference": "e43de70f3c7166169d0f14a374505392734160e5", "shasum": "" }, "require": { @@ -1585,7 +1809,7 @@ "selenium", "webdriver" ], - "time": "2018-05-16T17:37:13+00:00" + "time": "2019-06-13T08:02:18+00:00" }, { "name": "flow/jsonpath", @@ -1678,39 +1902,6 @@ ], "time": "2018-07-12T10:23:15+00:00" }, - { - "name": "g1a/composer-test-scenarios", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/g1a/composer-test-scenarios.git", - "reference": "a166fd15191aceab89f30c097e694b7cf3db4880" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/g1a/composer-test-scenarios/zipball/a166fd15191aceab89f30c097e694b7cf3db4880", - "reference": "a166fd15191aceab89f30c097e694b7cf3db4880", - "shasum": "" - }, - "bin": [ - "scripts/create-scenario", - "scripts/dependency-licenses", - "scripts/install-scenario" - ], - "type": "library", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Greg Anderson", - "email": "greg.1.anderson@greenknowe.org" - } - ], - "description": "Useful scripts for testing multiple sets of Composer dependencies.", - "time": "2018-08-08T23:37:23+00:00" - }, { "name": "grasmash/expander", "version": "1.0.0", @@ -1924,32 +2115,37 @@ }, { "name": "guzzlehttp/psr7", - "version": "1.4.2", + "version": "1.6.1", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c" + "reference": "239400de7a173fe9901b9ac7c06497751f00727a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c", - "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/239400de7a173fe9901b9ac7c06497751f00727a", + "reference": "239400de7a173fe9901b9ac7c06497751f00727a", "shasum": "" }, "require": { "php": ">=5.4.0", - "psr/http-message": "~1.0" + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" }, "provide": { "psr/http-message-implementation": "1.0" }, "require-dev": { - "phpunit/phpunit": "~4.0" + "ext-zlib": "*", + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8" + }, + "suggest": { + "zendframework/zend-httphandlerrunner": "Emit PSR-7 responses" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4-dev" + "dev-master": "1.6-dev" } }, "autoload": { @@ -1979,13 +2175,56 @@ "keywords": [ "http", "message", + "psr-7", "request", "response", "stream", "uri", "url" ], - "time": "2017-03-20T17:10:46+00:00" + "time": "2019-07-01T23:21:34+00:00" + }, + { + "name": "ircmaxell/password-compat", + "version": "v1.0.4", + "source": { + "type": "git", + "url": "https://github.com/ircmaxell/password_compat.git", + "reference": "5c5cde8822a69545767f7c7f3058cb15ff84614c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ircmaxell/password_compat/zipball/5c5cde8822a69545767f7c7f3058cb15ff84614c", + "reference": "5c5cde8822a69545767f7c7f3058cb15ff84614c", + "shasum": "" + }, + "require-dev": { + "phpunit/phpunit": "4.*" + }, + "type": "library", + "autoload": { + "files": [ + "lib/password.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Anthony Ferrara", + "email": "ircmaxell@php.net", + "homepage": "http://blog.ircmaxell.com" + } + ], + "description": "A compatibility library for the proposed simplified password hashing algorithm: https://wiki.php.net/rfc/password_hash", + "homepage": "https://github.com/ircmaxell/password_compat", + "keywords": [ + "hashing", + "password" + ], + "time": "2014-11-20T16:49:30+00:00" }, { "name": "jms/metadata", @@ -2079,56 +2318,44 @@ }, { "name": "jms/serializer", - "version": "1.14.0", + "version": "0.16.0", "source": { "type": "git", "url": "https://github.com/schmittjoh/serializer.git", - "reference": "ee96d57024af9a7716d56fcbe3aa94b3d030f3ca" + "reference": "c8a171357ca92b6706e395c757f334902d430ea9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/ee96d57024af9a7716d56fcbe3aa94b3d030f3ca", - "reference": "ee96d57024af9a7716d56fcbe3aa94b3d030f3ca", + "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/c8a171357ca92b6706e395c757f334902d430ea9", + "reference": "c8a171357ca92b6706e395c757f334902d430ea9", "shasum": "" }, "require": { - "doctrine/annotations": "^1.0", - "doctrine/instantiator": "^1.0.3", - "jms/metadata": "^1.3", + "doctrine/annotations": "1.*", + "jms/metadata": "~1.1", "jms/parser-lib": "1.*", - "php": "^5.5|^7.0", - "phpcollection/phpcollection": "~0.1", - "phpoption/phpoption": "^1.1" - }, - "conflict": { - "twig/twig": "<1.12" + "php": ">=5.3.2", + "phpcollection/phpcollection": "~0.1" }, "require-dev": { "doctrine/orm": "~2.1", - "doctrine/phpcr-odm": "^1.3|^2.0", - "ext-pdo_sqlite": "*", - "jackalope/jackalope-doctrine-dbal": "^1.1.5", - "phpunit/phpunit": "^4.8|^5.0", + "doctrine/phpcr-odm": "~1.0.1", + "jackalope/jackalope-doctrine-dbal": "1.0.*", "propel/propel1": "~1.7", - "psr/container": "^1.0", - "symfony/dependency-injection": "^2.7|^3.3|^4.0", - "symfony/expression-language": "^2.6|^3.0", - "symfony/filesystem": "^2.1", - "symfony/form": "~2.1|^3.0", - "symfony/translation": "^2.1|^3.0", - "symfony/validator": "^2.2|^3.0", - "symfony/yaml": "^2.1|^3.0", - "twig/twig": "~1.12|~2.0" + "symfony/filesystem": "2.*", + "symfony/form": "~2.1", + "symfony/translation": "~2.0", + "symfony/validator": "~2.0", + "symfony/yaml": "2.*", + "twig/twig": ">=1.8,<2.0-dev" }, "suggest": { - "doctrine/cache": "Required if you like to use cache functionality.", - "doctrine/collections": "Required if you like to use doctrine collection types as ArrayCollection.", "symfony/yaml": "Required if you'd like to serialize data to YAML format." }, "type": "library", "extra": { "branch-alias": { - "dev-1.x": "1.14-dev" + "dev-master": "0.15-dev" } }, "autoload": { @@ -2138,16 +2365,14 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "Apache2" ], "authors": [ { - "name": "Asmir Mustafic", - "email": "goetas@gmail.com" - }, - { - "name": "Johannes M. Schmitt", - "email": "schmittjoh@gmail.com" + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh", + "role": "Developer of wrapped JMSSerializerBundle" } ], "description": "Library for (de-)serializing data of any complexity; supports XML, JSON, and YAML.", @@ -2159,27 +2384,27 @@ "serialization", "xml" ], - "time": "2019-04-17T08:12:16+00:00" + "time": "2014-03-18T08:39:00+00:00" }, { "name": "justinrainbow/json-schema", - "version": "5.2.8", + "version": "5.2.9", "source": { "type": "git", "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "dcb6e1006bb5fd1e392b4daa68932880f37550d4" + "reference": "44c6787311242a979fa15c704327c20e7221a0e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/dcb6e1006bb5fd1e392b4daa68932880f37550d4", - "reference": "dcb6e1006bb5fd1e392b4daa68932880f37550d4", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/44c6787311242a979fa15c704327c20e7221a0e4", + "reference": "44c6787311242a979fa15c704327c20e7221a0e4", "shasum": "" }, "require": { "php": ">=5.3.3" }, "require-dev": { - "friendsofphp/php-cs-fixer": "~2.2.20", + "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", "json-schema/json-schema-test-suite": "1.2.0", "phpunit/phpunit": "^4.8.35" }, @@ -2225,7 +2450,7 @@ "json", "schema" ], - "time": "2019-01-14T23:55:14+00:00" + "time": "2019-09-25T14:49:45+00:00" }, { "name": "league/container", @@ -2294,16 +2519,16 @@ }, { "name": "league/flysystem", - "version": "1.0.53", + "version": "1.0.57", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "08e12b7628f035600634a5e76d95b5eb66cea674" + "reference": "0e9db7f0b96b9f12dcf6f65bc34b72b1a30ea55a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/08e12b7628f035600634a5e76d95b5eb66cea674", - "reference": "08e12b7628f035600634a5e76d95b5eb66cea674", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/0e9db7f0b96b9f12dcf6f65bc34b72b1a30ea55a", + "reference": "0e9db7f0b96b9f12dcf6f65bc34b72b1a30ea55a", "shasum": "" }, "require": { @@ -2374,20 +2599,20 @@ "sftp", "storage" ], - "time": "2019-06-18T20:09:29+00:00" + "time": "2019-10-16T21:01:05+00:00" }, { "name": "monolog/monolog", - "version": "1.24.0", + "version": "1.25.1", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266" + "reference": "70e65a5470a42cfec1a7da00d30edb6e617e8dcf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266", - "reference": "bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/70e65a5470a42cfec1a7da00d30edb6e617e8dcf", + "reference": "70e65a5470a42cfec1a7da00d30edb6e617e8dcf", "shasum": "" }, "require": { @@ -2452,56 +2677,7 @@ "logging", "psr-3" ], - "time": "2018-11-05T09:00:11+00:00" - }, - { - "name": "moontoast/math", - "version": "1.1.2", - "source": { - "type": "git", - "url": "https://github.com/ramsey/moontoast-math.git", - "reference": "c2792a25df5cad4ff3d760dd37078fc5b6fccc79" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ramsey/moontoast-math/zipball/c2792a25df5cad4ff3d760dd37078fc5b6fccc79", - "reference": "c2792a25df5cad4ff3d760dd37078fc5b6fccc79", - "shasum": "" - }, - "require": { - "ext-bcmath": "*", - "php": ">=5.3.3" - }, - "require-dev": { - "jakub-onderka/php-parallel-lint": "^0.9.0", - "phpunit/phpunit": "^4.7|>=5.0 <5.4", - "satooshi/php-coveralls": "^0.6.1", - "squizlabs/php_codesniffer": "^2.3" - }, - "type": "library", - "autoload": { - "psr-4": { - "Moontoast\\Math\\": "src/Moontoast/Math/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Ben Ramsey", - "email": "ben@benramsey.com", - "homepage": "https://benramsey.com" - } - ], - "description": "A mathematics library, providing functionality for large numbers", - "homepage": "https://github.com/ramsey/moontoast-math", - "keywords": [ - "bcmath", - "math" - ], - "time": "2017-02-16T16:54:46+00:00" + "time": "2019-09-06T13:49:17+00:00" }, { "name": "mustache/mustache", @@ -2551,25 +2727,28 @@ }, { "name": "myclabs/deep-copy", - "version": "1.7.0", + "version": "1.9.3", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e" + "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", - "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/007c053ae6f31bba39dfa19a7726f56e9763bbea", + "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "php": "^7.1" + }, + "replace": { + "myclabs/deep-copy": "self.version" }, "require-dev": { "doctrine/collections": "^1.0", "doctrine/common": "^2.6", - "phpunit/phpunit": "^4.1" + "phpunit/phpunit": "^7.1" }, "type": "library", "autoload": { @@ -2592,7 +2771,7 @@ "object", "object graph" ], - "time": "2017-10-19T19:58:43+00:00" + "time": "2019-08-09T12:45:53+00:00" }, { "name": "paragonie/random_compat", @@ -2791,35 +2970,33 @@ }, { "name": "phpdocumentor/reflection-common", - "version": "1.0.1", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" + "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", - "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a", + "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a", "shasum": "" }, "require": { - "php": ">=5.5" + "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "^4.6" + "phpunit/phpunit": "~6" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src" - ] + "phpDocumentor\\Reflection\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2841,30 +3018,30 @@ "reflection", "static analysis" ], - "time": "2017-09-11T18:02:19+00:00" + "time": "2018-08-07T13:53:10+00:00" }, { "name": "phpdocumentor/reflection-docblock", - "version": "4.3.0", + "version": "4.3.2", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "94fd0001232e47129dd3504189fa1c7225010d08" + "reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08", - "reference": "94fd0001232e47129dd3504189fa1c7225010d08", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/b83ff7cfcfee7827e1e78b637a5904fe6a96698e", + "reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e", "shasum": "" }, "require": { "php": "^7.0", - "phpdocumentor/reflection-common": "^1.0.0", - "phpdocumentor/type-resolver": "^0.4.0", + "phpdocumentor/reflection-common": "^1.0.0 || ^2.0.0", + "phpdocumentor/type-resolver": "~0.4 || ^1.0.0", "webmozart/assert": "^1.0" }, "require-dev": { - "doctrine/instantiator": "~1.0.5", + "doctrine/instantiator": "^1.0.5", "mockery/mockery": "^1.0", "phpunit/phpunit": "^6.4" }, @@ -2892,41 +3069,40 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2017-11-30T07:14:17+00:00" + "time": "2019-09-12T14:27:41+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "0.4.0", + "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" + "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", - "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", + "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", "shasum": "" }, "require": { - "php": "^5.5 || ^7.0", - "phpdocumentor/reflection-common": "^1.0" + "php": "^7.1", + "phpdocumentor/reflection-common": "^2.0" }, "require-dev": { - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^5.2||^4.8.24" + "ext-tokenizer": "^7.1", + "mockery/mockery": "~1", + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] + "phpDocumentor\\Reflection\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -2939,7 +3115,8 @@ "email": "me@mikevanriel.com" } ], - "time": "2017-07-14T14:27:02+00:00" + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "time": "2019-08-22T18:11:29+00:00" }, { "name": "phpoption/phpoption", @@ -2993,22 +3170,22 @@ }, { "name": "phpspec/prophecy", - "version": "1.8.0", + "version": "1.9.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06" + "reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06", - "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/f6811d96d97bdf400077a0cc100ae56aa32b9203", + "reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", "sebastian/comparator": "^1.1|^2.0|^3.0", "sebastian/recursion-context": "^1.0|^2.0|^3.0" }, @@ -3023,8 +3200,8 @@ } }, "autoload": { - "psr-0": { - "Prophecy\\": "src/" + "psr-4": { + "Prophecy\\": "src/Prophecy" } }, "notification-url": "https://packagist.org/downloads/", @@ -3052,44 +3229,44 @@ "spy", "stub" ], - "time": "2018-08-05T17:53:17+00:00" + "time": "2019-10-03T11:07:50+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "5.3.2", + "version": "6.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "c89677919c5dd6d3b3852f230a663118762218ac" + "reference": "4cab20a326d14de7575a8e235c70d879b569a57a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c89677919c5dd6d3b3852f230a663118762218ac", - "reference": "c89677919c5dd6d3b3852f230a663118762218ac", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/4cab20a326d14de7575a8e235c70d879b569a57a", + "reference": "4cab20a326d14de7575a8e235c70d879b569a57a", "shasum": "" }, "require": { "ext-dom": "*", "ext-xmlwriter": "*", - "php": "^7.0", + "php": "^7.1", "phpunit/php-file-iterator": "^1.4.2", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^2.0.1", + "phpunit/php-token-stream": "^3.0", "sebastian/code-unit-reverse-lookup": "^1.0.1", - "sebastian/environment": "^3.0", + "sebastian/environment": "^3.1", "sebastian/version": "^2.0.1", "theseer/tokenizer": "^1.1" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^7.0" }, "suggest": { - "ext-xdebug": "^2.5.5" + "ext-xdebug": "^2.6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.3.x-dev" + "dev-master": "6.0-dev" } }, "autoload": { @@ -3115,7 +3292,7 @@ "testing", "xunit" ], - "time": "2018-04-06T15:36:58+00:00" + "time": "2018-05-28T11:49:20+00:00" }, { "name": "phpunit/php-file-iterator", @@ -3207,28 +3384,28 @@ }, { "name": "phpunit/php-timer", - "version": "1.0.9", + "version": "2.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" + "reference": "1038454804406b0b5f5f520358e78c1c2f71501e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/1038454804406b0b5f5f520358e78c1c2f71501e", + "reference": "1038454804406b0b5f5f520358e78c1c2f71501e", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "2.1-dev" } }, "autoload": { @@ -3243,7 +3420,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -3252,33 +3429,33 @@ "keywords": [ "timer" ], - "time": "2017-02-26T11:10:40+00:00" + "time": "2019-06-07T04:22:29+00:00" }, { "name": "phpunit/php-token-stream", - "version": "2.0.2", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "791198a2c6254db10131eecfe8c06670700904db" + "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db", - "reference": "791198a2c6254db10131eecfe8c06670700904db", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/995192df77f63a59e47f025390d2d1fdf8f425ff", + "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff", "shasum": "" }, "require": { "ext-tokenizer": "*", - "php": "^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^6.2.4" + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "3.1-dev" } }, "autoload": { @@ -3301,20 +3478,20 @@ "keywords": [ "tokenizer" ], - "time": "2017-11-27T05:48:46+00:00" + "time": "2019-09-17T06:23:10+00:00" }, { "name": "phpunit/phpunit", - "version": "6.5.13", + "version": "7.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "0973426fb012359b2f18d3bd1e90ef1172839693" + "reference": "536f4d853c12d8189963435088e8ff7c0daeab2e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0973426fb012359b2f18d3bd1e90ef1172839693", - "reference": "0973426fb012359b2f18d3bd1e90ef1172839693", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/536f4d853c12d8189963435088e8ff7c0daeab2e", + "reference": "536f4d853c12d8189963435088e8ff7c0daeab2e", "shasum": "" }, "require": { @@ -3326,15 +3503,15 @@ "myclabs/deep-copy": "^1.6.1", "phar-io/manifest": "^1.0.1", "phar-io/version": "^1.0", - "php": "^7.0", + "php": "^7.1", "phpspec/prophecy": "^1.7", - "phpunit/php-code-coverage": "^5.3", + "phpunit/php-code-coverage": "^6.0.1", "phpunit/php-file-iterator": "^1.4.3", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-timer": "^1.0.9", - "phpunit/phpunit-mock-objects": "^5.0.9", + "phpunit/php-timer": "^2.0", + "phpunit/phpunit-mock-objects": "^6.0", "sebastian/comparator": "^2.1", - "sebastian/diff": "^2.0", + "sebastian/diff": "^3.0", "sebastian/environment": "^3.1", "sebastian/exporter": "^3.1", "sebastian/global-state": "^2.0", @@ -3342,16 +3519,12 @@ "sebastian/resource-operations": "^1.0", "sebastian/version": "^2.0.1" }, - "conflict": { - "phpdocumentor/reflection-docblock": "3.0.2", - "phpunit/dbunit": "<3.0" - }, "require-dev": { "ext-pdo": "*" }, "suggest": { "ext-xdebug": "*", - "phpunit/php-invoker": "^1.1" + "phpunit/php-invoker": "^2.0" }, "bin": [ "phpunit" @@ -3359,7 +3532,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "6.5.x-dev" + "dev-master": "7.0-dev" } }, "autoload": { @@ -3385,33 +3558,30 @@ "testing", "xunit" ], - "time": "2018-09-08T15:10:43+00:00" + "time": "2018-03-26T07:36:48+00:00" }, { "name": "phpunit/phpunit-mock-objects", - "version": "5.0.10", + "version": "6.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f" + "reference": "f9756fd4f43f014cb2dca98deeaaa8ce5500a36e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/cd1cf05c553ecfec36b170070573e540b67d3f1f", - "reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/f9756fd4f43f014cb2dca98deeaaa8ce5500a36e", + "reference": "f9756fd4f43f014cb2dca98deeaaa8ce5500a36e", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.5", - "php": "^7.0", + "php": "^7.1", "phpunit/php-text-template": "^1.2.1", "sebastian/exporter": "^3.1" }, - "conflict": { - "phpunit/phpunit": "<6.0" - }, "require-dev": { - "phpunit/phpunit": "^6.5.11" + "phpunit/phpunit": "^7.0" }, "suggest": { "ext-soap": "*" @@ -3419,7 +3589,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0.x-dev" + "dev-master": "6.1-dev" } }, "autoload": { @@ -3445,7 +3615,7 @@ "xunit" ], "abandoned": true, - "time": "2018-08-09T05:50:03+00:00" + "time": "2018-05-29T13:54:20+00:00" }, { "name": "psr/cache", @@ -3594,16 +3764,16 @@ }, { "name": "psr/log", - "version": "1.0.2", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" + "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", - "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", + "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", "shasum": "" }, "require": { @@ -3637,7 +3807,7 @@ "psr", "psr-3" ], - "time": "2016-10-10T12:19:37+00:00" + "time": "2018-11-20T15:27:04+00:00" }, { "name": "psr/simple-cache", @@ -3687,6 +3857,46 @@ ], "time": "2017-10-23T01:57:42+00:00" }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "time": "2019-03-08T08:55:37+00:00" + }, { "name": "ramsey/uuid", "version": "3.8.0", @@ -3880,28 +4090,29 @@ }, { "name": "sebastian/diff", - "version": "2.0.1", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd" + "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", - "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/720fcc7e9b5cf384ea68d9d930d480907a0c1a29", + "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29", "shasum": "" }, "require": { - "php": "^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^6.2" + "phpunit/phpunit": "^7.5 || ^8.0", + "symfony/process": "^2 || ^3.3 || ^4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -3926,9 +4137,12 @@ "description": "Diff implementation", "homepage": "https://github.com/sebastianbergmann/diff", "keywords": [ - "diff" + "diff", + "udiff", + "unidiff", + "unified diff" ], - "time": "2017-08-03T08:09:46+00:00" + "time": "2019-02-04T06:01:07+00:00" }, { "name": "sebastian/environment", @@ -3982,16 +4196,16 @@ }, { "name": "sebastian/exporter", - "version": "3.1.0", + "version": "3.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "234199f4528de6d12aaa58b612e98f7d36adb937" + "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937", - "reference": "234199f4528de6d12aaa58b612e98f7d36adb937", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/68609e1261d215ea5b21b7987539cbfbe156ec3e", + "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e", "shasum": "" }, "require": { @@ -4018,6 +4232,10 @@ "BSD-3-Clause" ], "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, { "name": "Jeff Welch", "email": "whatthejeff@gmail.com" @@ -4026,17 +4244,13 @@ "name": "Volker Dusch", "email": "github@wallbash.com" }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, { "name": "Adam Harvey", "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" } ], "description": "Provides the functionality to export PHP variables for visualization", @@ -4045,7 +4259,7 @@ "export", "exporter" ], - "time": "2017-04-03T13:19:02+00:00" + "time": "2019-09-14T09:02:43+00:00" }, { "name": "sebastian/global-state", @@ -4423,25 +4637,27 @@ }, { "name": "symfony/browser-kit", - "version": "v3.4.18", + "version": "v4.3.5", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "f6668d1a6182d5a8dec65a1c863a4c1d963816c0" + "reference": "78b7611c45039e8ce81698be319851529bf040b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/f6668d1a6182d5a8dec65a1c863a4c1d963816c0", - "reference": "f6668d1a6182d5a8dec65a1c863a4c1d963816c0", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/78b7611c45039e8ce81698be319851529bf040b1", + "reference": "78b7611c45039e8ce81698be319851529bf040b1", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/dom-crawler": "~2.8|~3.0|~4.0" + "php": "^7.1.3", + "symfony/dom-crawler": "~3.4|~4.0" }, "require-dev": { - "symfony/css-selector": "~2.8|~3.0|~4.0", - "symfony/process": "~2.8|~3.0|~4.0" + "symfony/css-selector": "~3.4|~4.0", + "symfony/http-client": "^4.3", + "symfony/mime": "^4.3", + "symfony/process": "~3.4|~4.0" }, "suggest": { "symfony/process": "" @@ -4449,7 +4665,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.3-dev" } }, "autoload": { @@ -4476,41 +4692,47 @@ ], "description": "Symfony BrowserKit Component", "homepage": "https://symfony.com", - "time": "2018-07-26T09:06:28+00:00" + "time": "2019-09-10T11:25:17+00:00" }, { "name": "symfony/console", - "version": "v3.4.18", + "version": "v4.3.5", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "1d228fb4602047d7b26a0554e0d3efd567da5803" + "reference": "929ddf360d401b958f611d44e726094ab46a7369" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/1d228fb4602047d7b26a0554e0d3efd567da5803", - "reference": "1d228fb4602047d7b26a0554e0d3efd567da5803", + "url": "https://api.github.com/repos/symfony/console/zipball/929ddf360d401b958f611d44e726094ab46a7369", + "reference": "929ddf360d401b958f611d44e726094ab46a7369", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/debug": "~2.8|~3.0|~4.0", - "symfony/polyfill-mbstring": "~1.0" + "php": "^7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.8", + "symfony/service-contracts": "^1.1" }, "conflict": { "symfony/dependency-injection": "<3.4", + "symfony/event-dispatcher": "<4.3", "symfony/process": "<3.3" }, + "provide": { + "psr/log-implementation": "1.0" + }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "~3.3|~4.0", + "symfony/config": "~3.4|~4.0", "symfony/dependency-injection": "~3.4|~4.0", - "symfony/event-dispatcher": "~2.8|~3.0|~4.0", + "symfony/event-dispatcher": "^4.3", "symfony/lock": "~3.4|~4.0", - "symfony/process": "~3.3|~4.0" + "symfony/process": "~3.4|~4.0", + "symfony/var-dumper": "^4.3" }, "suggest": { - "psr/log-implementation": "For using the console logger", + "psr/log": "For using the console logger", "symfony/event-dispatcher": "", "symfony/lock": "", "symfony/process": "" @@ -4518,7 +4740,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.3-dev" } }, "autoload": { @@ -4545,29 +4767,29 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2018-10-30T16:50:50+00:00" + "time": "2019-10-07T12:36:49+00:00" }, { "name": "symfony/css-selector", - "version": "v3.4.18", + "version": "v4.3.5", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "3503415d4aafabc31cd08c3a4ebac7f43fde8feb" + "reference": "f4b3ff6a549d9ed28b2b0ecd1781bf67cf220ee9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/3503415d4aafabc31cd08c3a4ebac7f43fde8feb", - "reference": "3503415d4aafabc31cd08c3a4ebac7f43fde8feb", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/f4b3ff6a549d9ed28b2b0ecd1781bf67cf220ee9", + "reference": "f4b3ff6a549d9ed28b2b0ecd1781bf67cf220ee9", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" + "php": "^7.1.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.3-dev" } }, "autoload": { @@ -4583,14 +4805,14 @@ "MIT" ], "authors": [ - { - "name": "Jean-François Simon", - "email": "jeanfrancois.simon@sensiolabs.com" - }, { "name": "Fabien Potencier", "email": "fabien@symfony.com" }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" @@ -4598,41 +4820,46 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "time": "2018-10-02T16:33:53+00:00" + "time": "2019-10-02T08:36:26+00:00" }, { - "name": "symfony/debug", - "version": "v3.4.18", + "name": "symfony/dom-crawler", + "version": "v4.3.5", "source": { "type": "git", - "url": "https://github.com/symfony/debug.git", - "reference": "fe9793af008b651c5441bdeab21ede8172dab097" + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "e9f7b4d19d69b133bd638eeddcdc757723b4211f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/fe9793af008b651c5441bdeab21ede8172dab097", - "reference": "fe9793af008b651c5441bdeab21ede8172dab097", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/e9f7b4d19d69b133bd638eeddcdc757723b4211f", + "reference": "e9f7b4d19d69b133bd638eeddcdc757723b4211f", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "psr/log": "~1.0" + "php": "^7.1.3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0" }, "conflict": { - "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" + "masterminds/html5": "<2.6" }, "require-dev": { - "symfony/http-kernel": "~2.8|~3.0|~4.0" + "masterminds/html5": "^2.6", + "symfony/css-selector": "~3.4|~4.0" + }, + "suggest": { + "symfony/css-selector": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.3-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\Debug\\": "" + "Symfony\\Component\\DomCrawler\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -4652,44 +4879,57 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Debug Component", + "description": "Symfony DomCrawler Component", "homepage": "https://symfony.com", - "time": "2018-10-31T09:06:03+00:00" + "time": "2019-09-28T21:25:05+00:00" }, { - "name": "symfony/dom-crawler", - "version": "v3.4.18", + "name": "symfony/event-dispatcher", + "version": "v4.3.5", "source": { "type": "git", - "url": "https://github.com/symfony/dom-crawler.git", - "reference": "c705bee03ade5b47c087807dd9ffaaec8dda2722" + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "6229f58993e5a157f6096fc7145c0717d0be8807" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/c705bee03ade5b47c087807dd9ffaaec8dda2722", - "reference": "c705bee03ade5b47c087807dd9ffaaec8dda2722", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/6229f58993e5a157f6096fc7145c0717d0be8807", + "reference": "6229f58993e5a157f6096fc7145c0717d0be8807", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.0" + "php": "^7.1.3", + "symfony/event-dispatcher-contracts": "^1.1" + }, + "conflict": { + "symfony/dependency-injection": "<3.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "1.1" }, "require-dev": { - "symfony/css-selector": "~2.8|~3.0|~4.0" + "psr/log": "~1.0", + "symfony/config": "~3.4|~4.0", + "symfony/dependency-injection": "~3.4|~4.0", + "symfony/expression-language": "~3.4|~4.0", + "symfony/http-foundation": "^3.4|^4.0", + "symfony/service-contracts": "^1.1", + "symfony/stopwatch": "~3.4|~4.0" }, "suggest": { - "symfony/css-selector": "" + "symfony/dependency-injection": "", + "symfony/http-kernel": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.3-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\DomCrawler\\": "" + "Symfony\\Component\\EventDispatcher\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -4709,54 +4949,41 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony DomCrawler Component", + "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2018-10-02T12:28:39+00:00" + "time": "2019-10-01T16:40:32+00:00" }, { - "name": "symfony/event-dispatcher", - "version": "v3.4.18", + "name": "symfony/event-dispatcher-contracts", + "version": "v1.1.7", "source": { "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "db9e829c8f34c3d35cf37fcd4cdb4293bc4a2f14" + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "c43ab685673fb6c8d84220c77897b1d6cdbe1d18" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/db9e829c8f34c3d35cf37fcd4cdb4293bc4a2f14", - "reference": "db9e829c8f34c3d35cf37fcd4cdb4293bc4a2f14", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/c43ab685673fb6c8d84220c77897b1d6cdbe1d18", + "reference": "c43ab685673fb6c8d84220c77897b1d6cdbe1d18", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" - }, - "conflict": { - "symfony/dependency-injection": "<3.3" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~2.8|~3.0|~4.0", - "symfony/dependency-injection": "~3.3|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/stopwatch": "~2.8|~3.0|~4.0" + "php": "^7.1.3" }, "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" + "psr/event-dispatcher": "", + "symfony/event-dispatcher-implementation": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "1.1-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\EventDispatcher\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Symfony\\Contracts\\EventDispatcher\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4764,40 +4991,48 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony EventDispatcher Component", + "description": "Generic abstractions related to dispatching event", "homepage": "https://symfony.com", - "time": "2018-10-30T16:50:50+00:00" + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-09-17T09:54:03+00:00" }, { "name": "symfony/filesystem", - "version": "v3.4.18", + "version": "v4.3.5", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "d69930fc337d767607267d57c20a7403d0a822a4" + "reference": "9abbb7ef96a51f4d7e69627bc6f63307994e4263" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/d69930fc337d767607267d57c20a7403d0a822a4", - "reference": "d69930fc337d767607267d57c20a7403d0a822a4", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/9abbb7ef96a51f4d7e69627bc6f63307994e4263", + "reference": "9abbb7ef96a51f4d7e69627bc6f63307994e4263", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", + "php": "^7.1.3", "symfony/polyfill-ctype": "~1.8" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.3-dev" } }, "autoload": { @@ -4824,29 +5059,29 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2018-10-02T12:28:39+00:00" + "time": "2019-08-20T14:07:54+00:00" }, { "name": "symfony/finder", - "version": "v3.4.18", + "version": "v4.3.5", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "54ba444dddc5bd5708a34bd095ea67c6eb54644d" + "reference": "5e575faa95548d0586f6bedaeabec259714e44d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/54ba444dddc5bd5708a34bd095ea67c6eb54644d", - "reference": "54ba444dddc5bd5708a34bd095ea67c6eb54644d", + "url": "https://api.github.com/repos/symfony/finder/zipball/5e575faa95548d0586f6bedaeabec259714e44d1", + "reference": "5e575faa95548d0586f6bedaeabec259714e44d1", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" + "php": "^7.1.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.3-dev" } }, "autoload": { @@ -4873,34 +5108,35 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2018-10-03T08:46:40+00:00" + "time": "2019-09-16T11:29:48+00:00" }, { "name": "symfony/http-foundation", - "version": "v3.4.18", + "version": "v2.8.50", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "5aea7a86ca3203dd7a257e765b4b9c9cfd01c6c0" + "reference": "746f8d3638bf46ee8b202e62f2b214c3d61fb06a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/5aea7a86ca3203dd7a257e765b4b9c9cfd01c6c0", - "reference": "5aea7a86ca3203dd7a257e765b4b9c9cfd01c6c0", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/746f8d3638bf46ee8b202e62f2b214c3d61fb06a", + "reference": "746f8d3638bf46ee8b202e62f2b214c3d61fb06a", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", + "php": ">=5.3.9", "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php70": "~1.6" + "symfony/polyfill-php54": "~1.0", + "symfony/polyfill-php55": "~1.0" }, "require-dev": { - "symfony/expression-language": "~2.8|~3.0|~4.0" + "symfony/expression-language": "~2.4|~3.0.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "2.8-dev" } }, "autoload": { @@ -4927,20 +5163,20 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2018-10-31T08:57:11+00:00" + "time": "2019-04-16T10:00:53+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.11.0", + "version": "v1.12.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "82ebae02209c21113908c229e9883c419720738a" + "reference": "550ebaac289296ce228a706d0867afc34687e3f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/82ebae02209c21113908c229e9883c419720738a", - "reference": "82ebae02209c21113908c229e9883c419720738a", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/550ebaac289296ce228a706d0867afc34687e3f4", + "reference": "550ebaac289296ce228a706d0867afc34687e3f4", "shasum": "" }, "require": { @@ -4952,7 +5188,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.11-dev" + "dev-master": "1.12-dev" } }, "autoload": { @@ -4968,13 +5204,13 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - }, { "name": "Gert de Pagter", "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony polyfill for ctype functions", @@ -4985,20 +5221,20 @@ "polyfill", "portable" ], - "time": "2019-02-06T07:57:58+00:00" + "time": "2019-08-06T08:03:45+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.10.0", + "version": "v1.12.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "c79c051f5b3a46be09205c73b80b346e4153e494" + "reference": "b42a2f66e8f1b15ccf25652c3424265923eb4f17" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/c79c051f5b3a46be09205c73b80b346e4153e494", - "reference": "c79c051f5b3a46be09205c73b80b346e4153e494", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/b42a2f66e8f1b15ccf25652c3424265923eb4f17", + "reference": "b42a2f66e8f1b15ccf25652c3424265923eb4f17", "shasum": "" }, "require": { @@ -5010,7 +5246,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.9-dev" + "dev-master": "1.12-dev" } }, "autoload": { @@ -5044,35 +5280,148 @@ "portable", "shim" ], - "time": "2018-09-21T13:07:52+00:00" + "time": "2019-08-06T08:03:45+00:00" }, { - "name": "symfony/polyfill-php70", - "version": "v1.10.0", + "name": "symfony/polyfill-php54", + "version": "v1.12.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php70.git", - "reference": "6b88000cdd431cd2e940caa2cb569201f3f84224" + "url": "https://github.com/symfony/polyfill-php54.git", + "reference": "a043bcced870214922fbb4bf22679d431ec0296a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/6b88000cdd431cd2e940caa2cb569201f3f84224", - "reference": "6b88000cdd431cd2e940caa2cb569201f3f84224", + "url": "https://api.github.com/repos/symfony/polyfill-php54/zipball/a043bcced870214922fbb4bf22679d431ec0296a", + "reference": "a043bcced870214922fbb4bf22679d431ec0296a", "shasum": "" }, "require": { - "paragonie/random_compat": "~1.0|~2.0|~9.99", "php": ">=5.3.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.9-dev" + "dev-master": "1.12-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php54\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 5.4+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2019-08-06T08:03:45+00:00" + }, + { + "name": "symfony/polyfill-php55", + "version": "v1.12.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php55.git", + "reference": "548bb39407e78e54f785b4e18c7e0d5d9e493265" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php55/zipball/548bb39407e78e54f785b4e18c7e0d5d9e493265", + "reference": "548bb39407e78e54f785b4e18c7e0d5d9e493265", + "shasum": "" + }, + "require": { + "ircmaxell/password-compat": "~1.0", + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.12-dev" } }, "autoload": { "psr-4": { - "Symfony\\Polyfill\\Php70\\": "" + "Symfony\\Polyfill\\Php55\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 5.5+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2019-08-06T08:03:45+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.12.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "2ceb49eaccb9352bff54d22570276bb75ba4a188" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/2ceb49eaccb9352bff54d22570276bb75ba4a188", + "reference": "2ceb49eaccb9352bff54d22570276bb75ba4a188", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.12-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" }, "files": [ "bootstrap.php" @@ -5095,7 +5444,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -5103,29 +5452,29 @@ "portable", "shim" ], - "time": "2018-09-21T06:26:08+00:00" + "time": "2019-08-06T08:03:45+00:00" }, { "name": "symfony/process", - "version": "v3.4.18", + "version": "v4.3.5", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "35c2914a9f50519bd207164c353ae4d59182c2cb" + "reference": "50556892f3cc47d4200bfd1075314139c4c9ff4b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/35c2914a9f50519bd207164c353ae4d59182c2cb", - "reference": "35c2914a9f50519bd207164c353ae4d59182c2cb", + "url": "https://api.github.com/repos/symfony/process/zipball/50556892f3cc47d4200bfd1075314139c4c9ff4b", + "reference": "50556892f3cc47d4200bfd1075314139c4c9ff4b", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" + "php": "^7.1.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.3-dev" } }, "autoload": { @@ -5152,24 +5501,82 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2018-10-14T17:33:21+00:00" + "time": "2019-09-26T21:17:10+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v1.1.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "ffcde9615dc5bb4825b9f6aed07716f1f57faae0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/ffcde9615dc5bb4825b9f6aed07716f1f57faae0", + "reference": "ffcde9615dc5bb4825b9f6aed07716f1f57faae0", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "psr/container": "^1.0" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-09-17T11:12:18+00:00" }, { "name": "symfony/yaml", - "version": "v3.4.28", + "version": "v4.3.5", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "212a27b731e5bfb735679d1ffaac82bd6a1dc996" + "reference": "41e16350a2a1c7383c4735aa2f9fce74cf3d1178" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/212a27b731e5bfb735679d1ffaac82bd6a1dc996", - "reference": "212a27b731e5bfb735679d1ffaac82bd6a1dc996", + "url": "https://api.github.com/repos/symfony/yaml/zipball/41e16350a2a1c7383c4735aa2f9fce74cf3d1178", + "reference": "41e16350a2a1c7383c4735aa2f9fce74cf3d1178", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", + "php": "^7.1.3", "symfony/polyfill-ctype": "~1.8" }, "conflict": { @@ -5184,7 +5591,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.3-dev" } }, "autoload": { @@ -5211,20 +5618,20 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2019-03-25T07:48:46+00:00" + "time": "2019-09-11T15:41:19+00:00" }, { "name": "theseer/tokenizer", - "version": "1.1.0", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b" + "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b", - "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9", + "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9", "shasum": "" }, "require": { @@ -5251,24 +5658,25 @@ } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "time": "2017-04-07T12:08:54+00:00" + "time": "2019-06-13T22:48:21+00:00" }, { "name": "vlucas/phpdotenv", - "version": "v2.5.1", + "version": "v2.6.1", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "8abb4f9aa89ddea9d52112c65bbe8d0125e2fa8e" + "reference": "2a7dcf7e3e02dc5e701004e51a6f304b713107d5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/8abb4f9aa89ddea9d52112c65bbe8d0125e2fa8e", - "reference": "8abb4f9aa89ddea9d52112c65bbe8d0125e2fa8e", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/2a7dcf7e3e02dc5e701004e51a6f304b713107d5", + "reference": "2a7dcf7e3e02dc5e701004e51a6f304b713107d5", "shasum": "" }, "require": { - "php": ">=5.3.9" + "php": ">=5.3.9", + "symfony/polyfill-ctype": "^1.9" }, "require-dev": { "phpunit/phpunit": "^4.8.35 || ^5.0" @@ -5276,7 +5684,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.5-dev" + "dev-master": "2.6-dev" } }, "autoload": { @@ -5301,28 +5709,28 @@ "env", "environment" ], - "time": "2018-07-29T20:33:41+00:00" + "time": "2019-01-29T11:11:52+00:00" }, { "name": "webmozart/assert", - "version": "1.3.0", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "0df1908962e7a3071564e857d86874dad1ef204a" + "reference": "88e6d84706d09a236046d686bbea96f07b3a34f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a", - "reference": "0df1908962e7a3071564e857d86874dad1ef204a", + "url": "https://api.github.com/repos/webmozart/assert/zipball/88e6d84706d09a236046d686bbea96f07b3a34f4", + "reference": "88e6d84706d09a236046d686bbea96f07b3a34f4", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": "^5.3.3 || ^7.0", + "symfony/polyfill-ctype": "^1.8" }, "require-dev": { - "phpunit/phpunit": "^4.6", - "sebastian/version": "^1.0.1" + "phpunit/phpunit": "^4.8.36 || ^7.5.13" }, "type": "library", "extra": { @@ -5351,7 +5759,7 @@ "check", "validate" ], - "time": "2018-01-29T19:49:41+00:00" + "time": "2019-08-24T08:43:50+00:00" }, { "name": "weew/helpers-array", @@ -5394,16 +5802,16 @@ "packages-dev": [ { "name": "brainmaestro/composer-git-hooks", - "version": "v2.6.1", + "version": "v2.8.2", "source": { "type": "git", "url": "https://github.com/BrainMaestro/composer-git-hooks.git", - "reference": "137dd2aec2be494918f8bdfb18f57b55ff20015e" + "reference": "c4a39fcbd73b8a5da8c02b8e0923b0836cc4fae0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/BrainMaestro/composer-git-hooks/zipball/137dd2aec2be494918f8bdfb18f57b55ff20015e", - "reference": "137dd2aec2be494918f8bdfb18f57b55ff20015e", + "url": "https://api.github.com/repos/BrainMaestro/composer-git-hooks/zipball/c4a39fcbd73b8a5da8c02b8e0923b0836cc4fae0", + "reference": "c4a39fcbd73b8a5da8c02b8e0923b0836cc4fae0", "shasum": "" }, "require": { @@ -5411,8 +5819,9 @@ "symfony/console": "^3.2 || ^4.0" }, "require-dev": { + "ext-json": "*", "friendsofphp/php-cs-fixer": "^2.9", - "phpunit/phpunit": "^5.7|^7.0" + "phpunit/phpunit": "^5.7 || ^7.0" }, "bin": [ "cghooks" @@ -5423,10 +5832,11 @@ "pre-commit": "composer check-style", "pre-push": [ "composer test", - "appver=$(grep -o -P '\\d.\\d.\\d' cghooks)", - "tag=$(git tag --sort=-v:refname | head -n 1 | tr -d v)", - "if [ \"$tag\" != \"$appver\" ]; then", - "echo \"The most recent tag v$tag does not match the application version $appver\n\"", + "appver=$(grep -o -E '\\d.\\d.\\d' cghooks)", + "tag=$(git describe --tags --abbrev=0)", + "if [ \"$tag\" != \"v$appver\" ]; then", + "echo \"The most recent tag $tag does not match the application version $appver\\n\"", + "tag=${tag#v}", "sed -i -E \"s/$appver/$tag/\" cghooks", "exit 1", "fi" @@ -5457,7 +5867,7 @@ "composer", "git" ], - "time": "2018-12-28T14:57:06+00:00" + "time": "2019-10-16T14:14:51+00:00" }, { "name": "codacy/coverage", @@ -5550,33 +5960,33 @@ }, { "name": "gitonomy/gitlib", - "version": "v1.0.4", + "version": "v1.1.0", "source": { "type": "git", "url": "https://github.com/gitonomy/gitlib.git", - "reference": "932a960221ae3484a3e82553b3be478e56beb68d" + "reference": "49e599915eae04b734f31e6e88f773d32d921e2e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/gitonomy/gitlib/zipball/932a960221ae3484a3e82553b3be478e56beb68d", - "reference": "932a960221ae3484a3e82553b3be478e56beb68d", + "url": "https://api.github.com/repos/gitonomy/gitlib/zipball/49e599915eae04b734f31e6e88f773d32d921e2e", + "reference": "49e599915eae04b734f31e6e88f773d32d921e2e", "shasum": "" }, "require": { - "php": "^5.3 || ^7.0", - "symfony/process": "^2.3|^3.0|^4.0" + "php": "^5.6 || ^7.0", + "symfony/process": "^3.4|^4.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35|^5.7", + "phpunit/phpunit": "^5.7|^6.5", "psr/log": "^1.0" }, "suggest": { - "psr/log": "Add some log" + "psr/log": "Required to use loggers for reporting of execution" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" } }, "autoload": { @@ -5602,7 +6012,7 @@ ], "description": "Library for accessing git", "homepage": "http://gitonomy.com", - "time": "2018-04-22T19:55:36+00:00" + "time": "2019-06-23T09:49:01+00:00" }, { "name": "goaop/framework", @@ -6023,16 +6433,16 @@ }, { "name": "phpmd/phpmd", - "version": "2.6.0", + "version": "2.7.0", "source": { "type": "git", "url": "https://github.com/phpmd/phpmd.git", - "reference": "4e9924b2c157a3eb64395460fcf56b31badc8374" + "reference": "a05a999c644f4bc9a204846017db7bb7809fbe4c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpmd/phpmd/zipball/4e9924b2c157a3eb64395460fcf56b31badc8374", - "reference": "4e9924b2c157a3eb64395460fcf56b31badc8374", + "url": "https://api.github.com/repos/phpmd/phpmd/zipball/a05a999c644f4bc9a204846017db7bb7809fbe4c", + "reference": "a05a999c644f4bc9a204846017db7bb7809fbe4c", "shasum": "" }, "require": { @@ -6041,13 +6451,15 @@ "php": ">=5.3.9" }, "require-dev": { - "phpunit/phpunit": "^4.0", + "gregwar/rst": "^1.0", + "mikey179/vfsstream": "^1.6.4", + "phpunit/phpunit": "^4.8.36 || ^5.7.27", "squizlabs/php_codesniffer": "^2.0" }, "bin": [ "src/bin/phpmd" ], - "type": "project", + "type": "library", "autoload": { "psr-0": { "PHPMD\\": "src/main/php" @@ -6064,20 +6476,20 @@ "homepage": "https://github.com/manuelpichler", "role": "Project Founder" }, - { - "name": "Other contributors", - "homepage": "https://github.com/phpmd/phpmd/graphs/contributors", - "role": "Contributors" - }, { "name": "Marc Würth", "email": "ravage@bluewin.ch", "homepage": "https://github.com/ravage84", "role": "Project Maintainer" + }, + { + "name": "Other contributors", + "homepage": "https://github.com/phpmd/phpmd/graphs/contributors", + "role": "Contributors" } ], "description": "PHPMD is a spin-off project of PHP Depend and aims to be a PHP equivalent of the well known Java tool PMD.", - "homepage": "http://phpmd.org/", + "homepage": "https://phpmd.org/", "keywords": [ "mess detection", "mess detector", @@ -6085,7 +6497,7 @@ "phpmd", "pmd" ], - "time": "2017-01-20T14:41:10+00:00" + "time": "2019-07-30T21:13:32+00:00" }, { "name": "rregeer/phpunit-coverage-check", @@ -6170,21 +6582,22 @@ }, { "name": "sebastian/phpcpd", - "version": "3.0.1", + "version": "4.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpcpd.git", - "reference": "dfed51c1288790fc957c9433e2f49ab152e8a564" + "reference": "0d9afa762f2400de077b2192f4a9d127de0bb78e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpcpd/zipball/dfed51c1288790fc957c9433e2f49ab152e8a564", - "reference": "dfed51c1288790fc957c9433e2f49ab152e8a564", + "url": "https://api.github.com/repos/sebastianbergmann/phpcpd/zipball/0d9afa762f2400de077b2192f4a9d127de0bb78e", + "reference": "0d9afa762f2400de077b2192f4a9d127de0bb78e", "shasum": "" }, "require": { - "php": "^5.6|^7.0", - "phpunit/php-timer": "^1.0.6", + "ext-dom": "*", + "php": "^7.1", + "phpunit/php-timer": "^2.0", "sebastian/finder-facade": "^1.1", "sebastian/version": "^1.0|^2.0", "symfony/console": "^2.7|^3.0|^4.0" @@ -6195,7 +6608,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -6216,20 +6629,20 @@ ], "description": "Copy/Paste Detector (CPD) for PHP code.", "homepage": "https://github.com/sebastianbergmann/phpcpd", - "time": "2017-11-16T08:49:28+00:00" + "time": "2018-09-17T17:17:27+00:00" }, { "name": "squizlabs/php_codesniffer", - "version": "3.3.2", + "version": "3.5.1", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "6ad28354c04b364c3c71a34e4a18b629cc3b231e" + "reference": "82cd0f854ceca17731d6d019c7098e3755c45060" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/6ad28354c04b364c3c71a34e4a18b629cc3b231e", - "reference": "6ad28354c04b364c3c71a34e4a18b629cc3b231e", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/82cd0f854ceca17731d6d019c7098e3755c45060", + "reference": "82cd0f854ceca17731d6d019c7098e3755c45060", "shasum": "" }, "require": { @@ -6262,41 +6675,41 @@ } ], "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "http://www.squizlabs.com/php-codesniffer", + "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", "keywords": [ "phpcs", "standards" ], - "time": "2018-09-23T23:08:17+00:00" + "time": "2019-10-16T21:14:26+00:00" }, { "name": "symfony/config", - "version": "v3.4.18", + "version": "v4.3.5", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "99b2fa8acc244e656cdf324ff419fbe6fd300a4d" + "reference": "0acb26407a9e1a64a275142f0ae5e36436342720" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/99b2fa8acc244e656cdf324ff419fbe6fd300a4d", - "reference": "99b2fa8acc244e656cdf324ff419fbe6fd300a4d", + "url": "https://api.github.com/repos/symfony/config/zipball/0acb26407a9e1a64a275142f0ae5e36436342720", + "reference": "0acb26407a9e1a64a275142f0ae5e36436342720", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/filesystem": "~2.8|~3.0|~4.0", + "php": "^7.1.3", + "symfony/filesystem": "~3.4|~4.0", "symfony/polyfill-ctype": "~1.8" }, "conflict": { - "symfony/dependency-injection": "<3.3", - "symfony/finder": "<3.3" + "symfony/finder": "<3.4" }, "require-dev": { - "symfony/dependency-injection": "~3.3|~4.0", - "symfony/event-dispatcher": "~3.3|~4.0", - "symfony/finder": "~3.3|~4.0", - "symfony/yaml": "~3.0|~4.0" + "symfony/dependency-injection": "~3.4|~4.0", + "symfony/event-dispatcher": "~3.4|~4.0", + "symfony/finder": "~3.4|~4.0", + "symfony/messenger": "~4.1", + "symfony/yaml": "~3.4|~4.0" }, "suggest": { "symfony/yaml": "To use the yaml reference dumper" @@ -6304,7 +6717,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.3-dev" } }, "autoload": { @@ -6331,38 +6744,40 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2018-10-31T09:06:03+00:00" + "time": "2019-09-19T15:51:53+00:00" }, { "name": "symfony/dependency-injection", - "version": "v3.4.18", + "version": "v4.3.5", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "9c98452ac7fff4b538956775630bc9701f5384ba" + "reference": "e1e0762a814b957a1092bff75a550db49724d05b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/9c98452ac7fff4b538956775630bc9701f5384ba", - "reference": "9c98452ac7fff4b538956775630bc9701f5384ba", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/e1e0762a814b957a1092bff75a550db49724d05b", + "reference": "e1e0762a814b957a1092bff75a550db49724d05b", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "psr/container": "^1.0" + "php": "^7.1.3", + "psr/container": "^1.0", + "symfony/service-contracts": "^1.1.6" }, "conflict": { - "symfony/config": "<3.3.7", - "symfony/finder": "<3.3", + "symfony/config": "<4.3", + "symfony/finder": "<3.4", "symfony/proxy-manager-bridge": "<3.4", "symfony/yaml": "<3.4" }, "provide": { - "psr/container-implementation": "1.0" + "psr/container-implementation": "1.0", + "symfony/service-implementation": "1.0" }, "require-dev": { - "symfony/config": "~3.3|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", + "symfony/config": "^4.3", + "symfony/expression-language": "~3.4|~4.0", "symfony/yaml": "~3.4|~4.0" }, "suggest": { @@ -6375,7 +6790,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.3-dev" } }, "autoload": { @@ -6402,20 +6817,20 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2018-10-31T10:49:51+00:00" + "time": "2019-10-02T12:58:58+00:00" }, { "name": "symfony/stopwatch", - "version": "v3.4.18", + "version": "v3.4.32", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "05e52a39de52ba690aebaed462b2bc8a9649f0a4" + "reference": "c0c27e38f8accb452f830a4ec8e8ac94b6ec864a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/05e52a39de52ba690aebaed462b2bc8a9649f0a4", - "reference": "05e52a39de52ba690aebaed462b2bc8a9649f0a4", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/c0c27e38f8accb452f830a4ec8e8ac94b6ec864a", + "reference": "c0c27e38f8accb452f830a4ec8e8ac94b6ec864a", "shasum": "" }, "require": { @@ -6451,7 +6866,7 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", - "time": "2018-10-02T12:28:39+00:00" + "time": "2019-08-06T13:24:37+00:00" }, { "name": "theseer/fdomdocument", From 2744889bde4600cb41d8a6c3c38edcbe9c86622f Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Tue, 22 Oct 2019 10:37:04 -0500 Subject: [PATCH 026/888] MQE-1796: Magento Git vs Composer and MFTF Fixed review comments. --- docs/guides/git-vs-composer-install.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guides/git-vs-composer-install.md b/docs/guides/git-vs-composer-install.md index baec08471..32b7a0a22 100644 --- a/docs/guides/git-vs-composer-install.md +++ b/docs/guides/git-vs-composer-install.md @@ -39,7 +39,7 @@ If you are developing your own module or adding MFTF tests to the module, you sh If you want to distribute the module and its tests, you can initialize a git repo and create a [composer package](https://devdocs.magento.com/guides/v2.3/extension-dev-guide/package/package_module.html). In this way others will be able to download and install your module and access your tests as a composer package, in their `` folder. -### MFTF test artifacts location +### MFTF test materials location - For GitHub installation, MFTF test materials are located at `/app/code///Test/Mftf/`. This is the directory to create new tests or maintain existing ones. @@ -74,7 +74,7 @@ In either of the installations, all tests and test data are read and merged by M ### Conclusion -There are no differences from MFTF's perspective between having the test materials in `app/code` or in `/vendor` as it reads artifacts from both paths. It works the same. Composer based install may benefit teams when there's a need to match file systems in dev and production. +There are no differences from MFTF's perspective between having the test materials in `app/code` or in `/vendor`. It works the same. Composer based install may benefit teams when there's a need to match file systems in dev and production. If you are a contributing developer with an understanding of Git and Composer commands, you can choose the GitHub installation method instead. From f2a9c029110960af91a313449ec0236048b7cb7e Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Wed, 23 Oct 2019 08:48:09 -0500 Subject: [PATCH 027/888] MQE-1833: CHANGELOG.MD and Composer version bump - Revert and reupdated composer.lock --- composer.lock | 1685 +++++++++++++++++++------------------------------ 1 file changed, 635 insertions(+), 1050 deletions(-) diff --git a/composer.lock b/composer.lock index fb8cb2056..2439f83ef 100644 --- a/composer.lock +++ b/composer.lock @@ -59,26 +59,25 @@ }, { "name": "allure-framework/allure-php-api", - "version": "1.1.5", + "version": "1.1.4", "source": { "type": "git", - "url": "https://github.com/allure-framework/allure-php-commons.git", - "reference": "c7a675823ad75b8e02ddc364baae21668e7c4e88" + "url": "https://github.com/allure-framework/allure-php-adapter-api.git", + "reference": "a462a0da121681577033e13c123b6cc4e89cdc64" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/allure-framework/allure-php-commons/zipball/c7a675823ad75b8e02ddc364baae21668e7c4e88", - "reference": "c7a675823ad75b8e02ddc364baae21668e7c4e88", + "url": "https://api.github.com/repos/allure-framework/allure-php-adapter-api/zipball/a462a0da121681577033e13c123b6cc4e89cdc64", + "reference": "a462a0da121681577033e13c123b6cc4e89cdc64", "shasum": "" }, "require": { - "jms/serializer": "^0.16.0", + "jms/serializer": ">=0.16.0", + "moontoast/math": ">=1.1.0", "php": ">=5.4.0", - "ramsey/uuid": "^3.0.0", - "symfony/http-foundation": "^2.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.0.0" + "phpunit/phpunit": ">=4.0.0", + "ramsey/uuid": ">=3.0.0", + "symfony/http-foundation": ">=2.0" }, "type": "library", "autoload": { @@ -108,20 +107,20 @@ "php", "report" ], - "time": "2018-05-25T14:02:11+00:00" + "time": "2016-12-07T12:15:46+00:00" }, { "name": "behat/gherkin", - "version": "v4.6.0", + "version": "v4.4.5", "source": { "type": "git", "url": "https://github.com/Behat/Gherkin.git", - "reference": "ab0a02ea14893860bca00f225f5621d351a3ad07" + "reference": "5c14cff4f955b17d20d088dec1bde61c0539ec74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Behat/Gherkin/zipball/ab0a02ea14893860bca00f225f5621d351a3ad07", - "reference": "ab0a02ea14893860bca00f225f5621d351a3ad07", + "url": "https://api.github.com/repos/Behat/Gherkin/zipball/5c14cff4f955b17d20d088dec1bde61c0539ec74", + "reference": "5c14cff4f955b17d20d088dec1bde61c0539ec74", "shasum": "" }, "require": { @@ -129,8 +128,8 @@ }, "require-dev": { "phpunit/phpunit": "~4.5|~5", - "symfony/phpunit-bridge": "~2.7|~3|~4", - "symfony/yaml": "~2.3|~3|~4" + "symfony/phpunit-bridge": "~2.7|~3", + "symfony/yaml": "~2.3|~3" }, "suggest": { "symfony/yaml": "If you want to parse features, represented in YAML files" @@ -167,7 +166,7 @@ "gherkin", "parser" ], - "time": "2019-01-16T14:22:17+00:00" + "time": "2016-10-30T11:50:56+00:00" }, { "name": "cache/cache", @@ -251,7 +250,7 @@ { "name": "Tobias Nyholm", "email": "tobias.nyholm@gmail.com", - "homepage": "https://github.com/nyholm" + "homepage": "https://github.com/Nyholm" } ], "description": "Library of all the php-cache adapters", @@ -264,28 +263,31 @@ }, { "name": "codeception/codeception", - "version": "2.4.5", + "version": "2.3.9", "source": { "type": "git", "url": "https://github.com/Codeception/Codeception.git", - "reference": "5fee32d5c82791548931cbc34806b4de6aa1abfc" + "reference": "104f46fa0bde339f1bcc3a375aac21eb36e65a1e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/Codeception/zipball/5fee32d5c82791548931cbc34806b4de6aa1abfc", - "reference": "5fee32d5c82791548931cbc34806b4de6aa1abfc", + "url": "https://api.github.com/repos/Codeception/Codeception/zipball/104f46fa0bde339f1bcc3a375aac21eb36e65a1e", + "reference": "104f46fa0bde339f1bcc3a375aac21eb36e65a1e", "shasum": "" }, "require": { - "behat/gherkin": "^4.4.0", - "codeception/phpunit-wrapper": "^6.0.9|^7.0.6", - "codeception/stub": "^2.0", + "behat/gherkin": "~4.4.0", + "codeception/stub": "^1.0", "ext-json": "*", "ext-mbstring": "*", "facebook/webdriver": ">=1.1.3 <2.0", "guzzlehttp/guzzle": ">=4.1.4 <7.0", "guzzlehttp/psr7": "~1.0", - "php": ">=5.6.0 <8.0", + "php": ">=5.4.0 <8.0", + "phpunit/php-code-coverage": ">=2.2.4 <6.0", + "phpunit/phpunit": ">=4.8.28 <5.0.0 || >=5.6.3 <7.0", + "sebastian/comparator": ">1.1 <3.0", + "sebastian/diff": ">=1.4 <3.0", "symfony/browser-kit": ">=2.7 <5.0", "symfony/console": ">=2.7 <5.0", "symfony/css-selector": ">=2.7 <5.0", @@ -351,66 +353,26 @@ "functional testing", "unit testing" ], - "time": "2018-08-01T07:21:49+00:00" - }, - { - "name": "codeception/phpunit-wrapper", - "version": "7.0.6", - "source": { - "type": "git", - "url": "https://github.com/Codeception/phpunit-wrapper.git", - "reference": "e8528cb777cf5a5ccea1cf57a3522b142625d1b5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Codeception/phpunit-wrapper/zipball/e8528cb777cf5a5ccea1cf57a3522b142625d1b5", - "reference": "e8528cb777cf5a5ccea1cf57a3522b142625d1b5", - "shasum": "" - }, - "require": { - "phpunit/php-code-coverage": "^6.0", - "phpunit/phpunit": "^7.0", - "sebastian/comparator": "^2.0", - "sebastian/diff": "^3.0" - }, - "require-dev": { - "codeception/specify": "*", - "vlucas/phpdotenv": "^2.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "Codeception\\PHPUnit\\": "src\\" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Davert", - "email": "davert.php@resend.cc" - } - ], - "description": "PHPUnit classes used by Codeception", - "time": "2018-03-31T18:49:51+00:00" + "time": "2018-02-26T23:29:41+00:00" }, { "name": "codeception/stub", - "version": "2.0.4", + "version": "1.0.4", "source": { "type": "git", "url": "https://github.com/Codeception/Stub.git", - "reference": "f50bc271f392a2836ff80690ce0c058efe1ae03e" + "reference": "681b62348837a5ef07d10d8a226f5bc358cc8805" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/Stub/zipball/f50bc271f392a2836ff80690ce0c058efe1ae03e", - "reference": "f50bc271f392a2836ff80690ce0c058efe1ae03e", + "url": "https://api.github.com/repos/Codeception/Stub/zipball/681b62348837a5ef07d10d8a226f5bc358cc8805", + "reference": "681b62348837a5ef07d10d8a226f5bc358cc8805", "shasum": "" }, "require": { + "phpunit/phpunit-mock-objects": ">2.3 <7.0" + }, + "require-dev": { "phpunit/phpunit": ">=4.8 <8.0" }, "type": "library", @@ -424,7 +386,7 @@ "MIT" ], "description": "Flexible Stub wrapper for PHPUnit's Mock Builder", - "time": "2018-07-26T11:55:37+00:00" + "time": "2018-05-17T09:31:08+00:00" }, { "name": "composer/ca-bundle", @@ -730,78 +692,34 @@ }, { "name": "consolidation/annotated-command", - "version": "2.12.0", + "version": "2.9.1", "source": { "type": "git", "url": "https://github.com/consolidation/annotated-command.git", - "reference": "512a2e54c98f3af377589de76c43b24652bcb789" + "reference": "4bdbb8fa149e1cc1511bd77b0bc4729fd66bccac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/annotated-command/zipball/512a2e54c98f3af377589de76c43b24652bcb789", - "reference": "512a2e54c98f3af377589de76c43b24652bcb789", + "url": "https://api.github.com/repos/consolidation/annotated-command/zipball/4bdbb8fa149e1cc1511bd77b0bc4729fd66bccac", + "reference": "4bdbb8fa149e1cc1511bd77b0bc4729fd66bccac", "shasum": "" }, "require": { - "consolidation/output-formatters": "^3.4", - "php": ">=5.4.5", + "consolidation/output-formatters": "^3.1.12", + "php": ">=5.4.0", "psr/log": "^1", "symfony/console": "^2.8|^3|^4", "symfony/event-dispatcher": "^2.5|^3|^4", "symfony/finder": "^2.5|^3|^4" }, "require-dev": { - "g1a/composer-test-scenarios": "^3", - "php-coveralls/php-coveralls": "^1", + "g1a/composer-test-scenarios": "^2", "phpunit/phpunit": "^6", + "satooshi/php-coveralls": "^2", "squizlabs/php_codesniffer": "^2.7" }, "type": "library", "extra": { - "scenarios": { - "symfony4": { - "require": { - "symfony/console": "^4.0" - }, - "config": { - "platform": { - "php": "7.1.3" - } - } - }, - "symfony2": { - "require": { - "symfony/console": "^2.8" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.36" - }, - "remove": [ - "php-coveralls/php-coveralls" - ], - "config": { - "platform": { - "php": "5.4.8" - } - }, - "scenario-options": { - "create-lockfile": "false" - } - }, - "phpunit4": { - "require-dev": { - "phpunit/phpunit": "^4.8.36" - }, - "remove": [ - "php-coveralls/php-coveralls" - ], - "config": { - "platform": { - "php": "5.4.8" - } - } - } - }, "branch-alias": { "dev-master": "2.x-dev" } @@ -822,20 +740,20 @@ } ], "description": "Initialize Symfony Console commands from annotated command class methods.", - "time": "2019-03-08T16:55:03+00:00" + "time": "2018-09-19T17:47:18+00:00" }, { "name": "consolidation/config", - "version": "1.2.1", + "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/consolidation/config.git", - "reference": "cac1279bae7efb5c7fb2ca4c3ba4b8eb741a96c1" + "reference": "925231dfff32f05b787e1fddb265e789b939cf4c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/config/zipball/cac1279bae7efb5c7fb2ca4c3ba4b8eb741a96c1", - "reference": "cac1279bae7efb5c7fb2ca4c3ba4b8eb741a96c1", + "url": "https://api.github.com/repos/consolidation/config/zipball/925231dfff32f05b787e1fddb265e789b939cf4c", + "reference": "925231dfff32f05b787e1fddb265e789b939cf4c", "shasum": "" }, "require": { @@ -844,9 +762,9 @@ "php": ">=5.4.0" }, "require-dev": { - "g1a/composer-test-scenarios": "^3", - "php-coveralls/php-coveralls": "^1", + "g1a/composer-test-scenarios": "^1", "phpunit/phpunit": "^5", + "satooshi/php-coveralls": "^1.0", "squizlabs/php_codesniffer": "2.*", "symfony/console": "^2.5|^3|^4", "symfony/yaml": "^2.8.11|^3|^4" @@ -856,33 +774,6 @@ }, "type": "library", "extra": { - "scenarios": { - "symfony4": { - "require-dev": { - "symfony/console": "^4.0" - }, - "config": { - "platform": { - "php": "7.1.3" - } - } - }, - "symfony2": { - "require-dev": { - "symfony/console": "^2.8", - "symfony/event-dispatcher": "^2.8", - "phpunit/phpunit": "^4.8.36" - }, - "remove": [ - "php-coveralls/php-coveralls" - ], - "config": { - "platform": { - "php": "5.4.8" - } - } - } - }, "branch-alias": { "dev-master": "1.x-dev" } @@ -903,76 +794,35 @@ } ], "description": "Provide configuration services for a commandline tool.", - "time": "2019-03-03T19:37:04+00:00" + "time": "2018-10-24T17:55:35+00:00" }, { "name": "consolidation/log", - "version": "1.1.1", + "version": "1.0.6", "source": { "type": "git", "url": "https://github.com/consolidation/log.git", - "reference": "b2e887325ee90abc96b0a8b7b474cd9e7c896e3a" + "reference": "dfd8189a771fe047bf3cd669111b2de5f1c79395" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/log/zipball/b2e887325ee90abc96b0a8b7b474cd9e7c896e3a", - "reference": "b2e887325ee90abc96b0a8b7b474cd9e7c896e3a", + "url": "https://api.github.com/repos/consolidation/log/zipball/dfd8189a771fe047bf3cd669111b2de5f1c79395", + "reference": "dfd8189a771fe047bf3cd669111b2de5f1c79395", "shasum": "" }, "require": { - "php": ">=5.4.5", - "psr/log": "^1.0", + "php": ">=5.5.0", + "psr/log": "~1.0", "symfony/console": "^2.8|^3|^4" }, "require-dev": { - "g1a/composer-test-scenarios": "^3", - "php-coveralls/php-coveralls": "^1", - "phpunit/phpunit": "^6", - "squizlabs/php_codesniffer": "^2" + "g1a/composer-test-scenarios": "^1", + "phpunit/phpunit": "4.*", + "satooshi/php-coveralls": "^2", + "squizlabs/php_codesniffer": "2.*" }, "type": "library", "extra": { - "scenarios": { - "symfony4": { - "require": { - "symfony/console": "^4.0" - }, - "config": { - "platform": { - "php": "7.1.3" - } - } - }, - "symfony2": { - "require": { - "symfony/console": "^2.8" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.36" - }, - "remove": [ - "php-coveralls/php-coveralls" - ], - "config": { - "platform": { - "php": "5.4.8" - } - } - }, - "phpunit4": { - "require-dev": { - "phpunit/phpunit": "^4.8.36" - }, - "remove": [ - "php-coveralls/php-coveralls" - ], - "config": { - "platform": { - "php": "5.4.8" - } - } - } - }, "branch-alias": { "dev-master": "1.x-dev" } @@ -993,20 +843,20 @@ } ], "description": "Improved Psr-3 / Psr\\Log logger based on Symfony Console components.", - "time": "2019-01-01T17:30:51+00:00" + "time": "2018-05-25T18:14:39+00:00" }, { "name": "consolidation/output-formatters", - "version": "3.5.0", + "version": "3.4.0", "source": { "type": "git", "url": "https://github.com/consolidation/output-formatters.git", - "reference": "99ec998ffb697e0eada5aacf81feebfb13023605" + "reference": "a942680232094c4a5b21c0b7e54c20cce623ae19" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/output-formatters/zipball/99ec998ffb697e0eada5aacf81feebfb13023605", - "reference": "99ec998ffb697e0eada5aacf81feebfb13023605", + "url": "https://api.github.com/repos/consolidation/output-formatters/zipball/a942680232094c4a5b21c0b7e54c20cce623ae19", + "reference": "a942680232094c4a5b21c0b7e54c20cce623ae19", "shasum": "" }, "require": { @@ -1016,10 +866,11 @@ "symfony/finder": "^2.5|^3|^4" }, "require-dev": { - "g1a/composer-test-scenarios": "^3", - "php-coveralls/php-coveralls": "^1", + "g1a/composer-test-scenarios": "^2", "phpunit/phpunit": "^5.7.27", + "satooshi/php-coveralls": "^2", "squizlabs/php_codesniffer": "^2.7", + "symfony/console": "3.2.3", "symfony/var-dumper": "^2.8|^3|^4", "victorjonsson/markdowndocs": "^1.3" }, @@ -1028,52 +879,6 @@ }, "type": "library", "extra": { - "scenarios": { - "symfony4": { - "require": { - "symfony/console": "^4.0" - }, - "require-dev": { - "phpunit/phpunit": "^6" - }, - "config": { - "platform": { - "php": "7.1.3" - } - } - }, - "symfony3": { - "require": { - "symfony/console": "^3.4", - "symfony/finder": "^3.4", - "symfony/var-dumper": "^3.4" - }, - "config": { - "platform": { - "php": "5.6.32" - } - } - }, - "symfony2": { - "require": { - "symfony/console": "^2.8" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.36" - }, - "remove": [ - "php-coveralls/php-coveralls" - ], - "config": { - "platform": { - "php": "5.4.8" - } - }, - "scenario-options": { - "create-lockfile": "false" - } - } - }, "branch-alias": { "dev-master": "3.x-dev" } @@ -1094,28 +899,29 @@ } ], "description": "Format text by applying transformations provided by plug-in formatters.", - "time": "2019-05-30T23:16:01+00:00" + "time": "2018-10-19T22:35:38+00:00" }, { "name": "consolidation/robo", - "version": "1.4.10", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/consolidation/Robo.git", - "reference": "e5a6ca64cf1324151873672e484aceb21f365681" + "reference": "31f2d2562c4e1dcde70f2659eefd59aa9c7f5b2d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/Robo/zipball/e5a6ca64cf1324151873672e484aceb21f365681", - "reference": "e5a6ca64cf1324151873672e484aceb21f365681", + "url": "https://api.github.com/repos/consolidation/Robo/zipball/31f2d2562c4e1dcde70f2659eefd59aa9c7f5b2d", + "reference": "31f2d2562c4e1dcde70f2659eefd59aa9c7f5b2d", "shasum": "" }, "require": { - "consolidation/annotated-command": "^2.10.2", - "consolidation/config": "^1.2", + "consolidation/annotated-command": "^2.8.2", + "consolidation/config": "^1.0.10", "consolidation/log": "~1", "consolidation/output-formatters": "^3.1.13", "consolidation/self-update": "^1", + "g1a/composer-test-scenarios": "^2", "grasmash/yaml-expander": "^1.3", "league/container": "^2.2", "php": ">=5.5.0", @@ -1132,15 +938,14 @@ "codeception/aspect-mock": "^1|^2.1.1", "codeception/base": "^2.3.7", "codeception/verify": "^0.3.2", - "g1a/composer-test-scenarios": "^3", "goaop/framework": "~2.1.2", "goaop/parser-reflection": "^1.1.0", "natxet/cssmin": "3.0.4", "nikic/php-parser": "^3.1.5", "patchwork/jsqueeze": "~2", - "pear/archive_tar": "^1.4.4", - "php-coveralls/php-coveralls": "^1", + "pear/archive_tar": "^1.4.2", "phpunit/php-code-coverage": "~2|~4", + "satooshi/php-coveralls": "^2", "squizlabs/php_codesniffer": "^2.8" }, "suggest": { @@ -1154,36 +959,9 @@ ], "type": "library", "extra": { - "scenarios": { - "symfony4": { - "require": { - "symfony/console": "^4" - }, - "config": { - "platform": { - "php": "7.1.3" - } - } - }, - "symfony2": { - "require": { - "symfony/console": "^2.8" - }, - "remove": [ - "goaop/framework" - ], - "config": { - "platform": { - "php": "5.5.9" - } - }, - "scenario-options": { - "create-lockfile": "false" - } - } - }, "branch-alias": { - "dev-master": "2.x-dev" + "dev-master": "1.x-dev", + "dev-state": "1.x-dev" } }, "autoload": { @@ -1202,7 +980,7 @@ } ], "description": "Modern task runner", - "time": "2019-07-29T15:40:50+00:00" + "time": "2018-08-17T18:44:18+00:00" }, { "name": "consolidation/self-update", @@ -1432,30 +1210,30 @@ }, { "name": "doctrine/annotations", - "version": "v1.8.0", + "version": "v1.4.0", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "904dca4eb10715b92569fbcd79e201d5c349b6bc" + "reference": "54cacc9b81758b14e3ce750f205a393d52339e97" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/904dca4eb10715b92569fbcd79e201d5c349b6bc", - "reference": "904dca4eb10715b92569fbcd79e201d5c349b6bc", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/54cacc9b81758b14e3ce750f205a393d52339e97", + "reference": "54cacc9b81758b14e3ce750f205a393d52339e97", "shasum": "" }, "require": { "doctrine/lexer": "1.*", - "php": "^7.1" + "php": "^5.6 || ^7.0" }, "require-dev": { "doctrine/cache": "1.*", - "phpunit/phpunit": "^7.5" + "phpunit/phpunit": "^5.7" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7.x-dev" + "dev-master": "1.4.x-dev" } }, "autoload": { @@ -1468,10 +1246,6 @@ "MIT" ], "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -1480,6 +1254,10 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -1496,7 +1274,7 @@ "docblock", "parser" ], - "time": "2019-10-01T18:55:10+00:00" + "time": "2017-02-24T16:22:25+00:00" }, { "name": "doctrine/cache", @@ -1637,34 +1415,32 @@ }, { "name": "doctrine/instantiator", - "version": "1.2.0", + "version": "1.0.5", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "a2c590166b2133a4633738648b6b064edae0814a" + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/a2c590166b2133a4633738648b6b064edae0814a", - "reference": "a2c590166b2133a4633738648b6b064edae0814a", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", "shasum": "" }, "require": { - "php": "^7.1" + "php": ">=5.3,<8.0-DEV" }, "require-dev": { - "doctrine/coding-standard": "^6.0", + "athletic/athletic": "~0.1.8", "ext-pdo": "*", "ext-phar": "*", - "phpbench/phpbench": "^0.13", - "phpstan/phpstan-phpunit": "^0.11", - "phpstan/phpstan-shim": "^0.11", - "phpunit/phpunit": "^7.0" + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~2.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { @@ -1684,12 +1460,12 @@ } ], "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "homepage": "https://github.com/doctrine/instantiator", "keywords": [ "constructor", "instantiate" ], - "time": "2019-03-17T17:37:11+00:00" + "time": "2015-06-14T21:17:01+00:00" }, { "name": "doctrine/lexer", @@ -1753,16 +1529,16 @@ }, { "name": "facebook/webdriver", - "version": "1.7.1", + "version": "1.6.0", "source": { "type": "git", "url": "https://github.com/facebook/php-webdriver.git", - "reference": "e43de70f3c7166169d0f14a374505392734160e5" + "reference": "bd8c740097eb9f2fc3735250fc1912bc811a954e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/e43de70f3c7166169d0f14a374505392734160e5", - "reference": "e43de70f3c7166169d0f14a374505392734160e5", + "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/bd8c740097eb9f2fc3735250fc1912bc811a954e", + "reference": "bd8c740097eb9f2fc3735250fc1912bc811a954e", "shasum": "" }, "require": { @@ -1809,7 +1585,7 @@ "selenium", "webdriver" ], - "time": "2019-06-13T08:02:18+00:00" + "time": "2018-05-16T17:37:13+00:00" }, { "name": "flow/jsonpath", @@ -1902,6 +1678,39 @@ ], "time": "2018-07-12T10:23:15+00:00" }, + { + "name": "g1a/composer-test-scenarios", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/g1a/composer-test-scenarios.git", + "reference": "a166fd15191aceab89f30c097e694b7cf3db4880" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/g1a/composer-test-scenarios/zipball/a166fd15191aceab89f30c097e694b7cf3db4880", + "reference": "a166fd15191aceab89f30c097e694b7cf3db4880", + "shasum": "" + }, + "bin": [ + "scripts/create-scenario", + "scripts/dependency-licenses", + "scripts/install-scenario" + ], + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Greg Anderson", + "email": "greg.1.anderson@greenknowe.org" + } + ], + "description": "Useful scripts for testing multiple sets of Composer dependencies.", + "time": "2018-08-08T23:37:23+00:00" + }, { "name": "grasmash/expander", "version": "1.0.0", @@ -2115,37 +1924,32 @@ }, { "name": "guzzlehttp/psr7", - "version": "1.6.1", + "version": "1.4.2", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "239400de7a173fe9901b9ac7c06497751f00727a" + "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/239400de7a173fe9901b9ac7c06497751f00727a", - "reference": "239400de7a173fe9901b9ac7c06497751f00727a", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c", + "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c", "shasum": "" }, "require": { "php": ">=5.4.0", - "psr/http-message": "~1.0", - "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" + "psr/http-message": "~1.0" }, "provide": { "psr/http-message-implementation": "1.0" }, "require-dev": { - "ext-zlib": "*", - "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8" - }, - "suggest": { - "zendframework/zend-httphandlerrunner": "Emit PSR-7 responses" + "phpunit/phpunit": "~4.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.6-dev" + "dev-master": "1.4-dev" } }, "autoload": { @@ -2175,56 +1979,13 @@ "keywords": [ "http", "message", - "psr-7", "request", "response", "stream", "uri", "url" ], - "time": "2019-07-01T23:21:34+00:00" - }, - { - "name": "ircmaxell/password-compat", - "version": "v1.0.4", - "source": { - "type": "git", - "url": "https://github.com/ircmaxell/password_compat.git", - "reference": "5c5cde8822a69545767f7c7f3058cb15ff84614c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ircmaxell/password_compat/zipball/5c5cde8822a69545767f7c7f3058cb15ff84614c", - "reference": "5c5cde8822a69545767f7c7f3058cb15ff84614c", - "shasum": "" - }, - "require-dev": { - "phpunit/phpunit": "4.*" - }, - "type": "library", - "autoload": { - "files": [ - "lib/password.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Anthony Ferrara", - "email": "ircmaxell@php.net", - "homepage": "http://blog.ircmaxell.com" - } - ], - "description": "A compatibility library for the proposed simplified password hashing algorithm: https://wiki.php.net/rfc/password_hash", - "homepage": "https://github.com/ircmaxell/password_compat", - "keywords": [ - "hashing", - "password" - ], - "time": "2014-11-20T16:49:30+00:00" + "time": "2017-03-20T17:10:46+00:00" }, { "name": "jms/metadata", @@ -2318,44 +2079,56 @@ }, { "name": "jms/serializer", - "version": "0.16.0", + "version": "1.14.0", "source": { "type": "git", "url": "https://github.com/schmittjoh/serializer.git", - "reference": "c8a171357ca92b6706e395c757f334902d430ea9" + "reference": "ee96d57024af9a7716d56fcbe3aa94b3d030f3ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/c8a171357ca92b6706e395c757f334902d430ea9", - "reference": "c8a171357ca92b6706e395c757f334902d430ea9", + "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/ee96d57024af9a7716d56fcbe3aa94b3d030f3ca", + "reference": "ee96d57024af9a7716d56fcbe3aa94b3d030f3ca", "shasum": "" }, "require": { - "doctrine/annotations": "1.*", - "jms/metadata": "~1.1", + "doctrine/annotations": "^1.0", + "doctrine/instantiator": "^1.0.3", + "jms/metadata": "^1.3", "jms/parser-lib": "1.*", - "php": ">=5.3.2", - "phpcollection/phpcollection": "~0.1" + "php": "^5.5|^7.0", + "phpcollection/phpcollection": "~0.1", + "phpoption/phpoption": "^1.1" + }, + "conflict": { + "twig/twig": "<1.12" }, "require-dev": { "doctrine/orm": "~2.1", - "doctrine/phpcr-odm": "~1.0.1", - "jackalope/jackalope-doctrine-dbal": "1.0.*", + "doctrine/phpcr-odm": "^1.3|^2.0", + "ext-pdo_sqlite": "*", + "jackalope/jackalope-doctrine-dbal": "^1.1.5", + "phpunit/phpunit": "^4.8|^5.0", "propel/propel1": "~1.7", - "symfony/filesystem": "2.*", - "symfony/form": "~2.1", - "symfony/translation": "~2.0", - "symfony/validator": "~2.0", - "symfony/yaml": "2.*", - "twig/twig": ">=1.8,<2.0-dev" + "psr/container": "^1.0", + "symfony/dependency-injection": "^2.7|^3.3|^4.0", + "symfony/expression-language": "^2.6|^3.0", + "symfony/filesystem": "^2.1", + "symfony/form": "~2.1|^3.0", + "symfony/translation": "^2.1|^3.0", + "symfony/validator": "^2.2|^3.0", + "symfony/yaml": "^2.1|^3.0", + "twig/twig": "~1.12|~2.0" }, "suggest": { + "doctrine/cache": "Required if you like to use cache functionality.", + "doctrine/collections": "Required if you like to use doctrine collection types as ArrayCollection.", "symfony/yaml": "Required if you'd like to serialize data to YAML format." }, "type": "library", "extra": { "branch-alias": { - "dev-master": "0.15-dev" + "dev-1.x": "1.14-dev" } }, "autoload": { @@ -2365,14 +2138,16 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "Apache2" + "MIT" ], "authors": [ { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com", - "homepage": "https://github.com/schmittjoh", - "role": "Developer of wrapped JMSSerializerBundle" + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" + }, + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com" } ], "description": "Library for (de-)serializing data of any complexity; supports XML, JSON, and YAML.", @@ -2384,7 +2159,7 @@ "serialization", "xml" ], - "time": "2014-03-18T08:39:00+00:00" + "time": "2019-04-17T08:12:16+00:00" }, { "name": "justinrainbow/json-schema", @@ -2519,16 +2294,16 @@ }, { "name": "league/flysystem", - "version": "1.0.57", + "version": "1.0.53", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "0e9db7f0b96b9f12dcf6f65bc34b72b1a30ea55a" + "reference": "08e12b7628f035600634a5e76d95b5eb66cea674" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/0e9db7f0b96b9f12dcf6f65bc34b72b1a30ea55a", - "reference": "0e9db7f0b96b9f12dcf6f65bc34b72b1a30ea55a", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/08e12b7628f035600634a5e76d95b5eb66cea674", + "reference": "08e12b7628f035600634a5e76d95b5eb66cea674", "shasum": "" }, "require": { @@ -2599,20 +2374,20 @@ "sftp", "storage" ], - "time": "2019-10-16T21:01:05+00:00" + "time": "2019-06-18T20:09:29+00:00" }, { "name": "monolog/monolog", - "version": "1.25.1", + "version": "1.24.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "70e65a5470a42cfec1a7da00d30edb6e617e8dcf" + "reference": "bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/70e65a5470a42cfec1a7da00d30edb6e617e8dcf", - "reference": "70e65a5470a42cfec1a7da00d30edb6e617e8dcf", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266", + "reference": "bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266", "shasum": "" }, "require": { @@ -2677,7 +2452,56 @@ "logging", "psr-3" ], - "time": "2019-09-06T13:49:17+00:00" + "time": "2018-11-05T09:00:11+00:00" + }, + { + "name": "moontoast/math", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/ramsey/moontoast-math.git", + "reference": "c2792a25df5cad4ff3d760dd37078fc5b6fccc79" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/moontoast-math/zipball/c2792a25df5cad4ff3d760dd37078fc5b6fccc79", + "reference": "c2792a25df5cad4ff3d760dd37078fc5b6fccc79", + "shasum": "" + }, + "require": { + "ext-bcmath": "*", + "php": ">=5.3.3" + }, + "require-dev": { + "jakub-onderka/php-parallel-lint": "^0.9.0", + "phpunit/phpunit": "^4.7|>=5.0 <5.4", + "satooshi/php-coveralls": "^0.6.1", + "squizlabs/php_codesniffer": "^2.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Moontoast\\Math\\": "src/Moontoast/Math/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + } + ], + "description": "A mathematics library, providing functionality for large numbers", + "homepage": "https://github.com/ramsey/moontoast-math", + "keywords": [ + "bcmath", + "math" + ], + "time": "2017-02-16T16:54:46+00:00" }, { "name": "mustache/mustache", @@ -2727,28 +2551,25 @@ }, { "name": "myclabs/deep-copy", - "version": "1.9.3", + "version": "1.7.0", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea" + "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/007c053ae6f31bba39dfa19a7726f56e9763bbea", - "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", "shasum": "" }, "require": { - "php": "^7.1" - }, - "replace": { - "myclabs/deep-copy": "self.version" + "php": "^5.6 || ^7.0" }, "require-dev": { "doctrine/collections": "^1.0", "doctrine/common": "^2.6", - "phpunit/phpunit": "^7.1" + "phpunit/phpunit": "^4.1" }, "type": "library", "autoload": { @@ -2771,7 +2592,7 @@ "object", "object graph" ], - "time": "2019-08-09T12:45:53+00:00" + "time": "2017-10-19T19:58:43+00:00" }, { "name": "paragonie/random_compat", @@ -2970,33 +2791,35 @@ }, { "name": "phpdocumentor/reflection-common", - "version": "2.0.0", + "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a" + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a", - "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=5.5" }, "require-dev": { - "phpunit/phpunit": "~6" + "phpunit/phpunit": "^4.6" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.x-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": "src/" + "phpDocumentor\\Reflection\\": [ + "src" + ] } }, "notification-url": "https://packagist.org/downloads/", @@ -3018,30 +2841,30 @@ "reflection", "static analysis" ], - "time": "2018-08-07T13:53:10+00:00" + "time": "2017-09-11T18:02:19+00:00" }, { "name": "phpdocumentor/reflection-docblock", - "version": "4.3.2", + "version": "4.3.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e" + "reference": "94fd0001232e47129dd3504189fa1c7225010d08" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/b83ff7cfcfee7827e1e78b637a5904fe6a96698e", - "reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08", + "reference": "94fd0001232e47129dd3504189fa1c7225010d08", "shasum": "" }, "require": { "php": "^7.0", - "phpdocumentor/reflection-common": "^1.0.0 || ^2.0.0", - "phpdocumentor/type-resolver": "~0.4 || ^1.0.0", + "phpdocumentor/reflection-common": "^1.0.0", + "phpdocumentor/type-resolver": "^0.4.0", "webmozart/assert": "^1.0" }, "require-dev": { - "doctrine/instantiator": "^1.0.5", + "doctrine/instantiator": "~1.0.5", "mockery/mockery": "^1.0", "phpunit/phpunit": "^6.4" }, @@ -3069,40 +2892,41 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2019-09-12T14:27:41+00:00" + "time": "2017-11-30T07:14:17+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "1.0.1", + "version": "0.4.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9" + "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", - "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", + "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", "shasum": "" }, "require": { - "php": "^7.1", - "phpdocumentor/reflection-common": "^2.0" + "php": "^5.5 || ^7.0", + "phpdocumentor/reflection-common": "^1.0" }, "require-dev": { - "ext-tokenizer": "^7.1", - "mockery/mockery": "~1", - "phpunit/phpunit": "^7.0" + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^5.2||^4.8.24" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": "src" + "phpDocumentor\\Reflection\\": [ + "src/" + ] } }, "notification-url": "https://packagist.org/downloads/", @@ -3115,8 +2939,7 @@ "email": "me@mikevanriel.com" } ], - "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "time": "2019-08-22T18:11:29+00:00" + "time": "2017-07-14T14:27:02+00:00" }, { "name": "phpoption/phpoption", @@ -3170,22 +2993,22 @@ }, { "name": "phpspec/prophecy", - "version": "1.9.0", + "version": "1.8.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203" + "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/f6811d96d97bdf400077a0cc100ae56aa32b9203", - "reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06", + "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", "sebastian/comparator": "^1.1|^2.0|^3.0", "sebastian/recursion-context": "^1.0|^2.0|^3.0" }, @@ -3200,8 +3023,8 @@ } }, "autoload": { - "psr-4": { - "Prophecy\\": "src/Prophecy" + "psr-0": { + "Prophecy\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -3229,44 +3052,44 @@ "spy", "stub" ], - "time": "2019-10-03T11:07:50+00:00" + "time": "2018-08-05T17:53:17+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "6.0.5", + "version": "5.3.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "4cab20a326d14de7575a8e235c70d879b569a57a" + "reference": "c89677919c5dd6d3b3852f230a663118762218ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/4cab20a326d14de7575a8e235c70d879b569a57a", - "reference": "4cab20a326d14de7575a8e235c70d879b569a57a", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c89677919c5dd6d3b3852f230a663118762218ac", + "reference": "c89677919c5dd6d3b3852f230a663118762218ac", "shasum": "" }, "require": { "ext-dom": "*", "ext-xmlwriter": "*", - "php": "^7.1", + "php": "^7.0", "phpunit/php-file-iterator": "^1.4.2", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^3.0", + "phpunit/php-token-stream": "^2.0.1", "sebastian/code-unit-reverse-lookup": "^1.0.1", - "sebastian/environment": "^3.1", + "sebastian/environment": "^3.0", "sebastian/version": "^2.0.1", "theseer/tokenizer": "^1.1" }, "require-dev": { - "phpunit/phpunit": "^7.0" + "phpunit/phpunit": "^6.0" }, "suggest": { - "ext-xdebug": "^2.6.0" + "ext-xdebug": "^2.5.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "6.0-dev" + "dev-master": "5.3.x-dev" } }, "autoload": { @@ -3292,7 +3115,7 @@ "testing", "xunit" ], - "time": "2018-05-28T11:49:20+00:00" + "time": "2018-04-06T15:36:58+00:00" }, { "name": "phpunit/php-file-iterator", @@ -3384,28 +3207,28 @@ }, { "name": "phpunit/php-timer", - "version": "2.1.2", + "version": "1.0.9", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "1038454804406b0b5f5f520358e78c1c2f71501e" + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/1038454804406b0b5f5f520358e78c1c2f71501e", - "reference": "1038454804406b0b5f5f520358e78c1c2f71501e", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", "shasum": "" }, "require": { - "php": "^7.1" + "php": "^5.3.3 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "^7.0" + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1-dev" + "dev-master": "1.0-dev" } }, "autoload": { @@ -3420,7 +3243,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", + "email": "sb@sebastian-bergmann.de", "role": "lead" } ], @@ -3429,33 +3252,33 @@ "keywords": [ "timer" ], - "time": "2019-06-07T04:22:29+00:00" + "time": "2017-02-26T11:10:40+00:00" }, { "name": "phpunit/php-token-stream", - "version": "3.1.1", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff" + "reference": "791198a2c6254db10131eecfe8c06670700904db" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/995192df77f63a59e47f025390d2d1fdf8f425ff", - "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db", + "reference": "791198a2c6254db10131eecfe8c06670700904db", "shasum": "" }, "require": { "ext-tokenizer": "*", - "php": "^7.1" + "php": "^7.0" }, "require-dev": { - "phpunit/phpunit": "^7.0" + "phpunit/phpunit": "^6.2.4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -3478,20 +3301,20 @@ "keywords": [ "tokenizer" ], - "time": "2019-09-17T06:23:10+00:00" + "time": "2017-11-27T05:48:46+00:00" }, { "name": "phpunit/phpunit", - "version": "7.0.3", + "version": "6.5.13", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "536f4d853c12d8189963435088e8ff7c0daeab2e" + "reference": "0973426fb012359b2f18d3bd1e90ef1172839693" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/536f4d853c12d8189963435088e8ff7c0daeab2e", - "reference": "536f4d853c12d8189963435088e8ff7c0daeab2e", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0973426fb012359b2f18d3bd1e90ef1172839693", + "reference": "0973426fb012359b2f18d3bd1e90ef1172839693", "shasum": "" }, "require": { @@ -3503,15 +3326,15 @@ "myclabs/deep-copy": "^1.6.1", "phar-io/manifest": "^1.0.1", "phar-io/version": "^1.0", - "php": "^7.1", + "php": "^7.0", "phpspec/prophecy": "^1.7", - "phpunit/php-code-coverage": "^6.0.1", + "phpunit/php-code-coverage": "^5.3", "phpunit/php-file-iterator": "^1.4.3", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-timer": "^2.0", - "phpunit/phpunit-mock-objects": "^6.0", + "phpunit/php-timer": "^1.0.9", + "phpunit/phpunit-mock-objects": "^5.0.9", "sebastian/comparator": "^2.1", - "sebastian/diff": "^3.0", + "sebastian/diff": "^2.0", "sebastian/environment": "^3.1", "sebastian/exporter": "^3.1", "sebastian/global-state": "^2.0", @@ -3519,12 +3342,16 @@ "sebastian/resource-operations": "^1.0", "sebastian/version": "^2.0.1" }, + "conflict": { + "phpdocumentor/reflection-docblock": "3.0.2", + "phpunit/dbunit": "<3.0" + }, "require-dev": { "ext-pdo": "*" }, "suggest": { "ext-xdebug": "*", - "phpunit/php-invoker": "^2.0" + "phpunit/php-invoker": "^1.1" }, "bin": [ "phpunit" @@ -3532,7 +3359,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "7.0-dev" + "dev-master": "6.5.x-dev" } }, "autoload": { @@ -3558,30 +3385,33 @@ "testing", "xunit" ], - "time": "2018-03-26T07:36:48+00:00" + "time": "2018-09-08T15:10:43+00:00" }, { "name": "phpunit/phpunit-mock-objects", - "version": "6.1.2", + "version": "5.0.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "f9756fd4f43f014cb2dca98deeaaa8ce5500a36e" + "reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/f9756fd4f43f014cb2dca98deeaaa8ce5500a36e", - "reference": "f9756fd4f43f014cb2dca98deeaaa8ce5500a36e", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/cd1cf05c553ecfec36b170070573e540b67d3f1f", + "reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.5", - "php": "^7.1", + "php": "^7.0", "phpunit/php-text-template": "^1.2.1", "sebastian/exporter": "^3.1" }, + "conflict": { + "phpunit/phpunit": "<6.0" + }, "require-dev": { - "phpunit/phpunit": "^7.0" + "phpunit/phpunit": "^6.5.11" }, "suggest": { "ext-soap": "*" @@ -3589,7 +3419,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "6.1-dev" + "dev-master": "5.0.x-dev" } }, "autoload": { @@ -3615,7 +3445,7 @@ "xunit" ], "abandoned": true, - "time": "2018-05-29T13:54:20+00:00" + "time": "2018-08-09T05:50:03+00:00" }, { "name": "psr/cache", @@ -3764,16 +3594,16 @@ }, { "name": "psr/log", - "version": "1.1.0", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd" + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", - "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", + "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", "shasum": "" }, "require": { @@ -3807,7 +3637,7 @@ "psr", "psr-3" ], - "time": "2018-11-20T15:27:04+00:00" + "time": "2016-10-10T12:19:37+00:00" }, { "name": "psr/simple-cache", @@ -3857,46 +3687,6 @@ ], "time": "2017-10-23T01:57:42+00:00" }, - { - "name": "ralouphie/getallheaders", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/ralouphie/getallheaders.git", - "reference": "120b605dfeb996808c31b6477290a714d356e822" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", - "reference": "120b605dfeb996808c31b6477290a714d356e822", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "require-dev": { - "php-coveralls/php-coveralls": "^2.1", - "phpunit/phpunit": "^5 || ^6.5" - }, - "type": "library", - "autoload": { - "files": [ - "src/getallheaders.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ralph Khattar", - "email": "ralph.khattar@gmail.com" - } - ], - "description": "A polyfill for getallheaders.", - "time": "2019-03-08T08:55:37+00:00" - }, { "name": "ramsey/uuid", "version": "3.8.0", @@ -4090,29 +3880,28 @@ }, { "name": "sebastian/diff", - "version": "3.0.2", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29" + "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/720fcc7e9b5cf384ea68d9d930d480907a0c1a29", - "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", + "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", "shasum": "" }, "require": { - "php": "^7.1" + "php": "^7.0" }, "require-dev": { - "phpunit/phpunit": "^7.5 || ^8.0", - "symfony/process": "^2 || ^3.3 || ^4" + "phpunit/phpunit": "^6.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -4137,12 +3926,9 @@ "description": "Diff implementation", "homepage": "https://github.com/sebastianbergmann/diff", "keywords": [ - "diff", - "udiff", - "unidiff", - "unified diff" + "diff" ], - "time": "2019-02-04T06:01:07+00:00" + "time": "2017-08-03T08:09:46+00:00" }, { "name": "sebastian/environment", @@ -4196,16 +3982,16 @@ }, { "name": "sebastian/exporter", - "version": "3.1.2", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e" + "reference": "234199f4528de6d12aaa58b612e98f7d36adb937" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/68609e1261d215ea5b21b7987539cbfbe156ec3e", - "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937", + "reference": "234199f4528de6d12aaa58b612e98f7d36adb937", "shasum": "" }, "require": { @@ -4232,10 +4018,6 @@ "BSD-3-Clause" ], "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, { "name": "Jeff Welch", "email": "whatthejeff@gmail.com" @@ -4245,12 +4027,16 @@ "email": "github@wallbash.com" }, { - "name": "Adam Harvey", - "email": "aharvey@php.net" + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" }, { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" } ], "description": "Provides the functionality to export PHP variables for visualization", @@ -4259,7 +4045,7 @@ "export", "exporter" ], - "time": "2019-09-14T09:02:43+00:00" + "time": "2017-04-03T13:19:02+00:00" }, { "name": "sebastian/global-state", @@ -4637,27 +4423,25 @@ }, { "name": "symfony/browser-kit", - "version": "v4.3.5", + "version": "v3.4.18", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "78b7611c45039e8ce81698be319851529bf040b1" + "reference": "f6668d1a6182d5a8dec65a1c863a4c1d963816c0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/78b7611c45039e8ce81698be319851529bf040b1", - "reference": "78b7611c45039e8ce81698be319851529bf040b1", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/f6668d1a6182d5a8dec65a1c863a4c1d963816c0", + "reference": "f6668d1a6182d5a8dec65a1c863a4c1d963816c0", "shasum": "" }, "require": { - "php": "^7.1.3", - "symfony/dom-crawler": "~3.4|~4.0" + "php": "^5.5.9|>=7.0.8", + "symfony/dom-crawler": "~2.8|~3.0|~4.0" }, "require-dev": { - "symfony/css-selector": "~3.4|~4.0", - "symfony/http-client": "^4.3", - "symfony/mime": "^4.3", - "symfony/process": "~3.4|~4.0" + "symfony/css-selector": "~2.8|~3.0|~4.0", + "symfony/process": "~2.8|~3.0|~4.0" }, "suggest": { "symfony/process": "" @@ -4665,7 +4449,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "3.4-dev" } }, "autoload": { @@ -4692,47 +4476,41 @@ ], "description": "Symfony BrowserKit Component", "homepage": "https://symfony.com", - "time": "2019-09-10T11:25:17+00:00" + "time": "2018-07-26T09:06:28+00:00" }, { "name": "symfony/console", - "version": "v4.3.5", + "version": "v3.4.18", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "929ddf360d401b958f611d44e726094ab46a7369" + "reference": "1d228fb4602047d7b26a0554e0d3efd567da5803" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/929ddf360d401b958f611d44e726094ab46a7369", - "reference": "929ddf360d401b958f611d44e726094ab46a7369", + "url": "https://api.github.com/repos/symfony/console/zipball/1d228fb4602047d7b26a0554e0d3efd567da5803", + "reference": "1d228fb4602047d7b26a0554e0d3efd567da5803", "shasum": "" }, "require": { - "php": "^7.1.3", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php73": "^1.8", - "symfony/service-contracts": "^1.1" + "php": "^5.5.9|>=7.0.8", + "symfony/debug": "~2.8|~3.0|~4.0", + "symfony/polyfill-mbstring": "~1.0" }, "conflict": { "symfony/dependency-injection": "<3.4", - "symfony/event-dispatcher": "<4.3", "symfony/process": "<3.3" }, - "provide": { - "psr/log-implementation": "1.0" - }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "~3.4|~4.0", + "symfony/config": "~3.3|~4.0", "symfony/dependency-injection": "~3.4|~4.0", - "symfony/event-dispatcher": "^4.3", + "symfony/event-dispatcher": "~2.8|~3.0|~4.0", "symfony/lock": "~3.4|~4.0", - "symfony/process": "~3.4|~4.0", - "symfony/var-dumper": "^4.3" + "symfony/process": "~3.3|~4.0" }, "suggest": { - "psr/log": "For using the console logger", + "psr/log-implementation": "For using the console logger", "symfony/event-dispatcher": "", "symfony/lock": "", "symfony/process": "" @@ -4740,7 +4518,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "3.4-dev" } }, "autoload": { @@ -4767,29 +4545,29 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2019-10-07T12:36:49+00:00" + "time": "2018-10-30T16:50:50+00:00" }, { "name": "symfony/css-selector", - "version": "v4.3.5", + "version": "v3.4.18", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "f4b3ff6a549d9ed28b2b0ecd1781bf67cf220ee9" + "reference": "3503415d4aafabc31cd08c3a4ebac7f43fde8feb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/f4b3ff6a549d9ed28b2b0ecd1781bf67cf220ee9", - "reference": "f4b3ff6a549d9ed28b2b0ecd1781bf67cf220ee9", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/3503415d4aafabc31cd08c3a4ebac7f43fde8feb", + "reference": "3503415d4aafabc31cd08c3a4ebac7f43fde8feb", "shasum": "" }, "require": { - "php": "^7.1.3" + "php": "^5.5.9|>=7.0.8" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "3.4-dev" } }, "autoload": { @@ -4805,14 +4583,14 @@ "MIT" ], "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, { "name": "Jean-François Simon", "email": "jeanfrancois.simon@sensiolabs.com" }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" @@ -4820,46 +4598,41 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "time": "2019-10-02T08:36:26+00:00" + "time": "2018-10-02T16:33:53+00:00" }, { - "name": "symfony/dom-crawler", - "version": "v4.3.5", + "name": "symfony/debug", + "version": "v3.4.18", "source": { "type": "git", - "url": "https://github.com/symfony/dom-crawler.git", - "reference": "e9f7b4d19d69b133bd638eeddcdc757723b4211f" + "url": "https://github.com/symfony/debug.git", + "reference": "fe9793af008b651c5441bdeab21ede8172dab097" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/e9f7b4d19d69b133bd638eeddcdc757723b4211f", - "reference": "e9f7b4d19d69b133bd638eeddcdc757723b4211f", + "url": "https://api.github.com/repos/symfony/debug/zipball/fe9793af008b651c5441bdeab21ede8172dab097", + "reference": "fe9793af008b651c5441bdeab21ede8172dab097", "shasum": "" }, "require": { - "php": "^7.1.3", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.0" + "php": "^5.5.9|>=7.0.8", + "psr/log": "~1.0" }, "conflict": { - "masterminds/html5": "<2.6" + "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" }, "require-dev": { - "masterminds/html5": "^2.6", - "symfony/css-selector": "~3.4|~4.0" - }, - "suggest": { - "symfony/css-selector": "" + "symfony/http-kernel": "~2.8|~3.0|~4.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "3.4-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\DomCrawler\\": "" + "Symfony\\Component\\Debug\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -4879,57 +4652,44 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony DomCrawler Component", + "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2019-09-28T21:25:05+00:00" + "time": "2018-10-31T09:06:03+00:00" }, { - "name": "symfony/event-dispatcher", - "version": "v4.3.5", + "name": "symfony/dom-crawler", + "version": "v3.4.18", "source": { "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "6229f58993e5a157f6096fc7145c0717d0be8807" + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "c705bee03ade5b47c087807dd9ffaaec8dda2722" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/6229f58993e5a157f6096fc7145c0717d0be8807", - "reference": "6229f58993e5a157f6096fc7145c0717d0be8807", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/c705bee03ade5b47c087807dd9ffaaec8dda2722", + "reference": "c705bee03ade5b47c087807dd9ffaaec8dda2722", "shasum": "" }, "require": { - "php": "^7.1.3", - "symfony/event-dispatcher-contracts": "^1.1" - }, - "conflict": { - "symfony/dependency-injection": "<3.4" - }, - "provide": { - "psr/event-dispatcher-implementation": "1.0", - "symfony/event-dispatcher-implementation": "1.1" + "php": "^5.5.9|>=7.0.8", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~3.4|~4.0", - "symfony/dependency-injection": "~3.4|~4.0", - "symfony/expression-language": "~3.4|~4.0", - "symfony/http-foundation": "^3.4|^4.0", - "symfony/service-contracts": "^1.1", - "symfony/stopwatch": "~3.4|~4.0" + "symfony/css-selector": "~2.8|~3.0|~4.0" }, "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" + "symfony/css-selector": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "3.4-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\EventDispatcher\\": "" + "Symfony\\Component\\DomCrawler\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -4949,41 +4709,54 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony EventDispatcher Component", + "description": "Symfony DomCrawler Component", "homepage": "https://symfony.com", - "time": "2019-10-01T16:40:32+00:00" + "time": "2018-10-02T12:28:39+00:00" }, { - "name": "symfony/event-dispatcher-contracts", - "version": "v1.1.7", + "name": "symfony/event-dispatcher", + "version": "v3.4.18", "source": { "type": "git", - "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "c43ab685673fb6c8d84220c77897b1d6cdbe1d18" + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "db9e829c8f34c3d35cf37fcd4cdb4293bc4a2f14" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/c43ab685673fb6c8d84220c77897b1d6cdbe1d18", - "reference": "c43ab685673fb6c8d84220c77897b1d6cdbe1d18", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/db9e829c8f34c3d35cf37fcd4cdb4293bc4a2f14", + "reference": "db9e829c8f34c3d35cf37fcd4cdb4293bc4a2f14", "shasum": "" }, "require": { - "php": "^7.1.3" + "php": "^5.5.9|>=7.0.8" + }, + "conflict": { + "symfony/dependency-injection": "<3.3" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~2.8|~3.0|~4.0", + "symfony/dependency-injection": "~3.3|~4.0", + "symfony/expression-language": "~2.8|~3.0|~4.0", + "symfony/stopwatch": "~2.8|~3.0|~4.0" }, "suggest": { - "psr/event-dispatcher": "", - "symfony/event-dispatcher-implementation": "" + "symfony/dependency-injection": "", + "symfony/http-kernel": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1-dev" + "dev-master": "3.4-dev" } }, "autoload": { "psr-4": { - "Symfony\\Contracts\\EventDispatcher\\": "" - } + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4991,48 +4764,40 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Generic abstractions related to dispatching event", + "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "time": "2019-09-17T09:54:03+00:00" + "time": "2018-10-30T16:50:50+00:00" }, { "name": "symfony/filesystem", - "version": "v4.3.5", + "version": "v3.4.18", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "9abbb7ef96a51f4d7e69627bc6f63307994e4263" + "reference": "d69930fc337d767607267d57c20a7403d0a822a4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/9abbb7ef96a51f4d7e69627bc6f63307994e4263", - "reference": "9abbb7ef96a51f4d7e69627bc6f63307994e4263", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/d69930fc337d767607267d57c20a7403d0a822a4", + "reference": "d69930fc337d767607267d57c20a7403d0a822a4", "shasum": "" }, "require": { - "php": "^7.1.3", + "php": "^5.5.9|>=7.0.8", "symfony/polyfill-ctype": "~1.8" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "3.4-dev" } }, "autoload": { @@ -5059,29 +4824,29 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2019-08-20T14:07:54+00:00" + "time": "2018-10-02T12:28:39+00:00" }, { "name": "symfony/finder", - "version": "v4.3.5", + "version": "v3.4.18", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "5e575faa95548d0586f6bedaeabec259714e44d1" + "reference": "54ba444dddc5bd5708a34bd095ea67c6eb54644d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/5e575faa95548d0586f6bedaeabec259714e44d1", - "reference": "5e575faa95548d0586f6bedaeabec259714e44d1", + "url": "https://api.github.com/repos/symfony/finder/zipball/54ba444dddc5bd5708a34bd095ea67c6eb54644d", + "reference": "54ba444dddc5bd5708a34bd095ea67c6eb54644d", "shasum": "" }, "require": { - "php": "^7.1.3" + "php": "^5.5.9|>=7.0.8" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "3.4-dev" } }, "autoload": { @@ -5108,35 +4873,34 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2019-09-16T11:29:48+00:00" + "time": "2018-10-03T08:46:40+00:00" }, { "name": "symfony/http-foundation", - "version": "v2.8.50", + "version": "v3.4.18", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "746f8d3638bf46ee8b202e62f2b214c3d61fb06a" + "reference": "5aea7a86ca3203dd7a257e765b4b9c9cfd01c6c0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/746f8d3638bf46ee8b202e62f2b214c3d61fb06a", - "reference": "746f8d3638bf46ee8b202e62f2b214c3d61fb06a", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/5aea7a86ca3203dd7a257e765b4b9c9cfd01c6c0", + "reference": "5aea7a86ca3203dd7a257e765b4b9c9cfd01c6c0", "shasum": "" }, "require": { - "php": ">=5.3.9", + "php": "^5.5.9|>=7.0.8", "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php54": "~1.0", - "symfony/polyfill-php55": "~1.0" + "symfony/polyfill-php70": "~1.6" }, "require-dev": { - "symfony/expression-language": "~2.4|~3.0.0" + "symfony/expression-language": "~2.8|~3.0|~4.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.8-dev" + "dev-master": "3.4-dev" } }, "autoload": { @@ -5163,20 +4927,20 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2019-04-16T10:00:53+00:00" + "time": "2018-10-31T08:57:11+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.12.0", + "version": "v1.11.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "550ebaac289296ce228a706d0867afc34687e3f4" + "reference": "82ebae02209c21113908c229e9883c419720738a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/550ebaac289296ce228a706d0867afc34687e3f4", - "reference": "550ebaac289296ce228a706d0867afc34687e3f4", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/82ebae02209c21113908c229e9883c419720738a", + "reference": "82ebae02209c21113908c229e9883c419720738a", "shasum": "" }, "require": { @@ -5188,7 +4952,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.12-dev" + "dev-master": "1.11-dev" } }, "autoload": { @@ -5204,13 +4968,13 @@ "MIT" ], "authors": [ - { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" - }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" + }, + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" } ], "description": "Symfony polyfill for ctype functions", @@ -5221,20 +4985,20 @@ "polyfill", "portable" ], - "time": "2019-08-06T08:03:45+00:00" + "time": "2019-02-06T07:57:58+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.12.0", + "version": "v1.10.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "b42a2f66e8f1b15ccf25652c3424265923eb4f17" + "reference": "c79c051f5b3a46be09205c73b80b346e4153e494" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/b42a2f66e8f1b15ccf25652c3424265923eb4f17", - "reference": "b42a2f66e8f1b15ccf25652c3424265923eb4f17", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/c79c051f5b3a46be09205c73b80b346e4153e494", + "reference": "c79c051f5b3a46be09205c73b80b346e4153e494", "shasum": "" }, "require": { @@ -5246,7 +5010,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.12-dev" + "dev-master": "1.9-dev" } }, "autoload": { @@ -5280,148 +5044,35 @@ "portable", "shim" ], - "time": "2019-08-06T08:03:45+00:00" - }, - { - "name": "symfony/polyfill-php54", - "version": "v1.12.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php54.git", - "reference": "a043bcced870214922fbb4bf22679d431ec0296a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php54/zipball/a043bcced870214922fbb4bf22679d431ec0296a", - "reference": "a043bcced870214922fbb4bf22679d431ec0296a", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.12-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php54\\": "" - }, - "files": [ - "bootstrap.php" - ], - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 5.4+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "time": "2019-08-06T08:03:45+00:00" + "time": "2018-09-21T13:07:52+00:00" }, { - "name": "symfony/polyfill-php55", - "version": "v1.12.0", + "name": "symfony/polyfill-php70", + "version": "v1.10.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php55.git", - "reference": "548bb39407e78e54f785b4e18c7e0d5d9e493265" + "url": "https://github.com/symfony/polyfill-php70.git", + "reference": "6b88000cdd431cd2e940caa2cb569201f3f84224" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php55/zipball/548bb39407e78e54f785b4e18c7e0d5d9e493265", - "reference": "548bb39407e78e54f785b4e18c7e0d5d9e493265", + "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/6b88000cdd431cd2e940caa2cb569201f3f84224", + "reference": "6b88000cdd431cd2e940caa2cb569201f3f84224", "shasum": "" }, "require": { - "ircmaxell/password-compat": "~1.0", + "paragonie/random_compat": "~1.0|~2.0|~9.99", "php": ">=5.3.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.12-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php55\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 5.5+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "time": "2019-08-06T08:03:45+00:00" - }, - { - "name": "symfony/polyfill-php73", - "version": "v1.12.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "2ceb49eaccb9352bff54d22570276bb75ba4a188" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/2ceb49eaccb9352bff54d22570276bb75ba4a188", - "reference": "2ceb49eaccb9352bff54d22570276bb75ba4a188", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.12-dev" + "dev-master": "1.9-dev" } }, "autoload": { "psr-4": { - "Symfony\\Polyfill\\Php73\\": "" + "Symfony\\Polyfill\\Php70\\": "" }, "files": [ "bootstrap.php" @@ -5444,7 +5095,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -5452,29 +5103,29 @@ "portable", "shim" ], - "time": "2019-08-06T08:03:45+00:00" + "time": "2018-09-21T06:26:08+00:00" }, { "name": "symfony/process", - "version": "v4.3.5", + "version": "v3.4.18", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "50556892f3cc47d4200bfd1075314139c4c9ff4b" + "reference": "35c2914a9f50519bd207164c353ae4d59182c2cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/50556892f3cc47d4200bfd1075314139c4c9ff4b", - "reference": "50556892f3cc47d4200bfd1075314139c4c9ff4b", + "url": "https://api.github.com/repos/symfony/process/zipball/35c2914a9f50519bd207164c353ae4d59182c2cb", + "reference": "35c2914a9f50519bd207164c353ae4d59182c2cb", "shasum": "" }, "require": { - "php": "^7.1.3" + "php": "^5.5.9|>=7.0.8" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "3.4-dev" } }, "autoload": { @@ -5501,82 +5152,24 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2019-09-26T21:17:10+00:00" - }, - { - "name": "symfony/service-contracts", - "version": "v1.1.7", - "source": { - "type": "git", - "url": "https://github.com/symfony/service-contracts.git", - "reference": "ffcde9615dc5bb4825b9f6aed07716f1f57faae0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/ffcde9615dc5bb4825b9f6aed07716f1f57faae0", - "reference": "ffcde9615dc5bb4825b9f6aed07716f1f57faae0", - "shasum": "" - }, - "require": { - "php": "^7.1.3", - "psr/container": "^1.0" - }, - "suggest": { - "symfony/service-implementation": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\Service\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Generic abstractions related to writing services", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "time": "2019-09-17T11:12:18+00:00" + "time": "2018-10-14T17:33:21+00:00" }, { "name": "symfony/yaml", - "version": "v4.3.5", + "version": "v3.4.28", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "41e16350a2a1c7383c4735aa2f9fce74cf3d1178" + "reference": "212a27b731e5bfb735679d1ffaac82bd6a1dc996" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/41e16350a2a1c7383c4735aa2f9fce74cf3d1178", - "reference": "41e16350a2a1c7383c4735aa2f9fce74cf3d1178", + "url": "https://api.github.com/repos/symfony/yaml/zipball/212a27b731e5bfb735679d1ffaac82bd6a1dc996", + "reference": "212a27b731e5bfb735679d1ffaac82bd6a1dc996", "shasum": "" }, "require": { - "php": "^7.1.3", + "php": "^5.5.9|>=7.0.8", "symfony/polyfill-ctype": "~1.8" }, "conflict": { @@ -5591,7 +5184,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "3.4-dev" } }, "autoload": { @@ -5618,20 +5211,20 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2019-09-11T15:41:19+00:00" + "time": "2019-03-25T07:48:46+00:00" }, { "name": "theseer/tokenizer", - "version": "1.1.3", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9" + "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9", - "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b", "shasum": "" }, "require": { @@ -5658,25 +5251,24 @@ } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "time": "2019-06-13T22:48:21+00:00" + "time": "2017-04-07T12:08:54+00:00" }, { "name": "vlucas/phpdotenv", - "version": "v2.6.1", + "version": "v2.5.1", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "2a7dcf7e3e02dc5e701004e51a6f304b713107d5" + "reference": "8abb4f9aa89ddea9d52112c65bbe8d0125e2fa8e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/2a7dcf7e3e02dc5e701004e51a6f304b713107d5", - "reference": "2a7dcf7e3e02dc5e701004e51a6f304b713107d5", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/8abb4f9aa89ddea9d52112c65bbe8d0125e2fa8e", + "reference": "8abb4f9aa89ddea9d52112c65bbe8d0125e2fa8e", "shasum": "" }, "require": { - "php": ">=5.3.9", - "symfony/polyfill-ctype": "^1.9" + "php": ">=5.3.9" }, "require-dev": { "phpunit/phpunit": "^4.8.35 || ^5.0" @@ -5684,7 +5276,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.6-dev" + "dev-master": "2.5-dev" } }, "autoload": { @@ -5709,28 +5301,28 @@ "env", "environment" ], - "time": "2019-01-29T11:11:52+00:00" + "time": "2018-07-29T20:33:41+00:00" }, { "name": "webmozart/assert", - "version": "1.5.0", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "88e6d84706d09a236046d686bbea96f07b3a34f4" + "reference": "0df1908962e7a3071564e857d86874dad1ef204a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/88e6d84706d09a236046d686bbea96f07b3a34f4", - "reference": "88e6d84706d09a236046d686bbea96f07b3a34f4", + "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a", + "reference": "0df1908962e7a3071564e857d86874dad1ef204a", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0", - "symfony/polyfill-ctype": "^1.8" + "php": "^5.3.3 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.36 || ^7.5.13" + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" }, "type": "library", "extra": { @@ -5759,7 +5351,7 @@ "check", "validate" ], - "time": "2019-08-24T08:43:50+00:00" + "time": "2018-01-29T19:49:41+00:00" }, { "name": "weew/helpers-array", @@ -5802,16 +5394,16 @@ "packages-dev": [ { "name": "brainmaestro/composer-git-hooks", - "version": "v2.8.2", + "version": "v2.6.1", "source": { "type": "git", "url": "https://github.com/BrainMaestro/composer-git-hooks.git", - "reference": "c4a39fcbd73b8a5da8c02b8e0923b0836cc4fae0" + "reference": "137dd2aec2be494918f8bdfb18f57b55ff20015e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/BrainMaestro/composer-git-hooks/zipball/c4a39fcbd73b8a5da8c02b8e0923b0836cc4fae0", - "reference": "c4a39fcbd73b8a5da8c02b8e0923b0836cc4fae0", + "url": "https://api.github.com/repos/BrainMaestro/composer-git-hooks/zipball/137dd2aec2be494918f8bdfb18f57b55ff20015e", + "reference": "137dd2aec2be494918f8bdfb18f57b55ff20015e", "shasum": "" }, "require": { @@ -5819,9 +5411,8 @@ "symfony/console": "^3.2 || ^4.0" }, "require-dev": { - "ext-json": "*", "friendsofphp/php-cs-fixer": "^2.9", - "phpunit/phpunit": "^5.7 || ^7.0" + "phpunit/phpunit": "^5.7|^7.0" }, "bin": [ "cghooks" @@ -5832,11 +5423,10 @@ "pre-commit": "composer check-style", "pre-push": [ "composer test", - "appver=$(grep -o -E '\\d.\\d.\\d' cghooks)", - "tag=$(git describe --tags --abbrev=0)", - "if [ \"$tag\" != \"v$appver\" ]; then", - "echo \"The most recent tag $tag does not match the application version $appver\\n\"", - "tag=${tag#v}", + "appver=$(grep -o -P '\\d.\\d.\\d' cghooks)", + "tag=$(git tag --sort=-v:refname | head -n 1 | tr -d v)", + "if [ \"$tag\" != \"$appver\" ]; then", + "echo \"The most recent tag v$tag does not match the application version $appver\n\"", "sed -i -E \"s/$appver/$tag/\" cghooks", "exit 1", "fi" @@ -5867,7 +5457,7 @@ "composer", "git" ], - "time": "2019-10-16T14:14:51+00:00" + "time": "2018-12-28T14:57:06+00:00" }, { "name": "codacy/coverage", @@ -5960,33 +5550,33 @@ }, { "name": "gitonomy/gitlib", - "version": "v1.1.0", + "version": "v1.0.4", "source": { "type": "git", "url": "https://github.com/gitonomy/gitlib.git", - "reference": "49e599915eae04b734f31e6e88f773d32d921e2e" + "reference": "932a960221ae3484a3e82553b3be478e56beb68d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/gitonomy/gitlib/zipball/49e599915eae04b734f31e6e88f773d32d921e2e", - "reference": "49e599915eae04b734f31e6e88f773d32d921e2e", + "url": "https://api.github.com/repos/gitonomy/gitlib/zipball/932a960221ae3484a3e82553b3be478e56beb68d", + "reference": "932a960221ae3484a3e82553b3be478e56beb68d", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0", - "symfony/process": "^3.4|^4.0" + "php": "^5.3 || ^7.0", + "symfony/process": "^2.3|^3.0|^4.0" }, "require-dev": { - "phpunit/phpunit": "^5.7|^6.5", + "phpunit/phpunit": "^4.8.35|^5.7", "psr/log": "^1.0" }, "suggest": { - "psr/log": "Required to use loggers for reporting of execution" + "psr/log": "Add some log" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1-dev" + "dev-master": "1.0-dev" } }, "autoload": { @@ -6012,7 +5602,7 @@ ], "description": "Library for accessing git", "homepage": "http://gitonomy.com", - "time": "2019-06-23T09:49:01+00:00" + "time": "2018-04-22T19:55:36+00:00" }, { "name": "goaop/framework", @@ -6433,16 +6023,16 @@ }, { "name": "phpmd/phpmd", - "version": "2.7.0", + "version": "2.6.0", "source": { "type": "git", "url": "https://github.com/phpmd/phpmd.git", - "reference": "a05a999c644f4bc9a204846017db7bb7809fbe4c" + "reference": "4e9924b2c157a3eb64395460fcf56b31badc8374" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpmd/phpmd/zipball/a05a999c644f4bc9a204846017db7bb7809fbe4c", - "reference": "a05a999c644f4bc9a204846017db7bb7809fbe4c", + "url": "https://api.github.com/repos/phpmd/phpmd/zipball/4e9924b2c157a3eb64395460fcf56b31badc8374", + "reference": "4e9924b2c157a3eb64395460fcf56b31badc8374", "shasum": "" }, "require": { @@ -6451,15 +6041,13 @@ "php": ">=5.3.9" }, "require-dev": { - "gregwar/rst": "^1.0", - "mikey179/vfsstream": "^1.6.4", - "phpunit/phpunit": "^4.8.36 || ^5.7.27", + "phpunit/phpunit": "^4.0", "squizlabs/php_codesniffer": "^2.0" }, "bin": [ "src/bin/phpmd" ], - "type": "library", + "type": "project", "autoload": { "psr-0": { "PHPMD\\": "src/main/php" @@ -6476,20 +6064,20 @@ "homepage": "https://github.com/manuelpichler", "role": "Project Founder" }, + { + "name": "Other contributors", + "homepage": "https://github.com/phpmd/phpmd/graphs/contributors", + "role": "Contributors" + }, { "name": "Marc Würth", "email": "ravage@bluewin.ch", "homepage": "https://github.com/ravage84", "role": "Project Maintainer" - }, - { - "name": "Other contributors", - "homepage": "https://github.com/phpmd/phpmd/graphs/contributors", - "role": "Contributors" } ], "description": "PHPMD is a spin-off project of PHP Depend and aims to be a PHP equivalent of the well known Java tool PMD.", - "homepage": "https://phpmd.org/", + "homepage": "http://phpmd.org/", "keywords": [ "mess detection", "mess detector", @@ -6497,7 +6085,7 @@ "phpmd", "pmd" ], - "time": "2019-07-30T21:13:32+00:00" + "time": "2017-01-20T14:41:10+00:00" }, { "name": "rregeer/phpunit-coverage-check", @@ -6582,22 +6170,21 @@ }, { "name": "sebastian/phpcpd", - "version": "4.1.0", + "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpcpd.git", - "reference": "0d9afa762f2400de077b2192f4a9d127de0bb78e" + "reference": "dfed51c1288790fc957c9433e2f49ab152e8a564" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpcpd/zipball/0d9afa762f2400de077b2192f4a9d127de0bb78e", - "reference": "0d9afa762f2400de077b2192f4a9d127de0bb78e", + "url": "https://api.github.com/repos/sebastianbergmann/phpcpd/zipball/dfed51c1288790fc957c9433e2f49ab152e8a564", + "reference": "dfed51c1288790fc957c9433e2f49ab152e8a564", "shasum": "" }, "require": { - "ext-dom": "*", - "php": "^7.1", - "phpunit/php-timer": "^2.0", + "php": "^5.6|^7.0", + "phpunit/php-timer": "^1.0.6", "sebastian/finder-facade": "^1.1", "sebastian/version": "^1.0|^2.0", "symfony/console": "^2.7|^3.0|^4.0" @@ -6608,7 +6195,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -6629,20 +6216,20 @@ ], "description": "Copy/Paste Detector (CPD) for PHP code.", "homepage": "https://github.com/sebastianbergmann/phpcpd", - "time": "2018-09-17T17:17:27+00:00" + "time": "2017-11-16T08:49:28+00:00" }, { "name": "squizlabs/php_codesniffer", - "version": "3.5.1", + "version": "3.3.2", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "82cd0f854ceca17731d6d019c7098e3755c45060" + "reference": "6ad28354c04b364c3c71a34e4a18b629cc3b231e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/82cd0f854ceca17731d6d019c7098e3755c45060", - "reference": "82cd0f854ceca17731d6d019c7098e3755c45060", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/6ad28354c04b364c3c71a34e4a18b629cc3b231e", + "reference": "6ad28354c04b364c3c71a34e4a18b629cc3b231e", "shasum": "" }, "require": { @@ -6675,41 +6262,41 @@ } ], "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", + "homepage": "http://www.squizlabs.com/php-codesniffer", "keywords": [ "phpcs", "standards" ], - "time": "2019-10-16T21:14:26+00:00" + "time": "2018-09-23T23:08:17+00:00" }, { "name": "symfony/config", - "version": "v4.3.5", + "version": "v3.4.18", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "0acb26407a9e1a64a275142f0ae5e36436342720" + "reference": "99b2fa8acc244e656cdf324ff419fbe6fd300a4d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/0acb26407a9e1a64a275142f0ae5e36436342720", - "reference": "0acb26407a9e1a64a275142f0ae5e36436342720", + "url": "https://api.github.com/repos/symfony/config/zipball/99b2fa8acc244e656cdf324ff419fbe6fd300a4d", + "reference": "99b2fa8acc244e656cdf324ff419fbe6fd300a4d", "shasum": "" }, "require": { - "php": "^7.1.3", - "symfony/filesystem": "~3.4|~4.0", + "php": "^5.5.9|>=7.0.8", + "symfony/filesystem": "~2.8|~3.0|~4.0", "symfony/polyfill-ctype": "~1.8" }, "conflict": { - "symfony/finder": "<3.4" + "symfony/dependency-injection": "<3.3", + "symfony/finder": "<3.3" }, "require-dev": { - "symfony/dependency-injection": "~3.4|~4.0", - "symfony/event-dispatcher": "~3.4|~4.0", - "symfony/finder": "~3.4|~4.0", - "symfony/messenger": "~4.1", - "symfony/yaml": "~3.4|~4.0" + "symfony/dependency-injection": "~3.3|~4.0", + "symfony/event-dispatcher": "~3.3|~4.0", + "symfony/finder": "~3.3|~4.0", + "symfony/yaml": "~3.0|~4.0" }, "suggest": { "symfony/yaml": "To use the yaml reference dumper" @@ -6717,7 +6304,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "3.4-dev" } }, "autoload": { @@ -6744,40 +6331,38 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2019-09-19T15:51:53+00:00" + "time": "2018-10-31T09:06:03+00:00" }, { "name": "symfony/dependency-injection", - "version": "v4.3.5", + "version": "v3.4.18", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "e1e0762a814b957a1092bff75a550db49724d05b" + "reference": "9c98452ac7fff4b538956775630bc9701f5384ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/e1e0762a814b957a1092bff75a550db49724d05b", - "reference": "e1e0762a814b957a1092bff75a550db49724d05b", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/9c98452ac7fff4b538956775630bc9701f5384ba", + "reference": "9c98452ac7fff4b538956775630bc9701f5384ba", "shasum": "" }, "require": { - "php": "^7.1.3", - "psr/container": "^1.0", - "symfony/service-contracts": "^1.1.6" + "php": "^5.5.9|>=7.0.8", + "psr/container": "^1.0" }, "conflict": { - "symfony/config": "<4.3", - "symfony/finder": "<3.4", + "symfony/config": "<3.3.7", + "symfony/finder": "<3.3", "symfony/proxy-manager-bridge": "<3.4", "symfony/yaml": "<3.4" }, "provide": { - "psr/container-implementation": "1.0", - "symfony/service-implementation": "1.0" + "psr/container-implementation": "1.0" }, "require-dev": { - "symfony/config": "^4.3", - "symfony/expression-language": "~3.4|~4.0", + "symfony/config": "~3.3|~4.0", + "symfony/expression-language": "~2.8|~3.0|~4.0", "symfony/yaml": "~3.4|~4.0" }, "suggest": { @@ -6790,7 +6375,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "3.4-dev" } }, "autoload": { @@ -6817,20 +6402,20 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2019-10-02T12:58:58+00:00" + "time": "2018-10-31T10:49:51+00:00" }, { "name": "symfony/stopwatch", - "version": "v3.4.32", + "version": "v3.4.18", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "c0c27e38f8accb452f830a4ec8e8ac94b6ec864a" + "reference": "05e52a39de52ba690aebaed462b2bc8a9649f0a4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/c0c27e38f8accb452f830a4ec8e8ac94b6ec864a", - "reference": "c0c27e38f8accb452f830a4ec8e8ac94b6ec864a", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/05e52a39de52ba690aebaed462b2bc8a9649f0a4", + "reference": "05e52a39de52ba690aebaed462b2bc8a9649f0a4", "shasum": "" }, "require": { @@ -6866,7 +6451,7 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", - "time": "2019-08-06T13:24:37+00:00" + "time": "2018-10-02T12:28:39+00:00" }, { "name": "theseer/fdomdocument", From 6aee6ff39870db8851c3ffbe72a3768098a0e0ca Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Wed, 23 Oct 2019 08:56:18 -0500 Subject: [PATCH 028/888] MQE-1833: CHANGELOG.MD and Composer version bump Reworded some items in Changelog. --- CHANGELOG.md | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e54636819..917e70b44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,18 +4,15 @@ Magento Functional Testing Framework Changelog ----- * Traceability - * Added test's filepath to Allure reports for ease of debugging. - -* Modularity - * Refactored problem methods to reduce cyclomatic complexity. - + * Allure report enhanced to display file path of tests. * Maintainability - * Added support to read MFTF test entities from path of MFTF test packages. + * Added support to read MFTF test entities from `dev/tests/acceptance/tests/functional///*` + * Removed path deprecation warning from `ModuleResolver`. + * Refactored problem methods to reduce cyclomatic complexity. ### Fixes * Added escaping for `magentoCLI` commands. * Fixed issue with builds due to absence of AcceptanceTester class. -* Removed path deprecation warning from ModuleResolver. ### GitHub Issues/Pull requests: * [#348](https://github.com/magento/magento2-functional-testing-framework/pull/348) -- executeInSelenium command fixed to prevent escaping double quotes. From 449f5e4932a408ebcbfc68812d7bdfc67bb113d4 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Wed, 23 Oct 2019 09:23:51 -0500 Subject: [PATCH 029/888] MQE-1833: CHANGELOG.MD and Composer version bump Updated Changelog. --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 917e70b44..84cc2cfad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,6 @@ Magento Functional Testing Framework Changelog * Refactored problem methods to reduce cyclomatic complexity. ### Fixes -* Added escaping for `magentoCLI` commands. * Fixed issue with builds due to absence of AcceptanceTester class. ### GitHub Issues/Pull requests: From d8c58af84dd91060947b7cf81e5088cd1340ef95 Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Wed, 23 Oct 2019 14:29:55 -0500 Subject: [PATCH 030/888] MQE-1782: MFTF run:group can't run test in a suite - Added unit test template for test/suite configuration method --- .../Console/BaseGenerateCommandTest.php | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php new file mode 100644 index 000000000..d1933c7d8 --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php @@ -0,0 +1,74 @@ + $testOne], [], []); + + $testArray = ['Test1' => $testOne]; + $suiteArray = ['Suite1' => $suiteOne]; + + $this->mockHandlers($testArray, $suiteArray); + + $actual = json_decode($this->callConfig(['Test1']), true); + $expected = ['tests' => null, 'suites' => ['Suite1' => ['Test1']]]; + $this->assertEquals($expected, $actual); + } + + /** + * Mock handlers to skip parsing + * @param array $testArray + * @param array $suiteArray + * @throws \Exception + */ + public function mockHandlers($testArray, $suiteArray) + { + AspectMock::double(TestObjectHandler::class,['initTestData' => ''])->make(); + $handler = TestObjectHandler::getInstance(); + $property = new \ReflectionProperty(TestObjectHandler::class, 'tests'); + $property->setAccessible(true); + $property->setValue($handler, $testArray); + + AspectMock::double(SuiteObjectHandler::class, ['initSuiteData' => ''])->make(); + $handler = SuiteObjectHandler::getInstance(); + $property = new \ReflectionProperty(SuiteObjectHandler::class, 'suiteObjects'); + $property->setAccessible(true); + $property->setValue($handler, $suiteArray); + } + + /** + * Changes visibility and runs getTestAndSuiteConfiguration + * @param array $testArray + * @return string + */ + public function callConfig($testArray) + { + $command = new BaseGenerateCommand(); + $class = new \ReflectionClass($command); + $method = $class->getMethod('getTestAndSuiteConfiguration'); + $method->setAccessible(true); + return $method->invokeArgs($command, [$testArray]); + } +} From 8e7494d91390ebf5a522205694a0f5262bd2fb89 Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Thu, 24 Oct 2019 08:34:47 -0500 Subject: [PATCH 031/888] MQE-1782: MFTF run:group can't run test in a suite - Moved group config function to BaseGenerateCommand - Added more unit tests --- .../Console/BaseGenerateCommandTest.php | 70 ++++++++++++++++++- .../Console/BaseGenerateCommand.php | 67 ++++++++++++++++++ .../Console/RunTestGroupCommand.php | 59 ---------------- 3 files changed, 134 insertions(+), 62 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php index d1933c7d8..82a223726 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php @@ -22,7 +22,7 @@ public function tearDown() /** * One test in one suite */ - public function testSimpleTestConfig() + public function testOneTestOneSuiteConfig() { $testOne = new TestObject('Test1', [], [], []); $suiteOne = new SuiteObject('Suite1', ['Test1' => $testOne], [], []); @@ -32,11 +32,61 @@ public function testSimpleTestConfig() $this->mockHandlers($testArray, $suiteArray); - $actual = json_decode($this->callConfig(['Test1']), true); + $actual = json_decode($this->callTestConfig(['Test1']), true); $expected = ['tests' => null, 'suites' => ['Suite1' => ['Test1']]]; $this->assertEquals($expected, $actual); } + + /** + * One test in one suite + */ + public function testOneTestTwoSuitesConfig() + { + $testOne = new TestObject('Test1', [], [], []); + $suiteOne = new SuiteObject('Suite1', ['Test1' => $testOne], [], []); + $suiteTwo = new SuiteObject('Suite2', ['Test1' => $testOne], [], []); + + $testArray = ['Test1' => $testOne]; + $suiteArray = ['Suite1' => $suiteOne, 'Suite2' => $suiteTwo]; + + $this->mockHandlers($testArray, $suiteArray); + + $actual = json_decode($this->callTestConfig(['Test1']), true); + $expected = ['tests' => null, 'suites' => ['Suite1' => ['Test1'], 'Suite2' => ['Test1']]]; + $this->assertEquals($expected, $actual); + } + + public function testOneTestOneGroup() + { + $testOne = new TestObject('Test1', [], ['group' => ['Group1']], []); + + $testArray = ['Test1' => $testOne]; + $suiteArray = []; + + $this->mockHandlers($testArray, $suiteArray); + + $actual = json_decode($this->callGroupConfig(['Group1']), true); + $expected = ['tests' => ['Test1'], 'suites' => null]; + $this->assertEquals($expected, $actual); + } + + public function testThreeTestsTwoGroup() + { + $testOne = new TestObject('Test1', [], ['group' => ['Group1']], []); + $testTwo = new TestObject('Test2', [], ['group' => ['Group1']], []); + $testThree = new TestObject('Test3', [], ['group' => ['Group2']], []); + + $testArray = ['Test1' => $testOne, 'Test2' => $testTwo, 'Test3' => $testThree]; + $suiteArray = []; + + $this->mockHandlers($testArray, $suiteArray); + + $actual = json_decode($this->callGroupConfig(['Group1', 'Group2']), true); + $expected = ['tests' => ['Test1', 'Test2', 'Test3'], 'suites' => null]; + $this->assertEquals($expected, $actual); + } + /** * Mock handlers to skip parsing * @param array $testArray @@ -63,7 +113,7 @@ public function mockHandlers($testArray, $suiteArray) * @param array $testArray * @return string */ - public function callConfig($testArray) + public function callTestConfig($testArray) { $command = new BaseGenerateCommand(); $class = new \ReflectionClass($command); @@ -71,4 +121,18 @@ public function callConfig($testArray) $method->setAccessible(true); return $method->invokeArgs($command, [$testArray]); } + + /** + * Changes visibility and runs getGroupAndSuiteConfiguration + * @param array $groupArray + * @return string + */ + public function callGroupConfig($groupArray) + { + $command = new BaseGenerateCommand(); + $class = new \ReflectionClass($command); + $method = $class->getMethod('getGroupAndSuiteConfiguration'); + $method->setAccessible(true); + return $method->invokeArgs($command, [$groupArray]); + } } diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index 87b203d66..0c7fff674 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -8,6 +8,7 @@ namespace Magento\FunctionalTestingFramework\Console; +use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; @@ -103,4 +104,70 @@ protected function getTestAndSuiteConfiguration(array $tests) $testConfigurationJson = json_encode($testConfiguration); return $testConfigurationJson; } + + /** second attempt at a cleaner implementation, needs work */ + protected function getGroupAndSuiteConfiguration(array $groupOrSuiteNames) + { + $result['tests'] = []; + $result['suites'] = []; + + $groups = []; + $suites = []; + + $allSuites = SuiteObjectHandler::getInstance()->getAllObjects(); + $testsInSuites = SuiteObjectHandler::getInstance()->getAllTestReferences(); + + foreach ($groupOrSuiteNames as $groupOrSuiteName) { + if (array_key_exists($groupOrSuiteName, $allSuites)) { + $suites[] = $groupOrSuiteName; + } else { + $groups[] = $groupOrSuiteName; + } + } + + foreach ($suites as $suite) { + $result['suites'][$suite] = []; + } + + foreach ($groups as $group) { + $testsInGroup = TestObjectHandler::getInstance()->getTestsByGroup($group); + + $testsInGroupAndNotInAnySuite = array_diff( + array_keys($testsInGroup), + array_keys($testsInSuites) + ); + + $testsInGroupAndInAnySuite = array_diff( + array_keys($testsInGroup), + $testsInGroupAndNotInAnySuite + ); + + foreach ($testsInGroupAndInAnySuite as $testInGroupAndInAnySuite) { + $cat = $testsInSuites[$testInGroupAndInAnySuite][0]; + $dog[$cat][] = $testInGroupAndInAnySuite; + + /* + * todo -- I left off here. Code works so far. + * I need to take this $dog array and put into the $result['suites'] array + * and then test it thoroughly + */ + + } + + $result['tests'] = array_merge( + $result['tests'], + $testsInGroupAndNotInAnySuite + ); + } + + if (empty($result['tests'])) { + $result['tests'] = null; + } + if (empty($result['suites'])) { + $result['suites'] = null; + } + + $json = json_encode($result); + return $json; + } } diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php index 86b349f53..d31bf7873 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php @@ -188,63 +188,4 @@ private function first_attempt_getGroupAndSuiteConfiguration(array $groups) $testConfigurationJson = json_encode($testConfiguration); return $testConfigurationJson; } - - /** second attempt at a cleaner implementation, needs work */ - private function getGroupAndSuiteConfiguration(array $groupOrSuiteNames) - { - $result['tests'] = []; - $result['suites'] = null; - - $groups = []; - $suites = []; - - $allSuites = SuiteObjectHandler::getInstance()->getAllObjects(); - $testsInSuites = SuiteObjectHandler::getInstance()->getAllTestReferences(); - - foreach ($groupOrSuiteNames as $groupOrSuiteName) { - if (array_key_exists($groupOrSuiteName, $allSuites)) { - $suites[] = $groupOrSuiteName; - } else { - $groups[] = $groupOrSuiteName; - } - } - - foreach ($suites as $suite) { - $result['suites'][$suite] = []; - } - - foreach ($groups as $group) { - $testsInGroup = TestObjectHandler::getInstance()->getTestsByGroup($group); - - $testsInGroupAndNotInAnySuite = array_diff( - array_keys($testsInGroup), - array_keys($testsInSuites) - ); - - $testsInGroupAndInAnySuite = array_diff( - array_keys($testsInGroup), - $testsInGroupAndNotInAnySuite - ); - - foreach ($testsInGroupAndInAnySuite as $testInGroupAndInAnySuite) { - $cat = $testsInSuites[$testInGroupAndInAnySuite][0]; - $dog[$cat][] = $testInGroupAndInAnySuite; - - /* - * todo -- I left off here. Code works so far. - * I need to take this $dog array and put into the $result['suites'] array - * and then test it thoroughly - */ - - } - - $result['tests'] = array_merge( - $result['tests'], - $testsInGroupAndNotInAnySuite - ); - } - - $json = json_encode($result); - return $json; - } } From 8dce78ff93b79e9b50ffd49e5126979bede12c24 Mon Sep 17 00:00:00 2001 From: Donald Booth Date: Thu, 24 Oct 2019 09:27:10 -0500 Subject: [PATCH 032/888] Grammar and formatting --- docs/guides/git-vs-composer-install.md | 66 ++++++++++++-------------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/docs/guides/git-vs-composer-install.md b/docs/guides/git-vs-composer-install.md index 32b7a0a22..076e5491d 100644 --- a/docs/guides/git-vs-composer-install.md +++ b/docs/guides/git-vs-composer-install.md @@ -1,51 +1,47 @@ -# Git vs Composer Installation of Magento with MFTF +# Git vs Composer installation of Magento with MFTF +Depending on how you plan to use Magnto code, there are different options for installing Magento. -### GitHub Installation +## GitHub Installation -If you are planning on contributing a PR to the Magento 2 codebase, you can download Magento 2 from GitHub. Contribution to the codebase is done using the 'fork and pull' model where contributors maintain their own fork of the repo. This repo is then used to submit a pull request to the base repo. +If you are contributing a pull request to the Magento 2 codebase, download Magento 2 from our GitHub repository. Contribution to the codebase is done using the 'fork and pull' model where contributors maintain their own fork of the repo. This repo is then used to submit a pull request to the base repo. -Install guide: [GitHub Installation](https://devdocs.magento.com/guides/v2.3/install-gde/prereq/dev_install.html) +Install guide: [GitHub Installation][] +## Composer based Installation -### Composer based Installation +A Composer install downloads released packages of Magento 2 from the composer repo [https://repo.magento.com](https://repo.magento.com). -Composer install downloads released packages of Magento 2 from the composer repo [https://repo.magento.com](https://repo.magento.com). +All Magento modules and their MFTF tests are put under `` directory, for convenience of 3rd party developers. With this setup, you can keep your custom modules separate from core modules. You can also develop modules in a separate VCS repository and add them to your `composer.json` which installs them into the `vendor` directory. -All Magento modules and their MFTF tests are put under `` directory for convenience of 3rd party developers. With this setup, you can keep your custom modules separate from the core. You can also develop modules in a separate VCS repository and add them to your `composer.json` which will allow them to be installed into the `vendor` directory. +Install guide: [Composer based Installation][] -Install guide: [Composer based Installation](https://devdocs.magento.com/guides/v2.3/install-gde/composer.html) +## MFTF Installation +After installing your Magento project in either of the above ways, the composer dependency `magento/magento2-functional-testing-framework` downloads and installs MFTF. MFTF is embedded in your Magento 2 installation and will cover your project with functional tests. -### MFTF Installation +If you want to contribute a pull request into MFTF codebase, you will need to install MFTF in the [Standalone][] mode. -After installing your Magento project in either of the above ways, the composer dependency `magento/magento2-functional-testing-framework` allows you to download and install MFTF. MFTF will be embedded in your Magento 2 installation and will cover your project with functional tests. +## Managing modules - Composer vs GitHub -If you want to contribute a PR into MFTF codebase, you will need to install MFTF in the [Standalone] mode. +### Via GitHub +Cloning the Magento 2 git repository is a way of installing where you do not have to worry about matching your codebase with production. Your version control system generally holds and manages your `app/code` folder and you can do manual, ad-hoc development here. -### Managing modules - Composer vs GitHub +### Via Composer -#### Via GitHub: +Magento advocates the use of composer for managing modules. When you install a module through composer, it is added to `vendor//`. -Cloning Magento 2 git repository is a way of installing when you don't have to worry frequently about matching the codebase with production. Your version control system generally holds and manages your `app/code` folder and you can do manual ad-hoc development here. +When developing your own module or adding MFTF tests to a module, you should not edit in `vendor` because a composer update could overwrite your changes. Instead, overwrite a module under `vendor` by adding files or cloning your module-specific Git repo to `app/code//`. -#### Via composer: +To distribute the module and its tests, you can initialize a git repo and create a [composer package][]. In this way others will be able to download and install your module and access your tests as a composer package, in their `` folder. -Magento 2 advocates the use of composer for managing modules. When you install a module through composer, it is added to `vendor//` +## MFTF test materials location -If you are developing your own module or adding MFTF tests to the module, you should not edit `vendor` because a composer update could clobber your changes. Instead, you can override a module under `vendor`, by adding files or cloning your module specific git repo to `app/code//`. +- For GitHub installations, MFTF test materials are located in `/app/code///Test/Mftf/`. This is the directory for new tests or to maintain existing ones. +- For Composer-based installations, MFTF test materials are located at `/vendor///Test/Mftf/`. This is the directory to run tests fetched by Composer. -If you want to distribute the module and its tests, you can initialize a git repo and create a [composer package](https://devdocs.magento.com/guides/v2.3/extension-dev-guide/package/package_module.html). In this way others will be able to download and install your module and access your tests as a composer package, in their `` folder. - - -### MFTF test materials location - -- For GitHub installation, MFTF test materials are located at `/app/code///Test/Mftf/`. This is the directory to create new tests or maintain existing ones. - -- For Composer based installation, MFTF test materials are located at `/vendor///Test/Mftf/`. This is the directory to run tests fetched by Composer. - -The file structure under both paths is the same as below: +The file structure under both paths is the same: ```tree @@ -63,22 +59,22 @@ The file structure under both paths is the same as below: └── ... ``` +## How ModuleResolver reads modules -### How ModuleResolver reads modules - -In either of the installations, all tests and test data are read and merged by MFTF's ModuleResolver in the order indicated below: +With either type of installation, all tests and test data are read and merged by MFTF's ModuleResolver in this order: 1. `/app/code///Test/Mftf/` -2. `/vendor///Test/Mftf/` +1. `/vendor///Test/Mftf/` +## Conclusion -### Conclusion - -There are no differences from MFTF's perspective between having the test materials in `app/code` or in `/vendor`. It works the same. Composer based install may benefit teams when there's a need to match file systems in dev and production. +There is no difference between having the test materials in `app/code` or in `/vendor`: it works the same. Composer-based installs may benefit teams when there is a need to match file systems in `development` and `production`. If you are a contributing developer with an understanding of Git and Composer commands, you can choose the GitHub installation method instead. - +[Composer based Installation]: https://devdocs.magento.com/guides/v2.3/install-gde/composer.html +[GitHub Installation]: https://devdocs.magento.com/guides/v2.3/install-gde/prereq/dev_install.html [Standalone]: ../getting-started.html#set-up-a-standalone-mftf +[composer package]: https://devdocs.magento.com/guides/v2.3/extension-dev-guide/package/package_module.html From 2789a154d9f57cd914a90745a3fe408e7a7317e4 Mon Sep 17 00:00:00 2001 From: Donald Booth Date: Thu, 24 Oct 2019 09:28:46 -0500 Subject: [PATCH 033/888] Trailing space. --- docs/guides/git-vs-composer-install.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/git-vs-composer-install.md b/docs/guides/git-vs-composer-install.md index 076e5491d..3a45e3a68 100644 --- a/docs/guides/git-vs-composer-install.md +++ b/docs/guides/git-vs-composer-install.md @@ -18,7 +18,7 @@ Install guide: [Composer based Installation][] ## MFTF Installation -After installing your Magento project in either of the above ways, the composer dependency `magento/magento2-functional-testing-framework` downloads and installs MFTF. MFTF is embedded in your Magento 2 installation and will cover your project with functional tests. +After installing your Magento project in either of the above ways, the composer dependency `magento/magento2-functional-testing-framework` downloads and installs MFTF. MFTF is embedded in your Magento 2 installation and will cover your project with functional tests. If you want to contribute a pull request into MFTF codebase, you will need to install MFTF in the [Standalone][] mode. From 09d8bfd5bd10ad305c0dd7e4168e2f786c8c0b0a Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Fri, 25 Oct 2019 09:23:42 -0500 Subject: [PATCH 034/888] MQE-1782: MFTF run:group can't run test in a suite - Removed old or unused code from implementation - Added unit tests --- .../Console/BaseGenerateCommandTest.php | 58 ++++++++++++-- .../Console/BaseGenerateCommand.php | 19 ++--- .../Console/RunTestGroupCommand.php | 77 ------------------- 3 files changed, 58 insertions(+), 96 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php index 82a223726..2d4df8096 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php @@ -12,6 +12,7 @@ use Magento\FunctionalTestingFramework\Suite\Handlers\SuiteObjectHandler; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; + class BaseGenerateCommandTest extends TestCase { public function tearDown() @@ -19,9 +20,6 @@ public function tearDown() AspectMock::clean(); } - /** - * One test in one suite - */ public function testOneTestOneSuiteConfig() { $testOne = new TestObject('Test1', [], [], []); @@ -37,10 +35,6 @@ public function testOneTestOneSuiteConfig() $this->assertEquals($expected, $actual); } - - /** - * One test in one suite - */ public function testOneTestTwoSuitesConfig() { $testOne = new TestObject('Test1', [], [], []); @@ -87,6 +81,54 @@ public function testThreeTestsTwoGroup() $this->assertEquals($expected, $actual); } + public function testOneTestOneSuiteOneGroupConfig() + { + $testOne = new TestObject('Test1', [], ['group' => ['Group1']], []); + $suiteOne = new SuiteObject('Suite1', ['Test1' => $testOne], [], []); + + $testArray = ['Test1' => $testOne]; + $suiteArray = ['Suite1' => $suiteOne]; + + $this->mockHandlers($testArray, $suiteArray); + + $actual = json_decode($this->callGroupConfig(['Group1']), true); + $expected = ['tests' => null, 'suites' => ['Suite1' => ['Test1']]]; + $this->assertEquals($expected, $actual); + } + + public function testTwoTestOneSuiteTwoGroupConfig() + { + $testOne = new TestObject('Test1', [], ['group' => ['Group1']], []); + $testTwo = new TestObject('Test2', [], ['group' => ['Group2']], []); + $suiteOne = new SuiteObject('Suite1', ['Test1' => $testOne, 'Test2' => $testTwo], [], []); + + $testArray = ['Test1' => $testOne, 'Test2' => $testTwo]; + $suiteArray = ['Suite1' => $suiteOne]; + + $this->mockHandlers($testArray, $suiteArray); + + $actual = json_decode($this->callGroupConfig(['Group1', 'Group2']), true); + $expected = ['tests' => null, 'suites' => ['Suite1' => ['Test1', 'Test2']]]; + $this->assertEquals($expected, $actual); + } + + public function testTwoTestTwoSuiteOneGroupConfig() + { + $testOne = new TestObject('Test1', [], ['group' => ['Group1']], []); + $testTwo = new TestObject('Test2', [], ['group' => ['Group1']], []); + $suiteOne = new SuiteObject('Suite1', ['Test1' => $testOne], [], []); + $suiteTwo = new SuiteObject('Suite2', ['Test2' => $testTwo], [], []); + + $testArray = ['Test1' => $testOne, 'Test2' => $testTwo]; + $suiteArray = ['Suite1' => $suiteOne, 'Suite2' => $suiteTwo]; + + $this->mockHandlers($testArray, $suiteArray); + + $actual = json_decode($this->callGroupConfig(['Group1']), true); + $expected = ['tests' => null, 'suites' => ['Suite1' => ['Test1'], 'Suite2' => ['Test2']]]; + $this->assertEquals($expected, $actual); + } + /** * Mock handlers to skip parsing * @param array $testArray @@ -95,7 +137,7 @@ public function testThreeTestsTwoGroup() */ public function mockHandlers($testArray, $suiteArray) { - AspectMock::double(TestObjectHandler::class,['initTestData' => ''])->make(); + AspectMock::double(TestObjectHandler::class, ['initTestData' => ''])->make(); $handler = TestObjectHandler::getInstance(); $property = new \ReflectionProperty(TestObjectHandler::class, 'tests'); $property->setAccessible(true); diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index 0c7fff674..d99839d7c 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -76,7 +76,6 @@ protected function removeGeneratedDirectory(OutputInterface $output, bool $verbo * @return false|string * @throws \Magento\FunctionalTestingFramework\Exceptions\XmlException */ - protected function getTestAndSuiteConfiguration(array $tests) { $testConfiguration['tests'] = null; @@ -105,7 +104,12 @@ protected function getTestAndSuiteConfiguration(array $tests) return $testConfigurationJson; } - /** second attempt at a cleaner implementation, needs work */ + /** + * Returns an array of test configuration to be used as an argument for generation of tests + * This function uses group or suite names for generation + * @return false|string + * @throws \Magento\FunctionalTestingFramework\Exceptions\XmlException + */ protected function getGroupAndSuiteConfiguration(array $groupOrSuiteNames) { $result['tests'] = []; @@ -143,15 +147,8 @@ protected function getGroupAndSuiteConfiguration(array $groupOrSuiteNames) ); foreach ($testsInGroupAndInAnySuite as $testInGroupAndInAnySuite) { - $cat = $testsInSuites[$testInGroupAndInAnySuite][0]; - $dog[$cat][] = $testInGroupAndInAnySuite; - - /* - * todo -- I left off here. Code works so far. - * I need to take this $dog array and put into the $result['suites'] array - * and then test it thoroughly - */ - + $suiteName = $testsInSuites[$testInGroupAndInAnySuite][0]; + $result['suites'][$suiteName][] = $testInGroupAndInAnySuite; } $result['tests'] = array_merge( diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php index d31bf7873..98d121d40 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php @@ -111,81 +111,4 @@ function ($type, $buffer) use ($output) { } ); } - - /** - * Returns a json string to be used as an argument for generation of a group or suite - * - * @param array $groups - * @return string - * @throws \Magento\FunctionalTestingFramework\Exceptions\XmlException - */ - private function OLDgetGroupAndSuiteConfiguration(array $groups) - { - $testConfiguration['tests'] = []; - $testConfiguration['suites'] = null; - $availableSuites = SuiteObjectHandler::getInstance()->getAllObjects(); - - foreach ($groups as $group) { - if (array_key_exists($group, $availableSuites)) { - $testConfiguration['suites'][$group] = []; - } - - $testConfiguration['tests'] = array_merge( - $testConfiguration['tests'], - array_keys(TestObjectHandler::getInstance()->getTestsByGroup($group)) - ); - } - - $testConfigurationJson = json_encode($testConfiguration); - return $testConfigurationJson; - } - - /** first attempt at an implementation, needs tested */ - private function first_attempt_getGroupAndSuiteConfiguration(array $groups) - { - $testConfiguration['tests'] = []; - $testConfiguration['suites'] = null; - $availableSuites = SuiteObjectHandler::getInstance()->getAllObjects(); - - // iterate through all group names passed into the command - foreach ($groups as $group) { - if (array_key_exists($group, $availableSuites)) { - // group is actually a suite, so add it to the suites array - $testConfiguration['suites'][$group] = []; - } else { - // group is a group, so find and add all tests from that group to the tests array - $testConfiguration['tests'] = array_merge( - $testConfiguration['tests'], - array_keys(TestObjectHandler::getInstance()->getTestsByGroup($group)) - ); - } - } - - // find all tests that are in suites and build pairs - $testsInSuites = SuiteObjectHandler::getInstance()->getAllTestReferences(); - $suiteToTestPair = []; - foreach ($testConfiguration['tests'] as $test) { - if (array_key_exists($test, $testsInSuites)) { - $suites = $testsInSuites[$test]; - foreach ($suites as $suite) { - $suiteToTestPair[] = "$suite:$test"; - } - } - } - - // add tests to suites array - $diff = []; - foreach ($suiteToTestPair as $pair) { - list($suite, $test) = explode(":", $pair); - $testConfiguration['suites'][$suite][] = $test; - $diff[] = $test; - } - - // remove tests in suites from the tests array - $testConfiguration['tests'] = array_diff($testConfiguration['tests'], $diff); - - // encode and return the result - $testConfigurationJson = json_encode($testConfiguration); - return $testConfigurationJson; - } } From 2a9df738db3cec1bce7fd18624b7b4312ccf1bfa Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Mon, 28 Oct 2019 13:44:54 -0500 Subject: [PATCH 035/888] MQE-1782: MFTF run:group can't run test in a suite - Fixed mixed group/suite usecase - Added Unit test --- .../Console/BaseGenerateCommandTest.php | 22 +++++++++++++++++++ .../Console/BaseGenerateCommand.php | 4 ++++ 2 files changed, 26 insertions(+) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php index 2d4df8096..f46becaa5 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php @@ -129,6 +129,28 @@ public function testTwoTestTwoSuiteOneGroupConfig() $this->assertEquals($expected, $actual); } + /** + * Test specific usecase of a test that is in a group with the group being called along with the suite + * i.e. run:group Group1 Suite1 + * @throws \Exception + */ + public function testThreeTestOneSuiteOneGroupMix() + { + $testOne = new TestObject('Test1', [], [], []); + $testTwo = new TestObject('Test2', [], [], []); + $testThree = new TestObject('Test3', [], ['group' => ['Group1']], []); + $suiteOne = new SuiteObject('Suite1', ['Test1' => $testOne, 'Test2' => $testTwo, 'Test3' => $testThree], [], []); + + $testArray = ['Test1' => $testOne, 'Test2' => $testTwo, 'Test3' => $testThree]; + $suiteArray = ['Suite1' => $suiteOne]; + + $this->mockHandlers($testArray, $suiteArray); + + $actual = json_decode($this->callGroupConfig(['Group1', 'Suite1']), true); + $expected = ['tests' => null, 'suites' => ['Suite1' => []]]; + $this->assertEquals($expected, $actual); + } + /** * Mock handlers to skip parsing * @param array $testArray diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index d99839d7c..244610877 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -148,6 +148,10 @@ protected function getGroupAndSuiteConfiguration(array $groupOrSuiteNames) foreach ($testsInGroupAndInAnySuite as $testInGroupAndInAnySuite) { $suiteName = $testsInSuites[$testInGroupAndInAnySuite][0]; + if (isset($result['suites'][$suiteName])) { + // Suite is already being called to run in its entirety, do not filter list + continue; + } $result['suites'][$suiteName][] = $testInGroupAndInAnySuite; } From 9cb452badb4c4353b80eb877bd0320903a5ea0e1 Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Mon, 28 Oct 2019 14:23:50 -0500 Subject: [PATCH 036/888] MQE-1782: MFTF run:group can't run test in a suite - changed from isset to array_search - fixed static check --- .../Console/BaseGenerateCommandTest.php | 7 ++++++- .../Console/BaseGenerateCommand.php | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php index f46becaa5..1b1686ce2 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php @@ -139,7 +139,12 @@ public function testThreeTestOneSuiteOneGroupMix() $testOne = new TestObject('Test1', [], [], []); $testTwo = new TestObject('Test2', [], [], []); $testThree = new TestObject('Test3', [], ['group' => ['Group1']], []); - $suiteOne = new SuiteObject('Suite1', ['Test1' => $testOne, 'Test2' => $testTwo, 'Test3' => $testThree], [], []); + $suiteOne = new SuiteObject( + 'Suite1', + ['Test1' => $testOne, 'Test2' => $testTwo, 'Test3' => $testThree], + [], + [] + ); $testArray = ['Test1' => $testOne, 'Test2' => $testTwo, 'Test3' => $testThree]; $suiteArray = ['Suite1' => $suiteOne]; diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index 244610877..5afaf17c5 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -148,7 +148,7 @@ protected function getGroupAndSuiteConfiguration(array $groupOrSuiteNames) foreach ($testsInGroupAndInAnySuite as $testInGroupAndInAnySuite) { $suiteName = $testsInSuites[$testInGroupAndInAnySuite][0]; - if (isset($result['suites'][$suiteName])) { + if (array_search($suiteName, $suites) !== false) { // Suite is already being called to run in its entirety, do not filter list continue; } From 72e69a0abce52428bf0e82df893f9b61830f2244 Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Wed, 30 Oct 2019 09:59:32 -0500 Subject: [PATCH 037/888] MQE-1870: AllureHelper exception in suites - AllureHelper checks storage before firing off event - Small bugfix to static-checks --- .../FunctionalTestingFramework/Allure/AllureHelper.php | 5 +++++ .../StaticCheck/TestDependencyCheck.php | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Allure/AllureHelper.php b/src/Magento/FunctionalTestingFramework/Allure/AllureHelper.php index d8f1c63d8..0fde0e8e7 100644 --- a/src/Magento/FunctionalTestingFramework/Allure/AllureHelper.php +++ b/src/Magento/FunctionalTestingFramework/Allure/AllureHelper.php @@ -34,6 +34,11 @@ public static function addAttachmentToLastStep($data, $caption) $rootStep = Allure::lifecycle()->getStepStorage()->getLast(); $trueLastStep = array_last($rootStep->getSteps()); + if ($trueLastStep == null) { + // Nothing to attach to; do not fire off allure event + return; + } + $attachmentEvent = new AddAttachmentEvent($data, $caption); $attachmentEvent->process($trueLastStep); } diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php index 6cfa4e9a8..19725dc18 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php @@ -66,7 +66,7 @@ class TestDependencyCheck implements StaticCheckInterface * Array containing all errors found after running the execute() function. * @var array */ - private $errors; + private $errors = []; /** * String representing the output summary found after running the execute() function. From 98edf4bc28542b364c5c80cb3793d35941867072 Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Wed, 30 Oct 2019 10:12:21 -0500 Subject: [PATCH 038/888] MQE-1870: AllureHelper exception in suites - Changelog and composer update --- CHANGELOG.md | 6 ++++++ bin/mftf | 2 +- composer.json | 2 +- composer.lock | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84cc2cfad..aec356c28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ Magento Functional Testing Framework Changelog ================================================ +2.5.3 +----- + +### Fixes +* Fixed an issue where `createData` actions would cause an exception when used in suites + 2.5.2 ----- diff --git a/bin/mftf b/bin/mftf index 355a851c8..9e5879280 100755 --- a/bin/mftf +++ b/bin/mftf @@ -29,7 +29,7 @@ try { try { $application = new Symfony\Component\Console\Application(); $application->setName('Magento Functional Testing Framework CLI'); - $application->setVersion('2.5.2'); + $application->setVersion('2.5.3'); /** @var \Magento\FunctionalTestingFramework\Console\CommandListInterface $commandList */ $commandList = new \Magento\FunctionalTestingFramework\Console\CommandList; foreach ($commandList->getCommands() as $command) { diff --git a/composer.json b/composer.json index bc2592d97..f4d192b8d 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "2.5.2", + "version": "2.5.3", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index 2439f83ef..34ea00854 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "5d566c152481274493082bdabb128c70", + "content-hash": "43ac7d340b672794730bbbe4b47894e0", "packages": [ { "name": "allure-framework/allure-codeception", From bdbe1ee0cc369ccd50ac4d8428436dd199a58ae5 Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Wed, 30 Oct 2019 10:12:55 -0500 Subject: [PATCH 039/888] MQE-1870: AllureHelper exception in suites - Changelog wording update --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aec356c28..fd1e02008 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ Magento Functional Testing Framework Changelog ----- ### Fixes -* Fixed an issue where `createData` actions would cause an exception when used in suites +* Fixed an issue where `createData` actions would cause an exception when used in `` hooks. 2.5.2 ----- From 5497d2123f4ed358add5aa4c1c0670fb8dafe2c1 Mon Sep 17 00:00:00 2001 From: Tom Reece Date: Wed, 30 Oct 2019 13:40:14 -0500 Subject: [PATCH 040/888] MQE-1845: Convert Writing tests with actiongroups --- docs/guides/action-groups.md | 82 ++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 docs/guides/action-groups.md diff --git a/docs/guides/action-groups.md b/docs/guides/action-groups.md new file mode 100644 index 000000000..69527d7cc --- /dev/null +++ b/docs/guides/action-groups.md @@ -0,0 +1,82 @@ +# Action Group Best Practices + +We should strive to write tests using only action groups. Fortunately we have built up a large set of action groups to get started. We can make use of them and extend them for our own specific needs. In some cases, we may never even need to write action groups of our own. We may be able to simply chain together calls to existing action groups to implement our new test case. + +## Why use Action Groups? + +Action groups simplify maintainability by reducing duplication. Because they are re-usable building blocks, odds are that they are already made use of by existing tests in the Magento codebase. This proves their stability through real-world use. Take for example, the action group named `LoginAsAdmin`: + +```xml + + + Login to Backend Admin using provided User Data. PLEASE NOTE: This Action Group does NOT validate that you are Logged In. + + + + + + + + + + + +``` + +As you may be able to guess, logging in to the admin panel is one of the most used action groups. It is used around 1,500 times at the time of this writing. + +Imagine if this wasn't an action group and instead we were to copy and paste these 5 actions so many times. In that scenario, if we need to make a small change it would require a lot of work. But with the action group, we can make the change in one place. + +## How can I extend Action Groups? + +Let's continue using `LoginAsAdmin` as our example. I have trimmed away metadata to clearly reveal that this action group performs 5 actions: + +``` + + ... + + + + + + +``` + +This works against the standard Magento admin panel login page. But let's imagine we're working on a Magento extension that adds a CAPTCHA field to the login page. If we create and activate this extension and then we try to run all existing tests, we can expect almost everything to fail because now we are unable to log in because we did not completely fill out all of the login form. The CAPTCHA field was left unfilled. + +We can overcome this by making use of MFTF's extensibility. All we need to do is to provide a "merge" that modifies the existing `LoginAsAdmin` action group. Our simple merge file will look like this: + +``` + + + +``` + +Because the name of this merge is also `LoginAsAdmin`, the two get merged together and an additional step happens everytime this action group is made use of. + +To continue this demonstration, let's imagine someone else is working on a Two Factor Authentication extension and they also provide a merge for the `LoginAsAdmin` action group. Their merge looks similar to what we've already seen. The only difference is that this time we fill a different field: + +``` + + + +``` + +Bringing it all together, our resulting `LoginAsAdmin` action group becomes this: + +``` + + ... + + + + + + + + +``` + +Note that no file actually contains these exact contents above, but instead all three files come together to form this action group. + +One final thing to be aware of is that this extensibility can be applied in many ways. Obviously we need to use it if we want to affect existing Magento entities like tests, action groups, and data. But something not so obvious is that this can be used within the walls of your own entities in order to make them more maintainable too. From 7ac812bed2cfe6f4f2570a4c818e1e3b0f4db5f8 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Wed, 30 Oct 2019 15:06:09 -0500 Subject: [PATCH 041/888] MQE-1257: MFTF Troubleshoot command --- dev/tests/functional/standalone_bootstrap.php | 8 +- .../Config/MftfApplicationConfig.php | 3 +- .../Console/CommandList.php | 27 +-- .../Console/TroubleShootCommand.php | 158 ++++++++++++++++++ .../Module/MagentoWebDriver.php | 33 ++++ .../Util/ModuleResolver.php | 2 +- .../FunctionalTestingFramework/_bootstrap.php | 8 +- 7 files changed, 218 insertions(+), 21 deletions(-) create mode 100644 src/Magento/FunctionalTestingFramework/Console/TroubleShootCommand.php diff --git a/dev/tests/functional/standalone_bootstrap.php b/dev/tests/functional/standalone_bootstrap.php index 763062d04..de6ef394d 100755 --- a/dev/tests/functional/standalone_bootstrap.php +++ b/dev/tests/functional/standalone_bootstrap.php @@ -15,10 +15,12 @@ require_once realpath(PROJECT_ROOT . '/vendor/autoload.php'); +$envFilePath = dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR; +defined('ENV_FILE_PATH') || define('ENV_FILE_PATH', $envFilePath); + //Load constants from .env file -$envFilePath = dirname(dirname(__DIR__)); -if (file_exists($envFilePath . DIRECTORY_SEPARATOR . '.env')) { - $env = new \Dotenv\Loader($envFilePath . DIRECTORY_SEPARATOR . '.env'); +if (file_exists(ENV_FILE_PATH . '.env')) { + $env = new \Dotenv\Loader(ENV_FILE_PATH . '.env'); $env->load(); foreach ($_ENV as $key => $var) { diff --git a/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php b/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php index 80db27de0..f429110d7 100644 --- a/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php +++ b/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php @@ -15,7 +15,8 @@ class MftfApplicationConfig const GENERATION_PHASE = "generation"; const EXECUTION_PHASE = "execution"; const UNIT_TEST_PHASE = "testing"; - const MFTF_PHASES = [self::GENERATION_PHASE, self::EXECUTION_PHASE, self::UNIT_TEST_PHASE]; + const DIAGNOSTIC_PHASE = "diagnostic"; + const MFTF_PHASES = [self::GENERATION_PHASE, self::EXECUTION_PHASE, self::UNIT_TEST_PHASE, self::DIAGNOSTIC_PHASE]; /** * Mftf debug levels diff --git a/src/Magento/FunctionalTestingFramework/Console/CommandList.php b/src/Magento/FunctionalTestingFramework/Console/CommandList.php index 34d221840..be62227ac 100644 --- a/src/Magento/FunctionalTestingFramework/Console/CommandList.php +++ b/src/Magento/FunctionalTestingFramework/Console/CommandList.php @@ -29,19 +29,20 @@ class CommandList implements CommandListInterface public function __construct(array $commands = []) { $this->commands = [ - 'build:project' => new BuildProjectCommand(), - 'reset' => new CleanProjectCommand(), - 'generate:urn-catalog' => new GenerateDevUrnCommand(), - 'generate:suite' => new GenerateSuiteCommand(), - 'generate:tests' => new GenerateTestsCommand(), - 'run:test' => new RunTestCommand(), - 'run:group' => new RunTestGroupCommand(), - 'run:failed' => new RunTestFailedCommand(), - 'run:manifest' => new RunManifestCommand(), - 'setup:env' => new SetupEnvCommand(), - 'upgrade:tests' => new UpgradeTestsCommand(), - 'generate:docs' => new GenerateDocsCommand(), - 'static-checks' => new StaticChecksCommand() + 'build:project' => new BuildProjectCommand(), + 'generate:docs' => new GenerateDocsCommand(), + 'generate:suite' => new GenerateSuiteCommand(), + 'generate:tests' => new GenerateTestsCommand(), + 'generate:urn-catalog' => new GenerateDevUrnCommand(), + 'reset' => new CleanProjectCommand(), + 'run:failed' => new RunTestFailedCommand(), + 'run:group' => new RunTestGroupCommand(), + 'run:manifest' => new RunManifestCommand(), + 'run:test' => new RunTestCommand(), + 'setup:env' => new SetupEnvCommand(), + 'static-checks' => new StaticChecksCommand(), + 'troubleshoot' => new TroubleShootCommand(), + 'upgrade:tests' => new UpgradeTestsCommand(), ] + $commands; } diff --git a/src/Magento/FunctionalTestingFramework/Console/TroubleShootCommand.php b/src/Magento/FunctionalTestingFramework/Console/TroubleShootCommand.php new file mode 100644 index 000000000..124473bcd --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Console/TroubleShootCommand.php @@ -0,0 +1,158 @@ +setName('troubleshoot') + ->setDescription( + 'This command checks environment readiness for generating and running MFTF tests.' + ); + } + + /** + * Executes the current command. + * + * @param InputInterface $input + * @param OutputInterface $output + * @return void + * @throws TestFrameworkException + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $cmdStatus = true; + + // Config application + $verbose = $output->isVerbose(); + $this->output = $output; + MftfApplicationConfig::create( + false, + MftfApplicationConfig::DIAGNOSTIC_PHASE, + $verbose, + MftfApplicationConfig::LEVEL_DEVELOPER, + false + ); + + // Check required PHP extensions + foreach (self::REQUIRED_PHP_EXTS as $ext) { + $status = $this->checkPhpExtIsAvailable($ext); + $cmdStatus = $cmdStatus && !$status ? false : $cmdStatus; + } + + // Check authentication to Magento Admin + $status = $this->checkAuthenticationToMagentoAdmin(); + $cmdStatus = $cmdStatus && !$status ? false : $cmdStatus; + + // Check connectivity and authentication to Magento Admin + $status = $this->checkConnectivityToSeleniumServer(); + $cmdStatus = $cmdStatus && !$status ? false : $cmdStatus; + + if ($cmdStatus) { + exit(0); + } else { + exit(1); + } + } + + /** + * Check php extention is installed and available + * + * @param string $ext + * @return boolean + */ + private function checkPhpExtIsAvailable($ext) + { + $result = false; + $this->output->writeln("\nChecking PHP extenstion \"{$ext}\" ..."); + if (extension_loaded(strtolower($ext))) { + $this->output->writeln('Successful'); + $result = true; + } else { + $this->output->writeln( + "MFTF requires \"{$ext}\" extension installed to make tests run\n" + . "Please make sure that the PHP you run has \"{$ext}\" installed and enabled." + ); + } + return $result; + } + + /** + * Check authentication to Magento Admin + * + * @return boolean + */ + private function checkAuthenticationToMagentoAdmin() + { + $result = false; + try { + $this->output->writeln("\nChecking authentication to Magento Admin ..."); + ModuleResolver::getInstance()->getAdminToken(); + $this->output->writeln('Successful'); + $result = true; + } catch (TestFrameworkException $e) { + $this->output->writeln($e->getMessage()); + } + return $result; + } + + /** + * Check Connectivity to Selenium Server + * + * @return boolean + */ + private function checkConnectivityToSeleniumServer() + { + $result = false; + + // Check connectivity to Selenium through Codeception + $this->output->writeln("\nChecking connectivity to Selenium Server ..."); + require_once realpath(self::CODECEPTION_AUTOLOAD_FILE); + + $config = Configuration::config(realpath(self::MFTF_CODECEPTION_CONFIG_FILE)); + $settings = Configuration::suiteSettings(self::SUITE, $config); + $dispatcher = new EventDispatcher(); + $suiteManager = new SuiteManager($dispatcher, self::SUITE, $settings); + try { + $suiteManager->initialize(); + $this->output->writeln('Successful'); + $result = true; + } catch (TestFrameworkException $e) { + $this->output->writeln($e->getMessage()); + } + return $result; + } +} diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 17a868efd..248e16e44 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -23,6 +23,9 @@ use Symfony\Component\Process\Process; use Yandex\Allure\Adapter\Support\AttachmentSupport; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Facebook\WebDriver\Remote\RemoteWebDriver; +use Facebook\WebDriver\Exception\WebDriverCurlException; /** * MagentoWebDriver module provides common Magento web actions through Selenium WebDriver. @@ -126,6 +129,11 @@ public function _initialize() $this->config = ConfigSanitizerUtil::sanitizeWebDriverConfig($this->config); parent::_initialize(); $this->cleanJsError(); + + // Check Selenium Server readiness if it's in diagnostic phase + if (MftfApplicationConfig::getConfig()->getPhase() === MftfApplicationConfig::DIAGNOSTIC_PHASE) { + $this->checkSeleniumServerReadiness(); + } } /** @@ -826,6 +834,31 @@ public function makeScreenshot($name = null) AllureHelper::addAttachmentToCurrentStep($screenName, 'Screenshot'); } + /** + * Check connectivity to running selenium server + * + * @return void + * @throws TestFrameworkException + */ + public function checkSeleniumServerReadiness() + { + try { + RemoteWebDriver::create( + $this->wdHost, + $this->capabilities, + $this->connectionTimeoutInMs, + $this->requestTimeoutInMs, + $this->httpProxy, + $this->httpProxyPort + ); + } catch (WebDriverCurlException $e) { + throw new TestFrameworkException( + "Can't connect to Webdriver at {$this->wdHost}.\n" + . "Please make sure that Selenium Server is running." + ); + } + } + /** * Takes given $command and executes it against bin/magento executable. Returns stdout output from the command. * diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index d776603d1..c9c050878 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -703,7 +703,7 @@ private function printMagentoVersionInfo() * * @return string|boolean */ - protected function getAdminToken() + public function getAdminToken() { $login = $_ENV['MAGENTO_ADMIN_USERNAME'] ?? null; $password = $_ENV['MAGENTO_ADMIN_PASSWORD'] ?? null; diff --git a/src/Magento/FunctionalTestingFramework/_bootstrap.php b/src/Magento/FunctionalTestingFramework/_bootstrap.php index 34807d2b9..dd7cfd37d 100644 --- a/src/Magento/FunctionalTestingFramework/_bootstrap.php +++ b/src/Magento/FunctionalTestingFramework/_bootstrap.php @@ -15,11 +15,13 @@ return; } defined('PROJECT_ROOT') || define('PROJECT_ROOT', $projectRootPath); -$envFilepath = realpath($projectRootPath . '/dev/tests/acceptance/'); +$envFilePath = realpath($projectRootPath . '/dev/tests/acceptance/'); +defined('ENV_FILE_PATH') || define('ENV_FILE_PATH', $envFilePath); -if (file_exists($envFilepath . DIRECTORY_SEPARATOR . '.env')) { - $env = new \Dotenv\Loader($envFilepath . DIRECTORY_SEPARATOR . '.env'); +//Load constants from .env file +if (file_exists(ENV_FILE_PATH . '.env')) { + $env = new \Dotenv\Loader(ENV_FILE_PATH . '.env'); $env->load(); if (array_key_exists('TESTS_MODULE_PATH', $_ENV) xor array_key_exists('TESTS_BP', $_ENV)) { From 7bdcafd91775c627377482a41bede5f9e80b9e9e Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Wed, 30 Oct 2019 15:34:47 -0500 Subject: [PATCH 042/888] MQE-1257: MFTF Troubleshoot command --- .../Console/TroubleShootCommand.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/TroubleShootCommand.php b/src/Magento/FunctionalTestingFramework/Console/TroubleShootCommand.php index 124473bcd..3dc9cb288 100644 --- a/src/Magento/FunctionalTestingFramework/Console/TroubleShootCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/TroubleShootCommand.php @@ -49,8 +49,9 @@ protected function configure() * * @param InputInterface $input * @param OutputInterface $output - * @return void + * @return integer * @throws TestFrameworkException + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ protected function execute(InputInterface $input, OutputInterface $output) { @@ -82,9 +83,9 @@ protected function execute(InputInterface $input, OutputInterface $output) $cmdStatus = $cmdStatus && !$status ? false : $cmdStatus; if ($cmdStatus) { - exit(0); + return 0; } else { - exit(1); + return 1; } } From 4fdf441f93b476dbeeb72a6cb032f50ee50bf06d Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Wed, 30 Oct 2019 16:09:03 -0500 Subject: [PATCH 043/888] MQE-1257: MFTF Troubleshoot command --- .../FunctionalTestingFramework/Module/MagentoWebDriver.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 248e16e44..2b41af99e 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -843,7 +843,7 @@ public function makeScreenshot($name = null) public function checkSeleniumServerReadiness() { try { - RemoteWebDriver::create( + $driver = RemoteWebDriver::create( $this->wdHost, $this->capabilities, $this->connectionTimeoutInMs, @@ -851,6 +851,7 @@ public function checkSeleniumServerReadiness() $this->httpProxy, $this->httpProxyPort ); + $driver->close(); } catch (WebDriverCurlException $e) { throw new TestFrameworkException( "Can't connect to Webdriver at {$this->wdHost}.\n" From aa1629d661b66ea8406a5d385d5e86974fffe1b4 Mon Sep 17 00:00:00 2001 From: Donald Booth Date: Fri, 1 Nov 2019 11:28:17 -0500 Subject: [PATCH 044/888] Editorial pass --- docs/guides/action-groups.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/guides/action-groups.md b/docs/guides/action-groups.md index 69527d7cc..30c531e4e 100644 --- a/docs/guides/action-groups.md +++ b/docs/guides/action-groups.md @@ -1,6 +1,6 @@ # Action Group Best Practices -We should strive to write tests using only action groups. Fortunately we have built up a large set of action groups to get started. We can make use of them and extend them for our own specific needs. In some cases, we may never even need to write action groups of our own. We may be able to simply chain together calls to existing action groups to implement our new test case. +We strive to write tests using only action groups. Fortunately, we have built up a large set of action groups to get started. We can make use of them and extend them for our own specific needs. In some cases, we may never even need to write action groups of our own. We may be able to simply chain together calls to existing action groups to implement our new test case. ## Why use Action Groups? @@ -23,15 +23,15 @@ Action groups simplify maintainability by reducing duplication. Because they are ``` -As you may be able to guess, logging in to the admin panel is one of the most used action groups. It is used around 1,500 times at the time of this writing. +Logging in to the admin panel is one of the most used action groups. It is used around 1,500 times at the time of this writing. -Imagine if this wasn't an action group and instead we were to copy and paste these 5 actions so many times. In that scenario, if we need to make a small change it would require a lot of work. But with the action group, we can make the change in one place. +Imagine if this was not an action group and instead we were to copy and paste these 5 actions every time. In that scenario, if a small change was needed, it would require a lot of work. But with the action group, we can make the change in one place. -## How can I extend Action Groups? +## How to extend action groups -Let's continue using `LoginAsAdmin` as our example. I have trimmed away metadata to clearly reveal that this action group performs 5 actions: +Again using `LoginAsAdmin` as our example, we trim away metadata to clearly reveal that this action group performs 5 actions: -``` +```xml ... @@ -42,21 +42,21 @@ Let's continue using `LoginAsAdmin` as our example. I have trimmed away metadata ``` -This works against the standard Magento admin panel login page. But let's imagine we're working on a Magento extension that adds a CAPTCHA field to the login page. If we create and activate this extension and then we try to run all existing tests, we can expect almost everything to fail because now we are unable to log in because we did not completely fill out all of the login form. The CAPTCHA field was left unfilled. +This works against the standard Magento admin panel login page. Bu imagine we are working on a Magento extension that adds a CAPTCHA field to the login page. If we create and activate this extension and then run all existing tests, we can expect almost everything to fail because the CAPTCHA field is left unfilled. -We can overcome this by making use of MFTF's extensibility. All we need to do is to provide a "merge" that modifies the existing `LoginAsAdmin` action group. Our simple merge file will look like this: +We can overcome this by making use of MFTF's extensibility. All we need to do is to provide a "merge" that modifies the existing `LoginAsAdmin` action group. Our merge file will look like: -``` +```xml ``` -Because the name of this merge is also `LoginAsAdmin`, the two get merged together and an additional step happens everytime this action group is made use of. +Because the name of this merge is also `LoginAsAdmin`, the two get merged together and an additional step happens everytime this action group is used. -To continue this demonstration, let's imagine someone else is working on a Two Factor Authentication extension and they also provide a merge for the `LoginAsAdmin` action group. Their merge looks similar to what we've already seen. The only difference is that this time we fill a different field: +To continue this example, imagine someone else is working on a 'Two-Factor Authentication' extension and they also provide a merge for the `LoginAsAdmin` action group. Their merge looks similar to what we have already seen. The only difference is that this time we fill a different field: -``` +```xml @@ -64,7 +64,7 @@ To continue this demonstration, let's imagine someone else is working on a Two F Bringing it all together, our resulting `LoginAsAdmin` action group becomes this: -``` +```xml ... @@ -77,6 +77,6 @@ Bringing it all together, our resulting `LoginAsAdmin` action group becomes this ``` -Note that no file actually contains these exact contents above, but instead all three files come together to form this action group. +No one file contains this exact content as above, but instead all three files come together to form this action group. -One final thing to be aware of is that this extensibility can be applied in many ways. Obviously we need to use it if we want to affect existing Magento entities like tests, action groups, and data. But something not so obvious is that this can be used within the walls of your own entities in order to make them more maintainable too. +This extensibility can be applied in many ways. We can use it to affect existing Magento entities such as tests, action groups, and data. Not so obvious is that this tehcnique can be used within your own entities to make them more maintainable as well. From f1299b1b03e2bfe7eb1a6382985b91fb3edba6de Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Fri, 8 Nov 2019 16:41:32 -0600 Subject: [PATCH 045/888] MQE-1257: MFTF doctor command --- .../Config/MftfApplicationConfig.php | 3 +- .../Console/CommandList.php | 2 +- ...ubleShootCommand.php => DoctorCommand.php} | 122 ++++++++++++------ .../Exceptions/TestFrameworkException.php | 18 +++ .../Module/MagentoWebDriver.php | 31 ----- .../Module/MagentoWebDriverDoctor.php | 87 +++++++++++++ 6 files changed, 188 insertions(+), 75 deletions(-) rename src/Magento/FunctionalTestingFramework/Console/{TroubleShootCommand.php => DoctorCommand.php} (56%) create mode 100644 src/Magento/FunctionalTestingFramework/Module/MagentoWebDriverDoctor.php diff --git a/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php b/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php index f429110d7..80db27de0 100644 --- a/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php +++ b/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php @@ -15,8 +15,7 @@ class MftfApplicationConfig const GENERATION_PHASE = "generation"; const EXECUTION_PHASE = "execution"; const UNIT_TEST_PHASE = "testing"; - const DIAGNOSTIC_PHASE = "diagnostic"; - const MFTF_PHASES = [self::GENERATION_PHASE, self::EXECUTION_PHASE, self::UNIT_TEST_PHASE, self::DIAGNOSTIC_PHASE]; + const MFTF_PHASES = [self::GENERATION_PHASE, self::EXECUTION_PHASE, self::UNIT_TEST_PHASE]; /** * Mftf debug levels diff --git a/src/Magento/FunctionalTestingFramework/Console/CommandList.php b/src/Magento/FunctionalTestingFramework/Console/CommandList.php index be62227ac..bf9cbd58e 100644 --- a/src/Magento/FunctionalTestingFramework/Console/CommandList.php +++ b/src/Magento/FunctionalTestingFramework/Console/CommandList.php @@ -30,6 +30,7 @@ public function __construct(array $commands = []) { $this->commands = [ 'build:project' => new BuildProjectCommand(), + 'doctor' => new DoctorCommand(), 'generate:docs' => new GenerateDocsCommand(), 'generate:suite' => new GenerateSuiteCommand(), 'generate:tests' => new GenerateTestsCommand(), @@ -41,7 +42,6 @@ public function __construct(array $commands = []) 'run:test' => new RunTestCommand(), 'setup:env' => new SetupEnvCommand(), 'static-checks' => new StaticChecksCommand(), - 'troubleshoot' => new TroubleShootCommand(), 'upgrade:tests' => new UpgradeTestsCommand(), ] + $commands; } diff --git a/src/Magento/FunctionalTestingFramework/Console/TroubleShootCommand.php b/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php similarity index 56% rename from src/Magento/FunctionalTestingFramework/Console/TroubleShootCommand.php rename to src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php index 3dc9cb288..469d4ac47 100644 --- a/src/Magento/FunctionalTestingFramework/Console/TroubleShootCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php @@ -16,13 +16,14 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Magento\FunctionalTestingFramework\Util\ModuleResolver; +use Magento\FunctionalTestingFramework\Module\MagentoWebDriver; +use Magento\FunctionalTestingFramework\Module\MagentoWebDriverDoctor; -class TroubleShootCommand extends Command +class DoctorCommand extends Command { const CODECEPTION_AUTOLOAD_FILE = PROJECT_ROOT . '/vendor/codeception/codeception/autoload.php'; const MFTF_CODECEPTION_CONFIG_FILE = ENV_FILE_PATH . 'codeception.yml'; const SUITE = 'functional'; - const REQUIRED_PHP_EXTS = ['CURL', 'mbstring', 'bcmath', 'zip', 'dom', 'gd', 'intl']; /** * Command Output @@ -31,6 +32,13 @@ class TroubleShootCommand extends Command */ private $output; + /** + * Exception Context + * + * @var array + */ + private $context = []; + /** * Configures the current command. * @@ -38,7 +46,7 @@ class TroubleShootCommand extends Command */ protected function configure() { - $this->setName('troubleshoot') + $this->setName('doctor') ->setDescription( 'This command checks environment readiness for generating and running MFTF tests.' ); @@ -62,24 +70,22 @@ protected function execute(InputInterface $input, OutputInterface $output) $this->output = $output; MftfApplicationConfig::create( false, - MftfApplicationConfig::DIAGNOSTIC_PHASE, + MftfApplicationConfig::GENERATION_PHASE, $verbose, MftfApplicationConfig::LEVEL_DEVELOPER, false ); - // Check required PHP extensions - foreach (self::REQUIRED_PHP_EXTS as $ext) { - $status = $this->checkPhpExtIsAvailable($ext); - $cmdStatus = $cmdStatus && !$status ? false : $cmdStatus; - } - // Check authentication to Magento Admin $status = $this->checkAuthenticationToMagentoAdmin(); $cmdStatus = $cmdStatus && !$status ? false : $cmdStatus; - // Check connectivity and authentication to Magento Admin - $status = $this->checkConnectivityToSeleniumServer(); + // Check connection to Selenium + $status = $this->checkConnectionToSeleniumServer(); + $cmdStatus = $cmdStatus && !$status ? false : $cmdStatus; + + // Check access to Magento CLI + $status = $this->checkAccessToMagentoCLI(); $cmdStatus = $cmdStatus && !$status ? false : $cmdStatus; if ($cmdStatus) { @@ -90,70 +96,104 @@ protected function execute(InputInterface $input, OutputInterface $output) } /** - * Check php extention is installed and available + * Check authentication to Magento Admin * - * @param string $ext * @return boolean */ - private function checkPhpExtIsAvailable($ext) + private function checkAuthenticationToMagentoAdmin() { $result = false; - $this->output->writeln("\nChecking PHP extenstion \"{$ext}\" ..."); - if (extension_loaded(strtolower($ext))) { + try { + $this->output->writeln("\nChecking authentication to Magento Admin ..."); + ModuleResolver::getInstance()->getAdminToken(); $this->output->writeln('Successful'); $result = true; - } else { - $this->output->writeln( - "MFTF requires \"{$ext}\" extension installed to make tests run\n" - . "Please make sure that the PHP you run has \"{$ext}\" installed and enabled." - ); + } catch (TestFrameworkException $e) { + $this->output->writeln($e->getMessage()); } return $result; } /** - * Check authentication to Magento Admin + * Check Connection to Selenium Server * * @return boolean */ - private function checkAuthenticationToMagentoAdmin() + private function checkConnectionToSeleniumServer() { - $result = false; - try { - $this->output->writeln("\nChecking authentication to Magento Admin ..."); - ModuleResolver::getInstance()->getAdminToken(); + // Check connection to Selenium through Codeception + $this->output->writeln("\nChecking connection to Selenium Server ..."); + $this->runMagentoWebDriverDoctor(); + + if (isset($this->context[MagentoWebDriverDoctor::EXCEPTION_TYPE_SELENIUM])) { + $this->output->write($this->context[MagentoWebDriverDoctor::EXCEPTION_TYPE_SELENIUM] . "\n"); + return false; + } else { $this->output->writeln('Successful'); - $result = true; - } catch (TestFrameworkException $e) { - $this->output->writeln($e->getMessage()); + return true; } - return $result; } /** - * Check Connectivity to Selenium Server + * Check access to Magento CLI setup * * @return boolean */ - private function checkConnectivityToSeleniumServer() + private function checkAccessToMagentoCLI() { - $result = false; + // Check Magento CLI setup + $this->output->writeln("\nChecking access to Magento CLI ..."); + $this->runMagentoWebDriverDoctor(); + + if (isset($this->context[MagentoWebDriverDoctor::EXCEPTION_TYPE_MAGENTO_CLI])) { + $this->output->write($this->context[MagentoWebDriverDoctor::EXCEPTION_TYPE_MAGENTO_CLI] . "\n"); + return false; + } else { + $this->output->writeln('Successful'); + return true; + } + } + + /** + * Run diagnose through MagentoWebDriverDoctor + * + * @return void + */ + private function runMagentoWebDriverDoctor() + { + if (!empty($this->context)) { + return; + } + + $magentoWebDriver = '\\' . MagentoWebDriver::class; + $magentoWebDriverDoctor = '\\' . MagentoWebDriverDoctor::class; - // Check connectivity to Selenium through Codeception - $this->output->writeln("\nChecking connectivity to Selenium Server ..."); require_once realpath(self::CODECEPTION_AUTOLOAD_FILE); $config = Configuration::config(realpath(self::MFTF_CODECEPTION_CONFIG_FILE)); $settings = Configuration::suiteSettings(self::SUITE, $config); + + // Enable MagentoWebDriverDoctor + $settings['modules']['enabled'][] = $magentoWebDriverDoctor; + $settings['modules']['config'][$magentoWebDriverDoctor] = + $settings['modules']['config'][$magentoWebDriver]; + + // Disable MagentoWebDriver to avoid conflicts + foreach ($settings['modules']['enabled'] as $index => $module) { + if ($module == $magentoWebDriver) { + unset($settings['modules']['enabled'][$index]); + break; + } + } + unset($settings['modules']['config'][$magentoWebDriver]); + $dispatcher = new EventDispatcher(); $suiteManager = new SuiteManager($dispatcher, self::SUITE, $settings); try { $suiteManager->initialize(); - $this->output->writeln('Successful'); - $result = true; + $this->context = ['Successful']; } catch (TestFrameworkException $e) { - $this->output->writeln($e->getMessage()); + $this->context = $e->getContext(); } - return $result; } } diff --git a/src/Magento/FunctionalTestingFramework/Exceptions/TestFrameworkException.php b/src/Magento/FunctionalTestingFramework/Exceptions/TestFrameworkException.php index 5e9e594c0..a82eddef0 100644 --- a/src/Magento/FunctionalTestingFramework/Exceptions/TestFrameworkException.php +++ b/src/Magento/FunctionalTestingFramework/Exceptions/TestFrameworkException.php @@ -13,6 +13,13 @@ */ class TestFrameworkException extends \Exception { + /** + * Exception context + * + * @var array + */ + protected $context; + /** * TestFrameworkException constructor. * @param string $message @@ -27,6 +34,17 @@ public function __construct($message, $context = []) $context ); + $this->context = $context; parent::__construct($message); } + + /** + * Return exception context + * + * @return array + */ + public function getContext() + { + return $this->context; + } } diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 2b41af99e..215438420 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -129,11 +129,6 @@ public function _initialize() $this->config = ConfigSanitizerUtil::sanitizeWebDriverConfig($this->config); parent::_initialize(); $this->cleanJsError(); - - // Check Selenium Server readiness if it's in diagnostic phase - if (MftfApplicationConfig::getConfig()->getPhase() === MftfApplicationConfig::DIAGNOSTIC_PHASE) { - $this->checkSeleniumServerReadiness(); - } } /** @@ -834,32 +829,6 @@ public function makeScreenshot($name = null) AllureHelper::addAttachmentToCurrentStep($screenName, 'Screenshot'); } - /** - * Check connectivity to running selenium server - * - * @return void - * @throws TestFrameworkException - */ - public function checkSeleniumServerReadiness() - { - try { - $driver = RemoteWebDriver::create( - $this->wdHost, - $this->capabilities, - $this->connectionTimeoutInMs, - $this->requestTimeoutInMs, - $this->httpProxy, - $this->httpProxyPort - ); - $driver->close(); - } catch (WebDriverCurlException $e) { - throw new TestFrameworkException( - "Can't connect to Webdriver at {$this->wdHost}.\n" - . "Please make sure that Selenium Server is running." - ); - } - } - /** * Takes given $command and executes it against bin/magento executable. Returns stdout output from the command. * diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriverDoctor.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriverDoctor.php new file mode 100644 index 000000000..3acde4a42 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriverDoctor.php @@ -0,0 +1,87 @@ +checkSeleniumServerReadiness(); + } catch (TestFrameworkException $e) { + $context[self::EXCEPTION_TYPE_SELENIUM] = $e->getMessage(); + } + + try { + $this->checkMagentoCLI(); + } catch (TestFrameworkException $e) { + $context[self::EXCEPTION_TYPE_MAGENTO_CLI] = $e->getMessage(); + } + + if (!empty($context)) { + throw new TestFrameworkException('MagentoWebDriverDoctor initialization failed', $context); + } + } + + /** + * Check connectivity to running selenium server + * + * @return void + * @throws TestFrameworkException + */ + private function checkSeleniumServerReadiness() + { + try { + $driver = RemoteWebDriver::create( + $this->wdHost, + $this->capabilities, + $this->connectionTimeoutInMs, + $this->requestTimeoutInMs, + $this->httpProxy, + $this->httpProxyPort + ); + $driver->close(); + } catch (\Exception $e) { + throw new TestFrameworkException( + "Can't connect to Webdriver at {$this->wdHost}.\n" + . "Please make sure that Selenium Server is running." + ); + } + } + + /** + * Check Magento CLI setup + * + * @return void + * @throws TestFrameworkException + */ + private function checkMagentoCLI() + { + parent::magentoCLI(self::MAGENTO_CLI_COMMAND); + } +} From 7c0dafd9cffef9f50b8b662c0b7dafb04d8cd6db Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Mon, 11 Nov 2019 08:58:26 -0600 Subject: [PATCH 046/888] MQE-1712: Get Error HTTP response code: 500 when using magentoCLI with command config:sensitive:set - command.php no longer overwrites potentially useful output with empty output --- etc/config/command.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/etc/config/command.php b/etc/config/command.php index 7b45a2595..adc372e43 100644 --- a/etc/config/command.php +++ b/etc/config/command.php @@ -31,7 +31,10 @@ $process->run(); $output = $process->getOutput(); if (!$process->isSuccessful()) { - $output = $process->getErrorOutput(); + $failureOutput = $process->getErrorOutput(); + if (!empty($failureOutput)) { + $output = $failureOutput; + } } if (empty($output)) { $output = "CLI did not return output."; From bfe90fd3340a0bd051c00fd07ca7c4a7d54ac723 Mon Sep 17 00:00:00 2001 From: filmaj Date: Tue, 12 Nov 2019 16:40:55 -0500 Subject: [PATCH 047/888] expanding on credential usage docs to explicitly call out how to use credentials differently in File vs Vault Storage configurations. --- docs/credentials.md | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/docs/credentials.md b/docs/credentials.md index 3065454b0..8aec0eacd 100644 --- a/docs/credentials.md +++ b/docs/credentials.md @@ -1,6 +1,6 @@ # Credentials -When you test functionality that involves external services such as UPS, FedEx, PayPal, or SignifyD, +When you test functionality that involves external services such as UPS, FedEx, PayPal, or SignifyD, use the MFTF credentials feature to hide sensitive [data][] like integration tokens and API keys. Currently the MFTF supports two types of credential storage: @@ -53,7 +53,7 @@ magento/carriers_usps_password=Lmgxvrq89uPwECeV #magento/carriers_dhl_id_us=dhl_test_user #magento/carriers_dhl_password_us=Mlgxv3dsagVeG .... -``` +``` Or add new key & value pairs for your own credentials. The keys use the following format: @@ -64,7 +64,7 @@ Or add new key & value pairs for your own credentials. The keys use the followin
The `/` symbol is not supported in a `key_name` other than the one after your vendor or extension name.
- + Otherwise you are free to use any other `key_name` you like, as they are merely the keys to reference from your tests. ```conf @@ -74,10 +74,10 @@ vendor/my_awesome_service_token=rRVSVnh3cbDsVG39oTMz4A ## Configure Vault Storage -Hashicorp vault secures, stores, and tightly controls access to data in modern computing. -It provides advanced data protection for your testing credentials. +Hashicorp vault secures, stores, and tightly controls access to data in modern computing. +It provides advanced data protection for your testing credentials. -The MFTF works with both `vault enterprise` and `vault open source` that use `KV Version 2` secret engine. +The MFTF works with both `vault enterprise` and `vault open source` that use `KV Version 2` secret engine. ### Install vault CLI @@ -95,8 +95,8 @@ vault login -method -path ### Store secrets in vault -The MFTF uses the `KV Version 2` secret engine for secret storage. -More information for working with `KV Version 2` can be found in [Vault KV2][Vault KV2]. +The MFTF uses the `KV Version 2` secret engine for secret storage. +More information for working with `KV Version 2` can be found in [Vault KV2][Vault KV2]. #### Secrets path and key convention @@ -125,9 +125,9 @@ vault kv put secret/mftf/magento/carriers_usps_password carriers_usps_password=L ### Setup MFTF to use vault -Add vault configuration environment variables [`CREDENTIAL_VAULT_ADDRESS`][] and [`CREDENTIAL_VAULT_SECRET_BASE_PATH`][] +Add vault configuration environment variables [`CREDENTIAL_VAULT_ADDRESS`][] and [`CREDENTIAL_VAULT_SECRET_BASE_PATH`][] from `etc/config/.env.example` in `.env`. -Set values according to your vault server configuration. +Set values according to your vault server configuration. ```conf # Default vault dev server @@ -137,7 +137,7 @@ CREDENTIAL_VAULT_SECRET_BASE_PATH=secret ## Configure both File Storage and Vault Storage -It is possible and sometimes useful to setup and use both `.credentials` file and vault for secret storage at the same time. +It is possible and sometimes useful to setup and use both `.credentials` file and vault for secret storage at the same time. In this case, the MFTF tests are able to read secret data at runtime from both storage options, but the local `.credentials` file will take precedence. @@ -150,11 +150,19 @@ Define the value as a reference to the corresponding key in the credentials file - `_CREDS` is an environment constant pointing to the `.credentials` file - `my_data_key` is a key in the the `.credentials` file or vault that contains the value to be used in a test step + - for File Storage, ensure your key contains the vendor prefix, i.e. `vendor/my_data_key` + - for Vault Storage, ensure your key contains your secret basepath + `/mftf/` + your vendor prefix + `/` and finally your key, i.e. `secret/mftf/vendor/my_data_key` + +For example, to reference secret data in the [`fillField`][] action, use the `userInput` attribute using a typical File Storage: + +```xml + +``` -For example, reference secret data in the [`fillField`][] action with the `userInput` attribute. +... whereas to do the same using Vault Storage: ```xml - + ``` From e894f75e9feb828859eb8d22eca3853158dd2d82 Mon Sep 17 00:00:00 2001 From: Donald Booth Date: Tue, 12 Nov 2019 16:03:21 -0600 Subject: [PATCH 048/888] Grammar fixup. --- docs/credentials.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/credentials.md b/docs/credentials.md index 8aec0eacd..3cc765a45 100644 --- a/docs/credentials.md +++ b/docs/credentials.md @@ -55,7 +55,7 @@ magento/carriers_usps_password=Lmgxvrq89uPwECeV .... ``` -Or add new key & value pairs for your own credentials. The keys use the following format: +Or add new key/value pairs for your own credentials. The keys use the following format: ```conf /= @@ -150,8 +150,8 @@ Define the value as a reference to the corresponding key in the credentials file - `_CREDS` is an environment constant pointing to the `.credentials` file - `my_data_key` is a key in the the `.credentials` file or vault that contains the value to be used in a test step - - for File Storage, ensure your key contains the vendor prefix, i.e. `vendor/my_data_key` - - for Vault Storage, ensure your key contains your secret basepath + `/mftf/` + your vendor prefix + `/` and finally your key, i.e. `secret/mftf/vendor/my_data_key` + - for File Storage, ensure your key contains the vendor prefix, i.e. `vendor/my_data_key` + - for Vault Storage, ensure your key contains your secret basepath + `/mftf/` + your vendor prefix + `/` and finally your key, i.e. `secret/mftf/vendor/my_data_key` For example, to reference secret data in the [`fillField`][] action, use the `userInput` attribute using a typical File Storage: @@ -159,7 +159,7 @@ For example, to reference secret data in the [`fillField`][] action, use the `us ``` -... whereas to do the same using Vault Storage: +To do the same using Vault Storage: ```xml From 6dd9655efae9ac00f104d52f1499246d721a6917 Mon Sep 17 00:00:00 2001 From: filmaj Date: Wed, 13 Nov 2019 15:28:12 -0500 Subject: [PATCH 049/888] remove vault-based credentials usage details for now --- docs/credentials.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/docs/credentials.md b/docs/credentials.md index 3cc765a45..a2850cfe8 100644 --- a/docs/credentials.md +++ b/docs/credentials.md @@ -151,7 +151,6 @@ Define the value as a reference to the corresponding key in the credentials file - `_CREDS` is an environment constant pointing to the `.credentials` file - `my_data_key` is a key in the the `.credentials` file or vault that contains the value to be used in a test step - for File Storage, ensure your key contains the vendor prefix, i.e. `vendor/my_data_key` - - for Vault Storage, ensure your key contains your secret basepath + `/mftf/` + your vendor prefix + `/` and finally your key, i.e. `secret/mftf/vendor/my_data_key` For example, to reference secret data in the [`fillField`][] action, use the `userInput` attribute using a typical File Storage: @@ -159,12 +158,6 @@ For example, to reference secret data in the [`fillField`][] action, use the `us ``` -To do the same using Vault Storage: - -```xml - -``` - ## Implementation details From 467c1570e80577dfe6fb815dee2396f75828475e Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Thu, 14 Nov 2019 16:50:41 -0600 Subject: [PATCH 050/888] MQE-1884: MFTF - failures override other failures attaching suppressed exception before _after hook failure to current step. --- .../Extension/TestContextExtension.php | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php index 9fe7adb7a..6e738418f 100644 --- a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php +++ b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php @@ -64,6 +64,8 @@ public function testStart() public function testFail(\Codeception\Event\FailEvent $e) { $cest = $e->getTest(); + //log suppressed exception in case of _after hook failure + $this->logPreviousException($e->getFail()); $context = $this->extractContext($e->getFail()->getTrace(), $cest->getTestMethod()); // Do not attempt to run _after if failure was in the _after block // Try to run _after but catch exceptions to prevent them from overwriting original failure. @@ -93,7 +95,9 @@ function () use ($cest) { if (!empty($errors)) { foreach ($errors as $error) { if ($error->failedTest()->getTestMethod() == $cest->getName()) { - $stack = $errors[0]->thrownException()->getTrace(); + //log suppressed exception in case of _after hook failure + $this->logPreviousException($error->thrownException()); + $stack = $error->thrownException()->getTrace(); $context = $this->extractContext($stack, $cest->getTestMethod()); // Do not attempt to run _after if failure was in the _after block // Try to run _after but catch exceptions to prevent them from overwriting original failure. @@ -150,6 +154,31 @@ public function extractContext($trace, $class) return null; } + /** + * Attach suppressed exception thrown before _after hook to the current step. + * @param \Exception $exception + * @return mixed + */ + public function logPreviousException(\Exception $exception) + { + $change = function(){ + if ($this instanceof \PHPUnit\Framework\ExceptionWrapper ) { + return $this->previous; + } + else { + return $this->getPrevious(); + } + }; + $firstException = $change->call($exception); + $bind = function() use ($firstException){ + $exception = $firstException; + }; + $bind->call($exception); + if ($firstException !== null) { + AllureHelper::addAttachmentToCurrentStep($firstException, 'Exception'); + } + } + /** * Codeception event listener function, triggered before step. * Check if it's a new page. From 722f3123d1852d9f794f647ac03e6fe29dcb3b46 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Thu, 14 Nov 2019 16:59:58 -0600 Subject: [PATCH 051/888] MQE-1884: MFTF - failures override other failures fixed static checks --- .../Extension/TestContextExtension.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php index 6e738418f..be7e2ca39 100644 --- a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php +++ b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php @@ -161,16 +161,15 @@ public function extractContext($trace, $class) */ public function logPreviousException(\Exception $exception) { - $change = function(){ - if ($this instanceof \PHPUnit\Framework\ExceptionWrapper ) { + $change = function () { + if ($this instanceof \PHPUnit\Framework\ExceptionWrapper) { return $this->previous; - } - else { + } else { return $this->getPrevious(); } }; $firstException = $change->call($exception); - $bind = function() use ($firstException){ + $bind = function () use ($firstException) { $exception = $firstException; }; $bind->call($exception); From 960320a4a80889d707b6dbfd12e80a26059bb37a Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Fri, 15 Nov 2019 08:29:14 -0600 Subject: [PATCH 052/888] MQE-1884: MFTF - failures override other failures fixed static checks --- .../Extension/TestContextExtension.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php index be7e2ca39..276e2e1c2 100644 --- a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php +++ b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php @@ -13,6 +13,7 @@ /** * Class TestContextExtension * @SuppressWarnings(PHPMD.UnusedPrivateField) + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class TestContextExtension extends BaseExtension { From 25c5706cc2df7384de31b6804fc5d76b120a347c Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Thu, 14 Nov 2019 15:46:24 -0600 Subject: [PATCH 053/888] MQE-1257: MFTF doctor command --- docs/commands/mftf.md | 14 +++ .../Console/DoctorCommand.php | 64 ++++++----- .../Module/MagentoWebDriverDoctor.php | 108 +++++++++++++++--- 3 files changed, 139 insertions(+), 47 deletions(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 58be6501e..5e9895958 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -109,6 +109,20 @@ You can include options to set configuration parameter values for your environme vendor/bin/mftf build:project --MAGENTO_BASE_URL=http://magento.local/ --MAGENTO_BACKEND_NAME=admin214365 ``` +### `doctor` + +#### Description + +Diagnose MFTF configuration and setup + +#### Usage + +```bash +vendor/bin/mftf doctor +``` + +#### Options + ### `generate:tests` #### Description diff --git a/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php b/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php index 469d4ac47..2caa47437 100644 --- a/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php @@ -67,6 +67,7 @@ protected function execute(InputInterface $input, OutputInterface $output) // Config application $verbose = $output->isVerbose(); + $this->input = $input; $this->output = $output; MftfApplicationConfig::create( false, @@ -81,11 +82,31 @@ protected function execute(InputInterface $input, OutputInterface $output) $cmdStatus = $cmdStatus && !$status ? false : $cmdStatus; // Check connection to Selenium - $status = $this->checkConnectionToSeleniumServer(); + $status = $this->checkContextOnStep( + MagentoWebDriverDoctor::EXCEPTION_CONTEXT_SELENIUM, + 'Connecting to Selenium Server' + ); + $cmdStatus = $cmdStatus && !$status ? false : $cmdStatus; + + // Check opening Magento Admin in web browser + $status = $this->checkContextOnStep( + MagentoWebDriverDoctor::EXCEPTION_CONTEXT_ADMIN, + 'Loading Admin page' + ); + $cmdStatus = $cmdStatus && !$status ? false : $cmdStatus; + + // Check opening Magento Storefront in web browser + $status = $this->checkContextOnStep( + MagentoWebDriverDoctor::EXCEPTION_CONTEXT_STOREFRONT, + 'Loading Storefront page' + ); $cmdStatus = $cmdStatus && !$status ? false : $cmdStatus; // Check access to Magento CLI - $status = $this->checkAccessToMagentoCLI(); + $status = $this->checkContextOnStep( + MagentoWebDriverDoctor::EXCEPTION_CONTEXT_CLI, + 'Running Magento CLI' + ); $cmdStatus = $cmdStatus && !$status ? false : $cmdStatus; if ($cmdStatus) { @@ -96,7 +117,7 @@ protected function execute(InputInterface $input, OutputInterface $output) } /** - * Check authentication to Magento Admin + * Check admin account authentication * * @return boolean */ @@ -104,7 +125,7 @@ private function checkAuthenticationToMagentoAdmin() { $result = false; try { - $this->output->writeln("\nChecking authentication to Magento Admin ..."); + $this->output->writeln("\nAuthenticating admin account by API ..."); ModuleResolver::getInstance()->getAdminToken(); $this->output->writeln('Successful'); $result = true; @@ -115,38 +136,20 @@ private function checkAuthenticationToMagentoAdmin() } /** - * Check Connection to Selenium Server - * - * @return boolean - */ - private function checkConnectionToSeleniumServer() - { - // Check connection to Selenium through Codeception - $this->output->writeln("\nChecking connection to Selenium Server ..."); - $this->runMagentoWebDriverDoctor(); - - if (isset($this->context[MagentoWebDriverDoctor::EXCEPTION_TYPE_SELENIUM])) { - $this->output->write($this->context[MagentoWebDriverDoctor::EXCEPTION_TYPE_SELENIUM] . "\n"); - return false; - } else { - $this->output->writeln('Successful'); - return true; - } - } - - /** - * Check access to Magento CLI setup + * Check exception context after runMagentoWebDriverDoctor * + * @param string $exceptionType + * @param string $message * @return boolean + * @throws TestFrameworkException */ - private function checkAccessToMagentoCLI() + private function checkContextOnStep($exceptionType, $message) { - // Check Magento CLI setup - $this->output->writeln("\nChecking access to Magento CLI ..."); + $this->output->writeln("\n$message ..."); $this->runMagentoWebDriverDoctor(); - if (isset($this->context[MagentoWebDriverDoctor::EXCEPTION_TYPE_MAGENTO_CLI])) { - $this->output->write($this->context[MagentoWebDriverDoctor::EXCEPTION_TYPE_MAGENTO_CLI] . "\n"); + if (isset($this->context[$exceptionType])) { + $this->output->write($this->context[$exceptionType] . "\n"); return false; } else { $this->output->writeln('Successful'); @@ -158,6 +161,7 @@ private function checkAccessToMagentoCLI() * Run diagnose through MagentoWebDriverDoctor * * @return void + * @throws TestFrameworkException */ private function runMagentoWebDriverDoctor() { diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriverDoctor.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriverDoctor.php index 3acde4a42..35fa37f03 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriverDoctor.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriverDoctor.php @@ -11,13 +11,22 @@ /** * MagentoWebDriverDoctor module extends MagentoWebDriver module and is a light weighted module to diagnose webdriver - * initialization and other setup issues. It uses in memory version of MagentoWebDriver's configuration file + * initialization and other setup issues. It uses in memory version of MagentoWebDriver's configuration file. */ class MagentoWebDriverDoctor extends MagentoWebDriver { const MAGENTO_CLI_COMMAND = 'list'; - const EXCEPTION_TYPE_SELENIUM = 'selenium'; - const EXCEPTION_TYPE_MAGENTO_CLI = 'cli'; + const EXCEPTION_CONTEXT_SELENIUM = 'selenium'; + const EXCEPTION_CONTEXT_ADMIN = 'admin'; + const EXCEPTION_CONTEXT_STOREFRONT = 'store'; + const EXCEPTION_CONTEXT_CLI = 'cli'; + + /** + * Remote Web Driver + * + * @var RemoteWebDriver + */ + private $remoteWebDriver = null; /** * Go through parent initialization routines and in addition diagnose potential environment issues @@ -32,32 +41,52 @@ public function _initialize() $context = []; try { - $this->checkSeleniumServerReadiness(); + $this->connectToSeleniumServer(); } catch (TestFrameworkException $e) { - $context[self::EXCEPTION_TYPE_SELENIUM] = $e->getMessage(); + $context[self::EXCEPTION_CONTEXT_SELENIUM] = $e->getMessage(); } try { - $this->checkMagentoCLI(); - } catch (TestFrameworkException $e) { - $context[self::EXCEPTION_TYPE_MAGENTO_CLI] = $e->getMessage(); + $adminUrl = rtrim(getenv('MAGENTO_BACKEND_BASE_URL'), '/') + ?: rtrim(getenv('MAGENTO_BASE_URL'), '/') + . '/' . getenv('MAGENTO_BACKEND_NAME') . '/admin'; + $this->loadPageAtUrl($adminUrl); + } catch (\Exception $e) { + $context[self::EXCEPTION_CONTEXT_ADMIN] = $e->getMessage(); + } + + try { + $storeUrl = getenv('MAGENTO_BASE_URL'); + $this->loadPageAtUrl($storeUrl); + } catch (\Exception $e) { + $context[self::EXCEPTION_CONTEXT_STOREFRONT] = $e->getMessage(); + } + + try { + $this->runMagentoCLI(); + } catch (\Exception $e) { + $context[self::EXCEPTION_CONTEXT_CLI] = $e->getMessage(); + } + + if (null !== $this->remoteWebDriver) { + $this->remoteWebDriver->close(); } if (!empty($context)) { - throw new TestFrameworkException('MagentoWebDriverDoctor initialization failed', $context); + throw new TestFrameworkException('Exception occurred in MagentoWebDriverDoctor', $context); } } /** - * Check connectivity to running selenium server + * Check connecting to running selenium server * * @return void * @throws TestFrameworkException */ - private function checkSeleniumServerReadiness() + private function connectToSeleniumServer() { try { - $driver = RemoteWebDriver::create( + $this->remoteWebDriver = RemoteWebDriver::create( $this->wdHost, $this->capabilities, $this->connectionTimeoutInMs, @@ -65,23 +94,68 @@ private function checkSeleniumServerReadiness() $this->httpProxy, $this->httpProxyPort ); - $driver->close(); } catch (\Exception $e) { throw new TestFrameworkException( - "Can't connect to Webdriver at {$this->wdHost}.\n" + "Failed to connect Selenium WebDriver at: {$this->wdHost}.\n" . "Please make sure that Selenium Server is running." ); } } /** - * Check Magento CLI setup + * Validate loading a web page at url in the browser controlled by selenium + * + * @param string $url + * @return void + * @throws TestFrameworkException + */ + private function loadPageAtUrl($url) + { + try { + // Open the web page at url first + $this->remoteWebDriver->get($url); + + // Execute Javascript to retrieve HTTP response code + $script = '' + . 'var xhr = new XMLHttpRequest();' + . "xhr.open('GET', '" . $url . "', false);" + . 'xhr.send(null); ' + . 'return xhr.status'; + $status = $this->remoteWebDriver->executeScript($script); + + if ($status === 200) { + return; + } + } catch (\Exception $e) { + } + + throw new TestFrameworkException( + "Failed to load page at url: $url\n" + . "Please check network connection for the browser running Selenium." + ); + } + + /** + * Check running Magento CLI command * * @return void * @throws TestFrameworkException */ - private function checkMagentoCLI() + private function runMagentoCLI() { - parent::magentoCLI(self::MAGENTO_CLI_COMMAND); + try { + $regex = '~^.*(?Magento CLI).*[\r\n]+(?Usage:).*~'; + $output = parent::magentoCLI(self::MAGENTO_CLI_COMMAND); + preg_match($regex, $output, $matches); + + if (isset($matches['name']) && isset($matches['usage'])) { + return; + } + } catch (\Exception $e) { + throw new TestFrameworkException( + "Failed to run Magento CLI command\n" + . "Please reference Magento DevDoc to setup command.php and .htaccess files." + ); + } } } From 4908777736d79ab58d04c72035957b38469fb3d6 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Fri, 15 Nov 2019 15:45:33 -0600 Subject: [PATCH 054/888] MQE-1257: MFTF doctor command - config color for console output --- .../Console/DoctorCommand.php | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php b/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php index 2caa47437..d75004fc2 100644 --- a/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php @@ -24,6 +24,10 @@ class DoctorCommand extends Command const CODECEPTION_AUTOLOAD_FILE = PROJECT_ROOT . '/vendor/codeception/codeception/autoload.php'; const MFTF_CODECEPTION_CONFIG_FILE = ENV_FILE_PATH . 'codeception.yml'; const SUITE = 'functional'; + const COLOR_LIGHT_GREEN = "\e[1;32m"; + const COLOR_LIGHT_RED = "\e[1;31m"; + const COLOR_LIGHT_DEFAULT = "\e[1;39m"; + const COLOR_RESTORE = "\e[0m"; /** * Command Output @@ -60,6 +64,7 @@ protected function configure() * @return integer * @throws TestFrameworkException * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ protected function execute(InputInterface $input, OutputInterface $output) { @@ -109,11 +114,7 @@ protected function execute(InputInterface $input, OutputInterface $output) ); $cmdStatus = $cmdStatus && !$status ? false : $cmdStatus; - if ($cmdStatus) { - return 0; - } else { - return 1; - } + return $cmdStatus ? 0 : 1; } /** @@ -125,12 +126,14 @@ private function checkAuthenticationToMagentoAdmin() { $result = false; try { - $this->output->writeln("\nAuthenticating admin account by API ..."); + $this->output->writeln( + "\n" . self::COLOR_LIGHT_DEFAULT . "Authenticating admin account by API ..." . self::COLOR_RESTORE + ); ModuleResolver::getInstance()->getAdminToken(); - $this->output->writeln('Successful'); + $this->output->writeln(self::COLOR_LIGHT_GREEN . 'Successful' . self::COLOR_RESTORE); $result = true; } catch (TestFrameworkException $e) { - $this->output->writeln($e->getMessage()); + $this->output->writeln(self::COLOR_LIGHT_RED . $e->getMessage() . self::COLOR_RESTORE); } return $result; } @@ -145,14 +148,14 @@ private function checkAuthenticationToMagentoAdmin() */ private function checkContextOnStep($exceptionType, $message) { - $this->output->writeln("\n$message ..."); + $this->output->writeln("\n" . self::COLOR_LIGHT_DEFAULT. $message . self::COLOR_RESTORE); $this->runMagentoWebDriverDoctor(); if (isset($this->context[$exceptionType])) { - $this->output->write($this->context[$exceptionType] . "\n"); + $this->output->writeln(self::COLOR_LIGHT_RED . $this->context[$exceptionType] . self::COLOR_RESTORE); return false; } else { - $this->output->writeln('Successful'); + $this->output->writeln(self::COLOR_LIGHT_GREEN . 'Successful' . self::COLOR_RESTORE); return true; } } From db8712bf5a46402b893fa950f8a80f52e4769591 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Mon, 18 Nov 2019 11:43:22 -0600 Subject: [PATCH 055/888] MQE-1884: MFTF - failures override other failures bumped up codeception version to 2.4.5 to be inline with magento version. Removed method runAfterBlock, 2.4.5 runs _after hook implicitly. --- composer.json | 2 +- composer.lock | 84 ++++++++++++++----- .../Extension/TestContextExtension.php | 44 ---------- 3 files changed, 63 insertions(+), 67 deletions(-) diff --git a/composer.json b/composer.json index f980005c1..3e3b0ab42 100755 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "php": "7.0.2||7.0.4||~7.0.6||~7.1.0||~7.2.0||~7.3.0", "ext-curl": "*", "allure-framework/allure-codeception": "~1.3.0", - "codeception/codeception": "~2.3.4 || ~2.4.0 ", + "codeception/codeception": "~2.4.5", "composer/composer": "^1.6", "consolidation/robo": "^1.0.0", "csharpru/vault-php": "~3.5.3", diff --git a/composer.lock b/composer.lock index 275ae9778..5c2ba8c2d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "beb8473a3c21b83da864289149fc03b4", + "content-hash": "1b0ef9b803188c23577751eba2a3d966", "packages": [ { "name": "allure-framework/allure-codeception", @@ -263,31 +263,28 @@ }, { "name": "codeception/codeception", - "version": "2.3.9", + "version": "2.4.5", "source": { "type": "git", "url": "https://github.com/Codeception/Codeception.git", - "reference": "104f46fa0bde339f1bcc3a375aac21eb36e65a1e" + "reference": "5fee32d5c82791548931cbc34806b4de6aa1abfc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/Codeception/zipball/104f46fa0bde339f1bcc3a375aac21eb36e65a1e", - "reference": "104f46fa0bde339f1bcc3a375aac21eb36e65a1e", + "url": "https://api.github.com/repos/Codeception/Codeception/zipball/5fee32d5c82791548931cbc34806b4de6aa1abfc", + "reference": "5fee32d5c82791548931cbc34806b4de6aa1abfc", "shasum": "" }, "require": { - "behat/gherkin": "~4.4.0", - "codeception/stub": "^1.0", + "behat/gherkin": "^4.4.0", + "codeception/phpunit-wrapper": "^6.0.9|^7.0.6", + "codeception/stub": "^2.0", "ext-json": "*", "ext-mbstring": "*", "facebook/webdriver": ">=1.1.3 <2.0", "guzzlehttp/guzzle": ">=4.1.4 <7.0", "guzzlehttp/psr7": "~1.0", - "php": ">=5.4.0 <8.0", - "phpunit/php-code-coverage": ">=2.2.4 <6.0", - "phpunit/phpunit": ">=4.8.28 <5.0.0 || >=5.6.3 <7.0", - "sebastian/comparator": ">1.1 <3.0", - "sebastian/diff": ">=1.4 <3.0", + "php": ">=5.6.0 <8.0", "symfony/browser-kit": ">=2.7 <5.0", "symfony/console": ">=2.7 <5.0", "symfony/css-selector": ">=2.7 <5.0", @@ -353,27 +350,70 @@ "functional testing", "unit testing" ], - "time": "2018-02-26T23:29:41+00:00" + "time": "2018-08-01T07:21:49+00:00" }, { - "name": "codeception/stub", - "version": "1.0.4", + "name": "codeception/phpunit-wrapper", + "version": "6.7.0", "source": { "type": "git", - "url": "https://github.com/Codeception/Stub.git", - "reference": "681b62348837a5ef07d10d8a226f5bc358cc8805" + "url": "https://github.com/Codeception/phpunit-wrapper.git", + "reference": "93f59e028826464eac086052fa226e58967f6907" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/Stub/zipball/681b62348837a5ef07d10d8a226f5bc358cc8805", - "reference": "681b62348837a5ef07d10d8a226f5bc358cc8805", + "url": "https://api.github.com/repos/Codeception/phpunit-wrapper/zipball/93f59e028826464eac086052fa226e58967f6907", + "reference": "93f59e028826464eac086052fa226e58967f6907", "shasum": "" }, "require": { - "phpunit/phpunit-mock-objects": ">2.3 <7.0" + "phpunit/php-code-coverage": ">=4.0.4 <6.0", + "phpunit/phpunit": ">=6.5.13 <7.0", + "sebastian/comparator": ">=1.2.4 <3.0", + "sebastian/diff": ">=1.4 <4.0" + }, + "replace": { + "codeception/phpunit-wrapper": "*" }, "require-dev": { - "phpunit/phpunit": ">=4.8 <8.0" + "codeception/specify": "*", + "vlucas/phpdotenv": "^3.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Codeception\\PHPUnit\\": "src\\" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Davert", + "email": "davert.php@resend.cc" + } + ], + "description": "PHPUnit classes used by Codeception", + "time": "2019-08-18T15:43:35+00:00" + }, + { + "name": "codeception/stub", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/Codeception/Stub.git", + "reference": "853657f988942f7afb69becf3fd0059f192c705a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/Stub/zipball/853657f988942f7afb69becf3fd0059f192c705a", + "reference": "853657f988942f7afb69becf3fd0059f192c705a", + "shasum": "" + }, + "require": { + "codeception/phpunit-wrapper": ">6.0.15 <6.1.0 | ^6.6.1 | ^7.7.1 | ^8.0.3" }, "type": "library", "autoload": { @@ -386,7 +426,7 @@ "MIT" ], "description": "Flexible Stub wrapper for PHPUnit's Mock Builder", - "time": "2018-05-17T09:31:08+00:00" + "time": "2019-03-02T15:35:10+00:00" }, { "name": "composer/ca-bundle", diff --git a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php index 276e2e1c2..b0f42590f 100644 --- a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php +++ b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php @@ -18,7 +18,6 @@ class TestContextExtension extends BaseExtension { const TEST_PHASE_AFTER = "_after"; - const CODECEPT_AFTER_VERSION = "2.3.9"; const TEST_FAILED_FILE = 'failed'; /** @@ -64,15 +63,8 @@ public function testStart() */ public function testFail(\Codeception\Event\FailEvent $e) { - $cest = $e->getTest(); //log suppressed exception in case of _after hook failure $this->logPreviousException($e->getFail()); - $context = $this->extractContext($e->getFail()->getTrace(), $cest->getTestMethod()); - // Do not attempt to run _after if failure was in the _after block - // Try to run _after but catch exceptions to prevent them from overwriting original failure. - if ($context != TestContextExtension::TEST_PHASE_AFTER) { - $this->runAfterBlock($e, $cest); - } } /** @@ -98,13 +90,6 @@ function () use ($cest) { if ($error->failedTest()->getTestMethod() == $cest->getName()) { //log suppressed exception in case of _after hook failure $this->logPreviousException($error->thrownException()); - $stack = $error->thrownException()->getTrace(); - $context = $this->extractContext($stack, $cest->getTestMethod()); - // Do not attempt to run _after if failure was in the _after block - // Try to run _after but catch exceptions to prevent them from overwriting original failure. - if ($context != TestContextExtension::TEST_PHASE_AFTER) { - $this->runAfterBlock($e, $cest); - } continue; } } @@ -113,31 +98,6 @@ function () use ($cest) { $this->getDriver()->_runAfter($e->getTest()); } - /** - * Runs cest's after block, if necessary. - * @param \Symfony\Component\EventDispatcher\Event $e - * @param \Codeception\TestInterface $cest - * @return void - */ - private function runAfterBlock($e, $cest) - { - try { - $actorClass = $e->getTest()->getMetadata()->getCurrent('actor'); - $I = new $actorClass($cest->getScenario()); - if (version_compare(\Codeception\Codecept::VERSION, TestContextExtension::CODECEPT_AFTER_VERSION, "<=")) { - call_user_func(\Closure::bind( - function () use ($cest, $I) { - $cest->executeHook($I, 'after'); - }, - null, - $cest - )); - } - } catch (\Exception $e) { - // Do not rethrow Exception - } - } - /** * Extracts hook method from trace, looking specifically for the cest class given. * @param array $trace @@ -170,10 +130,6 @@ public function logPreviousException(\Exception $exception) } }; $firstException = $change->call($exception); - $bind = function () use ($firstException) { - $exception = $firstException; - }; - $bind->call($exception); if ($firstException !== null) { AllureHelper::addAttachmentToCurrentStep($firstException, 'Exception'); } From 78d396f89c8c0f44d4107efd3cdbf7c3d731aa94 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Mon, 18 Nov 2019 20:58:06 -0600 Subject: [PATCH 056/888] MQE-1884: MFTF - failures override other failures Attached stack trace of full stack of exceptions Attachment name now has the test hook method in which the exception occured Removed test fail method --- .../Extension/TestContextExtension.php | 64 +++++++++++-------- 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php index b0f42590f..741e3d3b4 100644 --- a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php +++ b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php @@ -36,7 +36,6 @@ public function _initialize() { $events = [ Events::TEST_START => 'testStart', - Events::TEST_FAIL => 'testFail', Events::STEP_AFTER => 'afterStep', Events::TEST_END => 'testEnd', Events::RESULT_PRINT_AFTER => 'saveFailed' @@ -57,18 +56,7 @@ public function testStart() } /** - * Codeception event listener function, triggered on test failure. - * @param \Codeception\Event\FailEvent $e - * @return void - */ - public function testFail(\Codeception\Event\FailEvent $e) - { - //log suppressed exception in case of _after hook failure - $this->logPreviousException($e->getFail()); - } - - /** - * Codeception event listener function, triggered on test ending (naturally or by error). + * Codeception event listener function, triggered on test ending naturally or by errors/failures. * @param \Codeception\Event\TestEvent $e * @return void * @throws \Exception @@ -77,20 +65,28 @@ public function testEnd(\Codeception\Event\TestEvent $e) { $cest = $e->getTest(); - //Access private TestResultObject to find stack and if there are any errors (as opposed to failures) + //Access private TestResultObject to find stack and if there are any errors/failures $testResultObject = call_user_func(\Closure::bind( function () use ($cest) { return $cest->getTestResultObject(); }, $cest )); - $errors = $testResultObject->errors(); - if (!empty($errors)) { - foreach ($errors as $error) { - if ($error->failedTest()->getTestMethod() == $cest->getName()) { - //log suppressed exception in case of _after hook failure - $this->logPreviousException($error->thrownException()); - continue; + + // check for errors in all test hooks and attach in allure + if (!empty($testResultObject->errors())) { + foreach ($testResultObject->errors() as $error) { + if($error->failedTest()->getTestMethod() == $cest->getTestMethod()) { + $this->attachExceptionToAllure($error->thrownException(), $cest->getTestMethod()); + } + } + } + + // check for failures in all test hooks and attach in allure + if (!empty($testResultObject->failures())) { + foreach ($testResultObject->failures() as $failure) { + if($failure->failedTest()->getTestMethod() == $cest->getTestMethod()) { + $this->attachExceptionToAllure($failure->thrownException(), $cest->getTestMethod()); } } } @@ -116,12 +112,27 @@ public function extractContext($trace, $class) } /** - * Attach suppressed exception thrown before _after hook to the current step. + * Attach stack trace of exceptions thrown in each test hook to allure. * @param \Exception $exception + * @param String $testMethod * @return mixed */ - public function logPreviousException(\Exception $exception) + public function attachExceptionToAllure($exception, $testMethod) { + $exceptionType = null; + $trace = null; + + if (is_subclass_of($exception, \PHPUnit\Framework\Exception::class)) { + $trace = $exception->getSerializableTrace(); + } else { + $trace = $exception->getTrace(); + } + + $context = $this->extractContext($trace, $testMethod); + + AllureHelper::addAttachmentToCurrentStep($exception, $context . 'Exception'); + + //pop suppressed exceptions and attach to allure $change = function () { if ($this instanceof \PHPUnit\Framework\ExceptionWrapper) { return $this->previous; @@ -129,9 +140,10 @@ public function logPreviousException(\Exception $exception) return $this->getPrevious(); } }; - $firstException = $change->call($exception); - if ($firstException !== null) { - AllureHelper::addAttachmentToCurrentStep($firstException, 'Exception'); + $previousException = $change->call($exception); + + if ($previousException !== null) { + $this->attachExceptionToAllure($previousException, $testMethod); } } From 6db9c8d63acc790818ce81b339732358c0d9e464 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Mon, 18 Nov 2019 21:22:31 -0600 Subject: [PATCH 057/888] MQE-1884: MFTF - failures override other failures removed redundant var; code cleanup. --- .../Extension/TestContextExtension.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php index 741e3d3b4..33f49675c 100644 --- a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php +++ b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php @@ -119,9 +119,6 @@ public function extractContext($trace, $class) */ public function attachExceptionToAllure($exception, $testMethod) { - $exceptionType = null; - $trace = null; - if (is_subclass_of($exception, \PHPUnit\Framework\Exception::class)) { $trace = $exception->getSerializableTrace(); } else { @@ -140,6 +137,7 @@ public function attachExceptionToAllure($exception, $testMethod) return $this->getPrevious(); } }; + $previousException = $change->call($exception); if ($previousException !== null) { From d3e6a72ccac07b2a5656313e437b600580a46a8c Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Mon, 18 Nov 2019 22:22:39 -0600 Subject: [PATCH 058/888] MQE-1884: MFTF - failures override other failures fixed static checks --- .../Extension/TestContextExtension.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php index 33f49675c..e8e33a5be 100644 --- a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php +++ b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php @@ -76,7 +76,7 @@ function () use ($cest) { // check for errors in all test hooks and attach in allure if (!empty($testResultObject->errors())) { foreach ($testResultObject->errors() as $error) { - if($error->failedTest()->getTestMethod() == $cest->getTestMethod()) { + if ($error->failedTest()->getTestMethod() == $cest->getTestMethod()) { $this->attachExceptionToAllure($error->thrownException(), $cest->getTestMethod()); } } @@ -85,7 +85,7 @@ function () use ($cest) { // check for failures in all test hooks and attach in allure if (!empty($testResultObject->failures())) { foreach ($testResultObject->failures() as $failure) { - if($failure->failedTest()->getTestMethod() == $cest->getTestMethod()) { + if ($failure->failedTest()->getTestMethod() == $cest->getTestMethod()) { $this->attachExceptionToAllure($failure->thrownException(), $cest->getTestMethod()); } } @@ -114,7 +114,7 @@ public function extractContext($trace, $class) /** * Attach stack trace of exceptions thrown in each test hook to allure. * @param \Exception $exception - * @param String $testMethod + * @param string $testMethod * @return mixed */ public function attachExceptionToAllure($exception, $testMethod) From bea39a96e4822f8259633cd63e830b0febb552b9 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Tue, 19 Nov 2019 09:25:11 -0600 Subject: [PATCH 059/888] MQE-1257: MFTF doctor command --- docs/commands/mftf.md | 6 ++- .../Console/DoctorCommand.php | 34 ++++++++-------- .../Module/MagentoWebDriverDoctor.php | 40 +++++++++++-------- .../FunctionalTestingFramework/_bootstrap.php | 2 +- 4 files changed, 45 insertions(+), 37 deletions(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 5e9895958..a71b8a02c 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -113,7 +113,11 @@ vendor/bin/mftf build:project --MAGENTO_BASE_URL=http://magento.local/ --MAGENTO #### Description -Diagnose MFTF configuration and setup +Diagnose MFTF configuration and setup. Currently this command will check the following: +- Verify admin credentials are valid. Allowing MFTF authenticates and runs API requests to Magento through cURL +- Verify that Selenium is up and running and available for MFTF +- Verify that new session of browser can open Magento admin and store front urls +- Verify that MFTF can run MagentoCLI commands #### Usage diff --git a/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php b/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php index d75004fc2..4bd05b836 100644 --- a/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php @@ -18,23 +18,20 @@ use Magento\FunctionalTestingFramework\Util\ModuleResolver; use Magento\FunctionalTestingFramework\Module\MagentoWebDriver; use Magento\FunctionalTestingFramework\Module\MagentoWebDriverDoctor; +use Symfony\Component\Console\Style\SymfonyStyle; class DoctorCommand extends Command { const CODECEPTION_AUTOLOAD_FILE = PROJECT_ROOT . '/vendor/codeception/codeception/autoload.php'; const MFTF_CODECEPTION_CONFIG_FILE = ENV_FILE_PATH . 'codeception.yml'; const SUITE = 'functional'; - const COLOR_LIGHT_GREEN = "\e[1;32m"; - const COLOR_LIGHT_RED = "\e[1;31m"; - const COLOR_LIGHT_DEFAULT = "\e[1;39m"; - const COLOR_RESTORE = "\e[0m"; /** - * Command Output + * Console output style * - * @var OutputInterface + * @var SymfonyStyle */ - private $output; + private $ioStyle; /** * Exception Context @@ -63,17 +60,17 @@ protected function configure() * @param OutputInterface $output * @return integer * @throws TestFrameworkException - * @SuppressWarnings(PHPMD.UnusedFormalParameter) * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ protected function execute(InputInterface $input, OutputInterface $output) { + // For output style + $this->ioStyle = new SymfonyStyle($input, $output); + $cmdStatus = true; // Config application $verbose = $output->isVerbose(); - $this->input = $input; - $this->output = $output; MftfApplicationConfig::create( false, MftfApplicationConfig::GENERATION_PHASE, @@ -126,14 +123,15 @@ private function checkAuthenticationToMagentoAdmin() { $result = false; try { - $this->output->writeln( - "\n" . self::COLOR_LIGHT_DEFAULT . "Authenticating admin account by API ..." . self::COLOR_RESTORE - ); + $this->ioStyle->text("Requesting API token for admin user through cURL ..."); ModuleResolver::getInstance()->getAdminToken(); - $this->output->writeln(self::COLOR_LIGHT_GREEN . 'Successful' . self::COLOR_RESTORE); + $this->ioStyle->success('Successful'); $result = true; } catch (TestFrameworkException $e) { - $this->output->writeln(self::COLOR_LIGHT_RED . $e->getMessage() . self::COLOR_RESTORE); + $this->ioStyle->error( + $e->getMessage() + . "\nPlease verify MAGENTO_ADMIN_USERNAME and MAGENTO_ADMIN_PASSWORD in .env." + ); } return $result; } @@ -148,14 +146,14 @@ private function checkAuthenticationToMagentoAdmin() */ private function checkContextOnStep($exceptionType, $message) { - $this->output->writeln("\n" . self::COLOR_LIGHT_DEFAULT. $message . self::COLOR_RESTORE); + $this->ioStyle->text($message . ' ...'); $this->runMagentoWebDriverDoctor(); if (isset($this->context[$exceptionType])) { - $this->output->writeln(self::COLOR_LIGHT_RED . $this->context[$exceptionType] . self::COLOR_RESTORE); + $this->ioStyle->error($this->context[$exceptionType]); return false; } else { - $this->output->writeln(self::COLOR_LIGHT_GREEN . 'Successful' . self::COLOR_RESTORE); + $this->ioStyle->success('Successful'); return true; } } diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriverDoctor.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriverDoctor.php index 35fa37f03..082c2d7c6 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriverDoctor.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriverDoctor.php @@ -94,12 +94,16 @@ private function connectToSeleniumServer() $this->httpProxy, $this->httpProxyPort ); + if (null !== $this->remoteWebDriver) { + return; + } } catch (\Exception $e) { - throw new TestFrameworkException( - "Failed to connect Selenium WebDriver at: {$this->wdHost}.\n" - . "Please make sure that Selenium Server is running." - ); } + + throw new TestFrameworkException( + "Failed to connect Selenium WebDriver at: {$this->wdHost}.\n" + . "Please make sure that Selenium Server is running." + ); } /** @@ -112,19 +116,21 @@ private function connectToSeleniumServer() private function loadPageAtUrl($url) { try { - // Open the web page at url first - $this->remoteWebDriver->get($url); - - // Execute Javascript to retrieve HTTP response code - $script = '' - . 'var xhr = new XMLHttpRequest();' - . "xhr.open('GET', '" . $url . "', false);" - . 'xhr.send(null); ' - . 'return xhr.status'; - $status = $this->remoteWebDriver->executeScript($script); - - if ($status === 200) { - return; + if (null !== $this->remoteWebDriver) { + // Open the web page at url first + $this->remoteWebDriver->get($url); + + // Execute Javascript to retrieve HTTP response code + $script = '' + . 'var xhr = new XMLHttpRequest();' + . "xhr.open('GET', '" . $url . "', false);" + . 'xhr.send(null); ' + . 'return xhr.status'; + $status = $this->remoteWebDriver->executeScript($script); + + if ($status === 200) { + return; + } } } catch (\Exception $e) { } diff --git a/src/Magento/FunctionalTestingFramework/_bootstrap.php b/src/Magento/FunctionalTestingFramework/_bootstrap.php index dd7cfd37d..e401123b6 100644 --- a/src/Magento/FunctionalTestingFramework/_bootstrap.php +++ b/src/Magento/FunctionalTestingFramework/_bootstrap.php @@ -16,7 +16,7 @@ } defined('PROJECT_ROOT') || define('PROJECT_ROOT', $projectRootPath); -$envFilePath = realpath($projectRootPath . '/dev/tests/acceptance/'); +$envFilePath = realpath($projectRootPath . '/dev/tests/acceptance/') . DIRECTORY_SEPARATOR; defined('ENV_FILE_PATH') || define('ENV_FILE_PATH', $envFilePath); //Load constants from .env file From de359cb99281e0f0cfd667f2aa9a100a2c078c45 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Tue, 19 Nov 2019 09:43:40 -0600 Subject: [PATCH 060/888] MQE-1257: MFTF doctor command --- .../Module/MagentoWebDriverDoctor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriverDoctor.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriverDoctor.php index 082c2d7c6..98eb8bd4f 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriverDoctor.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriverDoctor.php @@ -137,7 +137,7 @@ private function loadPageAtUrl($url) throw new TestFrameworkException( "Failed to load page at url: $url\n" - . "Please check network connection for the browser running Selenium." + . "Please check Selenium Browser session have access to Magento instance." ); } From 795f09ef40535b5cc51a81d63798a44f6dc3030c Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Tue, 19 Nov 2019 12:11:40 -0600 Subject: [PATCH 061/888] MQE-1884: MFTF - failures override other failures Added mapping to contexts for allure attachments. --- .../Extension/TestContextExtension.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php index e8e33a5be..07153040c 100644 --- a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php +++ b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php @@ -18,7 +18,13 @@ class TestContextExtension extends BaseExtension { const TEST_PHASE_AFTER = "_after"; + const TEST_PHASE_BEFORE = "_before"; + const TEST_FAILED_FILE = 'failed'; + const TEST_HOOKS = [ + self::TEST_PHASE_AFTER => 'AfterHook', + self::TEST_PHASE_BEFORE => 'BeforeHook' + ]; /** * Codeception Events Mapping to methods @@ -127,6 +133,12 @@ public function attachExceptionToAllure($exception, $testMethod) $context = $this->extractContext($trace, $testMethod); + if (isset(self::TEST_HOOKS[$context])) { + $context = self::TEST_HOOKS[$context]; + } else { + $context = 'TestMethod'; + } + AllureHelper::addAttachmentToCurrentStep($exception, $context . 'Exception'); //pop suppressed exceptions and attach to allure From 3373f7d1b0844a8b09397af469e8be90465c557c Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Wed, 20 Nov 2019 13:13:36 -0600 Subject: [PATCH 062/888] MQE-1765: Introduce API Endpoint and Request Headers to Allure artifacts - Added new Allure event to MFTF codebase to prevent buggy allure behavior - Changed calls to AllureHelper to use this new event - Added calls to CurlHandler to add artifacts. - Unit Test fix --- .../Allure/AllureHelperTest.php | 36 +++++- .../Allure/AllureHelper.php | 5 +- .../Allure/Event/AddUniqueAttachmentEvent.php | 107 ++++++++++++++++++ .../DataGenerator/Persist/CurlHandler.php | 2 + 4 files changed, 146 insertions(+), 4 deletions(-) create mode 100644 src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php index 048c6f7de..0bf62c63e 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php @@ -6,6 +6,7 @@ namespace Tests\unit\Magento\FunctionalTestingFramework\Allure; use Magento\FunctionalTestingFramework\Allure\AllureHelper; +use Magento\FunctionalTestingFramework\Allure\Event\AddUniqueAttachmentEvent; use Yandex\Allure\Adapter\Allure; use Yandex\Allure\Adapter\Event\AddAttachmentEvent; use Yandex\Allure\Adapter\Event\StepFinishedEvent; @@ -84,14 +85,45 @@ public function testAddAttachmentToLastStep() $this->assertEmpty($thirdStep->getAttachments()); } + public function testAddAttachementUniqueName() + { + $this->mockCopyFile(); + $expectedData = "string"; + $expectedCaption = "caption"; + + //Prepare Allure lifecycle + Allure::lifecycle()->fire(new StepStartedEvent('firstStep')); + + //Call function twice + AllureHelper::addAttachmentToCurrentStep($expectedData, $expectedCaption); + AllureHelper::addAttachmentToCurrentStep($expectedData, $expectedCaption); + + // Assert file names for both attachments are not the same. + $step = Allure::lifecycle()->getStepStorage()->pollLast(); + $attachmentOne = $step->getAttachments()[0]->getSource(); + $attachmentTwo = $step->getAttachments()[1]->getSource(); + $this->assertNotEquals($attachmentOne, $attachmentTwo); + } + /** - * Mock file system manipulation function + * Mock entire attachment writing mechanisms * @throws \Exception */ public function mockAttachmentWriteEvent() { - AspectMock::double(AddAttachmentEvent::class, [ + AspectMock::double(AddUniqueAttachmentEvent::class, [ "getAttachmentFileName" => self::MOCK_FILENAME ]); } + + /** + * Mock only file writing mechanism + * @throws \Exception + */ + public function mockCopyFile() + { + AspectMock::double(AddUniqueAttachmentEvent::class, [ + "copyFile" => true + ]); + } } diff --git a/src/Magento/FunctionalTestingFramework/Allure/AllureHelper.php b/src/Magento/FunctionalTestingFramework/Allure/AllureHelper.php index d8f1c63d8..e1d871781 100644 --- a/src/Magento/FunctionalTestingFramework/Allure/AllureHelper.php +++ b/src/Magento/FunctionalTestingFramework/Allure/AllureHelper.php @@ -5,6 +5,7 @@ */ namespace Magento\FunctionalTestingFramework\Allure; +use Magento\FunctionalTestingFramework\Allure\Event\AddUniqueAttachmentEvent; use Yandex\Allure\Adapter\Allure; use Yandex\Allure\Adapter\Event\AddAttachmentEvent; @@ -19,7 +20,7 @@ class AllureHelper */ public static function addAttachmentToCurrentStep($data, $caption) { - Allure::lifecycle()->fire(new AddAttachmentEvent($data, $caption)); + Allure::lifecycle()->fire(new AddUniqueAttachmentEvent($data, $caption)); } /** @@ -34,7 +35,7 @@ public static function addAttachmentToLastStep($data, $caption) $rootStep = Allure::lifecycle()->getStepStorage()->getLast(); $trueLastStep = array_last($rootStep->getSteps()); - $attachmentEvent = new AddAttachmentEvent($data, $caption); + $attachmentEvent = new AddUniqueAttachmentEvent($data, $caption); $attachmentEvent->process($trueLastStep); } } diff --git a/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php b/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php new file mode 100644 index 000000000..b6ff032a9 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php @@ -0,0 +1,107 @@ +guessFileMimeType($filePath); + $this->type = $type; + } + + $fileExtension = $this->guessFileExtension($type); + + $fileSha1 = uniqid(sha1_file($filePath)); + $outputPath = parent::getOutputPath($fileSha1, $fileExtension); + if (!$this->copyFile($filePath, $outputPath)) { + throw new AllureException("Failed to copy attachment from $filePath to $outputPath."); + } + + return $this->getOutputFileName($fileSha1, $fileExtension); + } + + /** + * Copies file from one path to another. Wrapper for mocking in unit test. + * @param string $filePath + * @param string $outputPath + * @return bool + */ + private function copyFile($filePath, $outputPath) + { + return copy($filePath, $outputPath); + } + + /** + * Copy of parent private function + * @param string $filePath + * @return string + */ + private function guessFileMimeType($filePath) + { + $type = MimeTypeGuesser::getInstance()->guess($filePath); + if (!isset($type)) { + return DEFAULT_MIME_TYPE; + } + return $type; + } + + /** + * Copy of parent private function + * @param string $mimeType + * @return string + */ + private function guessFileExtension($mimeType) + { + $candidate = ExtensionGuesser::getInstance()->guess($mimeType); + if (!isset($candidate)) { + return DEFAULT_FILE_EXTENSION; + } + return $candidate; + } + + /** + * Copy of parent private function + * @param string $sha1 + * @param string $extension + * @return string + */ + public function getOutputFileName($sha1, $extension) + { + return $sha1 . '-attachment.' . $extension; + } +} diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php index 691ce3606..16584e7a3 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php @@ -123,6 +123,8 @@ public function executeRequest($dependentEntities) $returnRegex = $this->operationDefinition->getReturnRegex(); $returnIndex = $this->operationDefinition->getReturnIndex(); $method = $this->operationDefinition->getApiMethod(); + AllureHelper::addAttachmentToLastStep($apiUrl, 'API Endpoint'); + AllureHelper::addAttachmentToLastStep(json_encode($headers, JSON_PRETTY_PRINT), 'Request Headers'); $operationDataResolver = new OperationDataArrayResolver($dependentEntities); $this->requestData = $operationDataResolver->resolveOperationDataArray( From 001e5e29ab08f10d3bad4dee82ee3ec9e748b619 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Wed, 20 Nov 2019 11:59:23 -0600 Subject: [PATCH 063/888] MQE-1470: add interface to handle file path and url format --- .../Util/Path/FilePathFormatterTest.php | 82 ++++++++++++++ .../Util/Path/UrlFormatterTest.php | 84 ++++++++++++++ .../Util/ConfigSanitizerUtil.php | 71 +----------- .../Util/ModuleResolver.php | 7 +- .../Util/Path/FilePathFormatter.php | 31 ++++++ .../Util/Path/FileUrlFormatterInterface.php | 22 ++++ .../Util/Path/UrlFormatter.php | 103 ++++++++++++++++++ 7 files changed, 329 insertions(+), 71 deletions(-) create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/FilePathFormatterTest.php create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/UrlFormatterTest.php create mode 100644 src/Magento/FunctionalTestingFramework/Util/Path/FilePathFormatter.php create mode 100644 src/Magento/FunctionalTestingFramework/Util/Path/FileUrlFormatterInterface.php create mode 100644 src/Magento/FunctionalTestingFramework/Util/Path/UrlFormatter.php diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/FilePathFormatterTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/FilePathFormatterTest.php new file mode 100644 index 000000000..c583fd74c --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/FilePathFormatterTest.php @@ -0,0 +1,82 @@ +assertEquals($expectedPath, FilePathFormatter::format($path, $withTrailingSeparator)); + } else { + // Assert no exception + FilePathFormatter::format($path, $withTrailingSeparator); + $this->assertTrue(true); + } + } + + /** + * Test file format with exception + * + * @dataProvider formatExceptionDataProvider + * @param string $path + * @param boolean $withTrailingSeparator + * @return void + */ + public function testFormatWithException($path, $withTrailingSeparator) + { + $this->expectException(TestFrameworkException::class); + $this->expectExceptionMessage("Invalid or non-existing file: $path\n"); + FilePathFormatter::format($path, $withTrailingSeparator); + } + + /** + * Data input + * + * @return array + */ + public function formatDataProvider() + { + $path1 = rtrim(TESTS_BP, '/'); + $path2 = $path1 . DIRECTORY_SEPARATOR; + return [ + [$path1, null, $path1], + [$path1, false, $path1], + [$path1, true, $path2], + [$path2, null, $path1], + [$path2, false, $path1], + [$path2, true, $path2], + [__DIR__. DIRECTORY_SEPARATOR . basename(__FILE__), null, __FILE__], + ['', null, null] // Empty string is valid + ]; + } + + /** + * Invalid data input + * + * @return array + */ + public function formatExceptionDataProvider() + { + return [ + ['abc', null], + ['X://some\dir/@', null], + ]; + } +} diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/UrlFormatterTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/UrlFormatterTest.php new file mode 100644 index 000000000..86d1f0fad --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/UrlFormatterTest.php @@ -0,0 +1,84 @@ +assertEquals($expectedPath, UrlFormatter::format($path, $withTrailingSeparator)); + } + + /** + * Test url format with exception + * + * @dataProvider formatExceptionDataProvider + * @param string $path + * @param boolean $withTrailingSeparator + * @return void + */ + public function testFormatWithException($path, $withTrailingSeparator) + { + $this->expectException(TestFrameworkException::class); + $this->expectExceptionMessage("Invalid url: $path\n"); + UrlFormatter::format($path, $withTrailingSeparator); + } + + /** + * Data input + * + * @return array + */ + public function formatDataProvider() + { + $url1 = 'http://magento.local/index.php'; + $url2 = $url1 . '/'; + $url3 = 'https://www.example.com/index.php/admin'; + $url4 = $url3 . '/'; + $url5 = 'www.google.com'; + $url6 = 'http://www.google.com/'; + return [ + [$url1, null, $url1], + [$url1, false, $url1], + [$url1, true, $url2], + [$url2, null, $url1], + [$url2, false, $url1], + [$url2, true, $url2], + [$url3, null, $url3], + [$url3, false, $url3], + [$url3, true, $url4], + [$url4, null, $url3], + [$url4, false, $url3], + [$url4, true, $url4], + [$url5, true, $url6], + ]; + } + + /** + * Invalid data input + * + * @return array + */ + public function formatExceptionDataProvider() + { + return [ + ['', null], + ]; + } +} diff --git a/src/Magento/FunctionalTestingFramework/Util/ConfigSanitizerUtil.php b/src/Magento/FunctionalTestingFramework/Util/ConfigSanitizerUtil.php index ce5740493..3b92b48e4 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ConfigSanitizerUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/ConfigSanitizerUtil.php @@ -7,6 +7,8 @@ namespace Magento\FunctionalTestingFramework\Util; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; /** * Class ConfigSanitizerUtil @@ -24,7 +26,7 @@ public static function sanitizeWebDriverConfig($config, $params = ['url', 'selen self::validateConfigBasedVars($config); if (in_array('url', $params)) { - $config['url'] = self::sanitizeUrl($config['url']); + $config['url'] = UrlFormatter::format($config['url']); } if (in_array('selenium', $params)) { @@ -80,71 +82,4 @@ private static function validateConfigBasedVars($config) } } } - - /** - * Sanitizes and returns given URL. - * @param string $url - * @return string - */ - public static function sanitizeUrl($url) - { - if (strlen($url) == 0 && !MftfApplicationConfig::getConfig()->forceGenerateEnabled()) { - trigger_error("MAGENTO_BASE_URL must be defined in .env", E_USER_ERROR); - } - - if (filter_var($url, FILTER_VALIDATE_URL) === true) { - return rtrim($url, "/") . "/"; - } - - $urlParts = parse_url($url); - - if (!isset($urlParts['scheme'])) { - $urlParts['scheme'] = "http"; - } - if (!isset($urlParts['host'])) { - $urlParts['host'] = rtrim($urlParts['path'], "/"); - $urlParts['host'] = str_replace("//", "/", $urlParts['host']); - unset($urlParts['path']); - } - - if (!isset($urlParts['path'])) { - $urlParts['path'] = "/"; - } else { - $urlParts['path'] = rtrim($urlParts['path'], "/") . "/"; - } - - return str_replace("///", "//", self::buildUrl($urlParts)); - } - - /** - * 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 static function buildUrl(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" : ''); - } } diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index d776603d1..f5516b0db 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -9,6 +9,7 @@ use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; +use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; use Symfony\Component\HttpFoundation\Response; /** @@ -201,7 +202,7 @@ public function getEnabledModules() $token = $this->getAdminToken(); - $url = ConfigSanitizerUtil::sanitizeUrl(getenv('MAGENTO_BASE_URL')) . $this->moduleUrl; + $url = UrlFormatter::format(getenv('MAGENTO_BASE_URL')) . $this->moduleUrl; $headers = [ 'Authorization: Bearer ' . $token, @@ -677,7 +678,7 @@ private function printMagentoVersionInfo() if (MftfApplicationConfig::getConfig()->forceGenerateEnabled()) { return; } - $url = ConfigSanitizerUtil::sanitizeUrl(getenv('MAGENTO_BASE_URL')) . $this->versionUrl; + $url = UrlFormatter::format(getenv('MAGENTO_BASE_URL')) . $this->versionUrl; LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->info( "Fetching version information.", ['url' => $url] @@ -718,7 +719,7 @@ protected function getAdminToken() throw new TestFrameworkException($message, $context); } - $url = ConfigSanitizerUtil::sanitizeUrl($this->getBackendUrl()) . $this->adminTokenUrl; + $url = UrlFormatter::format($this->getBackendUrl()) . $this->adminTokenUrl; $data = [ 'username' => $login, 'password' => $password diff --git a/src/Magento/FunctionalTestingFramework/Util/Path/FilePathFormatter.php b/src/Magento/FunctionalTestingFramework/Util/Path/FilePathFormatter.php new file mode 100644 index 000000000..1337f1e3c --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/Path/FilePathFormatter.php @@ -0,0 +1,31 @@ + Date: Wed, 20 Nov 2019 13:20:26 -0600 Subject: [PATCH 064/888] MQE-1765: Introduce API Endpoint and Request Headers to Allure artifacts - static check fix --- .../Allure/Event/AddUniqueAttachmentEvent.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php b/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php index b6ff032a9..fc4ff64c2 100644 --- a/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php +++ b/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php @@ -59,7 +59,7 @@ public function getAttachmentFileName($filePathOrContents, $type) * Copies file from one path to another. Wrapper for mocking in unit test. * @param string $filePath * @param string $outputPath - * @return bool + * @return boolean */ private function copyFile($filePath, $outputPath) { From 44bd4bd2d995b52da8af69b6fffaa15ffb7c4b78 Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Wed, 20 Nov 2019 14:08:00 -0600 Subject: [PATCH 065/888] MQE-1765: Introduce API Endpoint and Request Headers to Allure artifact - PHPUnit test fix --- .../FunctionalTestFramework/Allure/AllureHelperTest.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php index 0bf62c63e..b7eafaead 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php @@ -25,6 +25,7 @@ class AllureHelperTest extends TestCase public function tearDown() { Allure::setDefaultLifecycle(); + AspectMock::clean(); } /** @@ -85,6 +86,10 @@ public function testAddAttachmentToLastStep() $this->assertEmpty($thirdStep->getAttachments()); } + /** + * AddAttachment actions should have files with different attachment names + * @throws \Yandex\Allure\Adapter\AllureException + */ public function testAddAttachementUniqueName() { $this->mockCopyFile(); From f039692292ce643ae9382575c8757912f0596e1b Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Thu, 21 Nov 2019 09:09:25 -0600 Subject: [PATCH 066/888] MQE-1774: Review community PR #343 Fix for pipeline step failures on execution of bin/magento from WebDriver. --- .../Module/MagentoWebDriver.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 215438420..f057cf171 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -517,11 +517,13 @@ public function scrollToTopOfPage() */ public function magentoCLI($command, $arguments = null) { - try { - return $this->shellExecMagentoCLI($command, $arguments); - } catch (\Exception $exception) { - return $this->curlExecMagentoCLI($command, $arguments); - } + return $this->curlExecMagentoCLI($command, $arguments); + //TODO: calling bin/magento from pipeline is timing out, needs investigation (ref: MQE-1774) +// try { +// return $this->shellExecMagentoCLI($command, $arguments); +// } catch (\Exception $exception) { +// return $this->curlExecMagentoCLI($command, $arguments); +// } } /** From de5bed6e36162c2dd8bcaf04c6a5d35b690c10c4 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Thu, 21 Nov 2019 09:20:52 -0600 Subject: [PATCH 067/888] MQE-1774: Review community PR #343 Fixed static checks --- .../FunctionalTestingFramework/Module/MagentoWebDriver.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index f057cf171..c1ab892d7 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -839,6 +839,7 @@ public function makeScreenshot($name = null) * * @throws \RuntimeException * @return string + * @SuppressWarnings(PHPMD.UnusedPrivateMethod) */ private function shellExecMagentoCLI($command, $arguments): string { From be71f945893f63e65cd1606d241b87631bbabd21 Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Thu, 21 Nov 2019 10:40:45 -0600 Subject: [PATCH 068/888] MQE-1520: Consolidate WAIT_TIMEOUT in .env and pageload_timeout in config - changed functional.suite.dist to use wait timeout - added default setters in bootstrap files (will always be defined) - removed default in actionObject --- dev/tests/functional/standalone_bootstrap.php | 5 ++++- etc/config/functional.suite.dist.yml | 2 +- .../FunctionalTestingFramework/Test/Objects/ActionObject.php | 3 +-- src/Magento/FunctionalTestingFramework/_bootstrap.php | 3 +++ 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/dev/tests/functional/standalone_bootstrap.php b/dev/tests/functional/standalone_bootstrap.php index de6ef394d..ab6372697 100755 --- a/dev/tests/functional/standalone_bootstrap.php +++ b/dev/tests/functional/standalone_bootstrap.php @@ -49,7 +49,10 @@ defined('DEFAULT_TIMEZONE') || define('DEFAULT_TIMEZONE', 'America/Los_Angeles'); $env->setEnvironmentVariable('DEFAULT_TIMEZONE', DEFAULT_TIMEZONE); - + + defined('WAIT_TIMEOUT') || define('WAIT_TIMEOUT', 10); + $env->setEnvironmentVariable('WAIT_TIMEOUT', 10); + try { new DateTimeZone(DEFAULT_TIMEZONE); } catch (\Exception $e) { diff --git a/etc/config/functional.suite.dist.yml b/etc/config/functional.suite.dist.yml index 12658515b..5487a3c99 100644 --- a/etc/config/functional.suite.dist.yml +++ b/etc/config/functional.suite.dist.yml @@ -27,7 +27,7 @@ modules: window_size: 1280x1024 username: "%MAGENTO_ADMIN_USERNAME%" password: "%MAGENTO_ADMIN_PASSWORD%" - pageload_timeout: 30 + pageload_timeout: "%WAIT_TIMEOUT%" host: "%SELENIUM_HOST%" port: "%SELENIUM_PORT%" protocol: "%SELENIUM_PROTOCOL%" diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php index 9b1cdf1af..8f60e1e90 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php @@ -71,7 +71,6 @@ class ActionObject const ACTION_ATTRIBUTE_VARIABLE_REGEX_PARAMETER = '/\(.+\)/'; const ACTION_ATTRIBUTE_VARIABLE_REGEX_PATTERN = '/({{[\w]+\.[\w\[\]]+}})|({{[\w]+\.[\w]+\((?(?!}}).)+\)}})/'; const STRING_PARAMETER_REGEX = "/'[^']+'/"; - const DEFAULT_WAIT_TIMEOUT = 10; const ACTION_ATTRIBUTE_USERINPUT = 'userInput'; const ACTION_TYPE_COMMENT = 'comment'; @@ -167,7 +166,7 @@ public function __construct( */ public static function getDefaultWaitTimeout() { - return getenv('WAIT_TIMEOUT') ?: self::DEFAULT_WAIT_TIMEOUT; + return getenv('WAIT_TIMEOUT'); } /** diff --git a/src/Magento/FunctionalTestingFramework/_bootstrap.php b/src/Magento/FunctionalTestingFramework/_bootstrap.php index e401123b6..490ff61de 100644 --- a/src/Magento/FunctionalTestingFramework/_bootstrap.php +++ b/src/Magento/FunctionalTestingFramework/_bootstrap.php @@ -50,6 +50,9 @@ defined('DEFAULT_TIMEZONE') || define('DEFAULT_TIMEZONE', 'America/Los_Angeles'); $env->setEnvironmentVariable('DEFAULT_TIMEZONE', DEFAULT_TIMEZONE); + defined('WAIT_TIMEOUT') || define('WAIT_TIMEOUT', 10); + $env->setEnvironmentVariable('WAIT_TIMEOUT', 10); + try { new DateTimeZone(DEFAULT_TIMEZONE); } catch (\Exception $e) { From cb5c63237ef851c2fc1b44c02402841ac6530ab2 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Thu, 21 Nov 2019 10:56:44 -0600 Subject: [PATCH 069/888] MQE-1470: add interface to handle file path and url format --- .../Util/Path/FilePathFormatterTest.php | 2 + .../Util/Path/UrlFormatterTest.php | 7 +++ .../Tests/SuiteGenerationTest.php | 6 +- .../Config/FileResolver/Primary.php | 8 ++- .../Config/FileResolver/Root.php | 5 +- .../Config/SchemaLocator.php | 11 +++- .../Console/BaseGenerateCommand.php | 5 +- .../Console/BuildProjectCommand.php | 40 +++++++------ .../Console/CleanProjectCommand.php | 41 +++++++------ .../Console/GenerateDevUrnCommand.php | 23 +++++--- .../Console/RunManifestCommand.php | 26 +++++++-- .../Console/RunTestCommand.php | 4 +- .../Console/RunTestFailedCommand.php | 57 ++++++++++++------- .../Console/SetupEnvCommand.php | 5 +- .../Handlers/CredentialStore.php | 3 +- .../Handlers/SecretStorage/FileStorage.php | 4 +- .../Persist/Curl/AbstractExecutor.php | 5 +- .../Persist/Curl/AdminExecutor.php | 14 ++++- .../Persist/Curl/WebapiExecutor.php | 28 ++++++--- .../Module/MagentoWebDriver.php | 7 ++- .../Suite/SuiteGenerator.php | 12 +++- .../Suite/Util/SuiteObjectExtractor.php | 7 +-- .../Util/Env/EnvProcessor.php | 6 +- .../Util/Logger/LoggingUtil.php | 5 +- .../Util/Manifest/TestManifestFactory.php | 6 +- .../Util/ModuleResolver.php | 22 +++++-- .../Util/Path/FilePathFormatter.php | 4 +- ...erInterface.php => FormatterInterface.php} | 4 +- .../Util/Path/UrlFormatter.php | 6 +- .../Util/TestGenerator.php | 6 +- .../FunctionalTestingFramework/_bootstrap.php | 2 +- 31 files changed, 260 insertions(+), 121 deletions(-) rename src/Magento/FunctionalTestingFramework/Util/Path/{FileUrlFormatterInterface.php => FormatterInterface.php} (92%) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/FilePathFormatterTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/FilePathFormatterTest.php index c583fd74c..bac14113d 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/FilePathFormatterTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/FilePathFormatterTest.php @@ -19,6 +19,7 @@ class FilePathFormatterTest extends MagentoTestCase * @param boolean $withTrailingSeparator * @param mixed string|boolean $expectedPath * @return void + * @throws TestFrameworkException */ public function testFormat($path, $withTrailingSeparator, $expectedPath) { @@ -38,6 +39,7 @@ public function testFormat($path, $withTrailingSeparator, $expectedPath) * @param string $path * @param boolean $withTrailingSeparator * @return void + * @throws TestFrameworkException */ public function testFormatWithException($path, $withTrailingSeparator) { diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/UrlFormatterTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/UrlFormatterTest.php index 86d1f0fad..c66c9558c 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/UrlFormatterTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/UrlFormatterTest.php @@ -19,6 +19,7 @@ class UrlFormatterTest extends MagentoTestCase * @param boolean $withTrailingSeparator * @param mixed string|boolean $expectedPath * @return void + * @throws TestFrameworkException */ public function testFormat($path, $withTrailingSeparator, $expectedPath) { @@ -32,6 +33,7 @@ public function testFormat($path, $withTrailingSeparator, $expectedPath) * @param string $path * @param boolean $withTrailingSeparator * @return void + * @throws TestFrameworkException */ public function testFormatWithException($path, $withTrailingSeparator) { @@ -53,6 +55,9 @@ public function formatDataProvider() $url4 = $url3 . '/'; $url5 = 'www.google.com'; $url6 = 'http://www.google.com/'; + $url7 = 'http://127.0.0.1:8200'; + $url8 = 'wwøw.goåoøgle.coøm'; + $url9 = 'http://www.google.com'; return [ [$url1, null, $url1], [$url1, false, $url1], @@ -67,6 +72,8 @@ public function formatDataProvider() [$url4, false, $url3], [$url4, true, $url4], [$url5, true, $url6], + [$url7, false, $url7], + [$url8, false, $url9], ]; } diff --git a/dev/tests/verification/Tests/SuiteGenerationTest.php b/dev/tests/verification/Tests/SuiteGenerationTest.php index d2242fb52..485ef6411 100644 --- a/dev/tests/verification/Tests/SuiteGenerationTest.php +++ b/dev/tests/verification/Tests/SuiteGenerationTest.php @@ -6,11 +6,13 @@ namespace tests\verification\Tests; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Suite\SuiteGenerator; use Magento\FunctionalTestingFramework\Util\Filesystem\DirSetupUtil; use Magento\FunctionalTestingFramework\Util\Manifest\DefaultTestManifest; use Magento\FunctionalTestingFramework\Util\Manifest\ParallelTestManifest; use Magento\FunctionalTestingFramework\Util\Manifest\TestManifestFactory; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use PHPUnit\Util\Filesystem; use Symfony\Component\Yaml\Yaml; use tests\unit\Util\TestLoggingUtil; @@ -413,11 +415,11 @@ public static function tearDownAfterClass() * Getter for manifest file path * * @return string + * @throws TestFrameworkException */ private static function getManifestFilePath() { - return TESTS_BP . - DIRECTORY_SEPARATOR . + return FilePathFormatter::format(TESTS_BP) . "verification" . DIRECTORY_SEPARATOR . "_generated" . diff --git a/src/Magento/FunctionalTestingFramework/Config/FileResolver/Primary.php b/src/Magento/FunctionalTestingFramework/Config/FileResolver/Primary.php index 2376b3cf1..3a976944b 100644 --- a/src/Magento/FunctionalTestingFramework/Config/FileResolver/Primary.php +++ b/src/Magento/FunctionalTestingFramework/Config/FileResolver/Primary.php @@ -6,8 +6,10 @@ namespace Magento\FunctionalTestingFramework\Config\FileResolver; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Util\Iterator\File; use Magento\FunctionalTestingFramework\Config\FileResolverInterface; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; /** * Provides the list of global configuration files. @@ -54,6 +56,7 @@ private function getFilePaths($filename, $scope) * @param string $filename * @param string $scope * @return array + * @throws TestFrameworkException */ private function getPathPatterns($filename, $scope) { @@ -69,8 +72,9 @@ private function getPathPatterns($filename, $scope) $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 + FilePathFormatter::format(FW_BP) . $scope . DIRECTORY_SEPARATOR . $filename, + FilePathFormatter::format(FW_BP) . $scope . DIRECTORY_SEPARATOR . '*' . DIRECTORY_SEPARATOR + . $filename ]; } return str_replace(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR, $patterns); diff --git a/src/Magento/FunctionalTestingFramework/Config/FileResolver/Root.php b/src/Magento/FunctionalTestingFramework/Config/FileResolver/Root.php index 3b0940b28..4ebb11942 100644 --- a/src/Magento/FunctionalTestingFramework/Config/FileResolver/Root.php +++ b/src/Magento/FunctionalTestingFramework/Config/FileResolver/Root.php @@ -7,7 +7,9 @@ namespace Magento\FunctionalTestingFramework\Config\FileResolver; use Magento\FunctionalTestingFramework\Config\FileResolverInterface; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Util\Iterator\File; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; class Root extends Module { @@ -20,12 +22,13 @@ class Root extends Module * @param string $filename * @param string $scope * @return array|\Iterator,\Countable + * @throws TestFrameworkException */ public function get($filename, $scope) { // first pick up the root level test suite dir $paths = glob( - TESTS_BP . DIRECTORY_SEPARATOR . self::ROOT_SUITE_DIR + FilePathFormatter::format(TESTS_BP) . self::ROOT_SUITE_DIR . DIRECTORY_SEPARATOR . $filename ); diff --git a/src/Magento/FunctionalTestingFramework/Config/SchemaLocator.php b/src/Magento/FunctionalTestingFramework/Config/SchemaLocator.php index a92f536a3..869c58373 100644 --- a/src/Magento/FunctionalTestingFramework/Config/SchemaLocator.php +++ b/src/Magento/FunctionalTestingFramework/Config/SchemaLocator.php @@ -6,6 +6,9 @@ namespace Magento\FunctionalTestingFramework\Config; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; + /** * Configuration schema locator. */ @@ -30,12 +33,14 @@ class SchemaLocator implements \Magento\FunctionalTestingFramework\Config\Schema * * @param string $schemaPath * @param string|null $perFileSchema + * @throws TestFrameworkException */ public function __construct($schemaPath, $perFileSchema = null) { - if (constant('FW_BP') && file_exists(FW_BP . DIRECTORY_SEPARATOR . $schemaPath)) { - $this->schemaPath = FW_BP . DIRECTORY_SEPARATOR . $schemaPath; - $this->perFileSchema = $perFileSchema === null ? null : FW_BP . DIRECTORY_SEPARATOR . $perFileSchema; + if (constant('FW_BP') && file_exists(FilePathFormatter::format(FW_BP) . $schemaPath)) { + $this->schemaPath = FilePathFormatter::format(FW_BP) . $schemaPath; + $this->perFileSchema = $perFileSchema === null ? null : FilePathFormatter::format(FW_BP) + . $perFileSchema; } else { $path = dirname(dirname(dirname(__DIR__))); $path = str_replace('\\', DIRECTORY_SEPARATOR, $path); diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index 5afaf17c5..0953e9d68 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -8,7 +8,9 @@ namespace Magento\FunctionalTestingFramework\Console; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; @@ -57,10 +59,11 @@ protected function configure() * @param OutputInterface $output * @param bool $verbose * @return void + * @throws TestFrameworkException */ protected function removeGeneratedDirectory(OutputInterface $output, bool $verbose) { - $generatedDirectory = TESTS_MODULE_PATH . DIRECTORY_SEPARATOR . TestGenerator::GENERATED_DIR; + $generatedDirectory = FilePathFormatter::format(TESTS_MODULE_PATH) . TestGenerator::GENERATED_DIR; if (file_exists($generatedDirectory)) { DirSetupUtil::rmdirRecursive($generatedDirectory); diff --git a/src/Magento/FunctionalTestingFramework/Console/BuildProjectCommand.php b/src/Magento/FunctionalTestingFramework/Console/BuildProjectCommand.php index 5102a3fdf..02dfcda82 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BuildProjectCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BuildProjectCommand.php @@ -18,6 +18,7 @@ use Symfony\Component\Process\Process; use Magento\FunctionalTestingFramework\Util\Env\EnvProcessor; use Symfony\Component\Yaml\Yaml; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; /** * Class BuildProjectCommand @@ -28,7 +29,6 @@ class BuildProjectCommand extends Command { const DEFAULT_YAML_INLINE_DEPTH = 10; - const CREDENTIALS_FILE_PATH = TESTS_BP . DIRECTORY_SEPARATOR . '.credentials.example'; /** * Env processor manages .env files. @@ -41,6 +41,7 @@ class BuildProjectCommand extends Command * Configures the current command. * * @return void + * @throws TestFrameworkException */ protected function configure() { @@ -52,7 +53,7 @@ protected function configure() InputOption::VALUE_NONE, 'upgrade existing MFTF tests according to last major release requirements' ); - $this->envProcessor = new EnvProcessor(TESTS_BP . DIRECTORY_SEPARATOR . '.env'); + $this->envProcessor = new EnvProcessor(FilePathFormatter::format(TESTS_BP) . '.env'); $env = $this->envProcessor->getEnv(); foreach ($env as $key => $value) { $this->addOption($key, null, InputOption::VALUE_REQUIRED, '', $value); @@ -65,8 +66,7 @@ protected function configure() * @param InputInterface $input * @param OutputInterface $output * @return void - * @throws \Symfony\Component\Console\Exception\LogicException - * + * @throws \Exception * @SuppressWarnings(PHPMD.UnusedLocalVariable) */ protected function execute(InputInterface $input, OutputInterface $output) @@ -109,7 +109,7 @@ function ($type, $buffer) use ($output) { if ($input->getOption('upgrade')) { $upgradeCommand = new UpgradeTestsCommand(); - $upgradeOptions = new ArrayInput(['path' => TESTS_MODULE_PATH]); + $upgradeOptions = new ArrayInput(['path' => FilePathFormatter::format(TESTS_MODULE_PATH)]); $upgradeCommand->run($upgradeOptions, $output); } } @@ -119,6 +119,7 @@ function ($type, $buffer) use ($output) { * * @param OutputInterface $output * @return void + * @throws TestFrameworkException */ private function generateConfigFiles(OutputInterface $output) { @@ -126,45 +127,48 @@ private function generateConfigFiles(OutputInterface $output) //Find travel path from codeception.yml to FW_BP $relativePath = $fileSystem->makePathRelative(FW_BP, TESTS_BP); - if (!$fileSystem->exists(TESTS_BP . DIRECTORY_SEPARATOR . 'codeception.yml')) { + if (!$fileSystem->exists(FilePathFormatter::format(TESTS_BP) . 'codeception.yml')) { // read in the codeception.yml file - $configDistYml = Yaml::parse(file_get_contents(realpath(FW_BP . "/etc/config/codeception.dist.yml"))); + $configDistYml = Yaml::parse(file_get_contents( + realpath(FilePathFormatter::format(FW_BP) . "etc/config/codeception.dist.yml") + )); $configDistYml['paths']['support'] = $relativePath . 'src/Magento/FunctionalTestingFramework'; $configDistYml['paths']['envs'] = $relativePath . 'etc/_envs'; $configYmlText = Yaml::dump($configDistYml, self::DEFAULT_YAML_INLINE_DEPTH); // dump output to new codeception.yml file - file_put_contents(TESTS_BP . DIRECTORY_SEPARATOR . 'codeception.yml', $configYmlText); + file_put_contents(FilePathFormatter::format(TESTS_BP) . 'codeception.yml', $configYmlText); $output->writeln("codeception.yml configuration successfully applied."); } - $output->writeln("codeception.yml applied to " . TESTS_BP . DIRECTORY_SEPARATOR . 'codeception.yml'); + $output->writeln("codeception.yml applied to " . FilePathFormatter::format(TESTS_BP) . 'codeception.yml'); // copy the functional suite yml, will only copy if there are differences between the template the destination $fileSystem->copy( - realpath(FW_BP . '/etc/config/functional.suite.dist.yml'), - TESTS_BP . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'functional.suite.yml' + realpath(FilePathFormatter::format(FW_BP) . 'etc/config/functional.suite.dist.yml'), + FilePathFormatter::format(TESTS_BP) . 'tests' . DIRECTORY_SEPARATOR . 'functional.suite.yml' ); $output->writeln('functional.suite.yml configuration successfully applied.'); $output->writeln("functional.suite.yml applied to " . - TESTS_BP . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'functional.suite.yml'); + FilePathFormatter::format(TESTS_BP) . 'tests' . DIRECTORY_SEPARATOR . 'functional.suite.yml'); $fileSystem->copy( - FW_BP . '/etc/config/.credentials.example', - self::CREDENTIALS_FILE_PATH + FilePathFormatter::format(FW_BP) . 'etc/config/.credentials.example', + FilePathFormatter::format(TESTS_BP) . '.credentials.example' ); // copy command.php into magento instance - if (MAGENTO_BP === FW_BP) { + if (FilePathFormatter::format(MAGENTO_BP, false) + === FilePathFormatter::format(FW_BP, false)) { $output->writeln('MFTF standalone detected, command.php copy not applied.'); } else { $fileSystem->copy( - realpath(FW_BP . '/etc/config/command.php'), - TESTS_BP . DIRECTORY_SEPARATOR . "utils" . DIRECTORY_SEPARATOR .'command.php' + realpath(FilePathFormatter::format(FW_BP) . 'etc/config/command.php'), + FilePathFormatter::format(TESTS_BP) . "utils" . DIRECTORY_SEPARATOR .'command.php' ); $output->writeln('command.php copied to ' . - TESTS_BP . DIRECTORY_SEPARATOR . "utils" . DIRECTORY_SEPARATOR .'command.php'); + FilePathFormatter::format(TESTS_BP) . "utils" . DIRECTORY_SEPARATOR .'command.php'); } // Remove and Create Log File diff --git a/src/Magento/FunctionalTestingFramework/Console/CleanProjectCommand.php b/src/Magento/FunctionalTestingFramework/Console/CleanProjectCommand.php index b2b2c01f3..641cfe1ed 100644 --- a/src/Magento/FunctionalTestingFramework/Console/CleanProjectCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/CleanProjectCommand.php @@ -7,6 +7,8 @@ namespace Magento\FunctionalTestingFramework\Console; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -16,21 +18,6 @@ class CleanProjectCommand extends Command { - const CONFIGURATION_FILES = [ - // codeception.yml file for top level config - TESTS_BP . DIRECTORY_SEPARATOR . 'codeception.yml', - // functional.suite.yml for test execution config - TESTS_BP . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'functional.suite.yml', - // Acceptance Tester Actions generated by codeception - FW_BP . '/src/Magento/FunctionalTestingFramework/_generated', - // AcceptanceTester Class generated by codeception - FW_BP . '/src/Magento/FunctionalTestingFramework/AcceptanceTester.php' - ]; - - const GENERATED_FILES = [ - TESTS_MODULE_PATH . '/_generated' - ]; - /** * Configures the current command. * @@ -52,22 +39,40 @@ protected function configure() * @param OutputInterface $output * @return void * @throws \Symfony\Component\Console\Exception\LogicException + * @throws TestFrameworkException */ protected function execute(InputInterface $input, OutputInterface $output) { + $configFiles = [ + // codeception.yml file for top level config + FilePathFormatter::format(TESTS_BP) . 'codeception.yml', + // functional.suite.yml for test execution config + FilePathFormatter::format(TESTS_BP) . 'tests' . DIRECTORY_SEPARATOR . 'functional.suite.yml', + // Acceptance Tester Actions generated by codeception + FilePathFormatter::format(FW_BP) . 'src/Magento/FunctionalTestingFramework/_generated', + // AcceptanceTester Class generated by codeception + FilePathFormatter::format(FW_BP) . 'src/Magento/FunctionalTestingFramework/AcceptanceTester.php' + ]; + + $generatedFiles = [ + FilePathFormatter::format(TESTS_MODULE_PATH) . '_generated' + ]; + $isHardReset = $input->getOption('hard'); $fileSystem = new Filesystem(); $finder = new Finder(); - $finder->files()->name('*.php')->in(realpath(FW_BP . '/src/Magento/FunctionalTestingFramework/Group/')); + $finder->files()->name('*.php')->in( + realpath(FilePathFormatter::format(FW_BP) . 'src/Magento/FunctionalTestingFramework/Group/') + ); $filesForRemoval = []; // include config files if user specifies a hard reset for deletion if ($isHardReset) { - $filesForRemoval = array_merge($filesForRemoval, self::CONFIGURATION_FILES); + $filesForRemoval = array_merge($filesForRemoval, $configFiles); } // include the files mftf generates during test execution in TESTS_BP for deletion - $filesForRemoval = array_merge($filesForRemoval, self::GENERATED_FILES); + $filesForRemoval = array_merge($filesForRemoval, $generatedFiles); if ($output->isVerbose()) { $output->writeln('Deleting Files:'); diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateDevUrnCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateDevUrnCommand.php index 1147704c0..f953deb16 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateDevUrnCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateDevUrnCommand.php @@ -9,6 +9,7 @@ namespace Magento\FunctionalTestingFramework\Console; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -109,24 +110,32 @@ protected function execute(InputInterface $input, OutputInterface $output) /** * Generates urn => location array for all MFTF schema. * @return array + * @throws TestFrameworkException */ private function generateResourcesArray() { $resourcesArray = [ 'urn:magento:mftf:DataGenerator/etc/dataOperation.xsd' => - realpath(FW_BP . '/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd'), + realpath(FilePathFormatter::format(FW_BP) + . 'src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd'), 'urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd' => - realpath(FW_BP . '/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd'), + realpath(FilePathFormatter::format(FW_BP) + . 'src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd'), 'urn:magento:mftf:Page/etc/PageObject.xsd' => - realpath(FW_BP . '/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd'), + realpath(FilePathFormatter::format(FW_BP) + . 'src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd'), 'urn:magento:mftf:Page/etc/SectionObject.xsd' => - realpath(FW_BP . '/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd'), + realpath(FilePathFormatter::format(FW_BP) + . 'src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd'), 'urn:magento:mftf:Test/etc/actionGroupSchema.xsd' => - realpath(FW_BP . '/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd'), + realpath(FilePathFormatter::format(FW_BP) + . 'src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd'), 'urn:magento:mftf:Test/etc/testSchema.xsd' => - realpath(FW_BP . '/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd'), + realpath(FilePathFormatter::format(FW_BP) + . 'src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd'), 'urn:magento:mftf:Suite/etc/suiteSchema.xsd' => - realpath(FW_BP . '/src/Magento/FunctionalTestingFramework/Suite/etc/suiteSchema.xsd') + realpath(FilePathFormatter::format(FW_BP) + . 'src/Magento/FunctionalTestingFramework/Suite/etc/suiteSchema.xsd') ]; return $resourcesArray; } diff --git a/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php index e487d16cf..37a90bb77 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php @@ -13,6 +13,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Process\Process; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; class RunManifestCommand extends Command { @@ -31,6 +32,13 @@ class RunManifestCommand extends Command */ private $failedTests = []; + /** + * Path for a failed test + * + * @var string + */ + private $testsFailedFile; + /** * Configure the run:manifest command. * @@ -53,6 +61,14 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output): int { + $testsOutputDir = FilePathFormatter::format(TESTS_BP) . + "tests" . + DIRECTORY_SEPARATOR . + "_output" . + DIRECTORY_SEPARATOR; + + $this->testsFailedFile = $testsOutputDir . "failed"; + $path = $input->getArgument("path"); if (!file_exists($path)) { @@ -117,8 +133,8 @@ private function runManifestLine(string $manifestLine, OutputInterface $output) */ private function aggregateFailed() { - if (file_exists(RunTestFailedCommand::TESTS_FAILED_FILE)) { - $currentFile = file(RunTestFailedCommand::TESTS_FAILED_FILE, FILE_IGNORE_NEW_LINES); + if (file_exists($this->testsFailedFile)) { + $currentFile = file($this->testsFailedFile, FILE_IGNORE_NEW_LINES); $this->failedTests = array_merge( $this->failedTests, $currentFile @@ -133,8 +149,8 @@ private function aggregateFailed() */ private function deleteFailedFile() { - if (file_exists(RunTestFailedCommand::TESTS_FAILED_FILE)) { - unlink(RunTestFailedCommand::TESTS_FAILED_FILE); + if (file_exists($this->testsFailedFile)) { + unlink($this->testsFailedFile); } } @@ -146,7 +162,7 @@ private function deleteFailedFile() private function writeFailedFile() { foreach ($this->failedTests as $test) { - file_put_contents(RunTestFailedCommand::TESTS_FAILED_FILE, $test . "\n", FILE_APPEND); + file_put_contents($this->testsFailedFile, $test . "\n", FILE_APPEND); } } } diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php index 77b8be513..373256cfc 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php @@ -8,6 +8,7 @@ namespace Magento\FunctionalTestingFramework\Console; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Magento\FunctionalTestingFramework\Util\TestGenerator; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Input\InputArgument; @@ -122,8 +123,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int private function runTests(array $tests, OutputInterface $output) { $codeceptionCommand = realpath(PROJECT_ROOT . '/vendor/bin/codecept') . ' run functional '; - $testsDirectory = TESTS_MODULE_PATH . - DIRECTORY_SEPARATOR . + $testsDirectory = FilePathFormatter::format(TESTS_MODULE_PATH) . TestGenerator::GENERATED_DIR . DIRECTORY_SEPARATOR . TestGenerator::DEFAULT_DIR . diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php index 336fd5d87..5f0596a7f 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php @@ -8,6 +8,7 @@ namespace Magento\FunctionalTestingFramework\Console; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -22,20 +23,20 @@ class RunTestFailedCommand extends BaseGenerateCommand */ const DEFAULT_TEST_GROUP = 'default'; - const TESTS_OUTPUT_DIR = TESTS_BP . - DIRECTORY_SEPARATOR . - "tests" . - DIRECTORY_SEPARATOR . - "_output" . - DIRECTORY_SEPARATOR; - - const TESTS_FAILED_FILE = self::TESTS_OUTPUT_DIR . "failed"; - const TESTS_RERUN_FILE = self::TESTS_OUTPUT_DIR . "rerun_tests"; - const TESTS_MANIFEST_FILE= TESTS_MODULE_PATH . - DIRECTORY_SEPARATOR . - "_generated" . - DIRECTORY_SEPARATOR . - "testManifest.txt"; + /** + * @var string + */ + private $testsFailedFile; + + /** + * @var string + */ + private $testsReRunFile; + + /** + * @var string + */ + private $testsManifestFile; /** * @var array @@ -68,6 +69,19 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output): int { + $testsOutputDir = FilePathFormatter::format(TESTS_BP) . + "tests" . + DIRECTORY_SEPARATOR . + "_output" . + DIRECTORY_SEPARATOR; + + $this->testsFailedFile = $testsOutputDir . "failed"; + $this->testsReRunFile = $testsOutputDir . "rerun_tests"; + $this->testsManifestFile= FilePathFormatter::format(TESTS_MODULE_PATH) . + "_generated" . + DIRECTORY_SEPARATOR . + "testManifest.txt"; + $force = $input->getOption('force'); $debug = $input->getOption('debug') ?? MftfApplicationConfig::LEVEL_DEVELOPER; // for backward compatibility $allowSkipped = $input->getOption('allow-skipped'); @@ -115,15 +129,15 @@ function ($type, $buffer) use ($output) { $output->write($buffer); } )); - if (file_exists(self::TESTS_FAILED_FILE)) { + if (file_exists($this->testsFailedFile)) { $this->failedList = array_merge( $this->failedList, - $this->readFailedTestFile(self::TESTS_FAILED_FILE) + $this->readFailedTestFile($this->testsFailedFile) ); } } foreach ($this->failedList as $test) { - $this->writeFailedTestToFile($test, self::TESTS_FAILED_FILE); + $this->writeFailedTestToFile($test, $this->testsFailedFile); } return $returnCode; @@ -138,12 +152,12 @@ private function getFailedTestList() { $failedTestDetails = ['tests' => [], 'suites' => []]; - if (realpath(self::TESTS_FAILED_FILE)) { - $testList = $this->readFailedTestFile(self::TESTS_FAILED_FILE); + if (realpath($this->testsFailedFile)) { + $testList = $this->readFailedTestFile($this->testsFailedFile); foreach ($testList as $test) { if (!empty($test)) { - $this->writeFailedTestToFile($test, self::TESTS_RERUN_FILE); + $this->writeFailedTestToFile($test, $this->testsReRunFile); $testInfo = explode(DIRECTORY_SEPARATOR, $test); $testName = explode(":", $testInfo[count($testInfo) - 1])[1]; $suiteName = $testInfo[count($testInfo) - 2]; @@ -184,7 +198,7 @@ private function getFailedTestList() */ private function readTestManifestFile() { - return file(self::TESTS_MANIFEST_FILE, FILE_IGNORE_NEW_LINES); + return file($this->testsManifestFile, FILE_IGNORE_NEW_LINES); } /** @@ -202,6 +216,7 @@ private function readFailedTestFile($filePath) * Writes the test name to a file if it does not already exist * * @param string $test + * @param string $filePath * @return void */ private function writeFailedTestToFile($test, $filePath) diff --git a/src/Magento/FunctionalTestingFramework/Console/SetupEnvCommand.php b/src/Magento/FunctionalTestingFramework/Console/SetupEnvCommand.php index 4d1ce0334..65e8c61e7 100644 --- a/src/Magento/FunctionalTestingFramework/Console/SetupEnvCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/SetupEnvCommand.php @@ -7,6 +7,8 @@ namespace Magento\FunctionalTestingFramework\Console; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Exception\InvalidOptionException; @@ -27,12 +29,13 @@ class SetupEnvCommand extends Command * Configures the current command. * * @return void + * @throws TestFrameworkException */ protected function configure() { $this->setName('setup:env') ->setDescription("Generate .env file."); - $this->envProcessor = new EnvProcessor(TESTS_BP . DIRECTORY_SEPARATOR . '.env'); + $this->envProcessor = new EnvProcessor(FilePathFormatter::format(TESTS_BP) . '.env'); $env = $this->envProcessor->getEnv(); foreach ($env as $key => $value) { $this->addOption($key, null, InputOption::VALUE_REQUIRED, '', $value); diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php index 0514cfe57..94ff40069 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php @@ -9,6 +9,7 @@ use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\SecretStorage\FileStorage; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\SecretStorage\VaultStorage; +use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; class CredentialStore { @@ -63,7 +64,7 @@ private function __construct() if ($cvAddress !== false && $cvSecretPath !== false) { try { $this->credStorage[self::ARRAY_KEY_FOR_VAULT] = new VaultStorage( - rtrim($cvAddress, '/'), + UrlFormatter::format($cvAddress, false), '/' . trim($cvSecretPath, '/') ); } catch (TestFrameworkException $e) { diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/FileStorage.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/FileStorage.php index 064610c79..be77a6de2 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/FileStorage.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/FileStorage.php @@ -6,10 +6,10 @@ namespace Magento\FunctionalTestingFramework\DataGenerator\Handlers\SecretStorage; -use Magento\FunctionalTestingFramework\Console\BuildProjectCommand; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; class FileStorage extends BaseStorage { @@ -71,7 +71,7 @@ private function readInCredentialsFile() $credsFilePath = str_replace( '.credentials.example', '.credentials', - BuildProjectCommand::CREDENTIALS_FILE_PATH + FilePathFormatter::format(TESTS_BP) . '.credentials.example' ); if (!file_exists($credsFilePath)) { diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/AbstractExecutor.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/AbstractExecutor.php index b6c3f29ec..e27da3718 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/AbstractExecutor.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/AbstractExecutor.php @@ -6,6 +6,8 @@ namespace Magento\FunctionalTestingFramework\DataGenerator\Persist\Curl; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; use Magento\FunctionalTestingFramework\Util\Protocol\CurlInterface; /** @@ -23,9 +25,10 @@ abstract class AbstractExecutor implements CurlInterface /** * Returns base URL for Magento instance * @return string + * @throws TestFrameworkException */ public function getBaseUrl(): string { - return getenv('MAGENTO_BASE_URL'); + return UrlFormatter::format(getenv('MAGENTO_BASE_URL')); } } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/AdminExecutor.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/AdminExecutor.php index 4e11f5cec..86b3b742f 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/AdminExecutor.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/AdminExecutor.php @@ -6,6 +6,7 @@ namespace Magento\FunctionalTestingFramework\DataGenerator\Persist\Curl; +use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; use Magento\FunctionalTestingFramework\Util\Protocol\CurlInterface; use Magento\FunctionalTestingFramework\Util\Protocol\CurlTransport; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; @@ -59,11 +60,20 @@ public function __construct($removeBackend) /** * Returns base URL for Magento backend instance * @return string + * @throws TestFrameworkException */ public function getBaseUrl(): string { - $backendHost = getenv('MAGENTO_BACKEND_BASE_URL') ?: parent::getBaseUrl(); - return $backendHost . getenv('MAGENTO_BACKEND_NAME') . '/'; + $backendHost = getenv('MAGENTO_BACKEND_BASE_URL') + ? + UrlFormatter::format(getenv('MAGENTO_BACKEND_BASE_URL')) + : + parent::getBaseUrl(); + return empty(getenv('MAGENTO_BACKEND_NAME')) + ? + $backendHost + : + $backendHost . getenv('MAGENTO_BACKEND_NAME') . '/'; } /** diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/WebapiExecutor.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/WebapiExecutor.php index 281eaa24d..494ce8f97 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/WebapiExecutor.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/WebapiExecutor.php @@ -7,6 +7,7 @@ namespace Magento\FunctionalTestingFramework\DataGenerator\Persist\Curl; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; use Magento\FunctionalTestingFramework\Util\Protocol\CurlInterface; use Magento\FunctionalTestingFramework\Util\Protocol\CurlTransport; @@ -75,24 +76,32 @@ public function __construct($storeCode = null) /** * Returns base URL for Magento Web API instance * @return string + * @throws TestFrameworkException */ public function getBaseUrl(): string { - $baseUrl = parent::getBaseUrl(); - $webapiHost = getenv('MAGENTO_RESTAPI_SERVER_HOST'); $webapiPort = getenv("MAGENTO_RESTAPI_SERVER_PORT"); $webapiProtocol = getenv("MAGENTO_RESTAPI_SERVER_PROTOCOL"); - if ($webapiHost) { - $baseUrl = sprintf('%s://%s/', $webapiProtocol, $webapiHost); + if ($webapiHost && $webapiProtocol) { + $baseUrl = UrlFormatter::format( + sprintf('%s://%s', $webapiProtocol, $webapiHost), + false + ); + } elseif ($webapiHost) { + $baseUrl = UrlFormatter::format(sprintf('%s', $webapiProtocol, $webapiHost), false); + } + + if (!isset($baseUrl)) { + $baseUrl = rtrim(parent::getBaseUrl(), '/'); } if ($webapiPort) { - $baseUrl = rtrim($baseUrl, '/') . ':' . $webapiPort . '/'; + $baseUrl .= ':' . $webapiPort; } - return $baseUrl; + return $baseUrl . '/'; } /** @@ -175,22 +184,23 @@ public function close() * Builds and returns URL for request, appending storeCode if needed. * @param string $resource * @return string + * @throws TestFrameworkException */ public function getFormattedUrl($resource) { $urlResult = $this->getBaseUrl() . 'rest/'; if ($this->storeCode != null) { - $urlResult .= $this->storeCode . "/"; + $urlResult .= $this->storeCode . '/'; } - $urlResult .= trim($resource, "/"); + $urlResult .= trim($resource, '/'); return $urlResult; } /** * Return admin auth token. * - * @throws TestFrameworkException * @return string + * @throws TestFrameworkException */ public function getAuthToken() { diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 215438420..2dfe237ac 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -16,6 +16,7 @@ use Codeception\Util\Uri; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; use Magento\FunctionalTestingFramework\DataGenerator\Persist\Curl\WebapiExecutor; +use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; use Magento\FunctionalTestingFramework\Util\Protocol\CurlInterface; use Magento\FunctionalTestingFramework\Util\ConfigSanitizerUtil; use Yandex\Allure\Adapter\AllureException; @@ -869,7 +870,11 @@ private function curlExecMagentoCLI($command, $arguments): string str_replace('index.php', '', rtrim($this->config['url'], '/')), '/' ); - $apiURL = $baseUrl . '/' . ltrim(getenv('MAGENTO_CLI_COMMAND_PATH'), '/'); + + $apiURL = UrlFormatter::format( + $baseUrl . '/' . ltrim(getenv('MAGENTO_CLI_COMMAND_PATH'), '/'), + false + ); $restExecutor = new WebapiExecutor(); $executor = new CurlTransport(); diff --git a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php index 9f0045d19..4df7daa75 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php @@ -6,6 +6,7 @@ namespace Magento\FunctionalTestingFramework\Suite; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Suite\Generators\GroupClassGenerator; @@ -15,9 +16,14 @@ use Magento\FunctionalTestingFramework\Util\Filesystem\DirSetupUtil; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; use Magento\FunctionalTestingFramework\Util\Manifest\BaseTestManifest; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Magento\FunctionalTestingFramework\Util\TestGenerator; use Symfony\Component\Yaml\Yaml; +/** + * Class SuiteGenerator + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class SuiteGenerator { const YAML_CODECEPTION_DIST_FILENAME = 'codeception.dist.yml'; @@ -128,11 +134,12 @@ public function generateSuite($suiteName) * @return void * @throws TestReferenceException * @throws XmlException + * @throws TestFrameworkException */ private function generateSuiteFromTest($suiteName, $tests = [], $originalSuiteName = null) { $relativePath = TestGenerator::GENERATED_DIR . DIRECTORY_SEPARATOR . $suiteName; - $fullPath = TESTS_MODULE_PATH . DIRECTORY_SEPARATOR . $relativePath . DIRECTORY_SEPARATOR; + $fullPath = FilePathFormatter::format(TESTS_MODULE_PATH) . $relativePath . DIRECTORY_SEPARATOR; DirSetupUtil::createGroupDir($fullPath); @@ -348,9 +355,10 @@ private static function getYamlFileContents() * Static getter for the Config yml filepath (as path cannot be stored in a const) * * @return string + * @throws TestFrameworkException */ private static function getYamlConfigFilePath() { - return TESTS_BP . DIRECTORY_SEPARATOR; + return FilePathFormatter::format(TESTS_BP); } } diff --git a/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php index 7ef3d5e8c..2e4d7f9dd 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php @@ -13,6 +13,7 @@ use Magento\FunctionalTestingFramework\Test\Util\BaseObjectExtractor; use Magento\FunctionalTestingFramework\Test\Util\TestHookObjectExtractor; use Magento\FunctionalTestingFramework\Test\Util\TestObjectExtractor; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Magento\FunctionalTestingFramework\Util\Validation\NameValidationUtil; class SuiteObjectExtractor extends BaseObjectExtractor @@ -259,8 +260,7 @@ private function resolveFilePathTestNames($filename, $moduleName = null) { $filepath = $filename; if (!strstr($filepath, DIRECTORY_SEPARATOR)) { - $filepath = TESTS_MODULE_PATH . - DIRECTORY_SEPARATOR . + $filepath = FilePathFormatter::format(TESTS_MODULE_PATH) . $moduleName . DIRECTORY_SEPARATOR . 'Test' . @@ -293,8 +293,7 @@ private function resolveModulePathTestNames($moduleName) { $testObjects = []; $xmlFiles = glob( - TESTS_MODULE_PATH . - DIRECTORY_SEPARATOR . + FilePathFormatter::format(TESTS_MODULE_PATH) . $moduleName . DIRECTORY_SEPARATOR . 'Test' . diff --git a/src/Magento/FunctionalTestingFramework/Util/Env/EnvProcessor.php b/src/Magento/FunctionalTestingFramework/Util/Env/EnvProcessor.php index f09ab63fa..86f7fa89d 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Env/EnvProcessor.php +++ b/src/Magento/FunctionalTestingFramework/Util/Env/EnvProcessor.php @@ -7,6 +7,9 @@ namespace Magento\FunctionalTestingFramework\Util\Env; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; + /** * Helper class EnvProcessor for reading and writing .env files. * @@ -45,13 +48,14 @@ class EnvProcessor /** * EnvProcessor constructor. * @param string $envFile + * @throws TestFrameworkException */ public function __construct( string $envFile = '' ) { $this->envFile = $envFile; $this->envExists = file_exists($envFile); - $this->envExampleFile = realpath(FW_BP . "/etc/config/.env.example"); + $this->envExampleFile = realpath(FilePathFormatter::format(FW_BP) . "etc/config/.env.example"); } /** diff --git a/src/Magento/FunctionalTestingFramework/Util/Logger/LoggingUtil.php b/src/Magento/FunctionalTestingFramework/Util/Logger/LoggingUtil.php index 7ac128f28..97fdada21 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Logger/LoggingUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/Logger/LoggingUtil.php @@ -6,6 +6,8 @@ namespace Magento\FunctionalTestingFramework\Util\Logger; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Monolog\Handler\StreamHandler; use Monolog\Logger; @@ -82,9 +84,10 @@ public function getLogger($className): MftfLogger * Function which returns a static path to the the log file. * * @return string + * @throws TestFrameworkException */ public function getLoggingPath(): string { - return TESTS_BP . DIRECTORY_SEPARATOR . "mftf.log"; + return FilePathFormatter::format(TESTS_BP) . "mftf.log"; } } diff --git a/src/Magento/FunctionalTestingFramework/Util/Manifest/TestManifestFactory.php b/src/Magento/FunctionalTestingFramework/Util/Manifest/TestManifestFactory.php index 1cfa6559e..fd7d885bf 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Manifest/TestManifestFactory.php +++ b/src/Magento/FunctionalTestingFramework/Util/Manifest/TestManifestFactory.php @@ -6,7 +6,9 @@ namespace Magento\FunctionalTestingFramework\Util\Manifest; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Magento\FunctionalTestingFramework\Util\TestGenerator; class TestManifestFactory @@ -26,11 +28,11 @@ private function __construct() * @param array $suiteConfiguration * @param string $testPath * @return BaseTestManifest + * @throws TestFrameworkException */ public static function makeManifest($runConfig, $suiteConfiguration, $testPath = TestGenerator::DEFAULT_DIR) { - $testDirFullPath = TESTS_MODULE_PATH - . DIRECTORY_SEPARATOR + $testDirFullPath = FilePathFormatter::format(TESTS_MODULE_PATH) . TestGenerator::GENERATED_DIR . DIRECTORY_SEPARATOR . $testPath; diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index d5e6a8920..aa9a08ddb 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -9,6 +9,7 @@ use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; use Symfony\Component\HttpFoundation\Response; @@ -314,11 +315,11 @@ private function aggregateTestModulePaths() $allModulePaths = []; // Define the Module paths from magento bp - $magentoBaseCodePath = MAGENTO_BP; + $magentoBaseCodePath = FilePathFormatter::format(MAGENTO_BP, false); // Define the Module paths from default TESTS_MODULE_PATH $modulePath = defined('TESTS_MODULE_PATH') ? TESTS_MODULE_PATH : TESTS_BP; - $modulePath = rtrim($modulePath, DIRECTORY_SEPARATOR); + $modulePath = FilePathFormatter::format($modulePath, false); $vendorCodePath = DIRECTORY_SEPARATOR . self::VENDOR; $appCodePath = DIRECTORY_SEPARATOR . self::APP_CODE; @@ -416,15 +417,16 @@ private static function globRelevantWrapper($testPath, $pattern) * Aggregate all code paths with test module composer json files * * @return array + * @throws TestFrameworkException */ private function aggregateTestModulePathsFromComposerJson() { // Define the module paths - $magentoBaseCodePath = MAGENTO_BP; + $magentoBaseCodePath = FilePathFormatter::format(MAGENTO_BP, false); // Define the module paths from default TESTS_MODULE_PATH $modulePath = defined('TESTS_MODULE_PATH') ? TESTS_MODULE_PATH : TESTS_BP; - $modulePath = rtrim($modulePath, DIRECTORY_SEPARATOR); + $modulePath = FilePathFormatter::format($modulePath, false); $searchCodePaths = [ $magentoBaseCodePath . DIRECTORY_SEPARATOR . self::DEV_TESTS, @@ -719,7 +721,7 @@ public function getAdminToken() throw new TestFrameworkException($message, $context); } - $url = UrlFormatter::format($this->getBackendUrl()) . $this->adminTokenUrl; + $url = $this->getBackendUrl() . $this->adminTokenUrl; $data = [ 'username' => $login, 'password' => $password @@ -887,7 +889,15 @@ private function getRegisteredModuleList() */ private function getBackendUrl() { - return getenv('MAGENTO_BACKEND_BASE_URL') ?: getenv('MAGENTO_BASE_URL'); + try { + if (getenv('MAGENTO_BACKEND_BASE_URL')) { + return UrlFormatter::format(getenv('MAGENTO_BACKEND_BASE_URL')); + } else { + return UrlFormatter::format(getenv('MAGENTO_BASE_URL')); + } + } catch (TestFrameworkException $e) { + return null; + } } /** diff --git a/src/Magento/FunctionalTestingFramework/Util/Path/FilePathFormatter.php b/src/Magento/FunctionalTestingFramework/Util/Path/FilePathFormatter.php index 1337f1e3c..8b496e739 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Path/FilePathFormatter.php +++ b/src/Magento/FunctionalTestingFramework/Util/Path/FilePathFormatter.php @@ -8,7 +8,7 @@ use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; -class FilePathFormatter implements FileUrlFormatterInterface +class FilePathFormatter implements FormatterInterface { /** * Return formatted full file path from input string, or false on error @@ -18,7 +18,7 @@ class FilePathFormatter implements FileUrlFormatterInterface * @return string * @throws TestFrameworkException */ - public static function format($path, $withTrailingSeparator = false) + public static function format($path, $withTrailingSeparator = true) { $validPath = realpath($path); diff --git a/src/Magento/FunctionalTestingFramework/Util/Path/FileUrlFormatterInterface.php b/src/Magento/FunctionalTestingFramework/Util/Path/FormatterInterface.php similarity index 92% rename from src/Magento/FunctionalTestingFramework/Util/Path/FileUrlFormatterInterface.php rename to src/Magento/FunctionalTestingFramework/Util/Path/FormatterInterface.php index 3525dd75b..11de71204 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Path/FileUrlFormatterInterface.php +++ b/src/Magento/FunctionalTestingFramework/Util/Path/FormatterInterface.php @@ -8,7 +8,7 @@ use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; -interface FileUrlFormatterInterface +interface FormatterInterface { /** * Return formatted path (file path, url, etc) from input string, or false on error @@ -18,5 +18,5 @@ interface FileUrlFormatterInterface * @return string * @throws TestFrameworkException */ - public static function format($input, $withTrailingSeparator = false); + public static function format($input, $withTrailingSeparator = true); } diff --git a/src/Magento/FunctionalTestingFramework/Util/Path/UrlFormatter.php b/src/Magento/FunctionalTestingFramework/Util/Path/UrlFormatter.php index 3c2a9499e..2ff1e430b 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Path/UrlFormatter.php +++ b/src/Magento/FunctionalTestingFramework/Util/Path/UrlFormatter.php @@ -8,7 +8,7 @@ use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; -class UrlFormatter implements FileUrlFormatterInterface +class UrlFormatter implements FormatterInterface { /** * Return formatted url path from input string, or false on error @@ -21,18 +21,22 @@ class UrlFormatter implements FileUrlFormatterInterface public static function format($url, $withTrailingSeparator = true) { $sanitizedUrl = rtrim($url, '/'); + + // Remove all characters except letters, digits and $-_.+!*'(),{}|\\^~[]`<>#%";/?:@&= $sanitizedUrl = filter_var($sanitizedUrl, FILTER_SANITIZE_URL); if (false === $sanitizedUrl) { throw new TestFrameworkException("Invalid url: $url\n"); } + // Validate URL according to http://www.faqs.org/rfcs/rfc2396 $validUrl = filter_var($sanitizedUrl, FILTER_VALIDATE_URL); if (false !== $validUrl) { return $withTrailingSeparator ? $validUrl . '/' : $validUrl; } + // Validation might be failed due to missing URL scheme or host, attempt to build them and re-validate $validUrl = filter_var(self::buildUrl($sanitizedUrl), FILTER_VALIDATE_URL); if (false !== $validUrl) { diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index ce45af963..648f3055f 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -10,6 +10,7 @@ use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Suite\Handlers\SuiteObjectHandler; use Magento\FunctionalTestingFramework\Test\Handlers\ActionGroupObjectHandler; @@ -26,6 +27,7 @@ use Magento\FunctionalTestingFramework\Test\Util\TestObjectExtractor; use Magento\FunctionalTestingFramework\Util\Filesystem\DirSetupUtil; use Magento\FunctionalTestingFramework\Test\Util\ActionMergeUtil; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; /** * Class TestGenerator @@ -103,14 +105,14 @@ class TestGenerator * @param string $exportDir * @param array $tests * @param boolean $debug + * @throws TestFrameworkException */ private function __construct($exportDir, $tests, $debug = false) { // private constructor for factory $this->exportDirName = $exportDir ?? self::DEFAULT_DIR; $exportDir = $exportDir ?? self::DEFAULT_DIR; - $this->exportDirectory = TESTS_MODULE_PATH - . DIRECTORY_SEPARATOR + $this->exportDirectory = FilePathFormatter::format(TESTS_MODULE_PATH) . self::GENERATED_DIR . DIRECTORY_SEPARATOR . $exportDir; diff --git a/src/Magento/FunctionalTestingFramework/_bootstrap.php b/src/Magento/FunctionalTestingFramework/_bootstrap.php index e401123b6..f3bb099d0 100644 --- a/src/Magento/FunctionalTestingFramework/_bootstrap.php +++ b/src/Magento/FunctionalTestingFramework/_bootstrap.php @@ -61,7 +61,7 @@ defined('MAGENTO_BP') || define('MAGENTO_BP', realpath(PROJECT_ROOT)); // TODO REMOVE THIS CODE ONCE WE HAVE STOPPED SUPPORTING dev/tests/acceptance PATH // define TEST_PATH and TEST_MODULE_PATH -defined('TESTS_BP') || define('TESTS_BP', realpath(MAGENTO_BP . DIRECTORY_SEPARATOR . 'dev/tests/acceptance/')); +defined('TESTS_BP') || define('TESTS_BP', realpath(MAGENTO_BP . DIRECTORY_SEPARATOR . 'dev/tests/acceptance')); $RELATIVE_TESTS_MODULE_PATH = '/tests/functional/Magento/FunctionalTest'; defined('TESTS_MODULE_PATH') || define( From ab0d3c5bb77a1a70f7544df0287b04d519c13154 Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Thu, 21 Nov 2019 13:12:36 -0600 Subject: [PATCH 070/888] MQE-1520: Consolidate WAIT_TIMEOUT in .env and pageload_timeout - Fixed Verification Tests --- dev/tests/_bootstrap.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dev/tests/_bootstrap.php b/dev/tests/_bootstrap.php index b41f80394..3f57ad139 100644 --- a/dev/tests/_bootstrap.php +++ b/dev/tests/_bootstrap.php @@ -45,7 +45,8 @@ 'MAGENTO_BACKEND_NAME' => 'admin', 'MAGENTO_ADMIN_USERNAME' => 'admin', 'MAGENTO_ADMIN_PASSWORD' => 'admin123', - 'DEFAULT_TIMEZONE' => 'America/Los_Angeles' + 'DEFAULT_TIMEZONE' => 'America/Los_Angeles', + 'WAIT_TIMEOUT' => '10' ]; foreach ($TEST_ENVS as $key => $value) { From dc004a234a4529dc08d26606dbe519483b175a32 Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Thu, 21 Nov 2019 14:27:32 -0600 Subject: [PATCH 071/888] MQE-1627: RetrieveEntityField generation does not consider ActionGroup - Testgenerator fix - verification tests addition --- .../Resources/PersistenceCustomFieldsTest.txt | 31 +++++++++++++++++++ .../ActionGroup/PersistenceActionGroup.xml | 8 +++++ .../Test/PersistenceCustomFieldsTest.xml | 1 + .../Util/TestGenerator.php | 1 + 4 files changed, 41 insertions(+) diff --git a/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt b/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt index 38dc364e7..0a6deaca8 100644 --- a/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt +++ b/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt @@ -111,5 +111,36 @@ class PersistenceCustomFieldsTestCest ); $I->comment("Exiting Action Group [createdAG] PersistenceActionGroup"); + $I->comment("Entering Action Group [AGKEY] DataPersistenceSelfReferenceActionGroup"); + $I->comment("[createData1AGKEY] create 'entity1' entity"); + PersistedObjectHandler::getInstance()->createEntity( + "createData1AGKEY", + "test", + "entity1", + [], + [] + ); + + $I->comment("[createData2AGKEY] create 'entity2' entity"); + PersistedObjectHandler::getInstance()->createEntity( + "createData2AGKEY", + "test", + "entity2", + [], + [] + ); + + $createData3AGKEYFields['key1'] = PersistedObjectHandler::getInstance()->retrieveEntityField('createData1AGKEY', 'field', 'test'); + $createData3AGKEYFields['key2'] = PersistedObjectHandler::getInstance()->retrieveEntityField('createData2AGKEY', 'field', 'test'); + $I->comment("[createData3AGKEY] create 'entity3' entity"); + PersistedObjectHandler::getInstance()->createEntity( + "createData3AGKEY", + "test", + "entity3", + [], + $createData3AGKEYFields + ); + + $I->comment("Exiting Action Group [AGKEY] DataPersistenceSelfReferenceActionGroup"); } } diff --git a/dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup.xml index c4f894cfc..f98fd2406 100644 --- a/dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup.xml +++ b/dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup.xml @@ -30,4 +30,12 @@ + + + + + $createData1.field$ + $createData2.field$ + + \ No newline at end of file diff --git a/dev/tests/verification/TestModule/Test/PersistenceCustomFieldsTest.xml b/dev/tests/verification/TestModule/Test/PersistenceCustomFieldsTest.xml index 747c2c132..c56106693 100644 --- a/dev/tests/verification/TestModule/Test/PersistenceCustomFieldsTest.xml +++ b/dev/tests/verification/TestModule/Test/PersistenceCustomFieldsTest.xml @@ -33,5 +33,6 @@ +
diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index ce45af963..2909ab1dc 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1291,6 +1291,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato break; case "field": $fieldKey = $actionObject->getCustomActionAttributes()['key']; + $input = $this->resolveStepKeyReferences($input, $actionObject->getActionOrigin()); $input = $this->resolveTestVariable( [$input], $actionObject->getActionOrigin() From 97f3b3ed6095d78f3d44300aa20807601b87a386 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Thu, 21 Nov 2019 16:54:01 -0600 Subject: [PATCH 072/888] MQE-1711: Switch between Developer mode and Production mode takes long time and the test end up time out. --- etc/config/command.php | 3 ++- .../Module/MagentoWebDriver.php | 25 +++++++++++-------- .../Test/etc/Actions/customActions.xsd | 7 ++++++ .../Util/TestGenerator.php | 9 +++++-- 4 files changed, 31 insertions(+), 13 deletions(-) diff --git a/etc/config/command.php b/etc/config/command.php index adc372e43..b348bd3e5 100644 --- a/etc/config/command.php +++ b/etc/config/command.php @@ -14,6 +14,7 @@ $tokenPassedIn = urldecode($_POST['token'] ?? ''); $command = urldecode($_POST['command'] ?? ''); $arguments = urldecode($_POST['arguments'] ?? ''); + $timeout = urldecode($_POST['timeout'] ?? 60); // Token returned will be null if the token we passed in is invalid $tokenFromMagento = $tokenModel->loadByToken($tokenPassedIn)->getToken(); @@ -24,7 +25,7 @@ if ($valid) { $fullCommand = escapeshellcmd($magentoBinary . " $command" . " $arguments"); $process = new Symfony\Component\Process\Process($fullCommand); - $process->setIdleTimeout(60); + $process->setIdleTimeout($timeout); $process->setTimeout(0); $idleTimeout = false; try { diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index c1ab892d7..de8feaae2 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -510,14 +510,16 @@ public function scrollToTopOfPage() /** * Takes given $command and executes it against bin/magento or custom exposed entrypoint. Returns command output. * - * @param string $command - * @param string $arguments + * @param string $command + * @param string $arguments + * @param integer $timeout * @return string + * * @throws TestFrameworkException */ - public function magentoCLI($command, $arguments = null) + public function magentoCLI($command, $arguments = null, $timeout = null) { - return $this->curlExecMagentoCLI($command, $arguments); + return $this->curlExecMagentoCLI($command, $arguments, $timeout); //TODO: calling bin/magento from pipeline is timing out, needs investigation (ref: MQE-1774) // try { // return $this->shellExecMagentoCLI($command, $arguments); @@ -673,16 +675,17 @@ public function fillSecretField($field, $value) * * @param string $command * @param null $arguments + * @param int $timeout * @throws TestFrameworkException * @return string */ - public function magentoCLISecret($command, $arguments = null) + public function magentoCLISecret($command, $timeout, $arguments = null) { // to protect any secrets from being printed to console the values are executed only at the webdriver level as a // decrypted value $decryptedCommand = CredentialStore::getInstance()->decryptAllSecretsInString($command); - return $this->magentoCLI($decryptedCommand, $arguments); + return $this->magentoCLI($decryptedCommand, $timeout, $arguments); } /** @@ -860,12 +863,13 @@ private function shellExecMagentoCLI($command, $arguments): string /** * Takes given $command and executes it against exposed MTF CLI entry point. Returns response from server. * - * @param string $command - * @param string $arguments - * @return string + * @param string $command + * @param string $arguments + * @param integer $timeout + * * @throws TestFrameworkException */ - private function curlExecMagentoCLI($command, $arguments): string + private function curlExecMagentoCLI($command, $arguments, $timeout): string { // Remove index.php if it's present in url $baseUrl = rtrim( @@ -882,6 +886,7 @@ private function curlExecMagentoCLI($command, $arguments): string 'token' => $restExecutor->getAuthToken(), getenv('MAGENTO_CLI_COMMAND_PARAMETER') => $command, 'arguments' => $arguments, + 'timeout' => $timeout, ], CurlInterface::POST, [] diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd index 3a002e126..2424d0d31 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd @@ -50,6 +50,13 @@ + + + + Idle timeout in seconds, defaulted to 60s when not specified. + + + diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index ce45af963..be9d26c96 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -42,6 +42,7 @@ class TestGenerator const HOOK_SCOPE = 'hook'; const SUITE_SCOPE = 'suite'; const PRESSKEY_ARRAY_ANCHOR_KEY = '987654321098765432109876543210'; + const COMMAND_WAIT_TIMEOUT = 60; const PERSISTED_OBJECT_NOTATION_REGEX = '/\${1,2}[\w.\[\]]+\${1,2}/'; const NO_STEPKEY_ACTIONS = [ 'comment', @@ -532,6 +533,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $sortOrder = null; $storeCode = null; $format = null; + $commandTimeout = null; $assertExpected = null; $assertActual = null; @@ -609,10 +611,12 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $time = $customActionAttributes['time']; } if (isset($customActionAttributes['timeout'])) { - $time = $customActionAttributes['timeout']; + $commandTimeout = $customActionAttributes['timeout']; } $time = $time ?? ActionObject::getDefaultWaitTimeout(); + $commandTimeout = $commandTimeout ?? self::COMMAND_WAIT_TIMEOUT; + if (isset($customActionAttributes['parameterArray']) && $actionObject->getType() != 'pressKey') { // validate the param array is in the correct format $this->validateParameterArray($customActionAttributes['parameterArray']); @@ -1280,7 +1284,8 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $actor, $actionObject, $command, - $arguments + $arguments, + $commandTimeout ); $testSteps .= sprintf(self::STEP_KEY_ANNOTATION, $stepKey) . PHP_EOL; $testSteps .= sprintf( From cc5932aac7ae1b903681071573f86d93e730b7ce Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Fri, 22 Nov 2019 10:23:47 -0600 Subject: [PATCH 073/888] MQE-1520: Consolidate WAIT_TIMEOUT in .env and pageload_timeout - CR Fixes --- dev/tests/functional/standalone_bootstrap.php | 4 ++-- docs/configuration.md | 8 ++++++++ src/Magento/FunctionalTestingFramework/_bootstrap.php | 4 ++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/dev/tests/functional/standalone_bootstrap.php b/dev/tests/functional/standalone_bootstrap.php index ab6372697..486c7566b 100755 --- a/dev/tests/functional/standalone_bootstrap.php +++ b/dev/tests/functional/standalone_bootstrap.php @@ -50,8 +50,8 @@ defined('DEFAULT_TIMEZONE') || define('DEFAULT_TIMEZONE', 'America/Los_Angeles'); $env->setEnvironmentVariable('DEFAULT_TIMEZONE', DEFAULT_TIMEZONE); - defined('WAIT_TIMEOUT') || define('WAIT_TIMEOUT', 10); - $env->setEnvironmentVariable('WAIT_TIMEOUT', 10); + defined('WAIT_TIMEOUT') || define('WAIT_TIMEOUT', 30); + $env->setEnvironmentVariable('WAIT_TIMEOUT', 30); try { new DateTimeZone(DEFAULT_TIMEZONE); diff --git a/docs/configuration.md b/docs/configuration.md index 4af2c4e82..5140c01e7 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -295,6 +295,14 @@ Denoted in browser log entry as `"SOURCE": "type"`. BROWSER_LOG_BLACKLIST=other,console-api ``` +### WAIT_TIMEOUT + +Global MFTF configuration for the default amount of time (in seconds) that a test will wait while loading a page. + +```conf +WAIT_TIMEOUT=30 +``` + [`MAGENTO_CLI_COMMAND_PATH`]: #magento_cli_command_path diff --git a/src/Magento/FunctionalTestingFramework/_bootstrap.php b/src/Magento/FunctionalTestingFramework/_bootstrap.php index 490ff61de..ebc62e95d 100644 --- a/src/Magento/FunctionalTestingFramework/_bootstrap.php +++ b/src/Magento/FunctionalTestingFramework/_bootstrap.php @@ -50,8 +50,8 @@ defined('DEFAULT_TIMEZONE') || define('DEFAULT_TIMEZONE', 'America/Los_Angeles'); $env->setEnvironmentVariable('DEFAULT_TIMEZONE', DEFAULT_TIMEZONE); - defined('WAIT_TIMEOUT') || define('WAIT_TIMEOUT', 10); - $env->setEnvironmentVariable('WAIT_TIMEOUT', 10); + defined('WAIT_TIMEOUT') || define('WAIT_TIMEOUT', 30); + $env->setEnvironmentVariable('WAIT_TIMEOUT', 30); try { new DateTimeZone(DEFAULT_TIMEZONE); From 16e1f03ec072c6734f37e2338ceb450fa28fbb63 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Fri, 22 Nov 2019 13:45:05 -0600 Subject: [PATCH 074/888] MQE-1711: Switch between Developer mode and Production mode takes long time and the test end up time out --- .../Resources/BasicFunctionalTest.txt | 2 +- .../Resources/DataReplacementTest.txt | 2 +- .../Module/MagentoWebDriver.php | 24 ++++++++++--------- .../Test/Objects/ActionObject.php | 2 ++ .../Util/TestGenerator.php | 12 ++++++---- 5 files changed, 24 insertions(+), 18 deletions(-) diff --git a/dev/tests/verification/Resources/BasicFunctionalTest.txt b/dev/tests/verification/Resources/BasicFunctionalTest.txt index f82c84119..c5dc13e2e 100644 --- a/dev/tests/verification/Resources/BasicFunctionalTest.txt +++ b/dev/tests/verification/Resources/BasicFunctionalTest.txt @@ -126,7 +126,7 @@ class BasicFunctionalTestCest $grabMultipleKey1 = $I->grabMultiple(".functionalTestSelector"); // stepKey: grabMultipleKey1 $grabTextFromKey1 = $I->grabTextFrom(".functionalTestSelector"); // stepKey: grabTextFromKey1 $grabValueFromKey1 = $I->grabValueFrom(".functionalTestSelector"); // stepKey: grabValueFromKey1 - $magentoCli1 = $I->magentoCLI("maintenance:enable", "\"stuffHere\""); // stepKey: magentoCli1 + $magentoCli1 = $I->magentoCLI("maintenance:enable", "\"stuffHere\"", 60); // stepKey: magentoCli1 $I->comment($magentoCli1); $I->makeScreenshot("screenShotInput"); // stepKey: makeScreenshotKey1 $I->maximizeWindow(); // stepKey: maximizeWindowKey1 diff --git a/dev/tests/verification/Resources/DataReplacementTest.txt b/dev/tests/verification/Resources/DataReplacementTest.txt index 731ae63f8..4b4531a4e 100644 --- a/dev/tests/verification/Resources/DataReplacementTest.txt +++ b/dev/tests/verification/Resources/DataReplacementTest.txt @@ -52,7 +52,7 @@ class DataReplacementTestCest $I->searchAndMultiSelectOption("#selector", [msq("uniqueData") . "John", "Doe" . msq("uniqueData")]); // stepKey: parameterArrayReplacementMSQBoth $I->selectMultipleOptions("#Doe" . msq("uniqueData"), "#element", [msq("uniqueData") . "John", "Doe" . msq("uniqueData")]); // stepKey: multiSelectDataReplacement $I->fillField(".selector", "0"); // stepKey: insertZero - $insertCommand = $I->magentoCLI("do something Doe" . msq("uniqueData") . " with uniqueness"); // stepKey: insertCommand + $insertCommand = $I->magentoCLI("do something Doe" . msq("uniqueData") . " with uniqueness", 60); // stepKey: insertCommand $I->comment($insertCommand); $I->seeInPageSource("StringBefore John StringAfter"); // stepKey: htmlReplace1 $I->seeInPageSource("#John"); // stepKey: htmlReplace2 diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index de8feaae2..3602ddfb4 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -519,7 +519,7 @@ public function scrollToTopOfPage() */ public function magentoCLI($command, $arguments = null, $timeout = null) { - return $this->curlExecMagentoCLI($command, $arguments, $timeout); + return $this->curlExecMagentoCLI($command, $arguments, $timeout); //TODO: calling bin/magento from pipeline is timing out, needs investigation (ref: MQE-1774) // try { // return $this->shellExecMagentoCLI($command, $arguments); @@ -673,19 +673,19 @@ public function fillSecretField($field, $value) * Function used to create data that contains sensitive credentials in a override. * The data is decrypted immediately prior to data creation to avoid exposure in console or log. * - * @param string $command - * @param null $arguments - * @param int $timeout + * @param string $command + * @param null $arguments + * @param null $timeout * @throws TestFrameworkException * @return string */ - public function magentoCLISecret($command, $timeout, $arguments = null) + public function magentoCLISecret($command, $arguments = null, $timeout = null) { // to protect any secrets from being printed to console the values are executed only at the webdriver level as a // decrypted value $decryptedCommand = CredentialStore::getInstance()->decryptAllSecretsInString($command); - return $this->magentoCLI($decryptedCommand, $timeout, $arguments); + return $this->magentoCLI($decryptedCommand, $arguments, $timeout); } /** @@ -837,20 +837,21 @@ public function makeScreenshot($name = null) /** * Takes given $command and executes it against bin/magento executable. Returns stdout output from the command. * - * @param string $command - * @param string $arguments + * @param string $command + * @param string $arguments + * @param integer $timeout * * @throws \RuntimeException * @return string * @SuppressWarnings(PHPMD.UnusedPrivateMethod) */ - private function shellExecMagentoCLI($command, $arguments): string + private function shellExecMagentoCLI($command, $arguments, $timeout): string { $php = PHP_BINDIR ? PHP_BINDIR . DIRECTORY_SEPARATOR. 'php' : 'php'; $binMagento = realpath(MAGENTO_BP . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'magento'); $command = $php . ' -f ' . $binMagento . ' ' . $command . ' ' . $arguments; $process = new Process(escapeshellcmd($command), MAGENTO_BP); - $process->setIdleTimeout(60); + $process->setIdleTimeout($timeout); $process->setTimeout(0); $exitCode = $process->run(); if ($exitCode !== 0) { @@ -867,9 +868,10 @@ private function shellExecMagentoCLI($command, $arguments): string * @param string $arguments * @param integer $timeout * + * @return string * @throws TestFrameworkException */ - private function curlExecMagentoCLI($command, $arguments, $timeout): string + private function curlExecMagentoCLI($command, $arguments, $timeout): string { // Remove index.php if it's present in url $baseUrl = rtrim( diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php index 9b1cdf1af..0434ca22d 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php @@ -63,6 +63,7 @@ class ActionObject const DELETE_DATA_MUTUAL_EXCLUSIVE_ATTRIBUTES = ["url", "createDataKey"]; const EXTERNAL_URL_AREA_INVALID_ACTIONS = ['amOnPage']; const FUNCTION_CLOSURE_ACTIONS = ['waitForElementChange', 'performOn', 'executeInSelenium']; + const COMMAND_ACTION_ATTRIBUTES = ['magentoCLI', 'magentoCLISecret']; const MERGE_ACTION_ORDER_AFTER = 'after'; const MERGE_ACTION_ORDER_BEFORE = 'before'; const ACTION_ATTRIBUTE_TIMEZONE = 'timezone'; @@ -72,6 +73,7 @@ class ActionObject const ACTION_ATTRIBUTE_VARIABLE_REGEX_PATTERN = '/({{[\w]+\.[\w\[\]]+}})|({{[\w]+\.[\w]+\((?(?!}}).)+\)}})/'; const STRING_PARAMETER_REGEX = "/'[^']+'/"; const DEFAULT_WAIT_TIMEOUT = 10; + const DEFAULT_COMMAND_WAIT_TIMEOUT = 60; const ACTION_ATTRIBUTE_USERINPUT = 'userInput'; const ACTION_TYPE_COMMENT = 'comment'; diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index be9d26c96..766f65b60 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -42,7 +42,6 @@ class TestGenerator const HOOK_SCOPE = 'hook'; const SUITE_SCOPE = 'suite'; const PRESSKEY_ARRAY_ANCHOR_KEY = '987654321098765432109876543210'; - const COMMAND_WAIT_TIMEOUT = 60; const PERSISTED_OBJECT_NOTATION_REGEX = '/\${1,2}[\w.\[\]]+\${1,2}/'; const NO_STEPKEY_ACTIONS = [ 'comment', @@ -611,11 +610,14 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $time = $customActionAttributes['time']; } if (isset($customActionAttributes['timeout'])) { - $commandTimeout = $customActionAttributes['timeout']; + $time = $customActionAttributes['timeout']; } - $time = $time ?? ActionObject::getDefaultWaitTimeout(); - $commandTimeout = $commandTimeout ?? self::COMMAND_WAIT_TIMEOUT; + if (in_array($actionObject->getType(), ActionObject::COMMAND_ACTION_ATTRIBUTES)) { + $time = $time ?? ActionObject::DEFAULT_COMMAND_WAIT_TIMEOUT; + } else { + $time = $time ?? ActionObject::getDefaultWaitTimeout(); + } if (isset($customActionAttributes['parameterArray']) && $actionObject->getType() != 'pressKey') { // validate the param array is in the correct format @@ -1285,7 +1287,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $actionObject, $command, $arguments, - $commandTimeout + $time ); $testSteps .= sprintf(self::STEP_KEY_ANNOTATION, $stepKey) . PHP_EOL; $testSteps .= sprintf( From fceb17f52104dadb3e38a562a8c8730a9b2bd023 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Fri, 22 Nov 2019 14:46:57 -0600 Subject: [PATCH 075/888] MQE-1711: Switch between Developer mode and Production mode takes long time and the test end up time out fixed static checks + unit tests, added documentation. --- .../Resources/ActionGroupWithStepKeyReferences.txt | 2 +- docs/test/actions.md | 1 + .../FunctionalTestingFramework/Module/MagentoWebDriver.php | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt b/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt index eddaaf784..2bb414230 100644 --- a/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt +++ b/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt @@ -45,7 +45,7 @@ class ActionGroupWithStepKeyReferencesCest $I->fillField($action1); // stepKey: action1ActionGroup $I->comment("Invocation stepKey will be appended in non stepKey instances"); $action3ActionGroup = $I->executeJS($action3ActionGroup); // stepKey: action3ActionGroup - $action4ActionGroup = $I->magentoCLI($action4ActionGroup, "\"stuffHere\""); // stepKey: action4ActionGroup + $action4ActionGroup = $I->magentoCLI($action4ActionGroup, "\"stuffHere\"", 60); // stepKey: action4ActionGroup $I->comment($action4ActionGroup); $date = new \DateTime(); $date->setTimestamp(strtotime("{$action5}")); diff --git a/docs/test/actions.md b/docs/test/actions.md index 9b125d7fc..c5dc83fdb 100644 --- a/docs/test/actions.md +++ b/docs/test/actions.md @@ -1262,6 +1262,7 @@ Attribute|Type|Use|Description ---|---|---|--- `command`|string |optional| CLI command to be executed in Magento environment. `arguments`|string |optional| Unescaped arguments to be passed in with the CLI command. +`timeout`|string|optional| Number of seconds CLI command can run without outputting anything. `stepKey`|string|required| A unique identifier of the action. `before`|string|optional| `stepKey` of action that must be executed next. `after`|string|optional| `stepKey` of preceding action. diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 3602ddfb4..2d09e7f2a 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -673,9 +673,9 @@ public function fillSecretField($field, $value) * Function used to create data that contains sensitive credentials in a override. * The data is decrypted immediately prior to data creation to avoid exposure in console or log. * - * @param string $command - * @param null $arguments - * @param null $timeout + * @param string $command + * @param null $arguments + * @param null $timeout * @throws TestFrameworkException * @return string */ From 2e1887e1b92bdd9333767541488449e4d15f285d Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Fri, 22 Nov 2019 16:08:52 -0600 Subject: [PATCH 076/888] MQE-1711: Switch between Developer mode and Production mode takes long time and the test end up time out --- etc/config/command.php | 2 +- src/Magento/FunctionalTestingFramework/Util/TestGenerator.php | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/etc/config/command.php b/etc/config/command.php index b348bd3e5..e3b8f1191 100644 --- a/etc/config/command.php +++ b/etc/config/command.php @@ -14,7 +14,7 @@ $tokenPassedIn = urldecode($_POST['token'] ?? ''); $command = urldecode($_POST['command'] ?? ''); $arguments = urldecode($_POST['arguments'] ?? ''); - $timeout = urldecode($_POST['timeout'] ?? 60); + $timeout = floatval(urldecode($_POST['timeout'] ?? 60)); // Token returned will be null if the token we passed in is invalid $tokenFromMagento = $tokenModel->loadByToken($tokenPassedIn)->getToken(); diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 766f65b60..a566e95f6 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -532,7 +532,6 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $sortOrder = null; $storeCode = null; $format = null; - $commandTimeout = null; $assertExpected = null; $assertActual = null; From 8f72ffc123da6a0a1b7868ba2468f05c580f2ce2 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Mon, 25 Nov 2019 11:21:00 -0600 Subject: [PATCH 077/888] MQE-1520: Consolidate WAIT_TIMEOUT in .env and pageload_timeout Updated .env.example --- etc/config/.env.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/config/.env.example b/etc/config/.env.example index bb1d1ad63..e290c7815 100644 --- a/etc/config/.env.example +++ b/etc/config/.env.example @@ -53,7 +53,7 @@ MODULE_WHITELIST=Magento_Framework,ConfigurableProductWishlist,ConfigurableProdu #ALLOW_SKIPPED=true #*** Default timeout for wait actions -#WAIT_TIMEOUT=10 +#WAIT_TIMEOUT=30 #*** Uncomment and set to enable browser log entries on actions in Allure. Blacklist is used to filter logs of a specific "source" #ENABLE_BROWSER_LOG=true From d4faf137dbefe25850deea423a1c23cd803f57a1 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Mon, 25 Nov 2019 15:07:05 -0600 Subject: [PATCH 078/888] MQE-1711: Switch between Developer mode and Production mode takes long time and the test end up time out fixed issue with signature of magentoCLI --- .../ActionGroupWithStepKeyReferences.txt | 2 +- .../Resources/BasicFunctionalTest.txt | 4 +++- .../TestModule/Test/BasicFunctionalTest.xml | 1 + .../Module/MagentoWebDriver.php | 18 +++++++++--------- .../Util/TestGenerator.php | 4 ++-- 5 files changed, 16 insertions(+), 13 deletions(-) diff --git a/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt b/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt index 2bb414230..d1cae1da4 100644 --- a/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt +++ b/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt @@ -45,7 +45,7 @@ class ActionGroupWithStepKeyReferencesCest $I->fillField($action1); // stepKey: action1ActionGroup $I->comment("Invocation stepKey will be appended in non stepKey instances"); $action3ActionGroup = $I->executeJS($action3ActionGroup); // stepKey: action3ActionGroup - $action4ActionGroup = $I->magentoCLI($action4ActionGroup, "\"stuffHere\"", 60); // stepKey: action4ActionGroup + $action4ActionGroup = $I->magentoCLI($action4ActionGroup, 60, "\"stuffHere\""); // stepKey: action4ActionGroup $I->comment($action4ActionGroup); $date = new \DateTime(); $date->setTimestamp(strtotime("{$action5}")); diff --git a/dev/tests/verification/Resources/BasicFunctionalTest.txt b/dev/tests/verification/Resources/BasicFunctionalTest.txt index c5dc13e2e..2bae80f80 100644 --- a/dev/tests/verification/Resources/BasicFunctionalTest.txt +++ b/dev/tests/verification/Resources/BasicFunctionalTest.txt @@ -126,8 +126,10 @@ class BasicFunctionalTestCest $grabMultipleKey1 = $I->grabMultiple(".functionalTestSelector"); // stepKey: grabMultipleKey1 $grabTextFromKey1 = $I->grabTextFrom(".functionalTestSelector"); // stepKey: grabTextFromKey1 $grabValueFromKey1 = $I->grabValueFrom(".functionalTestSelector"); // stepKey: grabValueFromKey1 - $magentoCli1 = $I->magentoCLI("maintenance:enable", "\"stuffHere\"", 60); // stepKey: magentoCli1 + $magentoCli1 = $I->magentoCLI("maintenance:enable", 60, "\"stuffHere\""); // stepKey: magentoCli1 $I->comment($magentoCli1); + $magentoCli2 = $I->magentoCLI("maintenance:enable", 120, "\"stuffHere\""); // stepKey: magentoCli2 + $I->comment($magentoCli2); $I->makeScreenshot("screenShotInput"); // stepKey: makeScreenshotKey1 $I->maximizeWindow(); // stepKey: maximizeWindowKey1 $I->moveBack(); // stepKey: moveBackKey1 diff --git a/dev/tests/verification/TestModule/Test/BasicFunctionalTest.xml b/dev/tests/verification/TestModule/Test/BasicFunctionalTest.xml index ff0708554..09fedd1b8 100644 --- a/dev/tests/verification/TestModule/Test/BasicFunctionalTest.xml +++ b/dev/tests/verification/TestModule/Test/BasicFunctionalTest.xml @@ -76,6 +76,7 @@ + diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 2d09e7f2a..87e3b0c08 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -511,15 +511,15 @@ public function scrollToTopOfPage() * Takes given $command and executes it against bin/magento or custom exposed entrypoint. Returns command output. * * @param string $command - * @param string $arguments * @param integer $timeout + * @param string $arguments * @return string * * @throws TestFrameworkException */ - public function magentoCLI($command, $arguments = null, $timeout = null) + public function magentoCLI($command, $timeout = null, $arguments = null) { - return $this->curlExecMagentoCLI($command, $arguments, $timeout); + return $this->curlExecMagentoCLI($command, $timeout, $arguments); //TODO: calling bin/magento from pipeline is timing out, needs investigation (ref: MQE-1774) // try { // return $this->shellExecMagentoCLI($command, $arguments); @@ -674,18 +674,18 @@ public function fillSecretField($field, $value) * The data is decrypted immediately prior to data creation to avoid exposure in console or log. * * @param string $command - * @param null $arguments * @param null $timeout + * @param null $arguments * @throws TestFrameworkException * @return string */ - public function magentoCLISecret($command, $arguments = null, $timeout = null) + public function magentoCLISecret($command, $timeout = null, $arguments = null) { // to protect any secrets from being printed to console the values are executed only at the webdriver level as a // decrypted value $decryptedCommand = CredentialStore::getInstance()->decryptAllSecretsInString($command); - return $this->magentoCLI($decryptedCommand, $arguments, $timeout); + return $this->magentoCLI($decryptedCommand, $timeout, $arguments); } /** @@ -845,7 +845,7 @@ public function makeScreenshot($name = null) * @return string * @SuppressWarnings(PHPMD.UnusedPrivateMethod) */ - private function shellExecMagentoCLI($command, $arguments, $timeout): string + private function shellExecMagentoCLI($command, $arguments, $timeout = 60): string { $php = PHP_BINDIR ? PHP_BINDIR . DIRECTORY_SEPARATOR. 'php' : 'php'; $binMagento = realpath(MAGENTO_BP . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'magento'); @@ -865,13 +865,13 @@ private function shellExecMagentoCLI($command, $arguments, $timeout): string * Takes given $command and executes it against exposed MTF CLI entry point. Returns response from server. * * @param string $command - * @param string $arguments * @param integer $timeout + * @param string $arguments * * @return string * @throws TestFrameworkException */ - private function curlExecMagentoCLI($command, $arguments, $timeout): string + private function curlExecMagentoCLI($command, $timeout, $arguments): string { // Remove index.php if it's present in url $baseUrl = rtrim( diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index a566e95f6..a73054b08 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1285,8 +1285,8 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $actor, $actionObject, $command, - $arguments, - $time + $time, + $arguments ); $testSteps .= sprintf(self::STEP_KEY_ANNOTATION, $stepKey) . PHP_EOL; $testSteps .= sprintf( From 67472f582a3d386e2c47c6a17cb107edbf07d360 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Mon, 25 Nov 2019 15:23:52 -0600 Subject: [PATCH 079/888] MQE-1711: Switch between Developer mode and Production mode takes long time and the test end up time out fixed issue with signature of magentoCLI --- .../FunctionalTestingFramework/Module/MagentoWebDriver.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 87e3b0c08..66d103b0c 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -838,14 +838,14 @@ public function makeScreenshot($name = null) * Takes given $command and executes it against bin/magento executable. Returns stdout output from the command. * * @param string $command - * @param string $arguments * @param integer $timeout + * @param string $arguments * * @throws \RuntimeException * @return string * @SuppressWarnings(PHPMD.UnusedPrivateMethod) */ - private function shellExecMagentoCLI($command, $arguments, $timeout = 60): string + private function shellExecMagentoCLI($command, $timeout, $arguments): string { $php = PHP_BINDIR ? PHP_BINDIR . DIRECTORY_SEPARATOR. 'php' : 'php'; $binMagento = realpath(MAGENTO_BP . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'magento'); From 0f7bd4a3d63a7c80cdd4d80c6d326d0918698144 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Tue, 26 Nov 2019 10:34:47 -0600 Subject: [PATCH 080/888] MQE-1711: Switch between Developer mode and Production mode takes long time and the test end up time out Added verification test for magentoCLISecret. --- dev/tests/verification/Resources/BasicFunctionalTest.txt | 4 ++++ .../verification/TestModule/Test/BasicFunctionalTest.xml | 2 ++ 2 files changed, 6 insertions(+) diff --git a/dev/tests/verification/Resources/BasicFunctionalTest.txt b/dev/tests/verification/Resources/BasicFunctionalTest.txt index 2bae80f80..bc7fe0b94 100644 --- a/dev/tests/verification/Resources/BasicFunctionalTest.txt +++ b/dev/tests/verification/Resources/BasicFunctionalTest.txt @@ -130,6 +130,10 @@ class BasicFunctionalTestCest $I->comment($magentoCli1); $magentoCli2 = $I->magentoCLI("maintenance:enable", 120, "\"stuffHere\""); // stepKey: magentoCli2 $I->comment($magentoCli2); + $magentoCli3 = $I->magentoCLISecret("config:set somePath " . CredentialStore::getInstance()->getSecret("someKey"), 60); // stepKey: magentoCli3 + $I->comment($magentoCli3); // stepKey: magentoCli3 + $magentoCli4 = $I->magentoCLISecret("config:set somePath " . CredentialStore::getInstance()->getSecret("someKey"), 120); // stepKey: magentoCli4 + $I->comment($magentoCli4); // stepKey: magentoCli4 $I->makeScreenshot("screenShotInput"); // stepKey: makeScreenshotKey1 $I->maximizeWindow(); // stepKey: maximizeWindowKey1 $I->moveBack(); // stepKey: moveBackKey1 diff --git a/dev/tests/verification/TestModule/Test/BasicFunctionalTest.xml b/dev/tests/verification/TestModule/Test/BasicFunctionalTest.xml index 09fedd1b8..c23a3ce60 100644 --- a/dev/tests/verification/TestModule/Test/BasicFunctionalTest.xml +++ b/dev/tests/verification/TestModule/Test/BasicFunctionalTest.xml @@ -77,6 +77,8 @@ + + From f6a7763225ab6df1b331f00b8c33f82459c5dd08 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Tue, 26 Nov 2019 10:42:59 -0600 Subject: [PATCH 081/888] MQE-1711: Switch between Developer mode and Production mode takes long time and the test end up time out Resolved conflicts in ActionObject. --- .../FunctionalTestingFramework/Test/Objects/ActionObject.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php index eb5bfd5ce..ad5ca0c33 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php @@ -72,7 +72,6 @@ class ActionObject const ACTION_ATTRIBUTE_VARIABLE_REGEX_PARAMETER = '/\(.+\)/'; const ACTION_ATTRIBUTE_VARIABLE_REGEX_PATTERN = '/({{[\w]+\.[\w\[\]]+}})|({{[\w]+\.[\w]+\((?(?!}}).)+\)}})/'; const STRING_PARAMETER_REGEX = "/'[^']+'/"; - const DEFAULT_WAIT_TIMEOUT = 10; const DEFAULT_COMMAND_WAIT_TIMEOUT = 60; const ACTION_ATTRIBUTE_USERINPUT = 'userInput'; const ACTION_TYPE_COMMENT = 'comment'; From ebe8b149ad4aefc40e43c8ac5aa57fac1d1362f7 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Wed, 27 Nov 2019 13:11:33 -0600 Subject: [PATCH 082/888] MQE-1379: Fix MFTF custom actions to fully support Codeception dry-run functionality --- .../ActionGroupContainsStepKeyInArgText.txt | 2 - .../ActionGroupMergedViaInsertAfter.txt | 2 - .../ActionGroupMergedViaInsertBefore.txt | 2 - .../Resources/ActionGroupSkipReadiness.txt | 2 - .../Resources/ActionGroupToExtend.txt | 2 - .../Resources/ActionGroupUsingCreateData.txt | 6 +- .../ActionGroupUsingNestedArgument.txt | 2 - .../ActionGroupWithDataOverrideTest.txt | 4 +- .../Resources/ActionGroupWithDataTest.txt | 4 +- ...hDefaultArgumentAndStringSelectorParam.txt | 2 - ...eParameterSelectorsFromDefaultArgument.txt | 2 - .../Resources/ActionGroupWithNoArguments.txt | 2 - .../ActionGroupWithNoDefaultTest.txt | 4 +- ...roupWithParameterizedElementWithHyphen.txt | 2 - ...meterizedElementsWithStepKeyReferences.txt | 6 +- ...thPassedArgumentAndStringSelectorParam.txt | 2 - .../ActionGroupWithPersistedData.txt | 16 +- ...tionGroupWithSectionAndDataAsArguments.txt | 2 - ...WithSimpleDataUsageFromDefaultArgument.txt | 2 - ...pWithSimpleDataUsageFromPassedArgument.txt | 10 +- ...leParameterSelectorFromDefaultArgument.txt | 2 - ...gleParameterSelectorFromPassedArgument.txt | 2 - .../ActionGroupWithStepKeyReferences.txt | 14 +- .../ActionGroupWithTopLevelPersistedData.txt | 14 +- .../ArgumentWithSameNameAsElement.txt | 4 +- .../verification/Resources/AssertTest.txt | 28 ++-- .../Resources/BasicActionGroupTest.txt | 4 +- .../Resources/BasicFunctionalTest.txt | 4 +- .../verification/Resources/BasicMergeTest.txt | 2 - .../Resources/CharacterReplacementTest.txt | 2 - .../Resources/ChildExtendedTestAddHooks.txt | 2 - .../Resources/ChildExtendedTestMerging.txt | 2 - .../Resources/ChildExtendedTestNoParent.txt | 2 - .../ChildExtendedTestRemoveAction.txt | 2 - .../ChildExtendedTestRemoveHookAction.txt | 2 - .../Resources/ChildExtendedTestReplace.txt | 2 - .../ChildExtendedTestReplaceHook.txt | 2 - .../Resources/DataActionsTest.txt | 18 +- .../Resources/DataReplacementTest.txt | 2 - .../Resources/ExecuteInSeleniumTest.txt | 2 - .../Resources/ExecuteJsEscapingTest.txt | 8 +- .../Resources/ExtendParentDataTest.txt | 4 +- .../Resources/ExtendedActionGroup.txt | 2 - .../ExtendedChildTestInSuiteCest.txt | 2 - .../Resources/ExtendedChildTestNotInSuite.txt | 2 - .../Resources/ExtendedParameterArrayTest.txt | 4 +- .../Resources/ExtendedRemoveActionGroup.txt | 2 - .../Resources/ExtendingSkippedTest.txt | 2 - .../Resources/HookActionsTest.txt | 12 +- .../Resources/LocatorFunctionTest.txt | 12 +- .../Resources/MergeMassViaInsertAfter.txt | 2 - .../Resources/MergeMassViaInsertBefore.txt | 2 - .../verification/Resources/MergeSkip.txt | 2 - .../Resources/MergedActionGroupTest.txt | 4 +- .../Resources/MergedReferencesTest.txt | 2 - .../Resources/MultipleActionGroupsTest.txt | 4 +- .../Resources/PageReplacementTest.txt | 10 +- .../Resources/ParameterArrayTest.txt | 24 ++- .../Resources/ParentExtendedTest.txt | 2 - .../PersistedAndXmlEntityArguments.txt | 4 +- .../Resources/PersistedReplacementTest.txt | 50 +++--- .../PersistenceActionGroupAppendingTest.txt | 22 ++- .../Resources/PersistenceCustomFieldsTest.txt | 30 ++-- .../Resources/SectionReplacementTest.txt | 20 +-- .../verification/Resources/SkippedTest.txt | 2 - .../Resources/SkippedTestNoIssues.txt | 2 - .../Resources/SkippedTestTwoIssues.txt | 2 - .../Resources/SkippedTestWithHooks.txt | 2 - .../Resources/XmlCommentedActionGroupTest.txt | 2 - .../Resources/XmlCommentedTest.txt | 2 - .../Tests/SecretCredentialDataTest.php | 12 +- etc/config/functional.suite.dist.yml | 1 + .../Handlers/PersistedObjectHandler.php | 1 - .../DataGenerator/Persist/CurlHandler.php | 8 +- .../Module/MagentoActionProxies.php | 157 ++++++++++++++++++ .../Test/Objects/ActionObject.php | 2 +- .../Util/TestGenerator.php | 40 +++-- 77 files changed, 341 insertions(+), 308 deletions(-) create mode 100644 src/Magento/FunctionalTestingFramework/Module/MagentoActionProxies.php diff --git a/dev/tests/verification/Resources/ActionGroupContainsStepKeyInArgText.txt b/dev/tests/verification/Resources/ActionGroupContainsStepKeyInArgText.txt index d7e31b5f2..1eb3d6566 100644 --- a/dev/tests/verification/Resources/ActionGroupContainsStepKeyInArgText.txt +++ b/dev/tests/verification/Resources/ActionGroupContainsStepKeyInArgText.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/ActionGroupMergedViaInsertAfter.txt b/dev/tests/verification/Resources/ActionGroupMergedViaInsertAfter.txt index 127b9cc59..b4745e0c0 100644 --- a/dev/tests/verification/Resources/ActionGroupMergedViaInsertAfter.txt +++ b/dev/tests/verification/Resources/ActionGroupMergedViaInsertAfter.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/ActionGroupMergedViaInsertBefore.txt b/dev/tests/verification/Resources/ActionGroupMergedViaInsertBefore.txt index 1486d042e..b27328275 100644 --- a/dev/tests/verification/Resources/ActionGroupMergedViaInsertBefore.txt +++ b/dev/tests/verification/Resources/ActionGroupMergedViaInsertBefore.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/ActionGroupSkipReadiness.txt b/dev/tests/verification/Resources/ActionGroupSkipReadiness.txt index d11d5c238..11025fefe 100644 --- a/dev/tests/verification/Resources/ActionGroupSkipReadiness.txt +++ b/dev/tests/verification/Resources/ActionGroupSkipReadiness.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/ActionGroupToExtend.txt b/dev/tests/verification/Resources/ActionGroupToExtend.txt index d7e72260d..133c9fb9b 100644 --- a/dev/tests/verification/Resources/ActionGroupToExtend.txt +++ b/dev/tests/verification/Resources/ActionGroupToExtend.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt b/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt index 96134fd86..8ec0a88a8 100644 --- a/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt +++ b/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; @@ -27,7 +25,7 @@ class ActionGroupUsingCreateDataCest { $I->comment("Entering Action Group [Key1] actionGroupWithCreateData"); $I->comment("[createCategoryKey1] create 'ApiCategory' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createCategoryKey1", "hook", "ApiCategory", @@ -36,7 +34,7 @@ class ActionGroupUsingCreateDataCest ); $I->comment("[createConfigProductKey1] create 'ApiConfigurableProduct' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createConfigProductKey1", "hook", "ApiConfigurableProduct", diff --git a/dev/tests/verification/Resources/ActionGroupUsingNestedArgument.txt b/dev/tests/verification/Resources/ActionGroupUsingNestedArgument.txt index b69ee6c9d..5814e85e0 100644 --- a/dev/tests/verification/Resources/ActionGroupUsingNestedArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupUsingNestedArgument.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt b/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt index c0498101d..9ad3f7127 100644 --- a/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt +++ b/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; @@ -27,7 +25,7 @@ class ActionGroupWithDataOverrideTestCest public function _before(AcceptanceTester $I) { $I->comment("[createPersonParam] create 'ReplacementPerson' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createPersonParam", "hook", "ReplacementPerson", diff --git a/dev/tests/verification/Resources/ActionGroupWithDataTest.txt b/dev/tests/verification/Resources/ActionGroupWithDataTest.txt index 01a87104d..f1a0f6219 100644 --- a/dev/tests/verification/Resources/ActionGroupWithDataTest.txt +++ b/dev/tests/verification/Resources/ActionGroupWithDataTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; @@ -27,7 +25,7 @@ class ActionGroupWithDataTestCest public function _before(AcceptanceTester $I) { $I->comment("[createPersonParam] create 'ReplacementPerson' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createPersonParam", "hook", "ReplacementPerson", diff --git a/dev/tests/verification/Resources/ActionGroupWithDefaultArgumentAndStringSelectorParam.txt b/dev/tests/verification/Resources/ActionGroupWithDefaultArgumentAndStringSelectorParam.txt index ce8a4aed8..289bbe4e1 100644 --- a/dev/tests/verification/Resources/ActionGroupWithDefaultArgumentAndStringSelectorParam.txt +++ b/dev/tests/verification/Resources/ActionGroupWithDefaultArgumentAndStringSelectorParam.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.txt b/dev/tests/verification/Resources/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.txt index b7bef0135..4e94978ad 100644 --- a/dev/tests/verification/Resources/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/ActionGroupWithNoArguments.txt b/dev/tests/verification/Resources/ActionGroupWithNoArguments.txt index 6b81a187f..6158b5af7 100644 --- a/dev/tests/verification/Resources/ActionGroupWithNoArguments.txt +++ b/dev/tests/verification/Resources/ActionGroupWithNoArguments.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt b/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt index 6125c7697..99615c728 100644 --- a/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt +++ b/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; @@ -27,7 +25,7 @@ class ActionGroupWithNoDefaultTestCest public function _before(AcceptanceTester $I) { $I->comment("[createPersonParam] create 'ReplacementPerson' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createPersonParam", "hook", "ReplacementPerson", diff --git a/dev/tests/verification/Resources/ActionGroupWithParameterizedElementWithHyphen.txt b/dev/tests/verification/Resources/ActionGroupWithParameterizedElementWithHyphen.txt index 163ebc6ba..52dc8bd1b 100644 --- a/dev/tests/verification/Resources/ActionGroupWithParameterizedElementWithHyphen.txt +++ b/dev/tests/verification/Resources/ActionGroupWithParameterizedElementWithHyphen.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/ActionGroupWithParameterizedElementsWithStepKeyReferences.txt b/dev/tests/verification/Resources/ActionGroupWithParameterizedElementsWithStepKeyReferences.txt index de7af8209..561f4d1b2 100644 --- a/dev/tests/verification/Resources/ActionGroupWithParameterizedElementsWithStepKeyReferences.txt +++ b/dev/tests/verification/Resources/ActionGroupWithParameterizedElementsWithStepKeyReferences.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; @@ -32,7 +30,7 @@ class ActionGroupWithParameterizedElementsWithStepKeyReferencesCest $testVariableActionGroup = $I->executeJS("return 1"); // stepKey: testVariableActionGroup $testVariable2ActionGroup = $I->executeJS("return 'test'"); // stepKey: testVariable2ActionGroup $I->comment("[createSimpleDataActionGroup] create 'simpleData' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createSimpleDataActionGroup", "test", "simpleData", @@ -42,7 +40,7 @@ class ActionGroupWithParameterizedElementsWithStepKeyReferencesCest $I->click("#{$testVariable2ActionGroup} .John"); // stepKey: click1ActionGroup $I->click("#Doe-" . msq("simpleParamData") . "prename .{$testVariableActionGroup}"); // stepKey: click2ActionGroup - $I->seeElement("//div[@name='Tiberius'][@class={$testVariableActionGroup}][@data-element='{$testVariable2ActionGroup}'][" . PersistedObjectHandler::getInstance()->retrieveEntityField('createSimpleData', 'name', 'test') . "]"); // stepKey: see1ActionGroup + $I->seeElement("//div[@name='Tiberius'][@class={$testVariableActionGroup}][@data-element='{$testVariable2ActionGroup}'][" . $I->retrieveEntityField('createSimpleData', 'name', 'test') . "]"); // stepKey: see1ActionGroup $I->comment("Exiting Action Group [actionGroup] actionGroupWithParametrizedSelectors"); } } diff --git a/dev/tests/verification/Resources/ActionGroupWithPassedArgumentAndStringSelectorParam.txt b/dev/tests/verification/Resources/ActionGroupWithPassedArgumentAndStringSelectorParam.txt index 9720595e0..254fbe0f2 100644 --- a/dev/tests/verification/Resources/ActionGroupWithPassedArgumentAndStringSelectorParam.txt +++ b/dev/tests/verification/Resources/ActionGroupWithPassedArgumentAndStringSelectorParam.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt b/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt index da0480379..0bec544bf 100644 --- a/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt +++ b/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; @@ -27,7 +25,7 @@ class ActionGroupWithPersistedDataCest public function _before(AcceptanceTester $I) { $I->comment("[createPersonParam] create 'ReplacementPerson' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createPersonParam", "hook", "ReplacementPerson", @@ -74,7 +72,7 @@ class ActionGroupWithPersistedDataCest public function ActionGroupWithPersistedData(AcceptanceTester $I) { $I->comment("[createPerson] create 'DefaultPerson' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createPerson", "test", "DefaultPerson", @@ -83,11 +81,11 @@ class ActionGroupWithPersistedDataCest ); $I->comment("Entering Action Group [actionGroupWithPersistedData1] FunctionalActionGroupWithData"); - $I->amOnPage("/" . PersistedObjectHandler::getInstance()->retrieveEntityField('createPerson', 'firstname', 'test') . "/" . PersistedObjectHandler::getInstance()->retrieveEntityField('createPerson', 'lastname', 'test') . ".html"); // stepKey: amOnPage1ActionGroupWithPersistedData1 - $I->fillField("#foo", PersistedObjectHandler::getInstance()->retrieveEntityField('createPerson', 'firstname', 'test')); // stepKey: fillField1ActionGroupWithPersistedData1 - $I->fillField("#bar", PersistedObjectHandler::getInstance()->retrieveEntityField('createPerson', 'lastname', 'test')); // stepKey: fillField2ActionGroupWithPersistedData1 - $I->searchAndMultiSelectOption("#foo", [PersistedObjectHandler::getInstance()->retrieveEntityField('createPerson', 'firstname', 'test'), PersistedObjectHandler::getInstance()->retrieveEntityField('createPerson', 'lastname', 'test')]); // stepKey: multi1ActionGroupWithPersistedData1 - $I->see("#element ." . PersistedObjectHandler::getInstance()->retrieveEntityField('createPerson', 'firstname', 'test')); // stepKey: see1ActionGroupWithPersistedData1 + $I->amOnPage("/" . $I->retrieveEntityField('createPerson', 'firstname', 'test') . "/" . $I->retrieveEntityField('createPerson', 'lastname', 'test') . ".html"); // stepKey: amOnPage1ActionGroupWithPersistedData1 + $I->fillField("#foo", $I->retrieveEntityField('createPerson', 'firstname', 'test')); // stepKey: fillField1ActionGroupWithPersistedData1 + $I->fillField("#bar", $I->retrieveEntityField('createPerson', 'lastname', 'test')); // stepKey: fillField2ActionGroupWithPersistedData1 + $I->searchAndMultiSelectOption("#foo", [$I->retrieveEntityField('createPerson', 'firstname', 'test'), $I->retrieveEntityField('createPerson', 'lastname', 'test')]); // stepKey: multi1ActionGroupWithPersistedData1 + $I->see("#element ." . $I->retrieveEntityField('createPerson', 'firstname', 'test')); // stepKey: see1ActionGroupWithPersistedData1 $I->comment("Exiting Action Group [actionGroupWithPersistedData1] FunctionalActionGroupWithData"); } } diff --git a/dev/tests/verification/Resources/ActionGroupWithSectionAndDataAsArguments.txt b/dev/tests/verification/Resources/ActionGroupWithSectionAndDataAsArguments.txt index a0b6d0074..ec6111062 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSectionAndDataAsArguments.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSectionAndDataAsArguments.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromDefaultArgument.txt b/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromDefaultArgument.txt index 4d3da18a4..f4faf0773 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromDefaultArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromDefaultArgument.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromPassedArgument.txt b/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromPassedArgument.txt index d866c3992..86791407d 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromPassedArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromPassedArgument.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; @@ -46,19 +44,19 @@ class ActionGroupWithSimpleDataUsageFromPassedArgumentCest $I->see("simpleData.firstname", "#element .simpleData.firstname"); // stepKey: see1ActionGroup2 $I->comment("Exiting Action Group [actionGroup2] actionGroupWithStringUsage"); $I->comment("Entering Action Group [actionGroup3] actionGroupWithStringUsage"); - $I->see(PersistedObjectHandler::getInstance()->retrieveEntityField('persisted', 'data', 'test'), "#element ." . PersistedObjectHandler::getInstance()->retrieveEntityField('persisted', 'data', 'test')); // stepKey: see1ActionGroup3 + $I->see($I->retrieveEntityField('persisted', 'data', 'test'), "#element ." . $I->retrieveEntityField('persisted', 'data', 'test')); // stepKey: see1ActionGroup3 $I->comment("Exiting Action Group [actionGroup3] actionGroupWithStringUsage"); $I->comment("Entering Action Group [actionGroup4] actionGroupWithEntityUsage"); $I->see("John", "#element .John"); // stepKey: see1ActionGroup4 $I->comment("Exiting Action Group [actionGroup4] actionGroupWithEntityUsage"); $I->comment("Entering Action Group [actionGroup5] actionGroupWithEntityUsage"); - $I->see(PersistedObjectHandler::getInstance()->retrieveEntityField('simpleData', 'firstname', 'test'), "#element ." . PersistedObjectHandler::getInstance()->retrieveEntityField('simpleData', 'firstname', 'test')); // stepKey: see1ActionGroup5 + $I->see($I->retrieveEntityField('simpleData', 'firstname', 'test'), "#element ." . $I->retrieveEntityField('simpleData', 'firstname', 'test')); // stepKey: see1ActionGroup5 $I->comment("Exiting Action Group [actionGroup5] actionGroupWithEntityUsage"); $I->comment("Entering Action Group [actionGroup6] actionGroupWithEntityUsage"); - $I->see(PersistedObjectHandler::getInstance()->retrieveEntityField('simpleData', 'firstname[0]', 'test'), "#element ." . PersistedObjectHandler::getInstance()->retrieveEntityField('simpleData', 'firstname[0]', 'test')); // stepKey: see1ActionGroup6 + $I->see($I->retrieveEntityField('simpleData', 'firstname[0]', 'test'), "#element ." . $I->retrieveEntityField('simpleData', 'firstname[0]', 'test')); // stepKey: see1ActionGroup6 $I->comment("Exiting Action Group [actionGroup6] actionGroupWithEntityUsage"); $I->comment("Entering Action Group [actionGroup7] actionGroupWithEntityUsage"); - $I->see(PersistedObjectHandler::getInstance()->retrieveEntityField('simpleData', 'firstname[data_index]', 'test'), "#element ." . PersistedObjectHandler::getInstance()->retrieveEntityField('simpleData', 'firstname[data_index]', 'test')); // stepKey: see1ActionGroup7 + $I->see($I->retrieveEntityField('simpleData', 'firstname[data_index]', 'test'), "#element ." . $I->retrieveEntityField('simpleData', 'firstname[data_index]', 'test')); // stepKey: see1ActionGroup7 $I->comment("Exiting Action Group [actionGroup7] actionGroupWithEntityUsage"); } } diff --git a/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromDefaultArgument.txt b/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromDefaultArgument.txt index af7af43a4..5d8298108 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromDefaultArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromDefaultArgument.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromPassedArgument.txt b/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromPassedArgument.txt index 096623789..283a9fdd7 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromPassedArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromPassedArgument.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt b/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt index eddaaf784..c8ddb15bf 100644 --- a/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt +++ b/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; @@ -30,7 +28,7 @@ class ActionGroupWithStepKeyReferencesCest { $I->comment("Entering Action Group [actionGroup] FunctionActionGroupWithStepKeyReferences"); $I->comment("[createSimpleDataActionGroup] create 'simpleData' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createSimpleDataActionGroup", "test", "simpleData", @@ -39,7 +37,7 @@ class ActionGroupWithStepKeyReferencesCest ); $grabTextDataActionGroup = $I->grabTextFrom(".class"); // stepKey: grabTextDataActionGroup - $I->fillField(".{$grabTextDataActionGroup}", PersistedObjectHandler::getInstance()->retrieveEntityField('createSimpleDataActionGroup', 'field', 'test')); // stepKey: fill1ActionGroup + $I->fillField(".{$grabTextDataActionGroup}", $I->retrieveEntityField('createSimpleDataActionGroup', 'field', 'test')); // stepKey: fill1ActionGroup $I->comment("Invocation stepKey will not be appended in non stepKey instances"); $I->click($action0); // stepKey: action0ActionGroup $I->fillField($action1); // stepKey: action1ActionGroup @@ -54,13 +52,13 @@ class ActionGroupWithStepKeyReferencesCest $action6ActionGroup = $I->formatMoney($action6ActionGroup); // stepKey: action6ActionGroup $I->comment("[action7ActionGroup] delete entity '{$action7ActionGroupActionGroup}'"); - PersistedObjectHandler::getInstance()->deleteEntity( + $I->deleteEntity( "{$action7ActionGroupActionGroup}", "test" ); $I->comment("[action8ActionGroup] get '{$action8}' entity"); - PersistedObjectHandler::getInstance()->getEntity( + $I->getEntity( "action8ActionGroup", "test", "{$action8}", @@ -69,7 +67,7 @@ class ActionGroupWithStepKeyReferencesCest ); $I->comment("[action9ActionGroup] update '1' entity to '{$action9}'"); - PersistedObjectHandler::getInstance()->updateEntity( + $I->updateEntity( "1", "test", "{$action9}", @@ -77,7 +75,7 @@ class ActionGroupWithStepKeyReferencesCest ); $I->comment("[action10ActionGroup] create '{$action10}' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "action10ActionGroup", "test", "{$action10}", diff --git a/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt b/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt index ef1a5636c..6567bdbb0 100644 --- a/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt +++ b/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; @@ -27,7 +25,7 @@ class ActionGroupWithTopLevelPersistedDataCest public function _before(AcceptanceTester $I) { $I->comment("[createPersonParam] create 'ReplacementPerson' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createPersonParam", "hook", "ReplacementPerson", @@ -74,11 +72,11 @@ class ActionGroupWithTopLevelPersistedDataCest public function ActionGroupWithTopLevelPersistedData(AcceptanceTester $I) { $I->comment("Entering Action Group [actionGroupWithPersistedData1] FunctionalActionGroupWithData"); - $I->amOnPage("/" . PersistedObjectHandler::getInstance()->retrieveEntityField('createPersonParam', 'firstname', 'test') . "/" . PersistedObjectHandler::getInstance()->retrieveEntityField('createPersonParam', 'lastname', 'test') . ".html"); // stepKey: amOnPage1ActionGroupWithPersistedData1 - $I->fillField("#foo", PersistedObjectHandler::getInstance()->retrieveEntityField('createPersonParam', 'firstname', 'test')); // stepKey: fillField1ActionGroupWithPersistedData1 - $I->fillField("#bar", PersistedObjectHandler::getInstance()->retrieveEntityField('createPersonParam', 'lastname', 'test')); // stepKey: fillField2ActionGroupWithPersistedData1 - $I->searchAndMultiSelectOption("#foo", [PersistedObjectHandler::getInstance()->retrieveEntityField('createPersonParam', 'firstname', 'test'), PersistedObjectHandler::getInstance()->retrieveEntityField('createPersonParam', 'lastname', 'test')]); // stepKey: multi1ActionGroupWithPersistedData1 - $I->see("#element ." . PersistedObjectHandler::getInstance()->retrieveEntityField('createPersonParam', 'firstname', 'test')); // stepKey: see1ActionGroupWithPersistedData1 + $I->amOnPage("/" . $I->retrieveEntityField('createPersonParam', 'firstname', 'test') . "/" . $I->retrieveEntityField('createPersonParam', 'lastname', 'test') . ".html"); // stepKey: amOnPage1ActionGroupWithPersistedData1 + $I->fillField("#foo", $I->retrieveEntityField('createPersonParam', 'firstname', 'test')); // stepKey: fillField1ActionGroupWithPersistedData1 + $I->fillField("#bar", $I->retrieveEntityField('createPersonParam', 'lastname', 'test')); // stepKey: fillField2ActionGroupWithPersistedData1 + $I->searchAndMultiSelectOption("#foo", [$I->retrieveEntityField('createPersonParam', 'firstname', 'test'), $I->retrieveEntityField('createPersonParam', 'lastname', 'test')]); // stepKey: multi1ActionGroupWithPersistedData1 + $I->see("#element ." . $I->retrieveEntityField('createPersonParam', 'firstname', 'test')); // stepKey: see1ActionGroupWithPersistedData1 $I->comment("Exiting Action Group [actionGroupWithPersistedData1] FunctionalActionGroupWithData"); } } diff --git a/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt b/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt index 2da03b506..54bb012e9 100644 --- a/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt +++ b/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; @@ -27,7 +25,7 @@ class ArgumentWithSameNameAsElementCest public function _before(AcceptanceTester $I) { $I->comment("[createPersonParam] create 'ReplacementPerson' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createPersonParam", "hook", "ReplacementPerson", diff --git a/dev/tests/verification/Resources/AssertTest.txt b/dev/tests/verification/Resources/AssertTest.txt index 28c38bc0b..50eb50e24 100644 --- a/dev/tests/verification/Resources/AssertTest.txt +++ b/dev/tests/verification/Resources/AssertTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; @@ -26,7 +24,7 @@ class AssertTestCest public function _before(AcceptanceTester $I) { $I->comment("[createData1] create 'ReplacementPerson' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createData1", "hook", "ReplacementPerson", @@ -46,7 +44,7 @@ class AssertTestCest public function AssertTest(AcceptanceTester $I) { $I->comment("[createData2] create 'UniquePerson' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createData2", "test", "UniquePerson", @@ -138,15 +136,15 @@ class AssertTestCest $I->expectException(new MyException('exception msg'), function() {$this->doSomethingBad();}); // stepKey: expectExceptionBackwardCompatible $I->comment("string type that use created data"); $I->comment("string type that use created data"); - $I->assertStringStartsWith("D", PersistedObjectHandler::getInstance()->retrieveEntityField('createData1', 'lastname', 'test') . ", " . PersistedObjectHandler::getInstance()->retrieveEntityField('createData1', 'firstname', 'test'), "fail"); // stepKey: assert1 - $I->assertStringStartsNotWith("W", PersistedObjectHandler::getInstance()->retrieveEntityField('createData2', 'firstname', 'test') . ", " . PersistedObjectHandler::getInstance()->retrieveEntityField('createData2', 'lastname', 'test'), "pass"); // stepKey: assert2 - $I->assertEquals(PersistedObjectHandler::getInstance()->retrieveEntityField('createData1', 'lastname', 'test'), PersistedObjectHandler::getInstance()->retrieveEntityField('createData1', 'lastname', 'test'), "pass"); // stepKey: assert5 + $I->assertStringStartsWith("D", $I->retrieveEntityField('createData1', 'lastname', 'test') . ", " . $I->retrieveEntityField('createData1', 'firstname', 'test'), "fail"); // stepKey: assert1 + $I->assertStringStartsNotWith("W", $I->retrieveEntityField('createData2', 'firstname', 'test') . ", " . $I->retrieveEntityField('createData2', 'lastname', 'test'), "pass"); // stepKey: assert2 + $I->assertEquals($I->retrieveEntityField('createData1', 'lastname', 'test'), $I->retrieveEntityField('createData1', 'lastname', 'test'), "pass"); // stepKey: assert5 $I->comment("array type that use created data"); $I->comment("array type that use created data"); - $I->assertArraySubset([PersistedObjectHandler::getInstance()->retrieveEntityField('createData1', 'lastname', 'test'), PersistedObjectHandler::getInstance()->retrieveEntityField('createData1', 'firstname', 'test')], [PersistedObjectHandler::getInstance()->retrieveEntityField('createData1', 'lastname', 'test'), PersistedObjectHandler::getInstance()->retrieveEntityField('createData1', 'firstname', 'test'), "1"], "pass"); // stepKey: assert9 - $I->assertArraySubset([PersistedObjectHandler::getInstance()->retrieveEntityField('createData2', 'firstname', 'test'), PersistedObjectHandler::getInstance()->retrieveEntityField('createData2', 'lastname', 'test')], [PersistedObjectHandler::getInstance()->retrieveEntityField('createData2', 'firstname', 'test'), PersistedObjectHandler::getInstance()->retrieveEntityField('createData2', 'lastname', 'test'), "1"], "pass"); // stepKey: assert10 - $I->assertArrayHasKey("lastname", ['lastname' => PersistedObjectHandler::getInstance()->retrieveEntityField('createData1', 'lastname', 'test'), 'firstname' => PersistedObjectHandler::getInstance()->retrieveEntityField('createData1', 'firstname', 'test')], "pass"); // stepKey: assert3 - $I->assertArrayHasKey("lastname", ['lastname' => PersistedObjectHandler::getInstance()->retrieveEntityField('createData2', 'lastname', 'test'), 'firstname' => PersistedObjectHandler::getInstance()->retrieveEntityField('createData2', 'firstname', 'test')], "pass"); // stepKey: assert4 + $I->assertArraySubset([$I->retrieveEntityField('createData1', 'lastname', 'test'), $I->retrieveEntityField('createData1', 'firstname', 'test')], [$I->retrieveEntityField('createData1', 'lastname', 'test'), $I->retrieveEntityField('createData1', 'firstname', 'test'), "1"], "pass"); // stepKey: assert9 + $I->assertArraySubset([$I->retrieveEntityField('createData2', 'firstname', 'test'), $I->retrieveEntityField('createData2', 'lastname', 'test')], [$I->retrieveEntityField('createData2', 'firstname', 'test'), $I->retrieveEntityField('createData2', 'lastname', 'test'), "1"], "pass"); // stepKey: assert10 + $I->assertArrayHasKey("lastname", ['lastname' => $I->retrieveEntityField('createData1', 'lastname', 'test'), 'firstname' => $I->retrieveEntityField('createData1', 'firstname', 'test')], "pass"); // stepKey: assert3 + $I->assertArrayHasKey("lastname", ['lastname' => $I->retrieveEntityField('createData2', 'lastname', 'test'), 'firstname' => $I->retrieveEntityField('createData2', 'firstname', 'test')], "pass"); // stepKey: assert4 $I->comment("this section can only be generated and cannot run"); $I->assertInstanceOf(User::class, $text, "pass"); // stepKey: assertInstanceOf $I->assertNotInstanceOf(User::class, 21, "pass"); // stepKey: assertNotInstanceOf @@ -156,8 +154,8 @@ class AssertTestCest $I->assertNull($text, "pass"); // stepKey: assertNull $I->expectException(new MyException('exception msg'), function() {$this->doSomethingBad();}); // stepKey: expectException $I->fail("fail"); // stepKey: fail - $I->fail(PersistedObjectHandler::getInstance()->retrieveEntityField('createData2', 'firstname', 'test') . " " . PersistedObjectHandler::getInstance()->retrieveEntityField('createData2', 'lastname', 'test')); // stepKey: assert7 - $I->fail(PersistedObjectHandler::getInstance()->retrieveEntityField('createData1', 'firstname', 'test') . " " . PersistedObjectHandler::getInstance()->retrieveEntityField('createData1', 'lastname', 'test')); // stepKey: assert8 + $I->fail($I->retrieveEntityField('createData2', 'firstname', 'test') . " " . $I->retrieveEntityField('createData2', 'lastname', 'test')); // stepKey: assert7 + $I->fail($I->retrieveEntityField('createData1', 'firstname', 'test') . " " . $I->retrieveEntityField('createData1', 'lastname', 'test')); // stepKey: assert8 $I->comment("assertElementContainsAttribute examples"); $I->assertElementContainsAttribute("#username", "class", "admin__control-text"); // stepKey: assertElementContainsAttribute1 $I->assertElementContainsAttribute("#username", "name", "login[username]"); // stepKey: assertElementContainsAttribute2 @@ -165,8 +163,8 @@ class AssertTestCest $I->assertElementContainsAttribute("#username", "data-validate", "{required:true}"); // stepKey: assertElementContainsAttribute4 $I->assertElementContainsAttribute(".admin__menu-overlay", "style", "display: none;"); // stepKey: assertElementContainsAttribute5 $I->assertElementContainsAttribute(".admin__menu-overlay", "border", "0"); // stepKey: assertElementContainsAttribute6 - $I->assertElementContainsAttribute("#username", "value", PersistedObjectHandler::getInstance()->retrieveEntityField('createData2', 'firstname', 'test')); // stepKey: assertElementContainsAttribute7 - $I->assertElementContainsAttribute("#username", "value", PersistedObjectHandler::getInstance()->retrieveEntityField('createData1', 'firstname', 'test')); // stepKey: assertElementContainsAttribute8 + $I->assertElementContainsAttribute("#username", "value", $I->retrieveEntityField('createData2', 'firstname', 'test')); // stepKey: assertElementContainsAttribute7 + $I->assertElementContainsAttribute("#username", "value", $I->retrieveEntityField('createData1', 'firstname', 'test')); // stepKey: assertElementContainsAttribute8 $I->comment("assert entity resolution"); $I->assertEquals("John", "Doe", "pass"); // stepKey: assertEqualsEntity } diff --git a/dev/tests/verification/Resources/BasicActionGroupTest.txt b/dev/tests/verification/Resources/BasicActionGroupTest.txt index 4bb9c1a95..79fbd3513 100644 --- a/dev/tests/verification/Resources/BasicActionGroupTest.txt +++ b/dev/tests/verification/Resources/BasicActionGroupTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; @@ -27,7 +25,7 @@ class BasicActionGroupTestCest public function _before(AcceptanceTester $I) { $I->comment("[createPersonParam] create 'ReplacementPerson' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createPersonParam", "hook", "ReplacementPerson", diff --git a/dev/tests/verification/Resources/BasicFunctionalTest.txt b/dev/tests/verification/Resources/BasicFunctionalTest.txt index f82c84119..6f95df23d 100644 --- a/dev/tests/verification/Resources/BasicFunctionalTest.txt +++ b/dev/tests/verification/Resources/BasicFunctionalTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; @@ -77,7 +75,7 @@ class BasicFunctionalTestCest $I->closeTab(); // stepKey: closeTabKey1 $I->conditionalClick(".functionalTestSelector", ".functionalDependentTestSelector", true); // stepKey: conditionalClickKey1 $I->comment("[deleteKey1] delete entity 'createKey1'"); - PersistedObjectHandler::getInstance()->deleteEntity( + $I->deleteEntity( "createKey1", "test" ); diff --git a/dev/tests/verification/Resources/BasicMergeTest.txt b/dev/tests/verification/Resources/BasicMergeTest.txt index 5421efe33..c6fb58e3a 100644 --- a/dev/tests/verification/Resources/BasicMergeTest.txt +++ b/dev/tests/verification/Resources/BasicMergeTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/CharacterReplacementTest.txt b/dev/tests/verification/Resources/CharacterReplacementTest.txt index db3852b17..61729cc8b 100644 --- a/dev/tests/verification/Resources/CharacterReplacementTest.txt +++ b/dev/tests/verification/Resources/CharacterReplacementTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt b/dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt index e03501707..8362cf513 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/ChildExtendedTestMerging.txt b/dev/tests/verification/Resources/ChildExtendedTestMerging.txt index a99843b48..590ba6003 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestMerging.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestMerging.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/ChildExtendedTestNoParent.txt b/dev/tests/verification/Resources/ChildExtendedTestNoParent.txt index 1eec9e48c..5d72176c5 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestNoParent.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestNoParent.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/ChildExtendedTestRemoveAction.txt b/dev/tests/verification/Resources/ChildExtendedTestRemoveAction.txt index 20aa62e28..766bfd331 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestRemoveAction.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestRemoveAction.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/ChildExtendedTestRemoveHookAction.txt b/dev/tests/verification/Resources/ChildExtendedTestRemoveHookAction.txt index 561fd24fa..8497c29af 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestRemoveHookAction.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestRemoveHookAction.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/ChildExtendedTestReplace.txt b/dev/tests/verification/Resources/ChildExtendedTestReplace.txt index 8d131a83f..3b2e9d369 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestReplace.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestReplace.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/ChildExtendedTestReplaceHook.txt b/dev/tests/verification/Resources/ChildExtendedTestReplaceHook.txt index ae0b02c20..53ae22361 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestReplaceHook.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestReplaceHook.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/DataActionsTest.txt b/dev/tests/verification/Resources/DataActionsTest.txt index 380db238d..bbfbafa21 100644 --- a/dev/tests/verification/Resources/DataActionsTest.txt +++ b/dev/tests/verification/Resources/DataActionsTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; @@ -26,7 +24,7 @@ class DataActionsTestCest public function _before(AcceptanceTester $I) { $I->comment("[createdInBefore] create 'entity' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createdInBefore", "hook", "entity", @@ -35,7 +33,7 @@ class DataActionsTestCest ); $I->comment("[updateInBefore] update 'createdInBefore' entity to 'entity'"); - PersistedObjectHandler::getInstance()->updateEntity( + $I->updateEntity( "createdInBefore", "hook", "entity", @@ -43,7 +41,7 @@ class DataActionsTestCest ); $I->comment("[deleteInBefore] delete entity 'createdInBefore'"); - PersistedObjectHandler::getInstance()->deleteEntity( + $I->deleteEntity( "createdInBefore", "hook" ); @@ -60,7 +58,7 @@ class DataActionsTestCest public function DataActionsTest(AcceptanceTester $I) { $I->comment("[createdInTest] create 'entity' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createdInTest", "test", "entity", @@ -69,7 +67,7 @@ class DataActionsTestCest ); $I->comment("[updateInTest] update 'createdInTest' entity to 'entity'"); - PersistedObjectHandler::getInstance()->updateEntity( + $I->updateEntity( "createdInTest", "test", "entity", @@ -77,13 +75,13 @@ class DataActionsTestCest ); $I->comment("[deleteInTest] delete entity 'createdInTest'"); - PersistedObjectHandler::getInstance()->deleteEntity( + $I->deleteEntity( "createdInTest", "test" ); $I->comment("[updatedDataOutOfScope] update 'createdInBefore' entity to 'entity'"); - PersistedObjectHandler::getInstance()->updateEntity( + $I->updateEntity( "createdInBefore", "test", "entity", @@ -91,7 +89,7 @@ class DataActionsTestCest ); $I->comment("[deleteDataOutOfScope] delete entity 'createdInBefore'"); - PersistedObjectHandler::getInstance()->deleteEntity( + $I->deleteEntity( "createdInBefore", "test" ); diff --git a/dev/tests/verification/Resources/DataReplacementTest.txt b/dev/tests/verification/Resources/DataReplacementTest.txt index 731ae63f8..461a1e928 100644 --- a/dev/tests/verification/Resources/DataReplacementTest.txt +++ b/dev/tests/verification/Resources/DataReplacementTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/ExecuteInSeleniumTest.txt b/dev/tests/verification/Resources/ExecuteInSeleniumTest.txt index 6b709a0cb..cfd7a14ce 100644 --- a/dev/tests/verification/Resources/ExecuteInSeleniumTest.txt +++ b/dev/tests/verification/Resources/ExecuteInSeleniumTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/ExecuteJsEscapingTest.txt b/dev/tests/verification/Resources/ExecuteJsEscapingTest.txt index f7618cbf9..d0b7acc83 100644 --- a/dev/tests/verification/Resources/ExecuteJsEscapingTest.txt +++ b/dev/tests/verification/Resources/ExecuteJsEscapingTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; @@ -30,8 +28,8 @@ class ExecuteJsEscapingTestCest { $javaVariableEscape = $I->executeJS("return \$javascriptVariable"); // stepKey: javaVariableEscape $mftfVariableNotEscaped = $I->executeJS("return {$doNotEscape}"); // stepKey: mftfVariableNotEscaped - $persistedDataNotEscaped = $I->executeJS("return " . PersistedObjectHandler::getInstance()->retrieveEntityField('persisted', 'data', 'test')); // stepKey: persistedDataNotEscaped - $hookPersistedDataNotEscaped = $I->executeJS("return " . PersistedObjectHandler::getInstance()->retrieveEntityField('persisted', 'data', 'test')); // stepKey: hookPersistedDataNotEscaped - $addNewAttributeForRule = $I->executeJS("document.querySelector('entity option[value=" . PersistedObjectHandler::getInstance()->retrieveEntityField('productAttribute', 'attribute_code', 'test') . "]').setAttribute('selected', 'selected')"); // stepKey: addNewAttributeForRule + $persistedDataNotEscaped = $I->executeJS("return " . $I->retrieveEntityField('persisted', 'data', 'test')); // stepKey: persistedDataNotEscaped + $hookPersistedDataNotEscaped = $I->executeJS("return " . $I->retrieveEntityField('persisted', 'data', 'test')); // stepKey: hookPersistedDataNotEscaped + $addNewAttributeForRule = $I->executeJS("document.querySelector('entity option[value=" . $I->retrieveEntityField('productAttribute', 'attribute_code', 'test') . "]').setAttribute('selected', 'selected')"); // stepKey: addNewAttributeForRule } } diff --git a/dev/tests/verification/Resources/ExtendParentDataTest.txt b/dev/tests/verification/Resources/ExtendParentDataTest.txt index fb90599e3..5a698b55f 100644 --- a/dev/tests/verification/Resources/ExtendParentDataTest.txt +++ b/dev/tests/verification/Resources/ExtendParentDataTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; @@ -29,7 +27,7 @@ class ExtendParentDataTestCest public function ExtendParentDataTest(AcceptanceTester $I) { $I->comment("[simpleDataKey] create 'extendParentData' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "simpleDataKey", "test", "extendParentData", diff --git a/dev/tests/verification/Resources/ExtendedActionGroup.txt b/dev/tests/verification/Resources/ExtendedActionGroup.txt index 7456d99ce..3158161d9 100644 --- a/dev/tests/verification/Resources/ExtendedActionGroup.txt +++ b/dev/tests/verification/Resources/ExtendedActionGroup.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/ExtendedChildTestInSuiteCest.txt b/dev/tests/verification/Resources/ExtendedChildTestInSuiteCest.txt index f52a46c2f..bde2ce2b3 100644 --- a/dev/tests/verification/Resources/ExtendedChildTestInSuiteCest.txt +++ b/dev/tests/verification/Resources/ExtendedChildTestInSuiteCest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_suiteExtends\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt b/dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt index 3dfeac8f3..fc67be840 100644 --- a/dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt +++ b/dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/ExtendedParameterArrayTest.txt b/dev/tests/verification/Resources/ExtendedParameterArrayTest.txt index 21212ba1a..e5016216d 100644 --- a/dev/tests/verification/Resources/ExtendedParameterArrayTest.txt +++ b/dev/tests/verification/Resources/ExtendedParameterArrayTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; @@ -28,7 +26,7 @@ class ExtendParentDataTestCest public function ExtendParentDataTest(AcceptanceTester $I) { $I->amGoingTo("create entity that has the stepKey: simpleDataKey"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "simpleDataKey", "test", "extendParentData", diff --git a/dev/tests/verification/Resources/ExtendedRemoveActionGroup.txt b/dev/tests/verification/Resources/ExtendedRemoveActionGroup.txt index a9c971b96..5ba7a3cce 100644 --- a/dev/tests/verification/Resources/ExtendedRemoveActionGroup.txt +++ b/dev/tests/verification/Resources/ExtendedRemoveActionGroup.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/ExtendingSkippedTest.txt b/dev/tests/verification/Resources/ExtendingSkippedTest.txt index 681af0fef..73a1c89d7 100644 --- a/dev/tests/verification/Resources/ExtendingSkippedTest.txt +++ b/dev/tests/verification/Resources/ExtendingSkippedTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/HookActionsTest.txt b/dev/tests/verification/Resources/HookActionsTest.txt index 231353bc9..9ed9c0bc5 100644 --- a/dev/tests/verification/Resources/HookActionsTest.txt +++ b/dev/tests/verification/Resources/HookActionsTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; @@ -26,7 +24,7 @@ class HookActionsTestCest public function _before(AcceptanceTester $I) { $I->comment("[sampleCreateBefore] create 'sampleCreatedEntity' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "sampleCreateBefore", "hook", "sampleCreatedEntity", @@ -35,13 +33,13 @@ class HookActionsTestCest ); $I->comment("[sampleDeleteBefore] delete entity 'sampleCreateBefore'"); - PersistedObjectHandler::getInstance()->deleteEntity( + $I->deleteEntity( "sampleCreateBefore", "hook" ); $I->comment("[sampleCreateForAfter] create 'sampleCreatedEntity' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "sampleCreateForAfter", "hook", "sampleCreatedEntity", @@ -58,7 +56,7 @@ class HookActionsTestCest public function _after(AcceptanceTester $I) { $I->comment("[sampleCreateAfter] create 'sampleCreatedEntity' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "sampleCreateAfter", "hook", "sampleCreatedEntity", @@ -67,7 +65,7 @@ class HookActionsTestCest ); $I->comment("[sampleDeleteAfter] delete entity 'sampleCreateForAfter'"); - PersistedObjectHandler::getInstance()->deleteEntity( + $I->deleteEntity( "sampleCreateForAfter", "hook" ); diff --git a/dev/tests/verification/Resources/LocatorFunctionTest.txt b/dev/tests/verification/Resources/LocatorFunctionTest.txt index 00baeeac5..67f92543f 100644 --- a/dev/tests/verification/Resources/LocatorFunctionTest.txt +++ b/dev/tests/verification/Resources/LocatorFunctionTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; @@ -29,7 +27,7 @@ class LocatorFunctionTestCest public function LocatorFunctionTest(AcceptanceTester $I) { $I->comment("[data] create 'ReplacementPerson' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "data", "test", "ReplacementPerson", @@ -42,12 +40,12 @@ class LocatorFunctionTestCest $I->click(Locator::find("'img'", ['title' => 'diagram'])); // stepKey: ArrayLocator $I->click(Locator::contains("string", "'Name'")); // stepKey: OneParamLiteral $I->click(Locator::contains("John", "'Name'")); // stepKey: OneParamData - $I->click(Locator::contains(PersistedObjectHandler::getInstance()->retrieveEntityField('data', 'key', 'test'), "'Name'")); // stepKey: OneParamPersisted + $I->click(Locator::contains($I->retrieveEntityField('data', 'key', 'test'), "'Name'")); // stepKey: OneParamPersisted $I->click(Locator::contains("string1", "string2")); // stepKey: TwoParamLiteral $I->click(Locator::contains("John", "Doe")); // stepKey: TwoParamData - $I->click(Locator::contains(PersistedObjectHandler::getInstance()->retrieveEntityField('data', 'key1', 'test'), PersistedObjectHandler::getInstance()->retrieveEntityField('data', 'key2', 'test'))); // stepKey: TwoParamPersisted + $I->click(Locator::contains($I->retrieveEntityField('data', 'key1', 'test'), $I->retrieveEntityField('data', 'key2', 'test'))); // stepKey: TwoParamPersisted $I->click(Locator::contains("string1", "John")); // stepKey: TwoParamMix1 - $I->click(Locator::contains("string1", PersistedObjectHandler::getInstance()->retrieveEntityField('data', 'key1', 'test'))); // stepKey: TwoParamMix2 - $I->click(Locator::contains("John", PersistedObjectHandler::getInstance()->retrieveEntityField('data', 'key1', 'test'))); // stepKey: TwoParamMix3 + $I->click(Locator::contains("string1", $I->retrieveEntityField('data', 'key1', 'test'))); // stepKey: TwoParamMix2 + $I->click(Locator::contains("John", $I->retrieveEntityField('data', 'key1', 'test'))); // stepKey: TwoParamMix3 } } diff --git a/dev/tests/verification/Resources/MergeMassViaInsertAfter.txt b/dev/tests/verification/Resources/MergeMassViaInsertAfter.txt index 7d3bfec09..90c8c5373 100644 --- a/dev/tests/verification/Resources/MergeMassViaInsertAfter.txt +++ b/dev/tests/verification/Resources/MergeMassViaInsertAfter.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/MergeMassViaInsertBefore.txt b/dev/tests/verification/Resources/MergeMassViaInsertBefore.txt index 42a0fcf89..df569d66b 100644 --- a/dev/tests/verification/Resources/MergeMassViaInsertBefore.txt +++ b/dev/tests/verification/Resources/MergeMassViaInsertBefore.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/MergeSkip.txt b/dev/tests/verification/Resources/MergeSkip.txt index fdfbdbfe4..bf5903065 100644 --- a/dev/tests/verification/Resources/MergeSkip.txt +++ b/dev/tests/verification/Resources/MergeSkip.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/MergedActionGroupTest.txt b/dev/tests/verification/Resources/MergedActionGroupTest.txt index 636c28627..b2a4d4cd3 100644 --- a/dev/tests/verification/Resources/MergedActionGroupTest.txt +++ b/dev/tests/verification/Resources/MergedActionGroupTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; @@ -27,7 +25,7 @@ class MergedActionGroupTestCest public function _before(AcceptanceTester $I) { $I->comment("[createPersonParam] create 'ReplacementPerson' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createPersonParam", "hook", "ReplacementPerson", diff --git a/dev/tests/verification/Resources/MergedReferencesTest.txt b/dev/tests/verification/Resources/MergedReferencesTest.txt index 794ba6370..c4cc7276e 100644 --- a/dev/tests/verification/Resources/MergedReferencesTest.txt +++ b/dev/tests/verification/Resources/MergedReferencesTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/MultipleActionGroupsTest.txt b/dev/tests/verification/Resources/MultipleActionGroupsTest.txt index 186cd404c..bd40b3fa6 100644 --- a/dev/tests/verification/Resources/MultipleActionGroupsTest.txt +++ b/dev/tests/verification/Resources/MultipleActionGroupsTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; @@ -27,7 +25,7 @@ class MultipleActionGroupsTestCest public function _before(AcceptanceTester $I) { $I->comment("[createPersonParam] create 'ReplacementPerson' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createPersonParam", "hook", "ReplacementPerson", diff --git a/dev/tests/verification/Resources/PageReplacementTest.txt b/dev/tests/verification/Resources/PageReplacementTest.txt index f6c6b1bac..6cfcce367 100644 --- a/dev/tests/verification/Resources/PageReplacementTest.txt +++ b/dev/tests/verification/Resources/PageReplacementTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; @@ -29,7 +27,7 @@ class PageReplacementTestCest public function PageReplacementTest(AcceptanceTester $I) { $I->comment("[datakey] create 'simpleData' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "datakey", "test", "simpleData", @@ -40,11 +38,11 @@ class PageReplacementTestCest $I->amOnPage("/page.html"); // stepKey: noParamPage $I->amOnPage("/StringLiteral/page.html"); // stepKey: oneParamPageString $I->amOnPage("/John/page.html"); // stepKey: oneParamPageData - $I->amOnPage("/" . PersistedObjectHandler::getInstance()->retrieveEntityField('datakey', 'firstname', 'test') . "/page.html"); // stepKey: oneParamPagePersist + $I->amOnPage("/" . $I->retrieveEntityField('datakey', 'firstname', 'test') . "/page.html"); // stepKey: oneParamPagePersist $I->amOnPage("/StringLiteral1/StringLiteral2.html"); // stepKey: twoParamPageString $I->amOnPage("/John/StringLiteral2.html"); // stepKey: twoParamPageStringData - $I->amOnPage("/John/" . PersistedObjectHandler::getInstance()->retrieveEntityField('datakey', 'firstname', 'test') . ".html"); // stepKey: twoParamPageDataPersist - $I->amOnPage("/" . PersistedObjectHandler::getInstance()->retrieveEntityField('datakey', 'firstname', 'test') . "/StringLiteral2.html"); // stepKey: twoParamPagePersistString + $I->amOnPage("/John/" . $I->retrieveEntityField('datakey', 'firstname', 'test') . ".html"); // stepKey: twoParamPageDataPersist + $I->amOnPage("/" . $I->retrieveEntityField('datakey', 'firstname', 'test') . "/StringLiteral2.html"); // stepKey: twoParamPagePersistString $I->amOnPage("/" . getenv("MAGENTO_BACKEND_NAME") . "/backend"); // stepKey: onAdminPage $I->amOnPage("/" . getenv("MAGENTO_BACKEND_NAME") . "/StringLiteral/page.html"); // stepKey: oneParamAdminPageString $I->amOnUrl("http://myFullUrl.com/"); // stepKey: onExternalPage diff --git a/dev/tests/verification/Resources/ParameterArrayTest.txt b/dev/tests/verification/Resources/ParameterArrayTest.txt index 52332217b..f66ce9c47 100644 --- a/dev/tests/verification/Resources/ParameterArrayTest.txt +++ b/dev/tests/verification/Resources/ParameterArrayTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; @@ -29,7 +27,7 @@ class ParameterArrayTestCest public function ParameterArrayTest(AcceptanceTester $I) { $I->comment("[simpleDataKey] create 'simpleParamData' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "simpleDataKey", "test", "simpleParamData", @@ -40,9 +38,9 @@ class ParameterArrayTestCest $I->searchAndMultiSelectOption("#selector", ["name"]); // stepKey: xmlSimpleReplace $I->searchAndMultiSelectOption("#selector", [msq("simpleParamData") . "prename"]); // stepKey: xmlPrefix $I->searchAndMultiSelectOption("#selector", ["postname" . msq("simpleParamData")]); // stepKey: xmlSuffix - $I->searchAndMultiSelectOption("#selector", [PersistedObjectHandler::getInstance()->retrieveEntityField('simpleDataKey', 'name', 'test')]); // stepKey: persistSimple - $I->searchAndMultiSelectOption("#selector", ["name", PersistedObjectHandler::getInstance()->retrieveEntityField('simpleDataKey', 'name', 'test')]); // stepKey: persistXmlSimple - $I->searchAndMultiSelectOption("#selector", ['someKey' => PersistedObjectHandler::getInstance()->retrieveEntityField('simpleDataKey', 'name', 'test')]); // stepKey: literalKeyToPersist + $I->searchAndMultiSelectOption("#selector", [$I->retrieveEntityField('simpleDataKey', 'name', 'test')]); // stepKey: persistSimple + $I->searchAndMultiSelectOption("#selector", ["name", $I->retrieveEntityField('simpleDataKey', 'name', 'test')]); // stepKey: persistXmlSimple + $I->searchAndMultiSelectOption("#selector", ['someKey' => $I->retrieveEntityField('simpleDataKey', 'name', 'test')]); // stepKey: literalKeyToPersist $I->searchAndMultiSelectOption("#selector", ['someKey' => "name"]); // stepKey: literalKeyToStatic $I->searchAndMultiSelectOption("#selector", ['someKey' => msq("simpleParamData") . "prename"]); // stepKey: literalKeyToPrefixUnique $I->searchAndMultiSelectOption("#selector", ['someKey' => "postname" . msq("simpleParamData")]); // stepKey: literalKeyToSuffixUnique @@ -51,13 +49,13 @@ class ParameterArrayTestCest $I->unselectOption("#selector", ["name"]); // stepKey: 002 $I->unselectOption("#selector", [msq("simpleParamData") . "prename"]); // stepKey: 003 $I->unselectOption("#selector", ["postname" . msq("simpleParamData")]); // stepKey: 004 - $I->unselectOption("#selector", [PersistedObjectHandler::getInstance()->retrieveEntityField('simpleDataKey', 'name', 'test')]); // stepKey: 005 - $I->unselectOption("#selector", ["name", PersistedObjectHandler::getInstance()->retrieveEntityField('simpleDataKey', 'name', 'test')]); // stepKey: 006 - $I->pressKey("#selector", PersistedObjectHandler::getInstance()->retrieveEntityField('simpleDataKey', 'name', 'test'), ['ctrl', 'a'],\Facebook\WebDriver\WebDriverKeys::DELETE,PersistedObjectHandler::getInstance()->retrieveEntityField('simpleDataKey', 'name', 'test')); // stepKey: pressKey001 - $I->pressKey("#selector", ['ctrl', 'a'], 10, 20,\Facebook\WebDriver\WebDriverKeys::DELETE,PersistedObjectHandler::getInstance()->retrieveEntityField('simpleDataKey', 'name', 'test')); // stepKey: pressKey002 - $I->pressKey("#selector", ['ctrl', 'a'],'new', 10, 20,\Facebook\WebDriver\WebDriverKeys::DELETE,PersistedObjectHandler::getInstance()->retrieveEntityField('simpleDataKey', 'name', 'test')); // stepKey: pressKey003 - $I->pressKey("#selector", ['ctrl', 'a'],'new', 1, ['ctrl'], ['shift', 'ctrl', 'del'], [PersistedObjectHandler::getInstance()->retrieveEntityField('simpleDataKey', 'name', 'test'), 'a', "name"]); // stepKey: pressKey004 - $I->pressKey("#selector", ['ctrl', 'a'],'new', 1, ['ctrl'], ['shift', 'ctrl', 'del'], 0, [PersistedObjectHandler::getInstance()->retrieveEntityField('simpleDataKey', 'name', 'test'), PersistedObjectHandler::getInstance()->retrieveEntityField('simpleDataKey', 'name', 'test')]); // stepKey: pressKey005 + $I->unselectOption("#selector", [$I->retrieveEntityField('simpleDataKey', 'name', 'test')]); // stepKey: 005 + $I->unselectOption("#selector", ["name", $I->retrieveEntityField('simpleDataKey', 'name', 'test')]); // stepKey: 006 + $I->pressKey("#selector", $I->retrieveEntityField('simpleDataKey', 'name', 'test'), ['ctrl', 'a'],\Facebook\WebDriver\WebDriverKeys::DELETE,$I->retrieveEntityField('simpleDataKey', 'name', 'test')); // stepKey: pressKey001 + $I->pressKey("#selector", ['ctrl', 'a'], 10, 20,\Facebook\WebDriver\WebDriverKeys::DELETE,$I->retrieveEntityField('simpleDataKey', 'name', 'test')); // stepKey: pressKey002 + $I->pressKey("#selector", ['ctrl', 'a'],'new', 10, 20,\Facebook\WebDriver\WebDriverKeys::DELETE,$I->retrieveEntityField('simpleDataKey', 'name', 'test')); // stepKey: pressKey003 + $I->pressKey("#selector", ['ctrl', 'a'],'new', 1, ['ctrl'], ['shift', 'ctrl', 'del'], [$I->retrieveEntityField('simpleDataKey', 'name', 'test'), 'a', "name"]); // stepKey: pressKey004 + $I->pressKey("#selector", ['ctrl', 'a'],'new', 1, ['ctrl'], ['shift', 'ctrl', 'del'], 0, [$I->retrieveEntityField('simpleDataKey', 'name', 'test'), $I->retrieveEntityField('simpleDataKey', 'name', 'test')]); // stepKey: pressKey005 $I->pressKey("#selector", ['ctrl', 'a'],'new', 1, ['ctrl'], ['shift', 'ctrl', 'del'], [msq("simpleParamData") . "prename", "postname" . msq("simpleParamData")]); // stepKey: pressKey006 } } diff --git a/dev/tests/verification/Resources/ParentExtendedTest.txt b/dev/tests/verification/Resources/ParentExtendedTest.txt index aeae567a2..5662da744 100644 --- a/dev/tests/verification/Resources/ParentExtendedTest.txt +++ b/dev/tests/verification/Resources/ParentExtendedTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/PersistedAndXmlEntityArguments.txt b/dev/tests/verification/Resources/PersistedAndXmlEntityArguments.txt index c6c09c9c7..2f86f0af7 100644 --- a/dev/tests/verification/Resources/PersistedAndXmlEntityArguments.txt +++ b/dev/tests/verification/Resources/PersistedAndXmlEntityArguments.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; @@ -29,7 +27,7 @@ class PersistedAndXmlEntityArgumentsCest public function PersistedAndXmlEntityArguments(AcceptanceTester $I) { $I->comment("Entering Action Group [afterGroup] FunctionalActionGroupWithXmlAndPersistedData"); - $I->seeInCurrentUrl("/" . PersistedObjectHandler::getInstance()->retrieveEntityField('persistedInTest', 'urlKey', 'test') . ".html?___store=" . msq("uniqueData") . "John"); // stepKey: checkUrlAfterGroup + $I->seeInCurrentUrl("/" . $I->retrieveEntityField('persistedInTest', 'urlKey', 'test') . ".html?___store=" . msq("uniqueData") . "John"); // stepKey: checkUrlAfterGroup $I->comment("Exiting Action Group [afterGroup] FunctionalActionGroupWithXmlAndPersistedData"); } } diff --git a/dev/tests/verification/Resources/PersistedReplacementTest.txt b/dev/tests/verification/Resources/PersistedReplacementTest.txt index eb3642ed1..5d8a0f1e5 100644 --- a/dev/tests/verification/Resources/PersistedReplacementTest.txt +++ b/dev/tests/verification/Resources/PersistedReplacementTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; @@ -26,7 +24,7 @@ class PersistedReplacementTestCest public function _before(AcceptanceTester $I) { $I->comment("[createData1] create 'ReplacementPerson' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createData1", "hook", "ReplacementPerson", @@ -46,7 +44,7 @@ class PersistedReplacementTestCest public function PersistedReplacementTest(AcceptanceTester $I) { $I->comment("[createdData] create 'simpleData' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createdData", "test", "simpleData", @@ -54,27 +52,27 @@ class PersistedReplacementTestCest [] ); - $I->fillField("#selector", "StringBefore " . PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'firstname', 'test') . " StringAfter"); // stepKey: inputReplace - $I->fillField("#" . PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'firstname', 'test'), "input"); // stepKey: selectorReplace - $I->fillField("#" . getenv("MAGENTO_BASE_URL") . "#" . PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'firstname', 'test'), "input"); // stepKey: selectorReplace2 - $I->fillSecretField("#" . CredentialStore::getInstance()->getSecret("SECRET_PARAM") . "#" . PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'firstname', 'test'), "input"); // stepKey: selectorReplace3 - $I->dragAndDrop("#" . PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'firstname', 'test'), PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'lastname', 'test')); // stepKey: selector12Replace - $I->conditionalClick(PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'lastname', 'test'), "#" . PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'firstname', 'test'), true); // stepKey: dependentSelectorReplace - $I->amOnUrl(PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'firstname', 'test') . ".html"); // stepKey: urlReplace - $I->searchAndMultiSelectOption("#selector", [PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'firstname', 'test'), PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'lastname', 'test')]); // stepKey: parameterArrayReplacement - $I->fillField("#selector", "John " . PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'firstname', 'test') . " stringLiteral"); // stepKey: allTypesMixed - $I->searchAndMultiSelectOption("#selector", [PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'firstname', 'test'), "John", "stringLiteral"]); // stepKey: parameterArrayMixed - $I->seeInPageSource("StringBefore " . PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'firstname', 'test') . " StringAfter"); // stepKey: htmlReplace1 - $I->seeInPageSource("StringBefore " . PersistedObjectHandler::getInstance()->retrieveEntityField('createData1', 'firstname', 'test') . " StringAfter"); // stepKey: htmlReplace2 - $I->seeInPageSource("#" . getenv("MAGENTO_BASE_URL") . "#" . PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'firstname', 'test')); // stepKey: htmlReplace3 - $I->dontSeeInPageSource("StringBefore " . PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'firstname', 'test') . " StringAfter"); // stepKey: htmlReplace4 - $I->dontSeeInPageSource("StringBefore " . PersistedObjectHandler::getInstance()->retrieveEntityField('createData1', 'firstname', 'test') . " StringAfter"); // stepKey: htmlReplace5 - $I->dontSeeInPageSource("#" . getenv("MAGENTO_BASE_URL") . "#" . PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'firstname', 'test')); // stepKey: htmlReplace6 - $I->seeInSource("StringBefore " . PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'firstname', 'test') . " StringAfter"); // stepKey: htmlReplace7 - $I->seeInSource("StringBefore " . PersistedObjectHandler::getInstance()->retrieveEntityField('createData1', 'firstname', 'test') . " StringAfter"); // stepKey: htmlReplace8 - $I->seeInSource("#" . getenv("MAGENTO_BASE_URL") . "#" . PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'firstname', 'test')); // stepKey: htmlReplace9 - $I->dontSeeInSource("StringBefore " . PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'firstname', 'test') . " StringAfter"); // stepKey: htmlReplace10 - $I->dontSeeInSource("StringBefore " . PersistedObjectHandler::getInstance()->retrieveEntityField('createData1', 'firstname', 'test') . " StringAfter"); // stepKey: htmlReplace11 - $I->dontSeeInSource("#" . getenv("MAGENTO_BASE_URL") . "#" . PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'firstname', 'test')); // stepKey: htmlReplace12 + $I->fillField("#selector", "StringBefore " . $I->retrieveEntityField('createdData', 'firstname', 'test') . " StringAfter"); // stepKey: inputReplace + $I->fillField("#" . $I->retrieveEntityField('createdData', 'firstname', 'test'), "input"); // stepKey: selectorReplace + $I->fillField("#" . getenv("MAGENTO_BASE_URL") . "#" . $I->retrieveEntityField('createdData', 'firstname', 'test'), "input"); // stepKey: selectorReplace2 + $I->fillSecretField("#" . $I->getSecret("SECRET_PARAM") . "#" . $I->retrieveEntityField('createdData', 'firstname', 'test'), "input"); // stepKey: selectorReplace3 + $I->dragAndDrop("#" . $I->retrieveEntityField('createdData', 'firstname', 'test'), $I->retrieveEntityField('createdData', 'lastname', 'test')); // stepKey: selector12Replace + $I->conditionalClick($I->retrieveEntityField('createdData', 'lastname', 'test'), "#" . $I->retrieveEntityField('createdData', 'firstname', 'test'), true); // stepKey: dependentSelectorReplace + $I->amOnUrl($I->retrieveEntityField('createdData', 'firstname', 'test') . ".html"); // stepKey: urlReplace + $I->searchAndMultiSelectOption("#selector", [$I->retrieveEntityField('createdData', 'firstname', 'test'), $I->retrieveEntityField('createdData', 'lastname', 'test')]); // stepKey: parameterArrayReplacement + $I->fillField("#selector", "John " . $I->retrieveEntityField('createdData', 'firstname', 'test') . " stringLiteral"); // stepKey: allTypesMixed + $I->searchAndMultiSelectOption("#selector", [$I->retrieveEntityField('createdData', 'firstname', 'test'), "John", "stringLiteral"]); // stepKey: parameterArrayMixed + $I->seeInPageSource("StringBefore " . $I->retrieveEntityField('createdData', 'firstname', 'test') . " StringAfter"); // stepKey: htmlReplace1 + $I->seeInPageSource("StringBefore " . $I->retrieveEntityField('createData1', 'firstname', 'test') . " StringAfter"); // stepKey: htmlReplace2 + $I->seeInPageSource("#" . getenv("MAGENTO_BASE_URL") . "#" . $I->retrieveEntityField('createdData', 'firstname', 'test')); // stepKey: htmlReplace3 + $I->dontSeeInPageSource("StringBefore " . $I->retrieveEntityField('createdData', 'firstname', 'test') . " StringAfter"); // stepKey: htmlReplace4 + $I->dontSeeInPageSource("StringBefore " . $I->retrieveEntityField('createData1', 'firstname', 'test') . " StringAfter"); // stepKey: htmlReplace5 + $I->dontSeeInPageSource("#" . getenv("MAGENTO_BASE_URL") . "#" . $I->retrieveEntityField('createdData', 'firstname', 'test')); // stepKey: htmlReplace6 + $I->seeInSource("StringBefore " . $I->retrieveEntityField('createdData', 'firstname', 'test') . " StringAfter"); // stepKey: htmlReplace7 + $I->seeInSource("StringBefore " . $I->retrieveEntityField('createData1', 'firstname', 'test') . " StringAfter"); // stepKey: htmlReplace8 + $I->seeInSource("#" . getenv("MAGENTO_BASE_URL") . "#" . $I->retrieveEntityField('createdData', 'firstname', 'test')); // stepKey: htmlReplace9 + $I->dontSeeInSource("StringBefore " . $I->retrieveEntityField('createdData', 'firstname', 'test') . " StringAfter"); // stepKey: htmlReplace10 + $I->dontSeeInSource("StringBefore " . $I->retrieveEntityField('createData1', 'firstname', 'test') . " StringAfter"); // stepKey: htmlReplace11 + $I->dontSeeInSource("#" . getenv("MAGENTO_BASE_URL") . "#" . $I->retrieveEntityField('createdData', 'firstname', 'test')); // stepKey: htmlReplace12 } } diff --git a/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt b/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt index 95aab913f..2a3444324 100644 --- a/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt +++ b/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; @@ -27,7 +25,7 @@ class PersistenceActionGroupAppendingTestCest { $I->comment("Entering Action Group [ACTIONGROUPBEFORE] DataPersistenceAppendingActionGroup"); $I->comment("[createDataACTIONGROUPBEFORE] create 'entity' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createDataACTIONGROUPBEFORE", "hook", "entity", @@ -36,7 +34,7 @@ class PersistenceActionGroupAppendingTestCest ); $I->comment("[updateDataACTIONGROUPBEFORE] update 'createDataACTIONGROUPBEFORE' entity to 'newEntity'"); - PersistedObjectHandler::getInstance()->updateEntity( + $I->updateEntity( "createDataACTIONGROUPBEFORE", "hook", "newEntity", @@ -44,13 +42,13 @@ class PersistenceActionGroupAppendingTestCest ); $I->comment("[deleteDataACTIONGROUPBEFORE] delete entity 'createDataACTIONGROUPBEFORE'"); - PersistedObjectHandler::getInstance()->deleteEntity( + $I->deleteEntity( "createDataACTIONGROUPBEFORE", "hook" ); $I->comment("[getDataACTIONGROUPBEFORE] get 'someEneity' entity"); - PersistedObjectHandler::getInstance()->getEntity( + $I->getEntity( "getDataACTIONGROUPBEFORE", "hook", "someEneity", @@ -58,7 +56,7 @@ class PersistenceActionGroupAppendingTestCest null ); - $I->comment(PersistedObjectHandler::getInstance()->retrieveEntityField('createData', 'field', 'hook')); + $I->comment($I->retrieveEntityField('createData', 'field', 'hook')); $I->comment("Exiting Action Group [ACTIONGROUPBEFORE] DataPersistenceAppendingActionGroup"); } @@ -73,7 +71,7 @@ class PersistenceActionGroupAppendingTestCest { $I->comment("Entering Action Group [ACTIONGROUP] DataPersistenceAppendingActionGroup"); $I->comment("[createDataACTIONGROUP] create 'entity' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createDataACTIONGROUP", "test", "entity", @@ -82,7 +80,7 @@ class PersistenceActionGroupAppendingTestCest ); $I->comment("[updateDataACTIONGROUP] update 'createDataACTIONGROUP' entity to 'newEntity'"); - PersistedObjectHandler::getInstance()->updateEntity( + $I->updateEntity( "createDataACTIONGROUP", "test", "newEntity", @@ -90,13 +88,13 @@ class PersistenceActionGroupAppendingTestCest ); $I->comment("[deleteDataACTIONGROUP] delete entity 'createDataACTIONGROUP'"); - PersistedObjectHandler::getInstance()->deleteEntity( + $I->deleteEntity( "createDataACTIONGROUP", "test" ); $I->comment("[getDataACTIONGROUP] get 'someEneity' entity"); - PersistedObjectHandler::getInstance()->getEntity( + $I->getEntity( "getDataACTIONGROUP", "test", "someEneity", @@ -104,7 +102,7 @@ class PersistenceActionGroupAppendingTestCest null ); - $I->comment(PersistedObjectHandler::getInstance()->retrieveEntityField('createDataACTIONGROUP', 'field', 'test')); + $I->comment($I->retrieveEntityField('createDataACTIONGROUP', 'field', 'test')); $I->comment("Exiting Action Group [ACTIONGROUP] DataPersistenceAppendingActionGroup"); } } diff --git a/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt b/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt index 0a6deaca8..517bea53a 100644 --- a/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt +++ b/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; @@ -28,7 +26,7 @@ class PersistenceCustomFieldsTestCest $createData1Fields['firstname'] = "Mac"; $createData1Fields['lastname'] = "Doe"; $I->comment("[createData1] create 'DefaultPerson' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createData1", "hook", "DefaultPerson", @@ -36,9 +34,9 @@ class PersistenceCustomFieldsTestCest $createData1Fields ); - $createData2Fields['firstname'] = PersistedObjectHandler::getInstance()->retrieveEntityField('createData1', 'firstname', 'hook'); + $createData2Fields['firstname'] = $I->retrieveEntityField('createData1', 'firstname', 'hook'); $I->comment("[createData2] create 'uniqueData' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createData2", "hook", "uniqueData", @@ -60,7 +58,7 @@ class PersistenceCustomFieldsTestCest $createdDataFields['favoriteIndex'] = "1"; $createdDataFields['middlename'] = "Kovacs"; $I->comment("[createdData] create 'simpleData' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createdData", "test", "simpleData", @@ -71,7 +69,7 @@ class PersistenceCustomFieldsTestCest $createdData3Fields['firstname'] = "Takeshi"; $createdData3Fields['lastname'] = "Kovacs"; $I->comment("[createdData3] create 'UniquePerson' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createdData3", "test", "UniquePerson", @@ -82,7 +80,7 @@ class PersistenceCustomFieldsTestCest $I->comment("Entering Action Group [createdAG] PersistenceActionGroup"); $createDataAG1CreatedAGFields['firstname'] = "string1"; $I->comment("[createDataAG1CreatedAG] create 'simpleData' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createDataAG1CreatedAG", "test", "simpleData", @@ -92,7 +90,7 @@ class PersistenceCustomFieldsTestCest $createDataAG2CreatedAGFields['firstname'] = "Jane"; $I->comment("[createDataAG2CreatedAG] create 'simpleData' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createDataAG2CreatedAG", "test", "simpleData", @@ -100,9 +98,9 @@ class PersistenceCustomFieldsTestCest $createDataAG2CreatedAGFields ); - $createDataAG3CreatedAGFields['firstname'] = PersistedObjectHandler::getInstance()->retrieveEntityField('createdData3', 'firstname', 'test'); + $createDataAG3CreatedAGFields['firstname'] = $I->retrieveEntityField('createdData3', 'firstname', 'test'); $I->comment("[createDataAG3CreatedAG] create 'simpleData' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createDataAG3CreatedAG", "test", "simpleData", @@ -113,7 +111,7 @@ class PersistenceCustomFieldsTestCest $I->comment("Exiting Action Group [createdAG] PersistenceActionGroup"); $I->comment("Entering Action Group [AGKEY] DataPersistenceSelfReferenceActionGroup"); $I->comment("[createData1AGKEY] create 'entity1' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createData1AGKEY", "test", "entity1", @@ -122,7 +120,7 @@ class PersistenceCustomFieldsTestCest ); $I->comment("[createData2AGKEY] create 'entity2' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createData2AGKEY", "test", "entity2", @@ -130,10 +128,10 @@ class PersistenceCustomFieldsTestCest [] ); - $createData3AGKEYFields['key1'] = PersistedObjectHandler::getInstance()->retrieveEntityField('createData1AGKEY', 'field', 'test'); - $createData3AGKEYFields['key2'] = PersistedObjectHandler::getInstance()->retrieveEntityField('createData2AGKEY', 'field', 'test'); + $createData3AGKEYFields['key1'] = $I->retrieveEntityField('createData1AGKEY', 'field', 'test'); + $createData3AGKEYFields['key2'] = $I->retrieveEntityField('createData2AGKEY', 'field', 'test'); $I->comment("[createData3AGKEY] create 'entity3' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createData3AGKEY", "test", "entity3", diff --git a/dev/tests/verification/Resources/SectionReplacementTest.txt b/dev/tests/verification/Resources/SectionReplacementTest.txt index 5089cfbfd..04efcee4b 100644 --- a/dev/tests/verification/Resources/SectionReplacementTest.txt +++ b/dev/tests/verification/Resources/SectionReplacementTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; @@ -48,7 +46,7 @@ class SectionReplacementTestCest $I->click("#Doe" . msq("uniqueData") . "-stringLiteral2 .stringLiteral3"); // stepKey: selectorReplaceThreeParamDataRefMSQSuffix $I->click("#Doe" . msq("uniqueData") . "-stringLiteral2 .Doe" . msq("uniqueData") . " [stringLiteral3]"); // stepKey: selectorReplaceThreeParamOneDupeDataRefMSQSuffix $I->comment("[createdData] create 'simpleData' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createdData", "test", "simpleData", @@ -56,18 +54,18 @@ class SectionReplacementTestCest [] ); - $I->click("#element ." . PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'firstname', 'test')); // stepKey: selectorReplaceOneParamPersisted - $I->click("#" . PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'firstname', 'test') . " .stringLiteral2"); // stepKey: selectorReplaceTwoParamPersisted - $I->click("#" . PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'firstname', 'test') . "-stringLiteral2 .stringLiteral3"); // stepKey: selectorReplaceThreeParamPersisted - $I->click("#" . PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'firstname', 'test') . "-stringLiteral2 ." . PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'firstname', 'test') . " [stringLiteral3]"); // stepKey: selectorReplaceThreeParamOneDupePersisted + $I->click("#element ." . $I->retrieveEntityField('createdData', 'firstname', 'test')); // stepKey: selectorReplaceOneParamPersisted + $I->click("#" . $I->retrieveEntityField('createdData', 'firstname', 'test') . " .stringLiteral2"); // stepKey: selectorReplaceTwoParamPersisted + $I->click("#" . $I->retrieveEntityField('createdData', 'firstname', 'test') . "-stringLiteral2 .stringLiteral3"); // stepKey: selectorReplaceThreeParamPersisted + $I->click("#" . $I->retrieveEntityField('createdData', 'firstname', 'test') . "-stringLiteral2 ." . $I->retrieveEntityField('createdData', 'firstname', 'test') . " [stringLiteral3]"); // stepKey: selectorReplaceThreeParamOneDupePersisted $I->click("#element .{$data}"); // stepKey: selectorReplaceOneParamVariable $I->click("#{$data1} .{$data2}"); // stepKey: selectorReplaceTwoParamVariable $I->click("#{$data1}-{$data2} .{$data3}"); // stepKey: selectorReplaceThreeParamVariable $I->click("#John-Doe .John [Tiberius]"); // stepKey: selectorReplaceThreeParamVariableOneDupe - $I->click("#stringLiteral1-" . PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'firstname', 'test') . " .John"); // stepKey: selectorReplaceThreeParamMixed1 - $I->click("#stringLiteral1-" . PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'firstname', 'test') . " .{$data}"); // stepKey: selectorReplaceThreeParamMixed2 - $I->click("#stringLiteral1-" . PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'firstname', 'test') . " ." . msq("uniqueData") . "John"); // stepKey: selectorReplaceThreeParamMixedMSQPrefix - $I->click("#stringLiteral1-" . PersistedObjectHandler::getInstance()->retrieveEntityField('createdData', 'firstname', 'test') . " .Doe" . msq("uniqueData")); // stepKey: selectorReplaceThreeParamMixedMSQSuffix + $I->click("#stringLiteral1-" . $I->retrieveEntityField('createdData', 'firstname', 'test') . " .John"); // stepKey: selectorReplaceThreeParamMixed1 + $I->click("#stringLiteral1-" . $I->retrieveEntityField('createdData', 'firstname', 'test') . " .{$data}"); // stepKey: selectorReplaceThreeParamMixed2 + $I->click("#stringLiteral1-" . $I->retrieveEntityField('createdData', 'firstname', 'test') . " ." . msq("uniqueData") . "John"); // stepKey: selectorReplaceThreeParamMixedMSQPrefix + $I->click("#stringLiteral1-" . $I->retrieveEntityField('createdData', 'firstname', 'test') . " .Doe" . msq("uniqueData")); // stepKey: selectorReplaceThreeParamMixedMSQSuffix $I->click("#element .1#element .2"); // stepKey: selectorReplaceTwoParamElements $I->click("#element .1#element .{$data}"); // stepKey: selectorReplaceTwoParamMixedTypes $I->click("(//div[@data-role='slide'])[1]/a[@data-element='link'][contains(@href,'')]"); // stepKey: selectorParamWithEmptyString diff --git a/dev/tests/verification/Resources/SkippedTest.txt b/dev/tests/verification/Resources/SkippedTest.txt index 08ff4fd43..dcad67e83 100644 --- a/dev/tests/verification/Resources/SkippedTest.txt +++ b/dev/tests/verification/Resources/SkippedTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/SkippedTestNoIssues.txt b/dev/tests/verification/Resources/SkippedTestNoIssues.txt index 168077458..3a7ca6f59 100644 --- a/dev/tests/verification/Resources/SkippedTestNoIssues.txt +++ b/dev/tests/verification/Resources/SkippedTestNoIssues.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/SkippedTestTwoIssues.txt b/dev/tests/verification/Resources/SkippedTestTwoIssues.txt index 3de81e02f..d3859978f 100644 --- a/dev/tests/verification/Resources/SkippedTestTwoIssues.txt +++ b/dev/tests/verification/Resources/SkippedTestTwoIssues.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/SkippedTestWithHooks.txt b/dev/tests/verification/Resources/SkippedTestWithHooks.txt index a86924b94..667be6747 100644 --- a/dev/tests/verification/Resources/SkippedTestWithHooks.txt +++ b/dev/tests/verification/Resources/SkippedTestWithHooks.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/XmlCommentedActionGroupTest.txt b/dev/tests/verification/Resources/XmlCommentedActionGroupTest.txt index 7e43433a1..480e35b73 100644 --- a/dev/tests/verification/Resources/XmlCommentedActionGroupTest.txt +++ b/dev/tests/verification/Resources/XmlCommentedActionGroupTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Resources/XmlCommentedTest.txt b/dev/tests/verification/Resources/XmlCommentedTest.txt index f77aa5fe4..5b8057099 100644 --- a/dev/tests/verification/Resources/XmlCommentedTest.txt +++ b/dev/tests/verification/Resources/XmlCommentedTest.txt @@ -2,8 +2,6 @@ namespace Magento\AcceptanceTest\_default\Backend; use Magento\FunctionalTestingFramework\AcceptanceTester; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; diff --git a/dev/tests/verification/Tests/SecretCredentialDataTest.php b/dev/tests/verification/Tests/SecretCredentialDataTest.php index 46391feee..d1ef43745 100644 --- a/dev/tests/verification/Tests/SecretCredentialDataTest.php +++ b/dev/tests/verification/Tests/SecretCredentialDataTest.php @@ -37,7 +37,7 @@ public function secretCredentialDataTest(AcceptanceTester $I) $createProductWithFieldOverridesUsingHardcodedData1Fields['price'] = "12.34"; $I->comment("[createProductWithFieldOverridesUsingHardcodedData1] create '_defaultProduct' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createProductWithFieldOverridesUsingHardcodedData1", "test", "_defaultProduct", @@ -46,13 +46,13 @@ public function secretCredentialDataTest(AcceptanceTester $I) ); $createProductWithFieldOverridesUsingSecretCredData1Fields['qty'] = - CredentialStore::getInstance()->getSecret("payment_authorizenet_trans_key"); + $I->getSecret("payment_authorizenet_trans_key"); $createProductWithFieldOverridesUsingSecretCredData1Fields['price'] = - CredentialStore::getInstance()->getSecret("carriers_dhl_account_eu"); + $I->getSecret("carriers_dhl_account_eu"); $I->comment("[createProductWithFieldOverridesUsingSecretCredData1] create '_defaultProduct' entity"); - PersistedObjectHandler::getInstance()->createEntity( + $I->createEntity( "createProductWithFieldOverridesUsingSecretCredData1", "test", "_defaultProduct", @@ -61,14 +61,14 @@ public function secretCredentialDataTest(AcceptanceTester $I) ); $I->fillField("#username", "Hardcoded"); // stepKey: fillFieldUsingHardCodedData1 - $I->fillSecretField("#username", CredentialStore::getInstance()->getSecret("carriers_dhl_id_eu")); + $I->fillSecretField("#username", $I->getSecret("carriers_dhl_id_eu")); // stepKey: fillFieldUsingSecretCredData1 $magentoCliUsingHardcodedData1 = $I->magentoCLI("config:set cms/wysiwyg/enabled 0"); // stepKey: magentoCliUsingHardcodedData1 $I->comment($magentoCliUsingHardcodedData1); $magentoCliUsingSecretCredData1 = $I->magentoCLI("config:set cms/wysiwyg/enabled " . - CredentialStore::getInstance()->getSecret("payment_authorizenet_login")); + $I->getSecret("payment_authorizenet_login")); // stepKey: magentoCliUsingSecretCredData1 $I->comment($magentoCliUsingSecretCredData1); } diff --git a/etc/config/functional.suite.dist.yml b/etc/config/functional.suite.dist.yml index 5487a3c99..319804d7a 100644 --- a/etc/config/functional.suite.dist.yml +++ b/etc/config/functional.suite.dist.yml @@ -16,6 +16,7 @@ modules: - \Magento\FunctionalTestingFramework\Helper\MagentoFakerData - \Magento\FunctionalTestingFramework\Module\MagentoSequence - \Magento\FunctionalTestingFramework\Module\MagentoAssert + - \Magento\FunctionalTestingFramework\Module\MagentoActionProxies - Asserts config: \Magento\FunctionalTestingFramework\Module\MagentoWebDriver: diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php index 42286564f..2a0f11a01 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php @@ -55,7 +55,6 @@ private function __construct() * Return the singleton instance of this class. Initialize it if needed. * * @return PersistedObjectHandler - * @throws \Exception */ public static function getInstance() { diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php index 16584e7a3..05178c915 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php @@ -123,8 +123,8 @@ public function executeRequest($dependentEntities) $returnRegex = $this->operationDefinition->getReturnRegex(); $returnIndex = $this->operationDefinition->getReturnIndex(); $method = $this->operationDefinition->getApiMethod(); - AllureHelper::addAttachmentToLastStep($apiUrl, 'API Endpoint'); - AllureHelper::addAttachmentToLastStep(json_encode($headers, JSON_PRETTY_PRINT), 'Request Headers'); + AllureHelper::addAttachmentToCurrentStep($apiUrl, 'API Endpoint'); + AllureHelper::addAttachmentToCurrentStep(json_encode($headers, JSON_PRETTY_PRINT), 'Request Headers'); $operationDataResolver = new OperationDataArrayResolver($dependentEntities); $this->requestData = $operationDataResolver->resolveOperationDataArray( @@ -169,8 +169,8 @@ public function executeRequest($dependentEntities) $response = $executor->read($successRegex, $returnRegex, $returnIndex); $executor->close(); - AllureHelper::addAttachmentToLastStep(json_encode($this->requestData, JSON_PRETTY_PRINT), 'Request Body'); - AllureHelper::addAttachmentToLastStep( + AllureHelper::addAttachmentToCurrentStep(json_encode($this->requestData, JSON_PRETTY_PRINT), 'Request Body'); + AllureHelper::addAttachmentToCurrentStep( json_encode(json_decode($response, true), JSON_PRETTY_PRINT+JSON_UNESCAPED_UNICODE+JSON_UNESCAPED_SLASHES), 'Response Data' ); diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoActionProxies.php b/src/Magento/FunctionalTestingFramework/Module/MagentoActionProxies.php new file mode 100644 index 000000000..1cc02b58f --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoActionProxies.php @@ -0,0 +1,157 @@ + Value of override fields. + * @param string $storeCode + * @return void + */ + public function createEntity( + $key, + $scope, + $entity, + $dependentObjectKeys = [], + $overrideFields = [], + $storeCode = '' + ) { + if (!self::$persistHandler) { + self::$persistHandler = PersistedObjectHandler::getInstance(); + } + + self::$persistHandler->createEntity( + $key, + $scope, + $entity, + $dependentObjectKeys, + $overrideFields, + $storeCode + ); + } + + /** + * Retrieves and updates a previously created entity + * + * @param string $key StepKey of the createData action. + * @param string $scope + * @param string $updateEntity Name of the static XML data to update the entity with. + * @param array $dependentObjectKeys StepKeys of other createData actions that are required. + * @return void + */ + public function updateEntity($key, $scope, $updateEntity, $dependentObjectKeys = []) + { + if (!self::$persistHandler) { + self::$persistHandler = PersistedObjectHandler::getInstance(); + } + + self::$persistHandler->updateEntity( + $key, + $scope, + $updateEntity, + $dependentObjectKeys + ); + } + + /** + * Performs GET on given entity and stores entity for use + * + * @param string $key StepKey of getData action. + * @param string $scope + * @param string $entity Name of XML static data to use. + * @param array $dependentObjectKeys StepKeys of other createData actions that are required. + * @param string $storeCode + * @param integer $index + * @return void + */ + public function getEntity($key, $scope, $entity, $dependentObjectKeys = [], $storeCode = '', $index = null) + { + if (!self::$persistHandler) { + self::$persistHandler = PersistedObjectHandler::getInstance(); + } + + self::$persistHandler->getEntity( + $key, + $scope, + $entity, + $dependentObjectKeys, + $storeCode, + $index + ); + } + + /** + * Retrieves and deletes a previously created entity + * + * @param string $key StepKey of the createData action. + * @param string $scope + * @return void + */ + public function deleteEntity($key, $scope) + { + if (!self::$persistHandler) { + self::$persistHandler = PersistedObjectHandler::getInstance(); + } + + self::$persistHandler->deleteEntity($key, $scope); + } + + /** + * Retrieves a field from an entity, according to key and scope given + * + * @param string $stepKey + * @param string $field + * @param string $scope + * @return string + */ + public function retrieveEntityField($stepKey, $field, $scope) + { + if (!self::$persistHandler) { + self::$persistHandler = PersistedObjectHandler::getInstance(); + } + + return self::$persistHandler->retrieveEntityField($stepKey, $field, $scope); + } + + /** + * Get encrypted value by key + * + * @param string $key + * @return string|null + * @throws TestFrameworkException + */ + public function getSecret($key) + { + return CredentialStore::getInstance()->getSecret($key); + } +} diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php index 8f60e1e90..447869f38 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php @@ -192,7 +192,7 @@ public function getType() /** * Getter for actionOrigin * - * @return string + * @return array */ public function getActionOrigin() { diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 7b0d2916e..19c761d9c 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -57,6 +57,13 @@ class TestGenerator ]; const STEP_KEY_ANNOTATION = " // stepKey: %s"; + /** + * Actor name for AcceptanceTest + * + * @var string + */ + private $actor = 'I'; + /** * Path to the export dir. * @@ -97,7 +104,7 @@ class TestGenerator * * @var string */ - private $currentGenerationScope; + private $currentGenerationScope = TestGenerator::TEST_SCOPE; /** * TestGenerator constructor. @@ -326,8 +333,6 @@ private function debug($messages) private function generateUseStatementsPhp() { $useStatementsPhp = "use Magento\FunctionalTestingFramework\AcceptanceTester;\n"; - $useStatementsPhp .= "use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore;\n"; - $useStatementsPhp .= "use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler;\n"; $useStatementsPhp .= "use \Codeception\Util\Locator;\n"; $allureStatements = [ @@ -499,7 +504,8 @@ private function generateClassAnnotations($annotationType, $annotationName) public function generateStepsPhp($actionObjects, $generationScope = TestGenerator::TEST_SCOPE, $actor = "I") { //TODO: Refactor Method according to PHPMD warnings, remove @SuppressWarnings accordingly. - $testSteps = ""; + $testSteps = ''; + $this->actor = $actor; $this->currentGenerationScope = $generationScope; foreach ($actionObjects as $actionObject) { @@ -754,7 +760,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $scope = PersistedObjectHandler::SUITE_SCOPE; } - $createEntityFunctionCall = "\t\tPersistedObjectHandler::getInstance()->createEntity("; + $createEntityFunctionCall = "\t\t\${$actor}->createEntity("; $createEntityFunctionCall .= "\n\t\t\t\"{$stepKey}\","; $createEntityFunctionCall .= "\n\t\t\t\"{$scope}\","; $createEntityFunctionCall .= "\n\t\t\t\"{$entity}\""; @@ -795,7 +801,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $scope = PersistedObjectHandler::SUITE_SCOPE; } - $deleteEntityFunctionCall = "\t\tPersistedObjectHandler::getInstance()->deleteEntity("; + $deleteEntityFunctionCall = "\t\t\${$actor}->deleteEntity("; $deleteEntityFunctionCall .= "\n\t\t\t\"{$key}\","; $deleteEntityFunctionCall .= "\n\t\t\t\"{$scope}\""; $deleteEntityFunctionCall .= "\n\t\t);\n"; @@ -853,7 +859,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $scope = PersistedObjectHandler::SUITE_SCOPE; } - $updateEntityFunctionCall = "\t\tPersistedObjectHandler::getInstance()->updateEntity("; + $updateEntityFunctionCall = "\t\t\${$actor}->updateEntity("; $updateEntityFunctionCall .= "\n\t\t\t\"{$key}\","; $updateEntityFunctionCall .= "\n\t\t\t\"{$scope}\","; $updateEntityFunctionCall .= "\n\t\t\t\"{$updateEntity}\""; @@ -901,7 +907,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato } //Create Function - $getEntityFunctionCall = "\t\tPersistedObjectHandler::getInstance()->getEntity("; + $getEntityFunctionCall = "\t\t\${$actor}->getEntity("; $getEntityFunctionCall .= "\n\t\t\t\"{$stepKey}\","; $getEntityFunctionCall .= "\n\t\t\t\"{$scope}\","; $getEntityFunctionCall .= "\n\t\t\t\"{$entity}\""; @@ -1429,7 +1435,11 @@ private function replaceMatchesIntoArg($matches, &$outputArg) ); } - $replacement = "PersistedObjectHandler::getInstance()->retrieveEntityField"; + $actor = "\$" . $this->actor; + if ($this->currentGenerationScope === TestGenerator::SUITE_SCOPE) { + $actor = 'PersistedObjectHandler::getInstance()'; + } + $replacement = "{$actor}->retrieveEntityField"; $replacement .= "('{$variable[0]}', '$variable[1]', '{$this->currentGenerationScope}')"; //Determine if quoteBreak check is necessary. Assume replacement is surrounded in quotes, then override @@ -1484,9 +1494,14 @@ private function resolveStepKeyReferences($input, $actionGroupOrigin, $matchAll foreach ($stepKeys as $stepKey) { // MQE-1011 $stepKeyVarRef = "$" . $stepKey; - $persistedVarRef = "PersistedObjectHandler::getInstance()->retrieveEntityField('{$stepKey}'" + + $actor = "\$" . $this->actor; + if ($this->currentGenerationScope === TestGenerator::SUITE_SCOPE) { + $actor = 'PersistedObjectHandler::getInstance()'; + } + $persistedVarRef = "{$actor}->retrieveEntityField('{$stepKey}'" . ", 'field', 'test')"; - $persistedVarRefInvoked = "PersistedObjectHandler::getInstance()->retrieveEntityField('" + $persistedVarRefInvoked = "{$actor}->retrieveEntityField('" . $stepKey . $testInvocationKey . "', 'field', 'test')"; // only replace when whole word matches exactly @@ -1876,6 +1891,7 @@ private function wrapFunctionCallWithReturnValue($returnVariable, $actor, $actio $output .= implode(", ", array_filter($args, function($value) { return $value !== null; })) . ");"; return $output; } + // @codingStandardsIgnoreEnd /** @@ -1919,7 +1935,7 @@ private function resolveAllRuntimeReferences($args) { $runtimeReferenceRegex = [ "/{{_ENV\.([\w]+)}}/" => 'getenv', - ActionMergeUtil::CREDS_REGEX => 'CredentialStore::getInstance()->getSecret' + ActionMergeUtil::CREDS_REGEX => "\${$this->actor}->getSecret" ]; $argResult = $args; From 0cdb29408df31a431409abd12dce85fa6f5e62a0 Mon Sep 17 00:00:00 2001 From: Tom Reece Date: Mon, 2 Dec 2019 06:43:48 -0600 Subject: [PATCH 083/888] MQE-1463: Fixes for Suite documentation in devdocs --- docs/suite.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/suite.md b/docs/suite.md index e49dd02ab..045f557e1 100644 --- a/docs/suite.md +++ b/docs/suite.md @@ -4,9 +4,10 @@ Suites are essentially groups of tests that run in the specific conditions (prec They enable you including, excluding, and grouping tests for a customized test run when you need it. You can form suites using separate tests, groups, and modules. -Each suite must be defined in the `/dev/tests/acceptance/tests/_suite/suite.xml` file. -The generated tests for each suite go into a separate directory under `/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/_generated/`. -By default, all generated tests are stored in the _default_ suite under `.../Magento/FunctionalTest/_generated/default/` +Each suite must be defined in the `//Test/Mftf/Suite` directory. + +The tests for each suite will be generated in a separate directory under `/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/_generated/`. +All tests that aren't in a suite will be generated in the _default_ suite at `.../Magento/FunctionalTest/_generated/default/`
If a test is generated into at least one custom suite, it will not appear in the _default_ suite. @@ -59,8 +60,6 @@ The code lives in one place and executes once per suite. - Set up preconditions and postconditions using [actions] in [``] and [``] correspondingly, just similar to use in a [test]. - Clean up after suites just like after tests. The MFTF enforces the presence of both `` and `` if either is present. -- Do not reference in the subsequent tests to data that was persisted in the preconditions. - Referencing to `$stepKey.field$` of these actions is not valid. ## Test writing From c1964dc87f31ed31c079a7e3e6ca9633bc9092bd Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Mon, 2 Dec 2019 10:01:10 -0600 Subject: [PATCH 084/888] MQE-1379: Fix MFTF custom actions to fully support Codeception dry-run functionality --- dev/tests/verification/Resources/BasicFunctionalTest.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/tests/verification/Resources/BasicFunctionalTest.txt b/dev/tests/verification/Resources/BasicFunctionalTest.txt index 8e13d916c..812972eed 100644 --- a/dev/tests/verification/Resources/BasicFunctionalTest.txt +++ b/dev/tests/verification/Resources/BasicFunctionalTest.txt @@ -128,9 +128,9 @@ class BasicFunctionalTestCest $I->comment($magentoCli1); $magentoCli2 = $I->magentoCLI("maintenance:enable", 120, "\"stuffHere\""); // stepKey: magentoCli2 $I->comment($magentoCli2); - $magentoCli3 = $I->magentoCLISecret("config:set somePath " . CredentialStore::getInstance()->getSecret("someKey"), 60); // stepKey: magentoCli3 + $magentoCli3 = $I->magentoCLISecret("config:set somePath " . $I->getSecret("someKey"), 60); // stepKey: magentoCli3 $I->comment($magentoCli3); // stepKey: magentoCli3 - $magentoCli4 = $I->magentoCLISecret("config:set somePath " . CredentialStore::getInstance()->getSecret("someKey"), 120); // stepKey: magentoCli4 + $magentoCli4 = $I->magentoCLISecret("config:set somePath " . $I->getSecret("someKey"), 120); // stepKey: magentoCli4 $I->comment($magentoCli4); // stepKey: magentoCli4 $I->makeScreenshot("screenShotInput"); // stepKey: makeScreenshotKey1 $I->maximizeWindow(); // stepKey: maximizeWindowKey1 From 691b6753f439a516af5d6e17987c7ed89abc885a Mon Sep 17 00:00:00 2001 From: Tomash Khamlai Date: Mon, 2 Dec 2019 19:45:10 +0200 Subject: [PATCH 085/888] Add link to action-groups.md Signed-off-by: Tomash Khamlai --- docs/merging.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/merging.md b/docs/merging.md index 99df18464..e4b91fb5f 100644 --- a/docs/merging.md +++ b/docs/merging.md @@ -6,7 +6,7 @@ The MFTF allows you to merge test components defined in XML files, such as: - [``][] - [``][] - [``][] -- `` +- [``][] You can create, delete, or update the component. It is useful for supporting rapid test creation for extensions and customizations. @@ -569,3 +569,4 @@ The `_defaultSample` results corresponds to: [``]: ./page.md [``]: ./section.md [``]: ./test.md +[``]: ./test/action-groups.md From 1471d80270db517a4bd8871bca60e8cb4840fb3a Mon Sep 17 00:00:00 2001 From: Donald Booth Date: Mon, 2 Dec 2019 14:45:13 -0800 Subject: [PATCH 086/888] Grammar and formatting --- docs/suite.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/suite.md b/docs/suite.md index 045f557e1..3d737ece5 100644 --- a/docs/suite.md +++ b/docs/suite.md @@ -6,8 +6,8 @@ You can form suites using separate tests, groups, and modules. Each suite must be defined in the `//Test/Mftf/Suite` directory. -The tests for each suite will be generated in a separate directory under `/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/_generated/`. -All tests that aren't in a suite will be generated in the _default_ suite at `.../Magento/FunctionalTest/_generated/default/` +The tests for each suite are generated in a separate directory under `/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/_generated/`. +All tests that are not within a suite are generated in the _default_ suite at `.../Magento/FunctionalTest/_generated/default/`.
If a test is generated into at least one custom suite, it will not appear in the _default_ suite. From 3becb62e67c8200074144beffcd054b7f96ee717 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Tue, 3 Dec 2019 08:50:42 -0600 Subject: [PATCH 087/888] MQE-1902: Running bin/magento from MagentoWebDriver causing timeout issues on pipeline Updated shellExecMagentoCLI to mimic command.php Excluding cron from shell execution to prevent timeouts in pipeline. --- .../Module/MagentoWebDriver.php | 90 ++++++++++++++++--- 1 file changed, 76 insertions(+), 14 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index cbde1ddfc..37c39b0ec 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -22,6 +22,7 @@ use Yandex\Allure\Adapter\AllureException; use Magento\FunctionalTestingFramework\Util\Protocol\CurlTransport; use Symfony\Component\Process\Process; +use Symfony\Component\Process\Exception\ProcessTimedOutException; use Yandex\Allure\Adapter\Support\AttachmentSupport; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; @@ -52,6 +53,8 @@ class MagentoWebDriver extends WebDriver { use AttachmentSupport; + const COMMAND_CRON_RUN = 'cron:run'; + /** * List of known magento loading masks by selector * @@ -520,13 +523,14 @@ public function scrollToTopOfPage() */ public function magentoCLI($command, $timeout = null, $arguments = null) { - return $this->curlExecMagentoCLI($command, $timeout, $arguments); - //TODO: calling bin/magento from pipeline is timing out, needs investigation (ref: MQE-1774) -// try { -// return $this->shellExecMagentoCLI($command, $arguments); -// } catch (\Exception $exception) { -// return $this->curlExecMagentoCLI($command, $arguments); -// } + $magentoBinary = realpath(MAGENTO_BP . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'magento'); + $valid = $this->validateCommand($magentoBinary, $command); + // execute from shell when running tests from web root -- excludes cron jobs. + if ($valid && strpos($command, self::COMMAND_CRON_RUN) === false) { + return $this->shellExecMagentoCLI($magentoBinary, $command, $timeout, $arguments); + } else { + return $this->curlExecMagentoCLI($command, $timeout, $arguments); + } } /** @@ -838,6 +842,7 @@ public function makeScreenshot($name = null) /** * Takes given $command and executes it against bin/magento executable. Returns stdout output from the command. * + * @param string $magentoBinary * @param string $command * @param integer $timeout * @param string $arguments @@ -846,20 +851,41 @@ public function makeScreenshot($name = null) * @return string * @SuppressWarnings(PHPMD.UnusedPrivateMethod) */ - private function shellExecMagentoCLI($command, $timeout, $arguments): string + private function shellExecMagentoCLI($magentoBinary, $command, $timeout, $arguments): string { $php = PHP_BINDIR ? PHP_BINDIR . DIRECTORY_SEPARATOR. 'php' : 'php'; - $binMagento = realpath(MAGENTO_BP . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'magento'); - $command = $php . ' -f ' . $binMagento . ' ' . $command . ' ' . $arguments; - $process = new Process(escapeshellcmd($command), MAGENTO_BP); + $fullCommand = $php . ' -f ' . $magentoBinary . ' ' . $command . ' ' . $arguments; + $process = new Process(escapeshellcmd($fullCommand), MAGENTO_BP); $process->setIdleTimeout($timeout); $process->setTimeout(0); - $exitCode = $process->run(); + try { + $process->run(); + $output = $process->getOutput(); + if (!$process->isSuccessful()) { + $failureOutput = $process->getErrorOutput(); + if (!empty($failureOutput)) { + $output = $failureOutput; + } + } + if (empty($output)) { + $output = "CLI did not return output."; + } + + } catch (ProcessTimedOutException $exception) { + $output = "CLI command timed out, no output available."; + + } + + if ($this->checkForFilePath($output)) { + $output = "CLI output suppressed, filepath detected in output."; + } + + $exitCode = $process->getExitCode(); + if ($exitCode !== 0) { throw new \RuntimeException($process->getErrorOutput()); } - - return $process->getOutput(); + return $output; } /** @@ -904,4 +930,40 @@ private function curlExecMagentoCLI($command, $timeout, $arguments): string return $response; } + + /** + * Checks magento list of CLI commands for given $command. Does not check command parameters, just base command. + * @param string $magentoBinary + * @param string $command + * @return bool + */ + private function validateCommand($magentoBinary, $command) + { + exec($magentoBinary . ' list', $commandList); + // Trim list of commands after first whitespace + $commandList = array_map(array($this, 'trimAfterWhitespace'), $commandList); + return in_array($this->trimAfterWhitespace($command), $commandList); + } + + /** + * Returns given string trimmed of everything after the first found whitespace. + * @param string $string + * @return string + */ + private function trimAfterWhitespace($string) + { + return strtok($string, ' '); + } + + /** + * Detects file path in string. + * @param string $string + * @return boolean + */ + private function checkForFilePath($string) + { + return preg_match('/\/[\S]+\//', $string); + } + } + From 41afe3d9594f26ea1f700015a536ab0a807c4de2 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Tue, 3 Dec 2019 09:17:27 -0600 Subject: [PATCH 088/888] MQE-1902: Running bin/magento from MagentoWebDriver causing timeout issues on pipeline fixed phpunit checks --- .../Module/MagentoWebDriver.php | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 37c39b0ec..fa5bf2110 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -849,7 +849,6 @@ public function makeScreenshot($name = null) * * @throws \RuntimeException * @return string - * @SuppressWarnings(PHPMD.UnusedPrivateMethod) */ private function shellExecMagentoCLI($magentoBinary, $command, $timeout, $arguments): string { @@ -870,10 +869,8 @@ private function shellExecMagentoCLI($magentoBinary, $command, $timeout, $argume if (empty($output)) { $output = "CLI did not return output."; } - } catch (ProcessTimedOutException $exception) { $output = "CLI command timed out, no output available."; - } if ($this->checkForFilePath($output)) { @@ -933,21 +930,25 @@ private function curlExecMagentoCLI($command, $timeout, $arguments): string /** * Checks magento list of CLI commands for given $command. Does not check command parameters, just base command. + * * @param string $magentoBinary * @param string $command - * @return bool + * + * @return boolean */ private function validateCommand($magentoBinary, $command) { exec($magentoBinary . ' list', $commandList); // Trim list of commands after first whitespace - $commandList = array_map(array($this, 'trimAfterWhitespace'), $commandList); + $commandList = array_map([$this, 'trimAfterWhitespace'], $commandList); return in_array($this->trimAfterWhitespace($command), $commandList); } /** * Returns given string trimmed of everything after the first found whitespace. + * * @param string $string + * * @return string */ private function trimAfterWhitespace($string) @@ -957,13 +958,13 @@ private function trimAfterWhitespace($string) /** * Detects file path in string. + * * @param string $string + * * @return boolean */ private function checkForFilePath($string) { return preg_match('/\/[\S]+\//', $string); } - -} - +} \ No newline at end of file From dea0c05b621710d159fa88504ff2f777486a3303 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Tue, 3 Dec 2019 10:42:34 -0600 Subject: [PATCH 089/888] MQE-1902: Running bin/magento from MagentoWebDriver causing timeout issues on pipeline Not fetching output from cron. --- .../Module/MagentoWebDriver.php | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index fa5bf2110..ae12ad754 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -525,8 +525,8 @@ public function magentoCLI($command, $timeout = null, $arguments = null) { $magentoBinary = realpath(MAGENTO_BP . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'magento'); $valid = $this->validateCommand($magentoBinary, $command); - // execute from shell when running tests from web root -- excludes cron jobs. - if ($valid && strpos($command, self::COMMAND_CRON_RUN) === false) { + // execute from shell when running tests from web root. + if ($valid) { return $this->shellExecMagentoCLI($magentoBinary, $command, $timeout, $arguments); } else { return $this->curlExecMagentoCLI($command, $timeout, $arguments); @@ -854,16 +854,18 @@ private function shellExecMagentoCLI($magentoBinary, $command, $timeout, $argume { $php = PHP_BINDIR ? PHP_BINDIR . DIRECTORY_SEPARATOR. 'php' : 'php'; $fullCommand = $php . ' -f ' . $magentoBinary . ' ' . $command . ' ' . $arguments; - $process = new Process(escapeshellcmd($fullCommand), MAGENTO_BP); + $process = Process::fromShellCommandline(escapeshellcmd($fullCommand), MAGENTO_BP); $process->setIdleTimeout($timeout); $process->setTimeout(0); try { $process->run(); - $output = $process->getOutput(); - if (!$process->isSuccessful()) { - $failureOutput = $process->getErrorOutput(); - if (!empty($failureOutput)) { - $output = $failureOutput; + if (strpos($command, self::COMMAND_CRON_RUN) === false) { + $output = $process->getOutput(); + if (!$process->isSuccessful()) { + $failureOutput = $process->getErrorOutput(); + if (!empty($failureOutput)) { + $output = $failureOutput; + } } } if (empty($output)) { @@ -967,4 +969,5 @@ private function checkForFilePath($string) { return preg_match('/\/[\S]+\//', $string); } -} \ No newline at end of file +} + From be3bd6e7951affb025961a8745509586ed69a720 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Tue, 3 Dec 2019 11:48:52 -0600 Subject: [PATCH 090/888] MQE-1379: Fix MFTF custom actions to fully support Codeception dry-run functionality - work around MQE-1904 --- .../Module/MagentoActionProxies.php | 60 ++++----- .../Module/MagentoWebDriver.php | 116 ++++++++++++++++++ 2 files changed, 139 insertions(+), 37 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoActionProxies.php b/src/Magento/FunctionalTestingFramework/Module/MagentoActionProxies.php index 1cc02b58f..18c800e48 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoActionProxies.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoActionProxies.php @@ -20,15 +20,9 @@ */ class MagentoActionProxies extends CodeceptionModule { - /** - * PersistedObjectHandler instance - * - * @var PersistedObjectHandler - */ - private static $persistHandler = null; - /** * Create an entity + * TODO: un-comment this function after MQE-1904 * * @param string $key StepKey of the createData action. * @param string $scope @@ -38,6 +32,7 @@ class MagentoActionProxies extends CodeceptionModule * @param string $storeCode * @return void */ + /* public function createEntity( $key, $scope, @@ -46,11 +41,7 @@ public function createEntity( $overrideFields = [], $storeCode = '' ) { - if (!self::$persistHandler) { - self::$persistHandler = PersistedObjectHandler::getInstance(); - } - - self::$persistHandler->createEntity( + PersistedObjectHandler::getInstance()->createEntity( $key, $scope, $entity, @@ -59,9 +50,10 @@ public function createEntity( $storeCode ); } - + */ /** * Retrieves and updates a previously created entity + * TODO: un-comment this function after MQE-1904 * * @param string $key StepKey of the createData action. * @param string $scope @@ -69,22 +61,20 @@ public function createEntity( * @param array $dependentObjectKeys StepKeys of other createData actions that are required. * @return void */ + /* public function updateEntity($key, $scope, $updateEntity, $dependentObjectKeys = []) { - if (!self::$persistHandler) { - self::$persistHandler = PersistedObjectHandler::getInstance(); - } - - self::$persistHandler->updateEntity( + PersistedObjectHandler::getInstance()->updateEntity( $key, $scope, $updateEntity, $dependentObjectKeys ); } - + */ /** * Performs GET on given entity and stores entity for use + * TODO: un-comment this function after MQE-1904 * * @param string $key StepKey of getData action. * @param string $scope @@ -94,13 +84,10 @@ public function updateEntity($key, $scope, $updateEntity, $dependentObjectKeys = * @param integer $index * @return void */ + /* public function getEntity($key, $scope, $entity, $dependentObjectKeys = [], $storeCode = '', $index = null) { - if (!self::$persistHandler) { - self::$persistHandler = PersistedObjectHandler::getInstance(); - } - - self::$persistHandler->getEntity( + PersistedObjectHandler::getInstance()->getEntity( $key, $scope, $entity, @@ -109,49 +96,48 @@ public function getEntity($key, $scope, $entity, $dependentObjectKeys = [], $sto $index ); } - + */ /** * Retrieves and deletes a previously created entity + * TODO: un-comment this function after MQE-1904 * * @param string $key StepKey of the createData action. * @param string $scope * @return void */ + /* public function deleteEntity($key, $scope) { - if (!self::$persistHandler) { - self::$persistHandler = PersistedObjectHandler::getInstance(); - } - - self::$persistHandler->deleteEntity($key, $scope); + PersistedObjectHandler::getInstance()->deleteEntity($key, $scope); } - + */ /** * Retrieves a field from an entity, according to key and scope given + * TODO: un-comment this function after MQE-1904 * * @param string $stepKey * @param string $field * @param string $scope * @return string */ + /* public function retrieveEntityField($stepKey, $field, $scope) { - if (!self::$persistHandler) { - self::$persistHandler = PersistedObjectHandler::getInstance(); - } - - return self::$persistHandler->retrieveEntityField($stepKey, $field, $scope); + return PersistedObjectHandler::getInstance()->retrieveEntityField($stepKey, $field, $scope); } - + */ /** * Get encrypted value by key + * TODO: un-comment this function after MQE-1904 * * @param string $key * @return string|null * @throws TestFrameworkException */ + /* public function getSecret($key) { return CredentialStore::getInstance()->getSecret($key); } + */ } diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index cbde1ddfc..4cb980d9c 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -27,6 +27,7 @@ use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Facebook\WebDriver\Remote\RemoteWebDriver; use Facebook\WebDriver\Exception\WebDriverCurlException; +use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; /** * MagentoWebDriver module provides common Magento web actions through Selenium WebDriver. @@ -47,6 +48,7 @@ * ``` * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @SuppressWarnings(PHPMD.ExcessivePublicCount) */ class MagentoWebDriver extends WebDriver { @@ -904,4 +906,118 @@ private function curlExecMagentoCLI($command, $timeout, $arguments): string return $response; } + + /** + * Create an entity + * TODO: remove this function after MQE-1904 + * + * @param string $key StepKey of the createData action. + * @param string $scope + * @param string $entity Name of xml entity to create. + * @param array $dependentObjectKeys StepKeys of other createData actions that are required. + * @param array $overrideFields Array of FieldName => Value of override fields. + * @param string $storeCode + * @return void + */ + public function createEntity( + $key, + $scope, + $entity, + $dependentObjectKeys = [], + $overrideFields = [], + $storeCode = '' + ) { + PersistedObjectHandler::getInstance()->createEntity( + $key, + $scope, + $entity, + $dependentObjectKeys, + $overrideFields, + $storeCode + ); + } + + /** + * Retrieves and updates a previously created entity + * TODO: remove this function after MQE-1904 + * + * @param string $key StepKey of the createData action. + * @param string $scope + * @param string $updateEntity Name of the static XML data to update the entity with. + * @param array $dependentObjectKeys StepKeys of other createData actions that are required. + * @return void + */ + public function updateEntity($key, $scope, $updateEntity, $dependentObjectKeys = []) + { + PersistedObjectHandler::getInstance()->updateEntity( + $key, + $scope, + $updateEntity, + $dependentObjectKeys + ); + } + + /** + * Performs GET on given entity and stores entity for use + * TODO: remove this function after MQE-1904 + * + * @param string $key StepKey of getData action. + * @param string $scope + * @param string $entity Name of XML static data to use. + * @param array $dependentObjectKeys StepKeys of other createData actions that are required. + * @param string $storeCode + * @param integer $index + * @return void + */ + public function getEntity($key, $scope, $entity, $dependentObjectKeys = [], $storeCode = '', $index = null) + { + PersistedObjectHandler::getInstance()->getEntity( + $key, + $scope, + $entity, + $dependentObjectKeys, + $storeCode, + $index + ); + } + + /** + * Retrieves and deletes a previously created entity + * TODO: remove this function after MQE-1904 + * + * @param string $key StepKey of the createData action. + * @param string $scope + * @return void + */ + public function deleteEntity($key, $scope) + { + PersistedObjectHandler::getInstance()->deleteEntity($key, $scope); + } + + /** + * Retrieves a field from an entity, according to key and scope given + * TODO: remove this function after MQE-1904 + * + * @param string $stepKey + * @param string $field + * @param string $scope + * @return string + */ + public function retrieveEntityField($stepKey, $field, $scope) + { + return PersistedObjectHandler::getInstance()->retrieveEntityField($stepKey, $field, $scope); + } + + /** + * Get encrypted value by key + * TODO: remove this function after MQE-1904 + * + * @param string $key + * @return string|null + * @throws TestFrameworkException + */ + public function getSecret($key) + { + return CredentialStore::getInstance()->getSecret($key); + } } From 50d9cd27a4edb4b0801abc821469d45f5196d26b Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Tue, 3 Dec 2019 14:24:27 -0600 Subject: [PATCH 091/888] MQE-1902: Running bin/magento from MagentoWebDriver causing timeout issues on pipeline Reverted changes, build still hangs with starting cron process from shell. --- .../Module/MagentoWebDriver.php | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index ae12ad754..6bdfbcd12 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -525,8 +525,9 @@ public function magentoCLI($command, $timeout = null, $arguments = null) { $magentoBinary = realpath(MAGENTO_BP . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'magento'); $valid = $this->validateCommand($magentoBinary, $command); - // execute from shell when running tests from web root. - if ($valid) { + // execute from shell when running tests from web root -- excluding cron + //TODO: investigate why cron:run hangs with shell execution on pipeline + if ($valid && ($command !== self::COMMAND_CRON_RUN)) { return $this->shellExecMagentoCLI($magentoBinary, $command, $timeout, $arguments); } else { return $this->curlExecMagentoCLI($command, $timeout, $arguments); @@ -859,13 +860,11 @@ private function shellExecMagentoCLI($magentoBinary, $command, $timeout, $argume $process->setTimeout(0); try { $process->run(); - if (strpos($command, self::COMMAND_CRON_RUN) === false) { - $output = $process->getOutput(); - if (!$process->isSuccessful()) { - $failureOutput = $process->getErrorOutput(); - if (!empty($failureOutput)) { - $output = $failureOutput; - } + $output = $process->getOutput(); + if (!$process->isSuccessful()) { + $failureOutput = $process->getErrorOutput(); + if (!empty($failureOutput)) { + $output = $failureOutput; } } if (empty($output)) { From 5946652fcd956441c9fabf36f948f657e12013a7 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Tue, 3 Dec 2019 14:27:23 -0600 Subject: [PATCH 092/888] MQE-1902: Running bin/magento from MagentoWebDriver causing timeout issues on pipeline Reverted changes, build still hangs with starting cron process from shell. --- .../FunctionalTestingFramework/Module/MagentoWebDriver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 6bdfbcd12..43437d116 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -527,7 +527,7 @@ public function magentoCLI($command, $timeout = null, $arguments = null) $valid = $this->validateCommand($magentoBinary, $command); // execute from shell when running tests from web root -- excluding cron //TODO: investigate why cron:run hangs with shell execution on pipeline - if ($valid && ($command !== self::COMMAND_CRON_RUN)) { + if ($valid && strpos($command, self::COMMAND_CRON_RUN) === false) { return $this->shellExecMagentoCLI($magentoBinary, $command, $timeout, $arguments); } else { return $this->curlExecMagentoCLI($command, $timeout, $arguments); From 84b9f87123d00bd3b36cc2bad4358666ca48c756 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Tue, 3 Dec 2019 15:03:40 -0600 Subject: [PATCH 093/888] MQE-1902: Running bin/magento from MagentoWebDriver causing timeout issues on pipeline fixed phpunit checks --- .../FunctionalTestingFramework/Module/MagentoWebDriver.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 43437d116..710ea993e 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -969,4 +969,3 @@ private function checkForFilePath($string) return preg_match('/\/[\S]+\//', $string); } } - From e207c475faae37be3c1be9066572c5d25f135c16 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Wed, 4 Dec 2019 11:28:53 -0600 Subject: [PATCH 094/888] MQE-1902: Running bin/magento from MagentoWebDriver causing timeout issues on pipeline reverting changes of community PR#343 --- .../Module/MagentoWebDriver.php | 167 +++--------------- 1 file changed, 29 insertions(+), 138 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 710ea993e..dacfbb2d4 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -523,15 +523,35 @@ public function scrollToTopOfPage() */ public function magentoCLI($command, $timeout = null, $arguments = null) { - $magentoBinary = realpath(MAGENTO_BP . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'magento'); - $valid = $this->validateCommand($magentoBinary, $command); - // execute from shell when running tests from web root -- excluding cron - //TODO: investigate why cron:run hangs with shell execution on pipeline - if ($valid && strpos($command, self::COMMAND_CRON_RUN) === false) { - return $this->shellExecMagentoCLI($magentoBinary, $command, $timeout, $arguments); - } else { - return $this->curlExecMagentoCLI($command, $timeout, $arguments); - } + // Remove index.php if it's present in url + $baseUrl = rtrim( + str_replace('index.php', '', rtrim($this->config['url'], '/')), + '/' + ); + + $apiURL = UrlFormatter::format( + $baseUrl . '/' . ltrim(getenv('MAGENTO_CLI_COMMAND_PATH'), '/'), + false + ); + + $restExecutor = new WebapiExecutor(); + $executor = new CurlTransport(); + $executor->write( + $apiURL, + [ + 'token' => $restExecutor->getAuthToken(), + getenv('MAGENTO_CLI_COMMAND_PARAMETER') => $command, + 'arguments' => $arguments, + 'timeout' => $timeout, + ], + CurlInterface::POST, + [] + ); + $response = $executor->read(); + $restExecutor->close(); + $executor->close(); + + return $response; } /** @@ -839,133 +859,4 @@ public function makeScreenshot($name = null) $this->debug("Screenshot saved to $screenName"); AllureHelper::addAttachmentToCurrentStep($screenName, 'Screenshot'); } - - /** - * Takes given $command and executes it against bin/magento executable. Returns stdout output from the command. - * - * @param string $magentoBinary - * @param string $command - * @param integer $timeout - * @param string $arguments - * - * @throws \RuntimeException - * @return string - */ - private function shellExecMagentoCLI($magentoBinary, $command, $timeout, $arguments): string - { - $php = PHP_BINDIR ? PHP_BINDIR . DIRECTORY_SEPARATOR. 'php' : 'php'; - $fullCommand = $php . ' -f ' . $magentoBinary . ' ' . $command . ' ' . $arguments; - $process = Process::fromShellCommandline(escapeshellcmd($fullCommand), MAGENTO_BP); - $process->setIdleTimeout($timeout); - $process->setTimeout(0); - try { - $process->run(); - $output = $process->getOutput(); - if (!$process->isSuccessful()) { - $failureOutput = $process->getErrorOutput(); - if (!empty($failureOutput)) { - $output = $failureOutput; - } - } - if (empty($output)) { - $output = "CLI did not return output."; - } - } catch (ProcessTimedOutException $exception) { - $output = "CLI command timed out, no output available."; - } - - if ($this->checkForFilePath($output)) { - $output = "CLI output suppressed, filepath detected in output."; - } - - $exitCode = $process->getExitCode(); - - if ($exitCode !== 0) { - throw new \RuntimeException($process->getErrorOutput()); - } - return $output; - } - - /** - * Takes given $command and executes it against exposed MTF CLI entry point. Returns response from server. - * - * @param string $command - * @param integer $timeout - * @param string $arguments - * - * @return string - * @throws TestFrameworkException - */ - private function curlExecMagentoCLI($command, $timeout, $arguments): string - { - // Remove index.php if it's present in url - $baseUrl = rtrim( - str_replace('index.php', '', rtrim($this->config['url'], '/')), - '/' - ); - - $apiURL = UrlFormatter::format( - $baseUrl . '/' . ltrim(getenv('MAGENTO_CLI_COMMAND_PATH'), '/'), - false - ); - - $restExecutor = new WebapiExecutor(); - $executor = new CurlTransport(); - $executor->write( - $apiURL, - [ - 'token' => $restExecutor->getAuthToken(), - getenv('MAGENTO_CLI_COMMAND_PARAMETER') => $command, - 'arguments' => $arguments, - 'timeout' => $timeout, - ], - CurlInterface::POST, - [] - ); - $response = $executor->read(); - $restExecutor->close(); - $executor->close(); - - return $response; - } - - /** - * Checks magento list of CLI commands for given $command. Does not check command parameters, just base command. - * - * @param string $magentoBinary - * @param string $command - * - * @return boolean - */ - private function validateCommand($magentoBinary, $command) - { - exec($magentoBinary . ' list', $commandList); - // Trim list of commands after first whitespace - $commandList = array_map([$this, 'trimAfterWhitespace'], $commandList); - return in_array($this->trimAfterWhitespace($command), $commandList); - } - - /** - * Returns given string trimmed of everything after the first found whitespace. - * - * @param string $string - * - * @return string - */ - private function trimAfterWhitespace($string) - { - return strtok($string, ' '); - } - - /** - * Detects file path in string. - * - * @param string $string - * - * @return boolean - */ - private function checkForFilePath($string) - { - return preg_match('/\/[\S]+\//', $string); - } } From 712cc518039c2f87ee93e163d3e638019147ab63 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Wed, 4 Dec 2019 11:30:51 -0600 Subject: [PATCH 095/888] MQE-1902: Running bin/magento from MagentoWebDriver causing timeout issues on pipeline reverting changes of community PR#343 --- .../FunctionalTestingFramework/Module/MagentoWebDriver.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index dacfbb2d4..5c86e0346 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -53,8 +53,6 @@ class MagentoWebDriver extends WebDriver { use AttachmentSupport; - const COMMAND_CRON_RUN = 'cron:run'; - /** * List of known magento loading masks by selector * From fa8e51bab2821daddc4408a5c7516cd3174e5b7a Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Wed, 4 Dec 2019 13:06:18 -0600 Subject: [PATCH 096/888] MQE-1902: Running bin/magento from MagentoWebDriver causing timeout issues on pipeline removing unused references --- .../FunctionalTestingFramework/Module/MagentoWebDriver.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 5c86e0346..ff0c621dd 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -21,8 +21,6 @@ use Magento\FunctionalTestingFramework\Util\ConfigSanitizerUtil; use Yandex\Allure\Adapter\AllureException; use Magento\FunctionalTestingFramework\Util\Protocol\CurlTransport; -use Symfony\Component\Process\Process; -use Symfony\Component\Process\Exception\ProcessTimedOutException; use Yandex\Allure\Adapter\Support\AttachmentSupport; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; From 29f770c50d06922885d92df8dc543d423789f6be Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Wed, 4 Dec 2019 14:18:58 -0600 Subject: [PATCH 097/888] MQE-1379: Fix MFTF custom actions to fully support Codeception dry-run functionality --- .../Resources/ActionGroupUsingCreateData.txt | 20 +--- .../ActionGroupWithDataOverrideTest.txt | 10 +- .../Resources/ActionGroupWithDataTest.txt | 10 +- .../ActionGroupWithNoDefaultTest.txt | 10 +- ...meterizedElementsWithStepKeyReferences.txt | 10 +- .../ActionGroupWithPersistedData.txt | 20 +--- .../ActionGroupWithStepKeyReferences.txt | 46 +------- .../ActionGroupWithTopLevelPersistedData.txt | 10 +- .../ArgumentWithSameNameAsElement.txt | 10 +- .../verification/Resources/AssertTest.txt | 20 +--- .../Resources/BasicActionGroupTest.txt | 10 +- .../Resources/BasicFunctionalTest.txt | 10 +- .../Resources/DataActionsTest.txt | 68 ++---------- .../Resources/ExtendParentDataTest.txt | 10 +- .../Resources/ExtendedParameterArrayTest.txt | 9 +- .../Resources/HookActionsTest.txt | 44 +------- .../Resources/LocatorFunctionTest.txt | 10 +- .../Resources/MergedActionGroupTest.txt | 10 +- .../Resources/MultipleActionGroupsTest.txt | 10 +- .../Resources/PageReplacementTest.txt | 10 +- .../Resources/ParameterArrayTest.txt | 10 +- .../Resources/PersistedReplacementTest.txt | 20 +--- .../PersistenceActionGroupAppendingTest.txt | 72 ++----------- .../Resources/PersistenceCustomFieldsTest.txt | 100 ++---------------- .../Resources/SectionReplacementTest.txt | 10 +- .../Resources/functionalSuiteHooks.txt | 2 +- .../Allure/Adapter/MagentoAllureAdapter.php | 61 +++++++++-- .../Codeception/Subscriber/Console.php | 54 +++++++++- .../Test/Objects/ActionObject.php | 1 + .../Util/TestGenerator.php | 89 +++++----------- 30 files changed, 196 insertions(+), 580 deletions(-) diff --git a/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt b/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt index 8ec0a88a8..fb76b4f44 100644 --- a/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt +++ b/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt @@ -24,24 +24,8 @@ class ActionGroupUsingCreateDataCest public function _before(AcceptanceTester $I) { $I->comment("Entering Action Group [Key1] actionGroupWithCreateData"); - $I->comment("[createCategoryKey1] create 'ApiCategory' entity"); - $I->createEntity( - "createCategoryKey1", - "hook", - "ApiCategory", - [], - [] - ); - - $I->comment("[createConfigProductKey1] create 'ApiConfigurableProduct' entity"); - $I->createEntity( - "createConfigProductKey1", - "hook", - "ApiConfigurableProduct", - ["createCategoryKey1"], - [] - ); - + $I->createEntity("createCategoryKey1", "hook", "ApiCategory", [], []); // stepKey: createCategoryKey1 + $I->createEntity("createConfigProductKey1", "hook", "ApiConfigurableProduct", ["createCategoryKey1"], []); // stepKey: createConfigProductKey1 $I->comment("Exiting Action Group [Key1] actionGroupWithCreateData"); } diff --git a/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt b/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt index 9ad3f7127..a455d98e0 100644 --- a/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt +++ b/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt @@ -24,15 +24,7 @@ class ActionGroupWithDataOverrideTestCest */ public function _before(AcceptanceTester $I) { - $I->comment("[createPersonParam] create 'ReplacementPerson' entity"); - $I->createEntity( - "createPersonParam", - "hook", - "ReplacementPerson", - [], - [] - ); - + $I->createEntity("createPersonParam", "hook", "ReplacementPerson", [], []); // stepKey: createPersonParam $I->comment("Entering Action Group [beforeGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1BeforeGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2BeforeGroup diff --git a/dev/tests/verification/Resources/ActionGroupWithDataTest.txt b/dev/tests/verification/Resources/ActionGroupWithDataTest.txt index f1a0f6219..7ac32f550 100644 --- a/dev/tests/verification/Resources/ActionGroupWithDataTest.txt +++ b/dev/tests/verification/Resources/ActionGroupWithDataTest.txt @@ -24,15 +24,7 @@ class ActionGroupWithDataTestCest */ public function _before(AcceptanceTester $I) { - $I->comment("[createPersonParam] create 'ReplacementPerson' entity"); - $I->createEntity( - "createPersonParam", - "hook", - "ReplacementPerson", - [], - [] - ); - + $I->createEntity("createPersonParam", "hook", "ReplacementPerson", [], []); // stepKey: createPersonParam $I->comment("Entering Action Group [beforeGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1BeforeGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2BeforeGroup diff --git a/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt b/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt index 99615c728..ca6474a7b 100644 --- a/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt +++ b/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt @@ -24,15 +24,7 @@ class ActionGroupWithNoDefaultTestCest */ public function _before(AcceptanceTester $I) { - $I->comment("[createPersonParam] create 'ReplacementPerson' entity"); - $I->createEntity( - "createPersonParam", - "hook", - "ReplacementPerson", - [], - [] - ); - + $I->createEntity("createPersonParam", "hook", "ReplacementPerson", [], []); // stepKey: createPersonParam $I->comment("Entering Action Group [beforeGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1BeforeGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2BeforeGroup diff --git a/dev/tests/verification/Resources/ActionGroupWithParameterizedElementsWithStepKeyReferences.txt b/dev/tests/verification/Resources/ActionGroupWithParameterizedElementsWithStepKeyReferences.txt index 561f4d1b2..b0758e679 100644 --- a/dev/tests/verification/Resources/ActionGroupWithParameterizedElementsWithStepKeyReferences.txt +++ b/dev/tests/verification/Resources/ActionGroupWithParameterizedElementsWithStepKeyReferences.txt @@ -29,15 +29,7 @@ class ActionGroupWithParameterizedElementsWithStepKeyReferencesCest $I->comment("Entering Action Group [actionGroup] actionGroupWithParametrizedSelectors"); $testVariableActionGroup = $I->executeJS("return 1"); // stepKey: testVariableActionGroup $testVariable2ActionGroup = $I->executeJS("return 'test'"); // stepKey: testVariable2ActionGroup - $I->comment("[createSimpleDataActionGroup] create 'simpleData' entity"); - $I->createEntity( - "createSimpleDataActionGroup", - "test", - "simpleData", - [], - [] - ); - + $I->createEntity("createSimpleDataActionGroup", "test", "simpleData", [], []); // stepKey: createSimpleDataActionGroup $I->click("#{$testVariable2ActionGroup} .John"); // stepKey: click1ActionGroup $I->click("#Doe-" . msq("simpleParamData") . "prename .{$testVariableActionGroup}"); // stepKey: click2ActionGroup $I->seeElement("//div[@name='Tiberius'][@class={$testVariableActionGroup}][@data-element='{$testVariable2ActionGroup}'][" . $I->retrieveEntityField('createSimpleData', 'name', 'test') . "]"); // stepKey: see1ActionGroup diff --git a/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt b/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt index 0bec544bf..e8eb29996 100644 --- a/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt +++ b/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt @@ -24,15 +24,7 @@ class ActionGroupWithPersistedDataCest */ public function _before(AcceptanceTester $I) { - $I->comment("[createPersonParam] create 'ReplacementPerson' entity"); - $I->createEntity( - "createPersonParam", - "hook", - "ReplacementPerson", - [], - [] - ); - + $I->createEntity("createPersonParam", "hook", "ReplacementPerson", [], []); // stepKey: createPersonParam $I->comment("Entering Action Group [beforeGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1BeforeGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2BeforeGroup @@ -71,15 +63,7 @@ class ActionGroupWithPersistedDataCest */ public function ActionGroupWithPersistedData(AcceptanceTester $I) { - $I->comment("[createPerson] create 'DefaultPerson' entity"); - $I->createEntity( - "createPerson", - "test", - "DefaultPerson", - [], - [] - ); - + $I->createEntity("createPerson", "test", "DefaultPerson", [], []); // stepKey: createPerson $I->comment("Entering Action Group [actionGroupWithPersistedData1] FunctionalActionGroupWithData"); $I->amOnPage("/" . $I->retrieveEntityField('createPerson', 'firstname', 'test') . "/" . $I->retrieveEntityField('createPerson', 'lastname', 'test') . ".html"); // stepKey: amOnPage1ActionGroupWithPersistedData1 $I->fillField("#foo", $I->retrieveEntityField('createPerson', 'firstname', 'test')); // stepKey: fillField1ActionGroupWithPersistedData1 diff --git a/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt b/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt index aeda5e84e..2ee5b4bf9 100644 --- a/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt +++ b/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt @@ -27,15 +27,7 @@ class ActionGroupWithStepKeyReferencesCest public function ActionGroupWithStepKeyReferences(AcceptanceTester $I) { $I->comment("Entering Action Group [actionGroup] FunctionActionGroupWithStepKeyReferences"); - $I->comment("[createSimpleDataActionGroup] create 'simpleData' entity"); - $I->createEntity( - "createSimpleDataActionGroup", - "test", - "simpleData", - [], - [] - ); - + $I->createEntity("createSimpleDataActionGroup", "test", "simpleData", [], []); // stepKey: createSimpleDataActionGroup $grabTextDataActionGroup = $I->grabTextFrom(".class"); // stepKey: grabTextDataActionGroup $I->fillField(".{$grabTextDataActionGroup}", $I->retrieveEntityField('createSimpleDataActionGroup', 'field', 'test')); // stepKey: fill1ActionGroup $I->comment("Invocation stepKey will not be appended in non stepKey instances"); @@ -51,38 +43,10 @@ class ActionGroupWithStepKeyReferencesCest $action5ActionGroup = $date->format("H:i:s"); $action6ActionGroup = $I->formatMoney($action6ActionGroup); // stepKey: action6ActionGroup - $I->comment("[action7ActionGroup] delete entity '{$action7ActionGroupActionGroup}'"); - $I->deleteEntity( - "{$action7ActionGroupActionGroup}", - "test" - ); - - $I->comment("[action8ActionGroup] get '{$action8}' entity"); - $I->getEntity( - "action8ActionGroup", - "test", - "{$action8}", - [], - null - ); - - $I->comment("[action9ActionGroup] update '1' entity to '{$action9}'"); - $I->updateEntity( - "1", - "test", - "{$action9}", - [] - ); - - $I->comment("[action10ActionGroup] create '{$action10}' entity"); - $I->createEntity( - "action10ActionGroup", - "test", - "{$action10}", - [], - [] - ); - + $I->deleteEntity("{$action7ActionGroupActionGroup}", "test"); // stepKey: action7ActionGroup + $I->getEntity("action8ActionGroup", "test", "{$action8}", [], null); // stepKey: action8ActionGroup + $I->updateEntity("1", "test", "{$action9}",[]); // stepKey: action9ActionGroup + $I->createEntity("action10ActionGroup", "test", "{$action10}", [], []); // stepKey: action10ActionGroup $action11ActionGroup = $I->grabAttributeFrom($action11ActionGroup, "someInput"); // stepKey: action11ActionGroup $action12ActionGroup = $I->grabCookie($action12ActionGroup, ['domain' => 'www.google.com']); // stepKey: action12ActionGroup $action13ActionGroup = $I->grabFromCurrentUrl($action13ActionGroup); // stepKey: action13ActionGroup diff --git a/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt b/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt index 6567bdbb0..ca8325402 100644 --- a/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt +++ b/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt @@ -24,15 +24,7 @@ class ActionGroupWithTopLevelPersistedDataCest */ public function _before(AcceptanceTester $I) { - $I->comment("[createPersonParam] create 'ReplacementPerson' entity"); - $I->createEntity( - "createPersonParam", - "hook", - "ReplacementPerson", - [], - [] - ); - + $I->createEntity("createPersonParam", "hook", "ReplacementPerson", [], []); // stepKey: createPersonParam $I->comment("Entering Action Group [beforeGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1BeforeGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2BeforeGroup diff --git a/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt b/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt index 54bb012e9..44a00dbd9 100644 --- a/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt +++ b/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt @@ -24,15 +24,7 @@ class ArgumentWithSameNameAsElementCest */ public function _before(AcceptanceTester $I) { - $I->comment("[createPersonParam] create 'ReplacementPerson' entity"); - $I->createEntity( - "createPersonParam", - "hook", - "ReplacementPerson", - [], - [] - ); - + $I->createEntity("createPersonParam", "hook", "ReplacementPerson", [], []); // stepKey: createPersonParam $I->comment("Entering Action Group [beforeGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1BeforeGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2BeforeGroup diff --git a/dev/tests/verification/Resources/AssertTest.txt b/dev/tests/verification/Resources/AssertTest.txt index 50eb50e24..e7f24b605 100644 --- a/dev/tests/verification/Resources/AssertTest.txt +++ b/dev/tests/verification/Resources/AssertTest.txt @@ -23,15 +23,7 @@ class AssertTestCest */ public function _before(AcceptanceTester $I) { - $I->comment("[createData1] create 'ReplacementPerson' entity"); - $I->createEntity( - "createData1", - "hook", - "ReplacementPerson", - [], - [] - ); - + $I->createEntity("createData1", "hook", "ReplacementPerson", [], []); // stepKey: createData1 } /** @@ -43,15 +35,7 @@ class AssertTestCest */ public function AssertTest(AcceptanceTester $I) { - $I->comment("[createData2] create 'UniquePerson' entity"); - $I->createEntity( - "createData2", - "test", - "UniquePerson", - [], - [] - ); - + $I->createEntity("createData2", "test", "UniquePerson", [], []); // stepKey: createData2 $grabTextFrom1 = $I->grabTextFrom(".copyright>span"); // stepKey: grabTextFrom1 $I->comment("custom asserts"); $I->assertArrayIsSorted(["1", "2", "3", "4", "5"], "asc"); // stepKey: assertSorted1 diff --git a/dev/tests/verification/Resources/BasicActionGroupTest.txt b/dev/tests/verification/Resources/BasicActionGroupTest.txt index 79fbd3513..02915d1a8 100644 --- a/dev/tests/verification/Resources/BasicActionGroupTest.txt +++ b/dev/tests/verification/Resources/BasicActionGroupTest.txt @@ -24,15 +24,7 @@ class BasicActionGroupTestCest */ public function _before(AcceptanceTester $I) { - $I->comment("[createPersonParam] create 'ReplacementPerson' entity"); - $I->createEntity( - "createPersonParam", - "hook", - "ReplacementPerson", - [], - [] - ); - + $I->createEntity("createPersonParam", "hook", "ReplacementPerson", [], []); // stepKey: createPersonParam $I->comment("Entering Action Group [beforeGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1BeforeGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2BeforeGroup diff --git a/dev/tests/verification/Resources/BasicFunctionalTest.txt b/dev/tests/verification/Resources/BasicFunctionalTest.txt index 812972eed..5bcfd55dd 100644 --- a/dev/tests/verification/Resources/BasicFunctionalTest.txt +++ b/dev/tests/verification/Resources/BasicFunctionalTest.txt @@ -74,14 +74,8 @@ class BasicFunctionalTestCest $I->clickWithRightButton("#element .4123#element", 200, 300); // stepKey: clickWithRightButtonKeyXY1 $I->closeTab(); // stepKey: closeTabKey1 $I->conditionalClick(".functionalTestSelector", ".functionalDependentTestSelector", true); // stepKey: conditionalClickKey1 - $I->comment("[deleteKey1] delete entity 'createKey1'"); - $I->deleteEntity( - "createKey1", - "test" - ); - - $I->deleteEntityByUrl("/V1/categories{$grabbedData}"); - + $I->deleteEntity("createKey1", "test"); // stepKey: deleteKey1 + $I->deleteEntityByUrl("/V1/categories{$grabbedData}"); // stepKey: deleteKey2 $I->dontSee("someInput", ".functionalTestSelector"); // stepKey: dontSeeKey1 $I->dontSeeCheckboxIsChecked(".functionalTestSelector"); // stepKey: dontSeeCheckboxIsCheckedKey1 $I->dontSeeCookie("someInput"); // stepKey: dontSeeCookieKey1 diff --git a/dev/tests/verification/Resources/DataActionsTest.txt b/dev/tests/verification/Resources/DataActionsTest.txt index bbfbafa21..c3f8400b3 100644 --- a/dev/tests/verification/Resources/DataActionsTest.txt +++ b/dev/tests/verification/Resources/DataActionsTest.txt @@ -23,29 +23,9 @@ class DataActionsTestCest */ public function _before(AcceptanceTester $I) { - $I->comment("[createdInBefore] create 'entity' entity"); - $I->createEntity( - "createdInBefore", - "hook", - "entity", - [], - [] - ); - - $I->comment("[updateInBefore] update 'createdInBefore' entity to 'entity'"); - $I->updateEntity( - "createdInBefore", - "hook", - "entity", - [] - ); - - $I->comment("[deleteInBefore] delete entity 'createdInBefore'"); - $I->deleteEntity( - "createdInBefore", - "hook" - ); - + $I->createEntity("createdInBefore", "hook", "entity", [], []); // stepKey: createdInBefore + $I->updateEntity("createdInBefore", "hook", "entity",[]); // stepKey: updateInBefore + $I->deleteEntity("createdInBefore", "hook"); // stepKey: deleteInBefore } /** @@ -57,42 +37,10 @@ class DataActionsTestCest */ public function DataActionsTest(AcceptanceTester $I) { - $I->comment("[createdInTest] create 'entity' entity"); - $I->createEntity( - "createdInTest", - "test", - "entity", - [], - [] - ); - - $I->comment("[updateInTest] update 'createdInTest' entity to 'entity'"); - $I->updateEntity( - "createdInTest", - "test", - "entity", - [] - ); - - $I->comment("[deleteInTest] delete entity 'createdInTest'"); - $I->deleteEntity( - "createdInTest", - "test" - ); - - $I->comment("[updatedDataOutOfScope] update 'createdInBefore' entity to 'entity'"); - $I->updateEntity( - "createdInBefore", - "test", - "entity", - [] - ); - - $I->comment("[deleteDataOutOfScope] delete entity 'createdInBefore'"); - $I->deleteEntity( - "createdInBefore", - "test" - ); - + $I->createEntity("createdInTest", "test", "entity", [], []); // stepKey: createdInTest + $I->updateEntity("createdInTest", "test", "entity",[]); // stepKey: updateInTest + $I->deleteEntity("createdInTest", "test"); // stepKey: deleteInTest + $I->updateEntity("createdInBefore", "test", "entity",[]); // stepKey: updatedDataOutOfScope + $I->deleteEntity("createdInBefore", "test"); // stepKey: deleteDataOutOfScope } } diff --git a/dev/tests/verification/Resources/ExtendParentDataTest.txt b/dev/tests/verification/Resources/ExtendParentDataTest.txt index 5a698b55f..d26d91b08 100644 --- a/dev/tests/verification/Resources/ExtendParentDataTest.txt +++ b/dev/tests/verification/Resources/ExtendParentDataTest.txt @@ -26,15 +26,7 @@ class ExtendParentDataTestCest */ public function ExtendParentDataTest(AcceptanceTester $I) { - $I->comment("[simpleDataKey] create 'extendParentData' entity"); - $I->createEntity( - "simpleDataKey", - "test", - "extendParentData", - [], - [] - ); - + $I->createEntity("simpleDataKey", "test", "extendParentData", [], []); // stepKey: simpleDataKey $I->searchAndMultiSelectOption("#selector", ["otherName"]); // stepKey: getName $I->searchAndMultiSelectOption("#selector", ["extendName"]); // stepKey: getNameExtend $I->searchAndMultiSelectOption("#selector", ["item"]); // stepKey: emptyPost diff --git a/dev/tests/verification/Resources/ExtendedParameterArrayTest.txt b/dev/tests/verification/Resources/ExtendedParameterArrayTest.txt index e5016216d..d09e9a0b6 100644 --- a/dev/tests/verification/Resources/ExtendedParameterArrayTest.txt +++ b/dev/tests/verification/Resources/ExtendedParameterArrayTest.txt @@ -25,14 +25,7 @@ class ExtendParentDataTestCest */ public function ExtendParentDataTest(AcceptanceTester $I) { - $I->amGoingTo("create entity that has the stepKey: simpleDataKey"); - $I->createEntity( - "simpleDataKey", - "test", - "extendParentData", - [], - [] - ); + $I->createEntity("simpleDataKey", "test", "extendParentData", [], []); // stepKey: simpleDataKey $I->searchAndMultiSelectOption("#selector", ["otherName"]); $I->searchAndMultiSelectOption("#selector", ["extendName"]); $I->searchAndMultiSelectOption("#selector", ["item"]); diff --git a/dev/tests/verification/Resources/HookActionsTest.txt b/dev/tests/verification/Resources/HookActionsTest.txt index 9ed9c0bc5..c61cc86e2 100644 --- a/dev/tests/verification/Resources/HookActionsTest.txt +++ b/dev/tests/verification/Resources/HookActionsTest.txt @@ -23,30 +23,9 @@ class HookActionsTestCest */ public function _before(AcceptanceTester $I) { - $I->comment("[sampleCreateBefore] create 'sampleCreatedEntity' entity"); - $I->createEntity( - "sampleCreateBefore", - "hook", - "sampleCreatedEntity", - [], - [] - ); - - $I->comment("[sampleDeleteBefore] delete entity 'sampleCreateBefore'"); - $I->deleteEntity( - "sampleCreateBefore", - "hook" - ); - - $I->comment("[sampleCreateForAfter] create 'sampleCreatedEntity' entity"); - $I->createEntity( - "sampleCreateForAfter", - "hook", - "sampleCreatedEntity", - [], - [] - ); - + $I->createEntity("sampleCreateBefore", "hook", "sampleCreatedEntity", [], []); // stepKey: sampleCreateBefore + $I->deleteEntity("sampleCreateBefore", "hook"); // stepKey: sampleDeleteBefore + $I->createEntity("sampleCreateForAfter", "hook", "sampleCreatedEntity", [], []); // stepKey: sampleCreateForAfter } /** @@ -55,21 +34,8 @@ class HookActionsTestCest */ public function _after(AcceptanceTester $I) { - $I->comment("[sampleCreateAfter] create 'sampleCreatedEntity' entity"); - $I->createEntity( - "sampleCreateAfter", - "hook", - "sampleCreatedEntity", - [], - [] - ); - - $I->comment("[sampleDeleteAfter] delete entity 'sampleCreateForAfter'"); - $I->deleteEntity( - "sampleCreateForAfter", - "hook" - ); - + $I->createEntity("sampleCreateAfter", "hook", "sampleCreatedEntity", [], []); // stepKey: sampleCreateAfter + $I->deleteEntity("sampleCreateForAfter", "hook"); // stepKey: sampleDeleteAfter } /** diff --git a/dev/tests/verification/Resources/LocatorFunctionTest.txt b/dev/tests/verification/Resources/LocatorFunctionTest.txt index 67f92543f..f00392778 100644 --- a/dev/tests/verification/Resources/LocatorFunctionTest.txt +++ b/dev/tests/verification/Resources/LocatorFunctionTest.txt @@ -26,15 +26,7 @@ class LocatorFunctionTestCest */ public function LocatorFunctionTest(AcceptanceTester $I) { - $I->comment("[data] create 'ReplacementPerson' entity"); - $I->createEntity( - "data", - "test", - "ReplacementPerson", - [], - [] - ); - + $I->createEntity("data", "test", "ReplacementPerson", [], []); // stepKey: data $I->click(Locator::contains("'label'", "'Name'")); // stepKey: SimpleLocator $I->click(Locator::contains("'label'", "'Name'")); // stepKey: SimpleLocatorNonShorthand $I->click(Locator::find("'img'", ['title' => 'diagram'])); // stepKey: ArrayLocator diff --git a/dev/tests/verification/Resources/MergedActionGroupTest.txt b/dev/tests/verification/Resources/MergedActionGroupTest.txt index b2a4d4cd3..e0067b479 100644 --- a/dev/tests/verification/Resources/MergedActionGroupTest.txt +++ b/dev/tests/verification/Resources/MergedActionGroupTest.txt @@ -24,15 +24,7 @@ class MergedActionGroupTestCest */ public function _before(AcceptanceTester $I) { - $I->comment("[createPersonParam] create 'ReplacementPerson' entity"); - $I->createEntity( - "createPersonParam", - "hook", - "ReplacementPerson", - [], - [] - ); - + $I->createEntity("createPersonParam", "hook", "ReplacementPerson", [], []); // stepKey: createPersonParam $I->comment("Entering Action Group [beforeGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1BeforeGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2BeforeGroup diff --git a/dev/tests/verification/Resources/MultipleActionGroupsTest.txt b/dev/tests/verification/Resources/MultipleActionGroupsTest.txt index bd40b3fa6..8e5ea542e 100644 --- a/dev/tests/verification/Resources/MultipleActionGroupsTest.txt +++ b/dev/tests/verification/Resources/MultipleActionGroupsTest.txt @@ -24,15 +24,7 @@ class MultipleActionGroupsTestCest */ public function _before(AcceptanceTester $I) { - $I->comment("[createPersonParam] create 'ReplacementPerson' entity"); - $I->createEntity( - "createPersonParam", - "hook", - "ReplacementPerson", - [], - [] - ); - + $I->createEntity("createPersonParam", "hook", "ReplacementPerson", [], []); // stepKey: createPersonParam $I->comment("Entering Action Group [beforeGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1BeforeGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2BeforeGroup diff --git a/dev/tests/verification/Resources/PageReplacementTest.txt b/dev/tests/verification/Resources/PageReplacementTest.txt index 6cfcce367..f90a4fda7 100644 --- a/dev/tests/verification/Resources/PageReplacementTest.txt +++ b/dev/tests/verification/Resources/PageReplacementTest.txt @@ -26,15 +26,7 @@ class PageReplacementTestCest */ public function PageReplacementTest(AcceptanceTester $I) { - $I->comment("[datakey] create 'simpleData' entity"); - $I->createEntity( - "datakey", - "test", - "simpleData", - [], - [] - ); - + $I->createEntity("datakey", "test", "simpleData", [], []); // stepKey: datakey $I->amOnPage("/page.html"); // stepKey: noParamPage $I->amOnPage("/StringLiteral/page.html"); // stepKey: oneParamPageString $I->amOnPage("/John/page.html"); // stepKey: oneParamPageData diff --git a/dev/tests/verification/Resources/ParameterArrayTest.txt b/dev/tests/verification/Resources/ParameterArrayTest.txt index f66ce9c47..af47657ea 100644 --- a/dev/tests/verification/Resources/ParameterArrayTest.txt +++ b/dev/tests/verification/Resources/ParameterArrayTest.txt @@ -26,15 +26,7 @@ class ParameterArrayTestCest */ public function ParameterArrayTest(AcceptanceTester $I) { - $I->comment("[simpleDataKey] create 'simpleParamData' entity"); - $I->createEntity( - "simpleDataKey", - "test", - "simpleParamData", - [], - [] - ); - + $I->createEntity("simpleDataKey", "test", "simpleParamData", [], []); // stepKey: simpleDataKey $I->searchAndMultiSelectOption("#selector", ["name"]); // stepKey: xmlSimpleReplace $I->searchAndMultiSelectOption("#selector", [msq("simpleParamData") . "prename"]); // stepKey: xmlPrefix $I->searchAndMultiSelectOption("#selector", ["postname" . msq("simpleParamData")]); // stepKey: xmlSuffix diff --git a/dev/tests/verification/Resources/PersistedReplacementTest.txt b/dev/tests/verification/Resources/PersistedReplacementTest.txt index 5d8a0f1e5..009a8eac2 100644 --- a/dev/tests/verification/Resources/PersistedReplacementTest.txt +++ b/dev/tests/verification/Resources/PersistedReplacementTest.txt @@ -23,15 +23,7 @@ class PersistedReplacementTestCest */ public function _before(AcceptanceTester $I) { - $I->comment("[createData1] create 'ReplacementPerson' entity"); - $I->createEntity( - "createData1", - "hook", - "ReplacementPerson", - [], - [] - ); - + $I->createEntity("createData1", "hook", "ReplacementPerson", [], []); // stepKey: createData1 } /** @@ -43,15 +35,7 @@ class PersistedReplacementTestCest */ public function PersistedReplacementTest(AcceptanceTester $I) { - $I->comment("[createdData] create 'simpleData' entity"); - $I->createEntity( - "createdData", - "test", - "simpleData", - [], - [] - ); - + $I->createEntity("createdData", "test", "simpleData", [], []); // stepKey: createdData $I->fillField("#selector", "StringBefore " . $I->retrieveEntityField('createdData', 'firstname', 'test') . " StringAfter"); // stepKey: inputReplace $I->fillField("#" . $I->retrieveEntityField('createdData', 'firstname', 'test'), "input"); // stepKey: selectorReplace $I->fillField("#" . getenv("MAGENTO_BASE_URL") . "#" . $I->retrieveEntityField('createdData', 'firstname', 'test'), "input"); // stepKey: selectorReplace2 diff --git a/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt b/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt index 2a3444324..118db353a 100644 --- a/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt +++ b/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt @@ -24,38 +24,10 @@ class PersistenceActionGroupAppendingTestCest public function _before(AcceptanceTester $I) { $I->comment("Entering Action Group [ACTIONGROUPBEFORE] DataPersistenceAppendingActionGroup"); - $I->comment("[createDataACTIONGROUPBEFORE] create 'entity' entity"); - $I->createEntity( - "createDataACTIONGROUPBEFORE", - "hook", - "entity", - [], - [] - ); - - $I->comment("[updateDataACTIONGROUPBEFORE] update 'createDataACTIONGROUPBEFORE' entity to 'newEntity'"); - $I->updateEntity( - "createDataACTIONGROUPBEFORE", - "hook", - "newEntity", - [] - ); - - $I->comment("[deleteDataACTIONGROUPBEFORE] delete entity 'createDataACTIONGROUPBEFORE'"); - $I->deleteEntity( - "createDataACTIONGROUPBEFORE", - "hook" - ); - - $I->comment("[getDataACTIONGROUPBEFORE] get 'someEneity' entity"); - $I->getEntity( - "getDataACTIONGROUPBEFORE", - "hook", - "someEneity", - [], - null - ); - + $I->createEntity("createDataACTIONGROUPBEFORE", "hook", "entity", [], []); // stepKey: createDataACTIONGROUPBEFORE + $I->updateEntity("createDataACTIONGROUPBEFORE", "hook", "newEntity",[]); // stepKey: updateDataACTIONGROUPBEFORE + $I->deleteEntity("createDataACTIONGROUPBEFORE", "hook"); // stepKey: deleteDataACTIONGROUPBEFORE + $I->getEntity("getDataACTIONGROUPBEFORE", "hook", "someEneity", [], null); // stepKey: getDataACTIONGROUPBEFORE $I->comment($I->retrieveEntityField('createData', 'field', 'hook')); $I->comment("Exiting Action Group [ACTIONGROUPBEFORE] DataPersistenceAppendingActionGroup"); } @@ -70,38 +42,10 @@ class PersistenceActionGroupAppendingTestCest public function PersistenceActionGroupAppendingTest(AcceptanceTester $I) { $I->comment("Entering Action Group [ACTIONGROUP] DataPersistenceAppendingActionGroup"); - $I->comment("[createDataACTIONGROUP] create 'entity' entity"); - $I->createEntity( - "createDataACTIONGROUP", - "test", - "entity", - [], - [] - ); - - $I->comment("[updateDataACTIONGROUP] update 'createDataACTIONGROUP' entity to 'newEntity'"); - $I->updateEntity( - "createDataACTIONGROUP", - "test", - "newEntity", - [] - ); - - $I->comment("[deleteDataACTIONGROUP] delete entity 'createDataACTIONGROUP'"); - $I->deleteEntity( - "createDataACTIONGROUP", - "test" - ); - - $I->comment("[getDataACTIONGROUP] get 'someEneity' entity"); - $I->getEntity( - "getDataACTIONGROUP", - "test", - "someEneity", - [], - null - ); - + $I->createEntity("createDataACTIONGROUP", "test", "entity", [], []); // stepKey: createDataACTIONGROUP + $I->updateEntity("createDataACTIONGROUP", "test", "newEntity",[]); // stepKey: updateDataACTIONGROUP + $I->deleteEntity("createDataACTIONGROUP", "test"); // stepKey: deleteDataACTIONGROUP + $I->getEntity("getDataACTIONGROUP", "test", "someEneity", [], null); // stepKey: getDataACTIONGROUP $I->comment($I->retrieveEntityField('createDataACTIONGROUP', 'field', 'test')); $I->comment("Exiting Action Group [ACTIONGROUP] DataPersistenceAppendingActionGroup"); } diff --git a/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt b/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt index 517bea53a..221373be1 100644 --- a/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt +++ b/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt @@ -25,25 +25,9 @@ class PersistenceCustomFieldsTestCest { $createData1Fields['firstname'] = "Mac"; $createData1Fields['lastname'] = "Doe"; - $I->comment("[createData1] create 'DefaultPerson' entity"); - $I->createEntity( - "createData1", - "hook", - "DefaultPerson", - [], - $createData1Fields - ); - + $I->createEntity("createData1", "hook", "DefaultPerson", [], $createData1Fields); // stepKey: createData1 $createData2Fields['firstname'] = $I->retrieveEntityField('createData1', 'firstname', 'hook'); - $I->comment("[createData2] create 'uniqueData' entity"); - $I->createEntity( - "createData2", - "hook", - "uniqueData", - ["createData1"], - $createData2Fields - ); - + $I->createEntity("createData2", "hook", "uniqueData", ["createData1"], $createData2Fields); // stepKey: createData2 } /** @@ -57,88 +41,24 @@ class PersistenceCustomFieldsTestCest { $createdDataFields['favoriteIndex'] = "1"; $createdDataFields['middlename'] = "Kovacs"; - $I->comment("[createdData] create 'simpleData' entity"); - $I->createEntity( - "createdData", - "test", - "simpleData", - [], - $createdDataFields - ); - + $I->createEntity("createdData", "test", "simpleData", [], $createdDataFields); // stepKey: createdData $createdData3Fields['firstname'] = "Takeshi"; $createdData3Fields['lastname'] = "Kovacs"; - $I->comment("[createdData3] create 'UniquePerson' entity"); - $I->createEntity( - "createdData3", - "test", - "UniquePerson", - ["createdData"], - $createdData3Fields - ); - + $I->createEntity("createdData3", "test", "UniquePerson", ["createdData"], $createdData3Fields); // stepKey: createdData3 $I->comment("Entering Action Group [createdAG] PersistenceActionGroup"); $createDataAG1CreatedAGFields['firstname'] = "string1"; - $I->comment("[createDataAG1CreatedAG] create 'simpleData' entity"); - $I->createEntity( - "createDataAG1CreatedAG", - "test", - "simpleData", - [], - $createDataAG1CreatedAGFields - ); - + $I->createEntity("createDataAG1CreatedAG", "test", "simpleData", [], $createDataAG1CreatedAGFields); // stepKey: createDataAG1CreatedAG $createDataAG2CreatedAGFields['firstname'] = "Jane"; - $I->comment("[createDataAG2CreatedAG] create 'simpleData' entity"); - $I->createEntity( - "createDataAG2CreatedAG", - "test", - "simpleData", - [], - $createDataAG2CreatedAGFields - ); - + $I->createEntity("createDataAG2CreatedAG", "test", "simpleData", [], $createDataAG2CreatedAGFields); // stepKey: createDataAG2CreatedAG $createDataAG3CreatedAGFields['firstname'] = $I->retrieveEntityField('createdData3', 'firstname', 'test'); - $I->comment("[createDataAG3CreatedAG] create 'simpleData' entity"); - $I->createEntity( - "createDataAG3CreatedAG", - "test", - "simpleData", - [], - $createDataAG3CreatedAGFields - ); - + $I->createEntity("createDataAG3CreatedAG", "test", "simpleData", [], $createDataAG3CreatedAGFields); // stepKey: createDataAG3CreatedAG $I->comment("Exiting Action Group [createdAG] PersistenceActionGroup"); $I->comment("Entering Action Group [AGKEY] DataPersistenceSelfReferenceActionGroup"); - $I->comment("[createData1AGKEY] create 'entity1' entity"); - $I->createEntity( - "createData1AGKEY", - "test", - "entity1", - [], - [] - ); - - $I->comment("[createData2AGKEY] create 'entity2' entity"); - $I->createEntity( - "createData2AGKEY", - "test", - "entity2", - [], - [] - ); - + $I->createEntity("createData1AGKEY", "test", "entity1", [], []); // stepKey: createData1AGKEY + $I->createEntity("createData2AGKEY", "test", "entity2", [], []); // stepKey: createData2AGKEY $createData3AGKEYFields['key1'] = $I->retrieveEntityField('createData1AGKEY', 'field', 'test'); $createData3AGKEYFields['key2'] = $I->retrieveEntityField('createData2AGKEY', 'field', 'test'); - $I->comment("[createData3AGKEY] create 'entity3' entity"); - $I->createEntity( - "createData3AGKEY", - "test", - "entity3", - [], - $createData3AGKEYFields - ); - + $I->createEntity("createData3AGKEY", "test", "entity3", [], $createData3AGKEYFields); // stepKey: createData3AGKEY $I->comment("Exiting Action Group [AGKEY] DataPersistenceSelfReferenceActionGroup"); } } diff --git a/dev/tests/verification/Resources/SectionReplacementTest.txt b/dev/tests/verification/Resources/SectionReplacementTest.txt index 04efcee4b..2b2a8bcd6 100644 --- a/dev/tests/verification/Resources/SectionReplacementTest.txt +++ b/dev/tests/verification/Resources/SectionReplacementTest.txt @@ -45,15 +45,7 @@ class SectionReplacementTestCest $I->click("#Doe" . msq("uniqueData") . " .stringLiteral2"); // stepKey: selectorReplaceTwoParamDataRefMSQSuffix $I->click("#Doe" . msq("uniqueData") . "-stringLiteral2 .stringLiteral3"); // stepKey: selectorReplaceThreeParamDataRefMSQSuffix $I->click("#Doe" . msq("uniqueData") . "-stringLiteral2 .Doe" . msq("uniqueData") . " [stringLiteral3]"); // stepKey: selectorReplaceThreeParamOneDupeDataRefMSQSuffix - $I->comment("[createdData] create 'simpleData' entity"); - $I->createEntity( - "createdData", - "test", - "simpleData", - [], - [] - ); - + $I->createEntity("createdData", "test", "simpleData", [], []); // stepKey: createdData $I->click("#element ." . $I->retrieveEntityField('createdData', 'firstname', 'test')); // stepKey: selectorReplaceOneParamPersisted $I->click("#" . $I->retrieveEntityField('createdData', 'firstname', 'test') . " .stringLiteral2"); // stepKey: selectorReplaceTwoParamPersisted $I->click("#" . $I->retrieveEntityField('createdData', 'firstname', 'test') . "-stringLiteral2 .stringLiteral3"); // stepKey: selectorReplaceThreeParamPersisted diff --git a/dev/tests/verification/Resources/functionalSuiteHooks.txt b/dev/tests/verification/Resources/functionalSuiteHooks.txt index 05ada44f1..908cff8aa 100644 --- a/dev/tests/verification/Resources/functionalSuiteHooks.txt +++ b/dev/tests/verification/Resources/functionalSuiteHooks.txt @@ -122,7 +122,7 @@ class functionalSuiteHooks extends \Codeception\GroupObject // initialize the webdriver session $webDriver->_initializeSession(); $webDriver->amOnPage("some.url"); // stepKey: after - $webDriver->deleteEntityByUrl("deleteThis"); + $webDriver->deleteEntityByUrl("deleteThis"); // stepKey: delete print("Entering Action Group [AC] actionGroupWithTwoArguments"); $webDriver->see("John", msq("uniqueData") . "John"); // stepKey: seeFirstNameAC print("Exiting Action Group [AC] actionGroupWithTwoArguments"); diff --git a/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php b/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php index 4bce08d9f..1668f5b21 100644 --- a/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php +++ b/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php @@ -8,7 +8,8 @@ use Codeception\Step\Comment; use Magento\FunctionalTestingFramework\Suite\Handlers\SuiteObjectHandler; use Magento\FunctionalTestingFramework\Test\Objects\ActionGroupObject; -use \Magento\FunctionalTestingFramework\Util\TestGenerator; +use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; +use Magento\FunctionalTestingFramework\Util\TestGenerator; use Yandex\Allure\Adapter\Model\Status; use Yandex\Allure\Adapter\Model\Step; use Yandex\Allure\Codeception\AllureCodeception; @@ -41,6 +42,20 @@ class MagentoAllureAdapter extends AllureCodeception */ private $testFiles = []; + /** + * Boolean value to indicate if steps are invisible steps + * + * @var boolean + */ + private $atInvisibleSteps = false; + + /** + * Boolean array to store status of previous invisible steps + * + * @var array + */ + private $invisibleStepStatus = []; + /** * Array of group values passed to test runner command * @@ -122,9 +137,25 @@ private function sanitizeGroupName($group) * @param StepEvent $stepEvent * @return void * @throws \Yandex\Allure\Adapter\AllureException + * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) */ public function stepBefore(StepEvent $stepEvent) { + $stepAction = $stepEvent->getStep()->getAction(); + + // Set atInvisibleSteps flag and return if step is in INVISIBLE_STEP_ACTIONS + if (in_array($stepAction, ActionObject::INVISIBLE_STEP_ACTIONS)) { + $this->atInvisibleSteps = true; + return; + } + + // Set back atInvisibleSteps flag + if ($this->atInvisibleSteps && !in_array($stepAction, ActionObject::INVISIBLE_STEP_ACTIONS)) { + $this->atInvisibleSteps = false; + } + //Hard set to 200; we don't expose this config in MFTF $argumentsLength = 200; $stepKey = null; @@ -134,11 +165,9 @@ public function stepBefore(StepEvent $stepEvent) } // DO NOT alter action if actionGroup is starting, need the exact actionGroup name for good logging - if (strpos($stepEvent->getStep()->getAction(), ActionGroupObject::ACTION_GROUP_CONTEXT_START) !== false - || $stepEvent->getStep() instanceof Comment + if (strpos($stepAction, ActionGroupObject::ACTION_GROUP_CONTEXT_START) === false + && !($stepEvent->getStep() instanceof Comment) ) { - $stepAction = $stepEvent->getStep()->getAction(); - } else { $stepAction = $stepEvent->getStep()->getHumanizedActionWithoutArguments(); } $stepArgs = $stepEvent->getStep()->getArgumentsAsString($argumentsLength); @@ -169,8 +198,26 @@ public function stepBefore(StepEvent $stepEvent) */ public function stepAfter(StepEvent $stepEvent = null) { - if ($stepEvent->getStep()->hasFailed()) { - $this->getLifecycle()->fire(new StepFailedEvent()); + // Store invisible step status if step is in INVISIBLE_STEP_ACTIONS + if ($this->atInvisibleSteps && $stepEvent->getStep()->hasFailed()) { + $this->invisibleStepStatus[] = false; + return; + } elseif ($this->atInvisibleSteps) { + $this->invisibleStepStatus[] = true; + return; + } else { + // Check previous invisible steps status + $invisibleStepsPassed = true; + foreach ($this->invisibleStepStatus as $pass) { + if (!$pass) { + $invisibleStepsPassed = false; + break; + } + } + $this->invisibleStepStatus = []; + if ($stepEvent->getStep()->hasFailed() || !$invisibleStepsPassed) { + $this->getLifecycle()->fire(new StepFailedEvent()); + } } $this->getLifecycle()->fire(new StepFinishedEvent()); } diff --git a/src/Magento/FunctionalTestingFramework/Codeception/Subscriber/Console.php b/src/Magento/FunctionalTestingFramework/Codeception/Subscriber/Console.php index 0ba1a3b2f..b9e3f4ca1 100644 --- a/src/Magento/FunctionalTestingFramework/Codeception/Subscriber/Console.php +++ b/src/Magento/FunctionalTestingFramework/Codeception/Subscriber/Console.php @@ -12,6 +12,7 @@ use Codeception\Step\Comment; use Codeception\Test\Interfaces\ScenarioDriven; use Magento\FunctionalTestingFramework\Test\Objects\ActionGroupObject; +use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Magento\FunctionalTestingFramework\Util\TestGenerator; use Symfony\Component\Console\Formatter\OutputFormatter; @@ -31,6 +32,20 @@ class Console extends \Codeception\Subscriber\Console */ private $actionGroupStepKey = null; + /** + * Boolean value to indicate if steps are invisible steps + * + * @var boolean + */ + private $atInvisibleSteps = false; + + /** + * Boolean array to store status of previous invisible steps + * + * @var array + */ + private $invisibleStepStatus = []; + /** * Console constructor. Parent constructor requires codeception CLI options, and does not have its own configs. * Constructor is only different than parent due to the way Codeception instantiates Extensions. @@ -50,6 +65,8 @@ public function __construct($extensionOptions = [], $options = []) * * @param StepEvent $e * @return void + * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function beforeStep(StepEvent $e) { @@ -57,6 +74,19 @@ public function beforeStep(StepEvent $e) return; } + $stepAction = $e->getStep()->getAction(); + + // Set atInvisibleSteps flag and return if step is in INVISIBLE_STEP_ACTIONS + if (in_array($stepAction, ActionObject::INVISIBLE_STEP_ACTIONS)) { + $this->atInvisibleSteps = true; + return; + } + + // Set back atInvisibleSteps flag + if ($this->atInvisibleSteps && !in_array($stepAction, ActionObject::INVISIBLE_STEP_ACTIONS)) { + $this->atInvisibleSteps = false; + } + $metaStep = $e->getStep()->getMetaStep(); if ($metaStep and $this->metaStep != $metaStep) { $this->message(' ' . $metaStep->getPrefix()) @@ -77,9 +107,27 @@ public function beforeStep(StepEvent $e) */ public function afterStep(StepEvent $e) { - parent::afterStep($e); - if ($e->getStep()->hasFailed()) { - $this->actionGroupStepKey = null; + // Store invisible step status if step is in INVISIBLE_STEP_ACTIONS + if ($this->atInvisibleSteps && $e->getStep()->hasFailed()) { + $this->invisibleStepStatus[] = false; + return; + } elseif ($this->atInvisibleSteps) { + $this->invisibleStepStatus[] = true; + return; + } else { + // Check previous invisible steps status + $invisibleStepsPassed = true; + foreach ($this->invisibleStepStatus as $pass) { + if (!$pass) { + $invisibleStepsPassed = false; + break; + } + } + $this->invisibleStepStatus = []; + parent::afterStep($e); + if ($e->getStep()->hasFailed() || !$invisibleStepsPassed) { + $this->actionGroupStepKey = null; + } } } diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php index c188008e7..53743330e 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php @@ -75,6 +75,7 @@ class ActionObject const DEFAULT_COMMAND_WAIT_TIMEOUT = 60; const ACTION_ATTRIBUTE_USERINPUT = 'userInput'; const ACTION_TYPE_COMMENT = 'comment'; + const INVISIBLE_STEP_ACTIONS = ['retrieveEntityField', 'getSecret']; /** * The unique identifier for the action diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 7c8c59dbe..dc6aa9238 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -47,10 +47,8 @@ class TestGenerator const PERSISTED_OBJECT_NOTATION_REGEX = '/\${1,2}[\w.\[\]]+\${1,2}/'; const NO_STEPKEY_ACTIONS = [ 'comment', - 'createData', - 'deleteData', - 'updateData', - 'getData', + 'retrieveEntityField', + 'getSecret', 'magentoCLI', 'generateDate', 'field' @@ -732,13 +730,6 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato switch ($actionObject->getType()) { case "createData": $entity = $customActionAttributes['entity']; - //Add an informative statement to help the user debug test runs - $testSteps .= sprintf( - "\t\t$%s->comment(\"[%s] create '%s' entity\");\n", - $actor, - $stepKey, - $entity - ); //TODO refactor entity field override to not be individual actionObjects $customEntityFields = @@ -766,19 +757,19 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato } $createEntityFunctionCall = "\t\t\${$actor}->createEntity("; - $createEntityFunctionCall .= "\n\t\t\t\"{$stepKey}\","; - $createEntityFunctionCall .= "\n\t\t\t\"{$scope}\","; - $createEntityFunctionCall .= "\n\t\t\t\"{$entity}\""; - $createEntityFunctionCall .= ",\n\t\t\t[{$requiredEntityKeysArray}]"; + $createEntityFunctionCall .= "\"{$stepKey}\","; + $createEntityFunctionCall .= " \"{$scope}\","; + $createEntityFunctionCall .= " \"{$entity}\","; + $createEntityFunctionCall .= " [{$requiredEntityKeysArray}],"; if (count($customEntityFields) > 1) { - $createEntityFunctionCall .= ",\n\t\t\t\${$stepKey}Fields"; + $createEntityFunctionCall .= " \${$stepKey}Fields"; } else { - $createEntityFunctionCall .= ",\n\t\t\t[]"; + $createEntityFunctionCall .= " []"; } if ($storeCode !== null) { - $createEntityFunctionCall .= ",\n\t\t\t\"{$storeCode}\""; + $createEntityFunctionCall .= ", \"{$storeCode}\""; } - $createEntityFunctionCall .= "\n\t\t);\n"; + $createEntityFunctionCall .= ");"; $testSteps .= $createEntityFunctionCall; break; case "deleteData": @@ -790,13 +781,6 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato ); $actionGroup = $actionObject->getCustomActionAttributes()['actionGroup'] ?? null; $key .= $actionGroup; - //Add an informative statement to help the user debug test runs - $contextSetter = sprintf( - "\t\t$%s->comment(\"[%s] delete entity '%s'\");\n", - $actor, - $stepKey, - $key - ); //Determine Scope $scope = PersistedObjectHandler::TEST_SCOPE; @@ -807,17 +791,16 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato } $deleteEntityFunctionCall = "\t\t\${$actor}->deleteEntity("; - $deleteEntityFunctionCall .= "\n\t\t\t\"{$key}\","; - $deleteEntityFunctionCall .= "\n\t\t\t\"{$scope}\""; - $deleteEntityFunctionCall .= "\n\t\t);\n"; + $deleteEntityFunctionCall .= "\"{$key}\","; + $deleteEntityFunctionCall .= " \"{$scope}\""; + $deleteEntityFunctionCall .= ");"; - $testSteps .= $contextSetter; $testSteps .= $deleteEntityFunctionCall; } else { $url = $this->resolveAllRuntimeReferences([$url])[0]; $url = $this->resolveTestVariable([$url], null)[0]; $output = sprintf( - "\t\t$%s->deleteEntityByUrl(%s);\n", + "\t\t$%s->deleteEntityByUrl(%s);", $actor, $url ); @@ -834,15 +817,6 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $actionGroup = $actionObject->getCustomActionAttributes()['actionGroup'] ?? null; $key .= $actionGroup; - //Add an informative statement to help the user debug test runs - $testSteps .= sprintf( - "\t\t$%s->comment(\"[%s] update '%s' entity to '%s'\");\n", - $actor, - $stepKey, - $key, - $updateEntity - ); - // Build array of requiredEntities $requiredEntityKeys = []; foreach ($actionObject->getCustomActionAttributes() as $actionAttribute) { @@ -865,14 +839,14 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato } $updateEntityFunctionCall = "\t\t\${$actor}->updateEntity("; - $updateEntityFunctionCall .= "\n\t\t\t\"{$key}\","; - $updateEntityFunctionCall .= "\n\t\t\t\"{$scope}\","; - $updateEntityFunctionCall .= "\n\t\t\t\"{$updateEntity}\""; - $updateEntityFunctionCall .= ",\n\t\t\t[{$requiredEntityKeysArray}]"; + $updateEntityFunctionCall .= "\"{$key}\","; + $updateEntityFunctionCall .= " \"{$scope}\","; + $updateEntityFunctionCall .= " \"{$updateEntity}\","; + $updateEntityFunctionCall .= "[{$requiredEntityKeysArray}]"; if ($storeCode !== null) { - $updateEntityFunctionCall .= ",\n\t\t\t\"{$storeCode}\""; + $updateEntityFunctionCall .= ", \"{$storeCode}\""; } - $updateEntityFunctionCall .= "\n\t\t);\n"; + $updateEntityFunctionCall .= ");"; $testSteps .= $updateEntityFunctionCall; break; @@ -882,13 +856,6 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato if (isset($customActionAttributes['index'])) { $index = (int)$customActionAttributes['index']; } - //Add an informative statement to help the user debug test runs - $testSteps .= sprintf( - "\t\t$%s->comment(\"[%s] get '%s' entity\");\n", - $actor, - $stepKey, - $entity - ); // Build array of requiredEntities $requiredEntityKeys = []; @@ -913,19 +880,19 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato //Create Function $getEntityFunctionCall = "\t\t\${$actor}->getEntity("; - $getEntityFunctionCall .= "\n\t\t\t\"{$stepKey}\","; - $getEntityFunctionCall .= "\n\t\t\t\"{$scope}\","; - $getEntityFunctionCall .= "\n\t\t\t\"{$entity}\""; - $getEntityFunctionCall .= ",\n\t\t\t[{$requiredEntityKeysArray}]"; + $getEntityFunctionCall .= "\"{$stepKey}\","; + $getEntityFunctionCall .= " \"{$scope}\","; + $getEntityFunctionCall .= " \"{$entity}\","; + $getEntityFunctionCall .= " [{$requiredEntityKeysArray}],"; if ($storeCode !== null) { - $getEntityFunctionCall .= ",\n\t\t\t\"{$storeCode}\""; + $getEntityFunctionCall .= " \"{$storeCode}\""; } else { - $getEntityFunctionCall .= ",\n\t\t\tnull"; + $getEntityFunctionCall .= " null"; } if ($index !== null) { - $getEntityFunctionCall .= ",\n\t\t\t{$index}"; + $getEntityFunctionCall .= ", {$index}"; } - $getEntityFunctionCall .= "\n\t\t);\n"; + $getEntityFunctionCall .= ");"; $testSteps .= $getEntityFunctionCall; break; From 01f0847a0a67d8b7be1bcb0c97d30c8ad4f290e5 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Wed, 4 Dec 2019 15:30:53 -0600 Subject: [PATCH 098/888] MQE-1379: Fix MFTF custom actions to fully support Codeception dry-run functionality --- .../Module/MagentoActionProxies.php | 121 +----------------- .../Module/MagentoWebDriver.php | 12 +- 2 files changed, 7 insertions(+), 126 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoActionProxies.php b/src/Magento/FunctionalTestingFramework/Module/MagentoActionProxies.php index 18c800e48..5a3b2360b 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoActionProxies.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoActionProxies.php @@ -20,124 +20,5 @@ */ class MagentoActionProxies extends CodeceptionModule { - /** - * Create an entity - * TODO: un-comment this function after MQE-1904 - * - * @param string $key StepKey of the createData action. - * @param string $scope - * @param string $entity Name of xml entity to create. - * @param array $dependentObjectKeys StepKeys of other createData actions that are required. - * @param array $overrideFields Array of FieldName => Value of override fields. - * @param string $storeCode - * @return void - */ - /* - public function createEntity( - $key, - $scope, - $entity, - $dependentObjectKeys = [], - $overrideFields = [], - $storeCode = '' - ) { - PersistedObjectHandler::getInstance()->createEntity( - $key, - $scope, - $entity, - $dependentObjectKeys, - $overrideFields, - $storeCode - ); - } - */ - /** - * Retrieves and updates a previously created entity - * TODO: un-comment this function after MQE-1904 - * - * @param string $key StepKey of the createData action. - * @param string $scope - * @param string $updateEntity Name of the static XML data to update the entity with. - * @param array $dependentObjectKeys StepKeys of other createData actions that are required. - * @return void - */ - /* - public function updateEntity($key, $scope, $updateEntity, $dependentObjectKeys = []) - { - PersistedObjectHandler::getInstance()->updateEntity( - $key, - $scope, - $updateEntity, - $dependentObjectKeys - ); - } - */ - /** - * Performs GET on given entity and stores entity for use - * TODO: un-comment this function after MQE-1904 - * - * @param string $key StepKey of getData action. - * @param string $scope - * @param string $entity Name of XML static data to use. - * @param array $dependentObjectKeys StepKeys of other createData actions that are required. - * @param string $storeCode - * @param integer $index - * @return void - */ - /* - public function getEntity($key, $scope, $entity, $dependentObjectKeys = [], $storeCode = '', $index = null) - { - PersistedObjectHandler::getInstance()->getEntity( - $key, - $scope, - $entity, - $dependentObjectKeys, - $storeCode, - $index - ); - } - */ - /** - * Retrieves and deletes a previously created entity - * TODO: un-comment this function after MQE-1904 - * - * @param string $key StepKey of the createData action. - * @param string $scope - * @return void - */ - /* - public function deleteEntity($key, $scope) - { - PersistedObjectHandler::getInstance()->deleteEntity($key, $scope); - } - */ - /** - * Retrieves a field from an entity, according to key and scope given - * TODO: un-comment this function after MQE-1904 - * - * @param string $stepKey - * @param string $field - * @param string $scope - * @return string - */ - /* - public function retrieveEntityField($stepKey, $field, $scope) - { - return PersistedObjectHandler::getInstance()->retrieveEntityField($stepKey, $field, $scope); - } - */ - /** - * Get encrypted value by key - * TODO: un-comment this function after MQE-1904 - * - * @param string $key - * @return string|null - * @throws TestFrameworkException - */ - /* - public function getSecret($key) - { - return CredentialStore::getInstance()->getSecret($key); - } - */ + // TODO: placeholder for proxy functions currently in MagentoWebDriver (MQE-1904) } diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 4cb980d9c..a7407f356 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -909,7 +909,7 @@ private function curlExecMagentoCLI($command, $timeout, $arguments): string /** * Create an entity - * TODO: remove this function after MQE-1904 + * TODO: move this function to MagentoActionProxies after MQE-1904 * * @param string $key StepKey of the createData action. * @param string $scope @@ -939,7 +939,7 @@ public function createEntity( /** * Retrieves and updates a previously created entity - * TODO: remove this function after MQE-1904 + * TODO: move this function to MagentoActionProxies after MQE-1904 * * @param string $key StepKey of the createData action. * @param string $scope @@ -959,7 +959,7 @@ public function updateEntity($key, $scope, $updateEntity, $dependentObjectKeys = /** * Performs GET on given entity and stores entity for use - * TODO: remove this function after MQE-1904 + * TODO: move this function to MagentoActionProxies after MQE-1904 * * @param string $key StepKey of getData action. * @param string $scope @@ -983,7 +983,7 @@ public function getEntity($key, $scope, $entity, $dependentObjectKeys = [], $sto /** * Retrieves and deletes a previously created entity - * TODO: remove this function after MQE-1904 + * TODO: move this function to MagentoActionProxies after MQE-1904 * * @param string $key StepKey of the createData action. * @param string $scope @@ -996,7 +996,7 @@ public function deleteEntity($key, $scope) /** * Retrieves a field from an entity, according to key and scope given - * TODO: remove this function after MQE-1904 + * TODO: move this function to MagentoActionProxies after MQE-1904 * * @param string $stepKey * @param string $field @@ -1010,7 +1010,7 @@ public function retrieveEntityField($stepKey, $field, $scope) /** * Get encrypted value by key - * TODO: remove this function after MQE-1904 + * TODO: move this function to MagentoActionProxies after MQE-1904 * * @param string $key * @return string|null From 5fd746c9ff1d623774ad8517eec7b8c2dd65b8d1 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Thu, 5 Dec 2019 09:48:27 -0600 Subject: [PATCH 099/888] MQE-1379: Fix MFTF custom actions to fully support Codeception dry-run functionality --- .../Allure/Adapter/MagentoAllureAdapter.php | 39 +++++-------------- .../Codeception/Subscriber/Console.php | 36 ++++------------- 2 files changed, 17 insertions(+), 58 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php b/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php index 1668f5b21..e9e1c344c 100644 --- a/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php +++ b/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php @@ -49,13 +49,6 @@ class MagentoAllureAdapter extends AllureCodeception */ private $atInvisibleSteps = false; - /** - * Boolean array to store status of previous invisible steps - * - * @var array - */ - private $invisibleStepStatus = []; - /** * Array of group values passed to test runner command * @@ -137,9 +130,6 @@ private function sanitizeGroupName($group) * @param StepEvent $stepEvent * @return void * @throws \Yandex\Allure\Adapter\AllureException - * - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.NPathComplexity) */ public function stepBefore(StepEvent $stepEvent) { @@ -198,27 +188,18 @@ public function stepBefore(StepEvent $stepEvent) */ public function stepAfter(StepEvent $stepEvent = null) { - // Store invisible step status if step is in INVISIBLE_STEP_ACTIONS - if ($this->atInvisibleSteps && $stepEvent->getStep()->hasFailed()) { - $this->invisibleStepStatus[] = false; - return; - } elseif ($this->atInvisibleSteps) { - $this->invisibleStepStatus[] = true; - return; - } else { - // Check previous invisible steps status - $invisibleStepsPassed = true; - foreach ($this->invisibleStepStatus as $pass) { - if (!$pass) { - $invisibleStepsPassed = false; - break; - } - } - $this->invisibleStepStatus = []; - if ($stepEvent->getStep()->hasFailed() || !$invisibleStepsPassed) { - $this->getLifecycle()->fire(new StepFailedEvent()); + // Simply return if step is INVISIBLE_STEP_ACTIONS + if ($this->atInvisibleSteps) { + if ($stepEvent->getStep()->hasFailed()) { + $this->atInvisibleSteps = false; } + return; } + + if ($stepEvent->getStep()->hasFailed()) { + $this->getLifecycle()->fire(new StepFailedEvent()); + } + $this->getLifecycle()->fire(new StepFinishedEvent()); } diff --git a/src/Magento/FunctionalTestingFramework/Codeception/Subscriber/Console.php b/src/Magento/FunctionalTestingFramework/Codeception/Subscriber/Console.php index b9e3f4ca1..8c50f0670 100644 --- a/src/Magento/FunctionalTestingFramework/Codeception/Subscriber/Console.php +++ b/src/Magento/FunctionalTestingFramework/Codeception/Subscriber/Console.php @@ -39,13 +39,6 @@ class Console extends \Codeception\Subscriber\Console */ private $atInvisibleSteps = false; - /** - * Boolean array to store status of previous invisible steps - * - * @var array - */ - private $invisibleStepStatus = []; - /** * Console constructor. Parent constructor requires codeception CLI options, and does not have its own configs. * Constructor is only different than parent due to the way Codeception instantiates Extensions. @@ -65,8 +58,6 @@ public function __construct($extensionOptions = [], $options = []) * * @param StepEvent $e * @return void - * - * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function beforeStep(StepEvent $e) { @@ -107,27 +98,14 @@ public function beforeStep(StepEvent $e) */ public function afterStep(StepEvent $e) { - // Store invisible step status if step is in INVISIBLE_STEP_ACTIONS - if ($this->atInvisibleSteps && $e->getStep()->hasFailed()) { - $this->invisibleStepStatus[] = false; - return; - } elseif ($this->atInvisibleSteps) { - $this->invisibleStepStatus[] = true; - return; - } else { - // Check previous invisible steps status - $invisibleStepsPassed = true; - foreach ($this->invisibleStepStatus as $pass) { - if (!$pass) { - $invisibleStepsPassed = false; - break; - } - } - $this->invisibleStepStatus = []; + // Do usual after step if step is not INVISIBLE_STEP_ACTIONS + if (!$this->atInvisibleSteps) { parent::afterStep($e); - if ($e->getStep()->hasFailed() || !$invisibleStepsPassed) { - $this->actionGroupStepKey = null; - } + } + + if ($e->getStep()->hasFailed()) { + $this->actionGroupStepKey = null; + $this->atInvisibleSteps = false; } } From a51f3bfcebfcd51fc90aa1ef2efacf8960f5e826 Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Thu, 5 Dec 2019 10:08:41 -0600 Subject: [PATCH 100/888] MQE-1893: CHANGELOG.MD and Composer version bump - CHANGELOG update - Composer file and lock update --- CHANGELOG.md | 25 +++++++++++++++++++++++++ bin/mftf | 4 +++- composer.json | 2 +- composer.lock | 2 +- 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd1e02008..e9b935493 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,30 @@ Magento Functional Testing Framework Changelog ================================================ +2.5.4 +----- + +* Traceability + * Introduced new `mftf doctor` command + * Command verifies and troubleshoots some configuration steps required for running tests + * Please see DevDocs for more details + * `<*Data>` actions now contain `API Endpoint` and `Request Header` artifacts. + * Introduced new `.env` configurations `ENABLE_BROWSER_LOG` and `BROWSER_LOG_BLACKLIST` + * Configuration enables allure artifacts for browser log entries if they are present after the step. + * Blacklist filters out logs from specific sources. +* Customizability + * Introduced `timeout=""` to `magentoCLI` actions. + +### GitHub Issues/Pull requests: +* [#317](https://github.com/magento/magento2-functional-testing-framework/pull/317) -- RetrieveEntityField generation does not consider ActionGroup as part of namespace +* [#433](https://github.com/magento/magento2-functional-testing-framework/pull/433) -- Add possibility to include multiple non primitive types in an array + +### Fixes +* A test now contains attachments for every exception encountered in the test (fix for a test `` exception overriding all test exceptions). +* Fixed hard requirement for `MAGENTO_BASE_URL` to contain a leading `/`. +* `magentoCLI` actions for `config:sensitive:set` no longer obscure CLI output. +* `WAIT_TIMEOUT` in the `.env` now correctly sets `pageload_timeout` configuration. +* Fixed an issue where `run:group` could not consolidate a `group` that had tests in and out of ``s. + 2.5.3 ----- diff --git a/bin/mftf b/bin/mftf index 9e5879280..7a9ca1cf2 100755 --- a/bin/mftf +++ b/bin/mftf @@ -27,9 +27,11 @@ try { try { + $version = json_decode(file_get_contents(FW_BP . DIRECTORY_SEPARATOR . 'composer.json'), true); + $version = $version['version']; $application = new Symfony\Component\Console\Application(); $application->setName('Magento Functional Testing Framework CLI'); - $application->setVersion('2.5.3'); + $application->setVersion($version); /** @var \Magento\FunctionalTestingFramework\Console\CommandListInterface $commandList */ $commandList = new \Magento\FunctionalTestingFramework\Console\CommandList; foreach ($commandList->getCommands() as $command) { diff --git a/composer.json b/composer.json index e3e890fa1..2702f6b77 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "2.5.3", + "version": "2.5.4", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index 4bf9950d9..2ba66b1c9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7d881849489a99d20aa632226a061fbd", + "content-hash": "ee4db031a218f7a29853b2748fe493fe", "packages": [ { "name": "allure-framework/allure-codeception", From 6ab962ce0b4ca7472a9d3c8e8d94e70ebb0b603e Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Thu, 5 Dec 2019 10:13:13 -0600 Subject: [PATCH 101/888] MQE-1650: Update MFTF configuration to read Test entities from new location - Version change of composer/composer for 2.2 compat --- composer.json | 2 +- composer.lock | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/composer.json b/composer.json index e3e890fa1..281dad854 100755 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ "ext-curl": "*", "allure-framework/allure-codeception": "~1.3.0", "codeception/codeception": "~2.4.5", - "composer/composer": "^1.6", + "composer/composer": "^1.4", "consolidation/robo": "^1.0.0", "csharpru/vault-php": "~3.5.3", "csharpru/vault-php-guzzle6-transport": "^2.0", diff --git a/composer.lock b/composer.lock index 4bf9950d9..007349dcb 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7d881849489a99d20aa632226a061fbd", + "content-hash": "6d6e03ab3a48beba35d47504ddf95f0a", "packages": [ { "name": "allure-framework/allure-codeception", @@ -486,16 +486,16 @@ }, { "name": "composer/composer", - "version": "1.9.0", + "version": "1.9.1", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "314aa57fdcfc942065996f59fb73a8b3f74f3fa5" + "reference": "bb01f2180df87ce7992b8331a68904f80439dd2f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/314aa57fdcfc942065996f59fb73a8b3f74f3fa5", - "reference": "314aa57fdcfc942065996f59fb73a8b3f74f3fa5", + "url": "https://api.github.com/repos/composer/composer/zipball/bb01f2180df87ce7992b8331a68904f80439dd2f", + "reference": "bb01f2180df87ce7992b8331a68904f80439dd2f", "shasum": "" }, "require": { @@ -562,7 +562,7 @@ "dependency", "package" ], - "time": "2019-08-02T18:55:33+00:00" + "time": "2019-11-01T16:20:17+00:00" }, { "name": "composer/semver", From ca2e420a87770d047fb8b60a31d26ffd0504e57a Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Fri, 6 Dec 2019 10:55:38 -0600 Subject: [PATCH 102/888] MQE-1893: CHANGELOG.MD and Composer version bump - Reupdate lock file --- composer.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.lock b/composer.lock index 007349dcb..8f2fcb8e9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "6d6e03ab3a48beba35d47504ddf95f0a", + "content-hash": "59e95cc1ae6311e93111bd7ced180d29", "packages": [ { "name": "allure-framework/allure-codeception", From 61e6c2713697b7ba2bcc1c3ecc6ca772535862e9 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Fri, 6 Dec 2019 12:32:16 -0600 Subject: [PATCH 103/888] MQE-1908: Change doctor command to work with Curl version of MagentoCLI --- .../Console/DoctorCommand.php | 13 +++++++++++-- .../Module/MagentoWebDriverDoctor.php | 15 ++++++++------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php b/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php index 4bd05b836..0b144aabc 100644 --- a/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php @@ -8,6 +8,7 @@ namespace Magento\FunctionalTestingFramework\Console; use Codeception\Configuration; +use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; use Symfony\Component\EventDispatcher\EventDispatcher; use Codeception\SuiteManager; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; @@ -128,9 +129,17 @@ private function checkAuthenticationToMagentoAdmin() $this->ioStyle->success('Successful'); $result = true; } catch (TestFrameworkException $e) { + if (getenv('MAGENTO_BACKEND_BASE_URL')) { + $urlVar = 'MAGENTO_BACKEND_BASE_URL'; + } else { + $urlVar = 'MAGENTO_BASE_URL'; + } $this->ioStyle->error( - $e->getMessage() - . "\nPlease verify MAGENTO_ADMIN_USERNAME and MAGENTO_ADMIN_PASSWORD in .env." + $e->getMessage() . "\n" + . "Please verify the following configuration settings in .env:\n" + . $urlVar . ' = ' . getenv($urlVar) . "\n" + . "MAGENTO_ADMIN_USERNAME = " . $e->getContext()['MAGENTO_ADMIN_USERNAME'] . "\n" + . "MAGENTO_ADMIN_PASSWORD = " . $e->getContext()['MAGENTO_ADMIN_PASSWORD'] ); } return $result; diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriverDoctor.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriverDoctor.php index 98eb8bd4f..1407c957b 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriverDoctor.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriverDoctor.php @@ -15,7 +15,7 @@ */ class MagentoWebDriverDoctor extends MagentoWebDriver { - const MAGENTO_CLI_COMMAND = 'list'; + const MAGENTO_CLI_COMMAND = 'info:currency:list'; const EXCEPTION_CONTEXT_SELENIUM = 'selenium'; const EXCEPTION_CONTEXT_ADMIN = 'admin'; const EXCEPTION_CONTEXT_STOREFRONT = 'store'; @@ -150,18 +150,19 @@ private function loadPageAtUrl($url) private function runMagentoCLI() { try { - $regex = '~^.*(?Magento CLI).*[\r\n]+(?Usage:).*~'; + $regex = '~^.*[\r\n]+.*(?Currency).*(?Code).*~'; $output = parent::magentoCLI(self::MAGENTO_CLI_COMMAND); preg_match($regex, $output, $matches); - if (isset($matches['name']) && isset($matches['usage'])) { + if (isset($matches['name']) && isset($matches['code'])) { return; } } catch (\Exception $e) { - throw new TestFrameworkException( - "Failed to run Magento CLI command\n" - . "Please reference Magento DevDoc to setup command.php and .htaccess files." - ); } + + throw new TestFrameworkException( + "Failed to run Magento CLI command\n" + . "Please reference Magento DevDoc to setup command.php and .htaccess files." + ); } } From b4dbaa4e4683d5dbb833c935c2faed39a710f729 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Fri, 6 Dec 2019 13:19:02 -0600 Subject: [PATCH 104/888] MQE-1905: Inconsistent environment variable naming for MAGENTO_BACKEND_BASE_HOST --- etc/config/.env.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/config/.env.example b/etc/config/.env.example index e290c7815..7320d8b8b 100644 --- a/etc/config/.env.example +++ b/etc/config/.env.example @@ -5,7 +5,7 @@ MAGENTO_BASE_URL=http://devdocs.magento.com/ #*** Uncomment if you are running Admin Panel on separate domain (used with MAGENTO_BACKEND_NAME) ***# -# MAGENTO_BACKEND_BASE_HOST=http://admin.example.com/ +# MAGENTO_BACKEND_BASE_URL=http://admin.example.com/ #*** Set the Admin Username and Password for your Magento instance ***# MAGENTO_BACKEND_NAME=admin From a243dbdfb2cdfad597f3be78c9b872edc30bd195 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Fri, 6 Dec 2019 15:35:08 -0600 Subject: [PATCH 105/888] MQE-1908: Change doctor command to work with Curl version of MagentoCLI --- .../FunctionalTestingFramework/Console/DoctorCommand.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php b/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php index 0b144aabc..6fc9afa55 100644 --- a/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php @@ -135,11 +135,8 @@ private function checkAuthenticationToMagentoAdmin() $urlVar = 'MAGENTO_BASE_URL'; } $this->ioStyle->error( - $e->getMessage() . "\n" - . "Please verify the following configuration settings in .env:\n" - . $urlVar . ' = ' . getenv($urlVar) . "\n" - . "MAGENTO_ADMIN_USERNAME = " . $e->getContext()['MAGENTO_ADMIN_USERNAME'] . "\n" - . "MAGENTO_ADMIN_PASSWORD = " . $e->getContext()['MAGENTO_ADMIN_PASSWORD'] + $e->getMessage() . "\nPlease verify if " . $urlVar . ", " + . "MAGENTO_ADMIN_USERNAME and MAGENTO_ADMIN_PASSWORD in .env are valid." ); } return $result; From 9cd8891635460fa7003dd2d0769a16bb7999cafb Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Mon, 9 Dec 2019 11:45:38 -0600 Subject: [PATCH 106/888] MQE-1917: ENABLE_BROWSER_LOG = false attaches JS logs to allure --- .../Extension/TestContextExtension.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php index 07153040c..c50156f08 100644 --- a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php +++ b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php @@ -182,7 +182,7 @@ public function beforeStep(\Codeception\Event\StepEvent $e) public function afterStep(\Codeception\Event\StepEvent $e) { $browserLog = $this->getDriver()->webDriver->manage()->getLog("browser"); - if (getenv('ENABLE_BROWSER_LOG')) { + if (getenv('ENABLE_BROWSER_LOG') === 'true') { foreach (explode(',', getenv('BROWSER_LOG_BLACKLIST')) as $source) { $browserLog = BrowserLogUtil::filterLogsOfType($browserLog, $source); } From f4d2eb38da83568a82006bda7ff2babfe763a3bf Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Thu, 12 Dec 2019 13:45:42 -0600 Subject: [PATCH 107/888] 2.5.4-DemoLink - Added link to demo in changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9b935493..c8c4ca9b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ Magento Functional Testing Framework Changelog ================================================ 2.5.4 ----- - +[Demo Video](https://www.youtube.com/watch?v=tguvkw1HWKg) * Traceability * Introduced new `mftf doctor` command * Command verifies and troubleshoots some configuration steps required for running tests From 20fbe3d54d23995aebc37ae0d391e0d2283cbb85 Mon Sep 17 00:00:00 2001 From: Donald Booth Date: Fri, 13 Dec 2019 10:28:56 -0600 Subject: [PATCH 108/888] Update data file location --- docs/mftf-tests.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/mftf-tests.md b/docs/mftf-tests.md index b9d94baa9..d1bd1ce83 100644 --- a/docs/mftf-tests.md +++ b/docs/mftf-tests.md @@ -13,11 +13,11 @@ dl dt{ The Magento Functional Testing Framework runs tests on every Module within Magento. These files are stored within each Module folder in the Magento repo. This page lists all those tests so that developers can have a good sense of what is covered. -{% include mftf/mftf_data.md %} +{% include mftf/functional_data.md %} {% for item in mftf %} -### {{ item.name }} +### {{ item.name }} {% for file in item.items %} #### [{{ file.filename }}]({{file.repo}}) {: .mftf-test-link} From 9d85f414031fe11b93d8fe0531bed8bfe666c243 Mon Sep 17 00:00:00 2001 From: Donald Booth Date: Fri, 13 Dec 2019 10:59:56 -0600 Subject: [PATCH 109/888] Update include location. --- docs/mftf-tests.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/mftf-tests.md b/docs/mftf-tests.md index d1bd1ce83..08d1c59a1 100644 --- a/docs/mftf-tests.md +++ b/docs/mftf-tests.md @@ -5,7 +5,6 @@ dl dt{ font-weight:400; } - # MFTF functional test reference From 686f052859b158ad79b1e93742688b3d93661dce Mon Sep 17 00:00:00 2001 From: Adarsh Manickam Date: Sat, 14 Dec 2019 18:24:15 +0530 Subject: [PATCH 110/888] Added clarity in selector paths --- docs/guides/selectors.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/guides/selectors.md b/docs/guides/selectors.md index 3e019bb75..35a96d29f 100644 --- a/docs/guides/selectors.md +++ b/docs/guides/selectors.md @@ -208,7 +208,7 @@ Here is an example of what NOT to do, but this demonstrates how the selector wor In the BAD example above, we are specifying a very precise path to an input element in the DOM, starting from the very top of the document. -Similarly, the relative XPath selector is a double forward slash `//`. It is used to start searching for an element anywhere in the DOM. +Similarly, the relative XPath selector is a double forward slash `//`. It is used to start searching for an element anywhere in the DOM starting from the element preceedingly defined. If no element is defined before, the entire DOM is searched. Example: @@ -216,6 +216,8 @@ Example: //div[@class=’form-group’]//input[@id='user-message'] ``` +In the GOOD example above, all
elements in the DOM are matched first, and then all with
as one of its parents is matched. Doesn't matter if the parent is anywhere up in the parent hierarchy. + #### Parent Selectors The parent selector (`..`) allows you to jump to the parent element. From 34956406e94cb244f6aa5c6ad37badba55aeb67d Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Thu, 19 Dec 2019 09:51:06 -0600 Subject: [PATCH 111/888] MQE-1911: --allow-skipped removing test hooks - Fixed conditional - Modified existing conditional to follow same pattern --- .../Util/TestGenerator.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index dc6aa9238..09c353029 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -242,7 +242,7 @@ public function assembleTestPhp($testObject) $className = $testObject->getCodeceptionName(); try { - if (!$testObject->isSkipped() && !MftfApplicationConfig::getConfig()->allowSkipped()) { + if (!$testObject->isSkipped() || MftfApplicationConfig::getConfig()->allowSkipped()) { $hookPhp = $this->generateHooksPhp($testObject->getHooks()); } else { $hookPhp = null; @@ -1601,7 +1601,13 @@ private function generateTestPhp($test) $testName = str_replace(' ', '', $testName); $testAnnotations = $this->generateAnnotationsPhp($test->getAnnotations(), true); $dependencies = 'AcceptanceTester $I'; - if ($test->isSkipped() && !MftfApplicationConfig::getConfig()->allowSkipped()) { + if (!$test->isSkipped() || MftfApplicationConfig::getConfig()->allowSkipped()) { + try { + $steps = $this->generateStepsPhp($test->getOrderedActions()); + } catch (\Exception $e) { + throw new TestReferenceException($e->getMessage() . " in Test \"" . $test->getName() . "\""); + } + } else { $skipString = "This test is skipped due to the following issues:\\n"; $issues = $test->getAnnotations()['skip'] ?? null; if (isset($issues)) { @@ -1611,12 +1617,6 @@ private function generateTestPhp($test) } $steps = "\t\t" . '$scenario->skip("' . $skipString . '");' . "\n"; $dependencies .= ', \Codeception\Scenario $scenario'; - } else { - try { - $steps = $this->generateStepsPhp($test->getOrderedActions()); - } catch (\Exception $e) { - throw new TestReferenceException($e->getMessage() . " in Test \"" . $test->getName() . "\""); - } } $testPhp .= $testAnnotations; From 04ef38e2390ec07a4414ed86056433cb363104f7 Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Thu, 19 Dec 2019 12:28:49 -0600 Subject: [PATCH 112/888] MQE-1911: --allow-skipped removing test hooks - Unit test --- .../FunctionalTestFramework/Util/TestGeneratorTest.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php index cadc1c6a8..f25153513 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php @@ -9,6 +9,7 @@ use AspectMock\Test as AspectMock; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; +use Magento\FunctionalTestingFramework\Test\Objects\TestHookObject; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; use Magento\FunctionalTestingFramework\Util\MagentoTestCase; use Magento\FunctionalTestingFramework\Util\TestGenerator; @@ -76,14 +77,20 @@ public function testAllowSkipped() $actionObject = new ActionObject('fakeAction', 'comment', [ 'userInput' => $actionInput ]); + $beforeActionInput = 'beforeInput'; + $beforeActionObject = new ActionObject('beforeAction', 'comment', [ + 'userInput' => $beforeActionInput + ]); $annotations = ['skip' => ['issue']]; - $testObject = new TestObject("sampleTest", ["merge123" => $actionObject], $annotations, [], "filename"); + $beforeHook = new TestHookObject("before", "sampleTest", ['beforeAction' => $beforeActionObject]); + $testObject = new TestObject("sampleTest", ["fakeAction" => $actionObject], $annotations, ["before" => $beforeHook], "filename"); $testGeneratorObject = TestGenerator::getInstance("", ["sampleTest" => $testObject]); $output = $testGeneratorObject->assembleTestPhp($testObject); $this->assertNotContains('This test is skipped', $output); $this->assertContains($actionInput, $output); + $this->assertContains($beforeActionInput, $output); } } From 60a07a3113cb3b4e73f2f8ee81f2416075b4f87b Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Thu, 19 Dec 2019 12:40:06 -0600 Subject: [PATCH 113/888] MQE-1911: --allow-skipped removing test hooks - static check fix --- .../FunctionalTestFramework/Util/TestGeneratorTest.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php index f25153513..8f8eee749 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php @@ -84,7 +84,13 @@ public function testAllowSkipped() $annotations = ['skip' => ['issue']]; $beforeHook = new TestHookObject("before", "sampleTest", ['beforeAction' => $beforeActionObject]); - $testObject = new TestObject("sampleTest", ["fakeAction" => $actionObject], $annotations, ["before" => $beforeHook], "filename"); + $testObject = new TestObject( + "sampleTest", + ["fakeAction" => $actionObject], + $annotations, + ["before" => $beforeHook], + "filename" + ); $testGeneratorObject = TestGenerator::getInstance("", ["sampleTest" => $testObject]); $output = $testGeneratorObject->assembleTestPhp($testObject); From 0e0a514273b2164d4e47997dd9f160403211d44b Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Fri, 20 Dec 2019 09:07:53 -0600 Subject: [PATCH 114/888] Added clarity in selector paths - Code review --- docs/guides/selectors.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/selectors.md b/docs/guides/selectors.md index 35a96d29f..e060ba6c4 100644 --- a/docs/guides/selectors.md +++ b/docs/guides/selectors.md @@ -216,7 +216,7 @@ Example: //div[@class=’form-group’]//input[@id='user-message'] ``` -In the GOOD example above, all
elements in the DOM are matched first, and then all with
as one of its parents is matched. Doesn't matter if the parent is anywhere up in the parent hierarchy. +In the `GOOD` example above, all `
` elements in the DOM are matched first, and then all `` with `
` as one of its parents is matched. The parent does not have to immediately precede it since it uses another double forward slash `//`. #### Parent Selectors From 96b724983ec0108c815609659449a4c9af7cbc5f Mon Sep 17 00:00:00 2001 From: Donald Booth Date: Thu, 2 Jan 2020 09:59:00 -0600 Subject: [PATCH 115/888] Grammar fixes --- docs/guides/selectors.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guides/selectors.md b/docs/guides/selectors.md index e060ba6c4..d1441865a 100644 --- a/docs/guides/selectors.md +++ b/docs/guides/selectors.md @@ -208,7 +208,7 @@ Here is an example of what NOT to do, but this demonstrates how the selector wor In the BAD example above, we are specifying a very precise path to an input element in the DOM, starting from the very top of the document. -Similarly, the relative XPath selector is a double forward slash `//`. It is used to start searching for an element anywhere in the DOM starting from the element preceedingly defined. If no element is defined before, the entire DOM is searched. +Similarly, the relative XPath selector is a double forward slash `//`. It is used to start searching for an element anywhere in the DOM starting from the specified element. If no element is defined, the entire DOM is searched. Example: @@ -216,7 +216,7 @@ Example: //div[@class=’form-group’]//input[@id='user-message'] ``` -In the `GOOD` example above, all `
` elements in the DOM are matched first, and then all `` with `
` as one of its parents is matched. The parent does not have to immediately precede it since it uses another double forward slash `//`. +In the `GOOD` example above, all `
` elements in the DOM are matched first. Then all `` with `
` as one of its parents are matched. The parent does not have to immediately precede it since it uses another double forward slash `//`. #### Parent Selectors From 7926707b995929fa4bf03ba5c83aa112fd8bb086 Mon Sep 17 00:00:00 2001 From: Donald Booth Date: Thu, 2 Jan 2020 10:15:43 -0600 Subject: [PATCH 116/888] Fixes broken links --- docs/tips-tricks.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/tips-tricks.md b/docs/tips-tricks.md index 4f7539c6d..a2300c3bf 100644 --- a/docs/tips-tricks.md +++ b/docs/tips-tricks.md @@ -419,5 +419,5 @@ BAD: -[This test]: https://github.com/magento/magento2/blob/2.3-develop/app/code/Magento/Captcha/Test/Mftf/Test/StorefrontCaptchaRegisterNewCustomerTest.xml#L24 -[Data file]: https://github.com/magento/magento2/blob/2.3-develop/app/code/Magento/Captcha/Test/Mftf/Data/CaptchaConfigData.xml +[This test]: https://github.com/magento/magento2/blob/2.3/app/code/Magento/Captcha/Test/Mftf/Test/StorefrontCaptchaRegisterNewCustomerTest.xml#L24 +[Data file]: https://github.com/magento/magento2/blob/2.3/app/code/Magento/Captcha/Test/Mftf/Data/CaptchaConfigData.xml From 16d26ae6899b39d88a5a59e77dbad5413b4f0b91 Mon Sep 17 00:00:00 2001 From: Donald Booth Date: Thu, 2 Jan 2020 10:33:05 -0600 Subject: [PATCH 117/888] Removing stray file --- docs/mftf-tests.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/mftf-tests.md b/docs/mftf-tests.md index d1bd1ce83..b9d94baa9 100644 --- a/docs/mftf-tests.md +++ b/docs/mftf-tests.md @@ -13,11 +13,11 @@ dl dt{ The Magento Functional Testing Framework runs tests on every Module within Magento. These files are stored within each Module folder in the Magento repo. This page lists all those tests so that developers can have a good sense of what is covered. -{% include mftf/functional_data.md %} +{% include mftf/mftf_data.md %} {% for item in mftf %} -### {{ item.name }} +### {{ item.name }} {% for file in item.items %} #### [{{ file.filename }}]({{file.repo}}) {: .mftf-test-link} From 4e1ea0af8166fb3e40a4a0e2480183cb49137fb9 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Fri, 3 Jan 2020 13:37:59 -0600 Subject: [PATCH 118/888] MQE-1513: createData throws a useless error message during runtime when the entity does not exist --- .../Util/TestGeneratorTest.php | 26 +++++++++++++++++++ .../Util/TestGenerator.php | 7 +++++ 2 files changed, 33 insertions(+) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php index 8f8eee749..e86a924c9 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php @@ -14,6 +14,7 @@ use Magento\FunctionalTestingFramework\Util\MagentoTestCase; use Magento\FunctionalTestingFramework\Util\TestGenerator; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; class TestGeneratorTest extends MagentoTestCase { @@ -41,11 +42,36 @@ public function testEntityException() $testGeneratorObject->createAllTestFiles(null, []); } + /** + * Test to check exceptions for createData on referencing non-existent entity + * + * @throws TestReferenceException + */ + + public function testCreateDataException() + { + $actionObject = new ActionObject('fakeAction', 'createData', [ + 'entity' => 'invalidEntity' + ]); + + $testObject = new TestObject("sampleTest", ["merge123" => $actionObject], [], [], "filename"); + + $testGeneratorObject = TestGenerator::getInstance("", ["sampleTest" => $testObject]); + + AspectMock::double(TestGenerator::class, ['loadAllTestObjects' => ["sampleTest" => $testObject]]); + + $this->expectExceptionMessage("Entity \"invalidEntity\" does not exist." . + "\nException occurred parsing action at StepKey \"fakeAction\" in Test \"sampleTest\""); + + $testGeneratorObject->createAllTestFiles(null, []); + } + /** * Tests that skipped tests do not have a fully generated body * * @throws \Magento\FunctionalTestingFramework\Exceptions\TestReferenceException */ + public function testSkippedNoGeneration() { $actionInput = 'fakeInput'; diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 09c353029..762fbd346 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -731,6 +731,13 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato case "createData": $entity = $customActionAttributes['entity']; + if(DataObjectHandler::getInstance()->getObject($entity) === null) { + throw new TestReferenceException( + "Entity \"" . $entity . "\" does not exist." . + "\nException occurred parsing action at StepKey \"" . $stepKey . "\"" + ); + } + //TODO refactor entity field override to not be individual actionObjects $customEntityFields = $customActionAttributes[ActionObjectExtractor::ACTION_OBJECT_PERSISTENCE_FIELDS] ?? []; From 1075fd48fb90f2f4d5df673a5fbabcd1055868b9 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Fri, 3 Jan 2020 16:34:34 -0600 Subject: [PATCH 119/888] MQE-1513: createData throws a useless error message during runtime when the entity does not exist --- .../Util/TestGeneratorTest.php | 24 ------------------- .../Handlers/PersistedObjectHandler.php | 8 +++++++ .../Util/TestGenerator.php | 7 ------ 3 files changed, 8 insertions(+), 31 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php index e86a924c9..17da4cd20 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php @@ -42,30 +42,6 @@ public function testEntityException() $testGeneratorObject->createAllTestFiles(null, []); } - /** - * Test to check exceptions for createData on referencing non-existent entity - * - * @throws TestReferenceException - */ - - public function testCreateDataException() - { - $actionObject = new ActionObject('fakeAction', 'createData', [ - 'entity' => 'invalidEntity' - ]); - - $testObject = new TestObject("sampleTest", ["merge123" => $actionObject], [], [], "filename"); - - $testGeneratorObject = TestGenerator::getInstance("", ["sampleTest" => $testObject]); - - AspectMock::double(TestGenerator::class, ['loadAllTestObjects' => ["sampleTest" => $testObject]]); - - $this->expectExceptionMessage("Entity \"invalidEntity\" does not exist." . - "\nException occurred parsing action at StepKey \"fakeAction\" in Test \"sampleTest\""); - - $testGeneratorObject->createAllTestFiles(null, []); - } - /** * Tests that skipped tests do not have a fully generated body * diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php index 2a0f11a01..7015292c0 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php @@ -97,6 +97,14 @@ public function createEntity( } $retrievedEntity = DataObjectHandler::getInstance()->getObject($entity); + + if ($retrievedEntity === null) { + throw new TestReferenceException( + "Entity \"" . $entity . "\" does not exist." . + "\nException occurred parsing action at StepKey \"" . $key . "\"" + ); + } + $persistedObject = new DataPersistenceHandler( $retrievedEntity, $retrievedDependentObjects, diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 762fbd346..09c353029 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -731,13 +731,6 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato case "createData": $entity = $customActionAttributes['entity']; - if(DataObjectHandler::getInstance()->getObject($entity) === null) { - throw new TestReferenceException( - "Entity \"" . $entity . "\" does not exist." . - "\nException occurred parsing action at StepKey \"" . $stepKey . "\"" - ); - } - //TODO refactor entity field override to not be individual actionObjects $customEntityFields = $customActionAttributes[ActionObjectExtractor::ACTION_OBJECT_PERSISTENCE_FIELDS] ?? []; From a415f0554beb308c26f5a32ced30f40a9d11664f Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Fri, 3 Jan 2020 16:39:39 -0600 Subject: [PATCH 120/888] MQE-1513: createData throws a useless error message during runtime when the entity does not exist reverted changes --- .../Magento/FunctionalTestFramework/Util/TestGeneratorTest.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php index 17da4cd20..8f8eee749 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php @@ -14,7 +14,6 @@ use Magento\FunctionalTestingFramework\Util\MagentoTestCase; use Magento\FunctionalTestingFramework\Util\TestGenerator; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; -use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; class TestGeneratorTest extends MagentoTestCase { @@ -47,7 +46,6 @@ public function testEntityException() * * @throws \Magento\FunctionalTestingFramework\Exceptions\TestReferenceException */ - public function testSkippedNoGeneration() { $actionInput = 'fakeInput'; From fbf066d23812307f072cb17420b1a9c08c271b30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Bajsarowicz?= Date: Mon, 6 Jan 2020 01:31:07 +0100 Subject: [PATCH 121/888] Set of changes to TestGenerator --- .../Util/TestGenerator.php | 204 ++++++++++-------- 1 file changed, 120 insertions(+), 84 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 09c353029..89120a83e 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -40,9 +40,11 @@ class TestGenerator const REQUIRED_ENTITY_REFERENCE = 'createDataKey'; const GENERATED_DIR = '_generated'; const DEFAULT_DIR = 'default'; + const TEST_SCOPE = 'test'; const HOOK_SCOPE = 'hook'; const SUITE_SCOPE = 'suite'; + const PRESSKEY_ARRAY_ANCHOR_KEY = '987654321098765432109876543210'; const PERSISTED_OBJECT_NOTATION_REGEX = '/\${1,2}[\w.\[\]]+\${1,2}/'; const NO_STEPKEY_ACTIONS = [ @@ -53,7 +55,11 @@ class TestGenerator 'generateDate', 'field' ]; + const RULE_ERROR = 'On step with stepKey "%s", only one of the attributes: "%s" can be use for action "%s"'; + const STEP_KEY_ANNOTATION = " // stepKey: %s"; + const ARRAY_WRAP_OPEN = '['; + const ARRAY_WRAP_CLOSE = ']'; /** * Actor name for AcceptanceTest @@ -105,7 +111,7 @@ class TestGenerator private $currentGenerationScope = TestGenerator::TEST_SCOPE; /** - * TestGenerator constructor. + * Private constructor for Factory * * @param string $exportDir * @param array $tests @@ -114,13 +120,11 @@ class TestGenerator */ private function __construct($exportDir, $tests, $debug = false) { - // private constructor for factory $this->exportDirName = $exportDir ?? self::DEFAULT_DIR; - $exportDir = $exportDir ?? self::DEFAULT_DIR; $this->exportDirectory = FilePathFormatter::format(TESTS_MODULE_PATH) . self::GENERATED_DIR . DIRECTORY_SEPARATOR - . $exportDir; + . $this->exportDirName; $this->tests = $tests; $this->consoleOutput = new \Symfony\Component\Console\Output\ConsoleOutput(); $this->debug = $debug; @@ -185,13 +189,13 @@ private function loadAllTestObjects($testsToIgnore) * @return void * @throws \Exception */ - private function createCestFile($testPhp, $filename) + private function createCestFile(string $testPhp, string $filename) { $exportFilePath = $this->exportDirectory . DIRECTORY_SEPARATOR . $filename . ".php"; $file = fopen($exportFilePath, 'w'); if (!$file) { - throw new \Exception("Could not open the file."); + throw new \Exception(sprintf('Could not open test file: "%s"', $exportFilePath)); } fwrite($file, $testPhp); @@ -628,9 +632,9 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato // validate the param array is in the correct format $this->validateParameterArray($customActionAttributes['parameterArray']); - $parameterArray = "["; - $parameterArray .= $this->addUniquenessToParamArray($customActionAttributes['parameterArray']); - $parameterArray .= "]"; + $parameterArray = $this->wrapParameterArray( + $this->addUniquenessToParamArray($customActionAttributes['parameterArray']) + ); } if (isset($customActionAttributes['requiredAction'])) { @@ -748,13 +752,8 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato if (!empty($requiredEntityKeys)) { $requiredEntityKeysArray = '"' . implode('", "', $requiredEntityKeys) . '"'; } - //Determine Scope - $scope = PersistedObjectHandler::TEST_SCOPE; - if ($generationScope == TestGenerator::HOOK_SCOPE) { - $scope = PersistedObjectHandler::HOOK_SCOPE; - } elseif ($generationScope == TestGenerator::SUITE_SCOPE) { - $scope = PersistedObjectHandler::SUITE_SCOPE; - } + + $scope = $this->getObjectScope($generationScope); $createEntityFunctionCall = "\t\t\${$actor}->createEntity("; $createEntityFunctionCall .= "\"{$stepKey}\","; @@ -782,13 +781,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $actionGroup = $actionObject->getCustomActionAttributes()['actionGroup'] ?? null; $key .= $actionGroup; - //Determine Scope - $scope = PersistedObjectHandler::TEST_SCOPE; - if ($generationScope == TestGenerator::HOOK_SCOPE) { - $scope = PersistedObjectHandler::HOOK_SCOPE; - } elseif ($generationScope == TestGenerator::SUITE_SCOPE) { - $scope = PersistedObjectHandler::SUITE_SCOPE; - } + $scope = $this->getObjectScope($generationScope); $deleteEntityFunctionCall = "\t\t\${$actor}->deleteEntity("; $deleteEntityFunctionCall .= "\"{$key}\","; @@ -831,12 +824,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $requiredEntityKeysArray = '"' . implode('", "', $requiredEntityKeys) . '"'; } - $scope = PersistedObjectHandler::TEST_SCOPE; - if ($generationScope == TestGenerator::HOOK_SCOPE) { - $scope = PersistedObjectHandler::HOOK_SCOPE; - } elseif ($generationScope == TestGenerator::SUITE_SCOPE) { - $scope = PersistedObjectHandler::SUITE_SCOPE; - } + $scope = $this->getObjectScope($generationScope); $updateEntityFunctionCall = "\t\t\${$actor}->updateEntity("; $updateEntityFunctionCall .= "\"{$key}\","; @@ -870,13 +858,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $requiredEntityKeysArray = '"' . implode('", "', $requiredEntityKeys) . '"'; } - //Determine Scope - $scope = PersistedObjectHandler::TEST_SCOPE; - if ($generationScope == TestGenerator::HOOK_SCOPE) { - $scope = PersistedObjectHandler::HOOK_SCOPE; - } elseif ($generationScope == TestGenerator::SUITE_SCOPE) { - $scope = PersistedObjectHandler::SUITE_SCOPE; - } + $scope = $this->getObjectScope($generationScope); //Create Function $getEntityFunctionCall = "\t\t\${$actor}->getEntity("; @@ -1303,7 +1285,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato break; case "comment": $input = $input === null ? strtr($value, ['$' => '\$', '{' => '\{', '}' => '\}']) : $input; - // Combining userInput from native XML comment and action to fall-through 'default' case + // Combining userInput from native XML comment and action to fall-through 'default' case default: $testSteps .= $this->wrapFunctionCall( $actor, @@ -1380,9 +1362,9 @@ private function trimVariableIfNeeded($input) preg_match('/"{\$[a-z][a-zA-Z\d]+}"/', $input, $match); if (isset($match[0])) { return trim($input, '{}"'); - } else { - return $input; } + + return $input; } /** @@ -1403,7 +1385,7 @@ private function replaceMatchesIntoArg($matches, &$outputArg) $variable = $this->stripAndSplitReference($match, $delimiter); if (count($variable) != 2) { throw new \Exception( - "Invalid Persisted Entity Reference: {$match}. + "Invalid Persisted Entity Reference: {$match}. Test persisted entity references must follow {$delimiter}entityStepKey.field{$delimiter} format." ); } @@ -1480,7 +1462,7 @@ private function resolveStepKeyReferences($input, $actionGroupOrigin, $matchAll // only replace when whole word matches exactly // e.g. testVar => $testVar but not $testVar2 if (strpos($output, $stepKeyVarRef) !== false) { - $output = preg_replace('/\B\\' .$stepKeyVarRef. '\b/', $stepKeyVarRef . $testInvocationKey, $output); + $output = preg_replace('/\B\\' . $stepKeyVarRef . '\b/', $stepKeyVarRef . $testInvocationKey, $output); } if (strpos($output, $persistedVarRef) !== false) { @@ -1515,8 +1497,8 @@ private function wrapFunctionArgsWithQuotes($functionRegex, $input) foreach ($allArguments as $argument) { $argument = trim($argument); - if ($argument[0] == "[") { - $replacement = "[" . $this->addUniquenessToParamArray($argument) . "]"; + if ($argument[0] == self::ARRAY_WRAP_OPEN) { + $replacement = $this->wrapParameterArray($this->addUniquenessToParamArray($argument)); } elseif (is_numeric($argument)) { $replacement = $argument; } else { @@ -1685,8 +1667,9 @@ private function processPressKey($input) preg_match_all('/[\[][^\]]*?[\]]/', $input, $paramInput); if (!empty($paramInput)) { foreach ($paramInput[0] as $param) { - $arrayResult[self::PRESSKEY_ARRAY_ANCHOR_KEY . $count] = - '[' . trim($this->addUniquenessToParamArray($param)) . ']'; + $arrayResult[self::PRESSKEY_ARRAY_ANCHOR_KEY . $count] = $this->wrapParameterArray( + trim($this->addUniquenessToParamArray($param)) + ); $input = str_replace($param, self::PRESSKEY_ARRAY_ANCHOR_KEY . $count, $input); $count++; } @@ -1780,13 +1763,8 @@ private function stripWrappedQuotes($input) if (empty($input)) { return ''; } - if (substr($input, 0, 1) === '"') { - $input = substr($input, 1); - } - if (substr($input, -1, 1) === '"') { - $input = substr($input, 0, -1); - } - return $input; + + return trim($input, '"'); } /** @@ -1821,7 +1799,7 @@ private function wrapFunctionCall($actor, $action, ...$args) continue; } if ($args[$i] === "") { - $args[$i] = '"' . $args[$i] . '"'; + $args[$i] = '""'; } } if (!is_array($args)) { @@ -1829,7 +1807,7 @@ private function wrapFunctionCall($actor, $action, ...$args) } $args = $this->resolveAllRuntimeReferences($args); $args = $this->resolveTestVariable($args, $action->getActionOrigin()); - $output .= implode(", ", array_filter($args, function($value) { return $value !== null; })) . ");"; + $output .= implode(", ", array_filter($args, $this->filterNullCallback())) . ");"; return $output; } @@ -1853,7 +1831,7 @@ private function wrapFunctionCallWithReturnValue($returnVariable, $actor, $actio continue; } if ($args[$i] === "") { - $args[$i] = '"' . $args[$i] . '"'; + $args[$i] = '""'; } } if (!is_array($args)) { @@ -1861,12 +1839,22 @@ private function wrapFunctionCallWithReturnValue($returnVariable, $actor, $actio } $args = $this->resolveAllRuntimeReferences($args); $args = $this->resolveTestVariable($args, $action->getActionOrigin()); - $output .= implode(", ", array_filter($args, function($value) { return $value !== null; })) . ");"; + $output .= implode(", ", array_filter($args, $this->filterNullCallback())) . ");"; return $output; } // @codingStandardsIgnoreEnd + /** + * @return callable + */ + private function filterNullCallback() + { + return function ($value) { + return $value !== null; + }; + } + /** * Resolves {{_ENV.variable}} into getenv("variable") for test-runtime ENV referencing. * @param array $args @@ -1928,43 +1916,75 @@ private function resolveAllRuntimeReferences($args) */ private function validateParameterArray($paramArray) { - if (substr($paramArray, 0, 1) != "[" || substr($paramArray, strlen($paramArray) - 1, 1) != "]") { - throw new TestReferenceException("parameterArray must begin with `[` and end with `]"); + if (!$this->isWrappedArray($paramArray)) { + throw new TestReferenceException(sprintf( + "parameterArray must begin with `%s` and end with `%s`", + self::ARRAY_WRAP_OPEN, + self::ARRAY_WRAP_CLOSE + )); } } + /** + * @param string $paramArray + * @return boolean + */ + private function isWrappedArray(string $paramArray) + { + return 0 === strpos($paramArray, self::ARRAY_WRAP_OPEN) + && substr($paramArray, -1) === self::ARRAY_WRAP_CLOSE; + } + /** * Resolve value based on type. * - * @param string $value - * @param string $type - * @return string + * @param string|null $value + * @param string|null $type + * @return string|null * @throws TestReferenceException - * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ - private function resolveValueByType($value, $type) + private function resolveValueByType($value = null, $type = null) { - //TODO: Refactor to deal with PHPMD.CyclomaticComplexity, and remove @SuppressWarnings if (null === $value) { return null; } + if (null === $type) { $type = 'const'; } - if ($type == "string") { - return $this->addUniquenessFunctionCall($value); - } elseif ($type == "bool") { - return $this->toBoolean($value) ? "true" : "false"; - } elseif ($type == "int" || $type == "float") { - return $this->toNumber($value); - } elseif ($type == "array") { - $this->validateParameterArray($value); - return "[" . $this->addUniquenessToParamArray($value) . "]"; - } elseif ($type == "variable") { - return $this->addDollarSign($value); - } else { - return $value; + + switch ($type) { + case 'string': + return $this->addUniquenessFunctionCall($value); + case 'bool': + return $this->toBoolean($value) ? "true" : "false"; + case 'int': + case 'float': + return $this->toNumber($value); + case 'array': + $this->validateParameterArray($value); + return $this->wrapParameterArray($this->addUniquenessToParamArray($value)); + case 'variable': + return $this->addDollarSign($value); } + + return $value; + } + + /** + * @param string $generationScope + * @return string + */ + private function getObjectScope(string $generationScope): string + { + switch ($generationScope) { + case TestGenerator::SUITE_SCOPE: + return PersistedObjectHandler::SUITE_SCOPE; + case TestGenerator::HOOK_SCOPE: + return PersistedObjectHandler::HOOK_SCOPE; + } + + return PersistedObjectHandler::TEST_SCOPE; } /** @@ -1987,11 +2007,11 @@ private function toBoolean($inStr) private function toNumber($inStr) { $outStr = $this->stripQuotes($inStr); - if (strpos($outStr, localeconv()['decimal_point']) === false) { - return intval($outStr); - } else { + if ($this->hasDecimalPoint($outStr)) { return floatval($outStr); } + + return intval($outStr); } /** @@ -2078,9 +2098,25 @@ 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; + + printf(self::RULE_ERROR, $key, implode('", "', $attributes), $tagName); + } + + /** + * @param string $value + * @return string + */ + private function wrapParameterArray(string $value): string + { + return sprintf('%s%s%s', self::ARRAY_WRAP_OPEN, $value, self::ARRAY_WRAP_CLOSE); + } + + /** + * @param string $outStr + * @return boolean + */ + private function hasDecimalPoint(string $outStr) + { + return strpos($outStr, localeconv()['decimal_point']) === false; } } From 43ce9fc83cd2094fc476907b14c366a2195cd5cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Bajsarowicz?= Date: Mon, 6 Jan 2020 15:59:49 +0100 Subject: [PATCH 122/888] Introduce magentoCron command to execute Cron Jobs taking into consideration cron required interval (60 seconds) --- etc/di.xml | 2 +- .../Module/MagentoWebDriver.php | 110 ++++++++++++++++++ .../Test/etc/Actions/customActions.xsd | 37 +++++- .../Util/TestGenerator.php | 24 +++- 4 files changed, 170 insertions(+), 3 deletions(-) diff --git a/etc/di.xml b/etc/di.xml index 3e6313bf3..e5e31cf87 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -8,7 +8,7 @@ + ]> diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index a95586b26..3baa93cea 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -53,6 +53,9 @@ class MagentoWebDriver extends WebDriver { use AttachmentSupport; + const MAGENTO_CRON_INTERVAL = 60; + const MAGENTO_CRON_COMMAND = 'cron:run'; + /** * List of known magento loading masks by selector * @@ -121,6 +124,13 @@ class MagentoWebDriver extends WebDriver */ private $jsErrors = []; + /** + * Contains last execution times for Cron + * + * @var int[] + */ + private $cronExecution = []; + /** * Sanitizes config, then initializes using parent. * @@ -552,6 +562,74 @@ public function magentoCLI($command, $timeout = null, $arguments = null) return $response; } + /** + * Executes Magento Cron keeping the interval (> 60 seconds between each run) + * + * @param string|null $cronGroups + * @param int|null $timeout + * @param string|null $arguments + */ + public function magentoCron($cronGroups = null, $timeout = null, $arguments = null) + { + $cronGroups = explode(' ', $cronGroups); + return $this->executeCronjobs($cronGroups, $timeout, $arguments); + } + + /** + * Updates last execution time for Cron + * + * @param array $cronGroups + * @return void + */ + private function notifyCronFinished(array $cronGroups = []) + { + if (empty($cronGroups)) { + $this->cronExecution['*'] = time(); + } + + foreach ($cronGroups as $group) { + $this->cronExecution[$group] = time(); + } + } + + /** + * Returns last Cron execution time for specific cron or all crons + * + * @param array $cronGroups + * @return int + */ + private function getLastCronExecution(array $cronGroups = []) + { + if (empty($cronGroups)) { + return (int)max($this->cronExecution); + } + + $cronGroups = array_merge($cronGroups, ['*']); + + return array_reduce($cronGroups, function($lastExecution, $group) { + if (isset($this->cronExecution[$group]) && $this->cronExecution[$group] > $lastExecution) { + $lastExecution = $this->cronExecution[$group]; + } + + return (int)$lastExecution; + }, 0); + } + + /** + * Returns time to wait for next run + * + * @param array $cronGroups + * @param int $cronInterval + * @return int + */ + private function getCronWait(array $cronGroups = [], int $cronInterval = self::MAGENTO_CRON_INTERVAL) + { + $nextRun = $this->getLastCronExecution($cronGroups) + $cronInterval; + $toNextRun = $nextRun - time(); + + return max(0, $toNextRun); + } + /** * Runs DELETE request to delete a Magento entity against the url given. * @@ -971,4 +1049,36 @@ public function getSecret($key) { return CredentialStore::getInstance()->getSecret($key); } + + /** + * Waits proper amount of time to perform Cron execution + * + * @param $cronGroups + * @param $timeout + * @param $arguments + * @return string + * @throws TestFrameworkException + */ + private function executeCronjobs($cronGroups, $timeout, $arguments): string + { + $cronGroups = array_filter($cronGroups); + + $waitFor = $this->getCronWait($cronGroups); + + if ($waitFor) { + $this->wait($waitFor); + } + + $command = array_reduce($cronGroups, function ($command, $cronGroup) { + $command .= ' --group=' . $cronGroup; + return $command; + }, self::MAGENTO_CRON_COMMAND); + $timeStart = microtime(true); + $cronResult = $this->magentoCLI($command, $timeout, $arguments); + $timeEnd = microtime(true); + + $this->notifyCronFinished($cronGroups); + + return sprintf('%s (wait: %ss, execution: %ss)', $cronResult, $waitFor, round($timeEnd - $timeStart, 2)); + } } diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd index 2424d0d31..8670d9885 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd @@ -12,6 +12,7 @@ + @@ -62,6 +63,40 @@ + + + + Executes Magento Cron Jobs (selected groups) + + + + + + + + Cron groups to be executed (separated by space) + + + + + + + Arguments for Magento CLI command, will not be escaped. + + + + + + + Idle timeout in seconds, defaulted to 60s when not specified. + + + + + + + + @@ -285,4 +320,4 @@ - \ No newline at end of file + diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 09c353029..e98dcbe61 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -50,10 +50,12 @@ class TestGenerator 'retrieveEntityField', 'getSecret', 'magentoCLI', + 'magentoCron', 'generateDate', 'field' ]; const STEP_KEY_ANNOTATION = " // stepKey: %s"; + const CRON_INTERVAL = 60; /** * Actor name for AcceptanceTest @@ -534,6 +536,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $dependentSelector = null; $visible = null; $command = null; + $cronGroups = ''; $arguments = null; $sortOrder = null; $storeCode = null; @@ -551,6 +554,9 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato if (isset($customActionAttributes['command'])) { $command = $this->addUniquenessFunctionCall($customActionAttributes['command']); } + if (isset($customActionAttributes['groups'])) { + $cronGroups = $this->addUniquenessFunctionCall($customActionAttributes['groups']); + } if (isset($customActionAttributes['arguments'])) { $arguments = $this->addUniquenessFunctionCall($customActionAttributes['arguments']); } @@ -1270,6 +1276,22 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $stepKey ); break; + case 'magentoCron': + $testSteps .= $this->wrapFunctionCallWithReturnValue( + $stepKey, + $actor, + $actionObject, + $cronGroups, + self::CRON_INTERVAL + $time, + $arguments + ); + $testSteps .= sprintf(self::STEP_KEY_ANNOTATION, $stepKey) . PHP_EOL; + $testSteps .= sprintf( + "\t\t$%s->comment(\$%s);", + $actor, + $stepKey + ); + break; case "field": $fieldKey = $actionObject->getCustomActionAttributes()['key']; $input = $this->resolveStepKeyReferences($input, $actionObject->getActionOrigin()); @@ -1403,7 +1425,7 @@ private function replaceMatchesIntoArg($matches, &$outputArg) $variable = $this->stripAndSplitReference($match, $delimiter); if (count($variable) != 2) { throw new \Exception( - "Invalid Persisted Entity Reference: {$match}. + "Invalid Persisted Entity Reference: {$match}. Test persisted entity references must follow {$delimiter}entityStepKey.field{$delimiter} format." ); } From df058d78ed0b22eeb1d47352144c5a3828966d58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Bajsarowicz?= Date: Mon, 6 Jan 2020 16:12:02 +0100 Subject: [PATCH 123/888] Code Style like 80s! --- .../Module/MagentoWebDriver.php | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 3baa93cea..f44d7e1a0 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -565,9 +565,10 @@ public function magentoCLI($command, $timeout = null, $arguments = null) /** * Executes Magento Cron keeping the interval (> 60 seconds between each run) * - * @param string|null $cronGroups - * @param int|null $timeout - * @param string|null $arguments + * @param string|null $cronGroups + * @param integer|null $timeout + * @param string|null $arguments + * @return string */ public function magentoCron($cronGroups = null, $timeout = null, $arguments = null) { @@ -596,7 +597,7 @@ private function notifyCronFinished(array $cronGroups = []) * Returns last Cron execution time for specific cron or all crons * * @param array $cronGroups - * @return int + * @return integer */ private function getLastCronExecution(array $cronGroups = []) { @@ -606,7 +607,7 @@ private function getLastCronExecution(array $cronGroups = []) $cronGroups = array_merge($cronGroups, ['*']); - return array_reduce($cronGroups, function($lastExecution, $group) { + return array_reduce($cronGroups, function ($lastExecution, $group) { if (isset($this->cronExecution[$group]) && $this->cronExecution[$group] > $lastExecution) { $lastExecution = $this->cronExecution[$group]; } @@ -618,9 +619,9 @@ private function getLastCronExecution(array $cronGroups = []) /** * Returns time to wait for next run * - * @param array $cronGroups - * @param int $cronInterval - * @return int + * @param array $cronGroups + * @param integer $cronInterval + * @return integer */ private function getCronWait(array $cronGroups = [], int $cronInterval = self::MAGENTO_CRON_INTERVAL) { @@ -1053,9 +1054,9 @@ public function getSecret($key) /** * Waits proper amount of time to perform Cron execution * - * @param $cronGroups - * @param $timeout - * @param $arguments + * @param string $cronGroups + * @param integer $timeout + * @param string $arguments * @return string * @throws TestFrameworkException */ From af0a499d4b52c06d8053d2a57c7e9fe81227159a Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Mon, 6 Jan 2020 09:48:01 -0600 Subject: [PATCH 124/888] MQE-1513: createData throws a useless error message during runtime when the entity does not exist reverted changes Added unit test --- .../Handlers/PersistedObjectHandlerTest.php | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php index 6c3823466..34d59e8c8 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php @@ -32,6 +32,31 @@ public function setUp() TestLoggingUtil::getInstance()->setMockLoggingUtil(); } + public function testCreateInvalidEntity() + { + // Test Data and Variables + + $entityName = "InvalidEntity"; + $entityStepKey = "StepKey"; + $scope = PersistedObjectHandler::TEST_SCOPE; + + $exceptionMessage = "Entity \"" . $entityName . "\" does not exist." . + "\nException occurred parsing action at StepKey \"" . $entityStepKey . "\""; + + $this->expectException(TestReferenceException::class); + + $this->expectExceptionMessage($exceptionMessage); + + $handler = PersistedObjectHandler::getInstance(); + + // Call method + $handler->createEntity( + $entityStepKey, + $scope, + $entityName + ); + } + public function testCreateSimpleEntity() { // Test Data and Variables From 28804f4891ed698c91fd77040d411ede6de9bbfa Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Mon, 6 Jan 2020 15:00:21 -0600 Subject: [PATCH 125/888] MQE-1513: createData throws a useless error message during runtime when the entity does not exist reverted changes fixed unit test --- .../DataGenerator/Handlers/PersistedObjectHandlerTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php index 34d59e8c8..04e1f0810 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php @@ -32,10 +32,9 @@ public function setUp() TestLoggingUtil::getInstance()->setMockLoggingUtil(); } - public function testCreateInvalidEntity() + public function testCreateEntityWithNonExistingName() { // Test Data and Variables - $entityName = "InvalidEntity"; $entityStepKey = "StepKey"; $scope = PersistedObjectHandler::TEST_SCOPE; From 188d6bae7e827fefd83eb377adf52fd65d95b3f9 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Mon, 6 Jan 2020 15:45:31 -0600 Subject: [PATCH 126/888] MQE-1513: createData throws a useless error message during runtime when the entity does not exist reverted changes reworded message --- .../DataGenerator/Handlers/PersistedObjectHandlerTest.php | 2 +- .../DataGenerator/Handlers/PersistedObjectHandler.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php index 04e1f0810..592b87f4e 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php @@ -40,7 +40,7 @@ public function testCreateEntityWithNonExistingName() $scope = PersistedObjectHandler::TEST_SCOPE; $exceptionMessage = "Entity \"" . $entityName . "\" does not exist." . - "\nException occurred parsing action at StepKey \"" . $entityStepKey . "\""; + "\nException occurred executing action at StepKey \"" . $entityStepKey . "\""; $this->expectException(TestReferenceException::class); diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php index 7015292c0..00353856b 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php @@ -101,7 +101,7 @@ public function createEntity( if ($retrievedEntity === null) { throw new TestReferenceException( "Entity \"" . $entity . "\" does not exist." . - "\nException occurred parsing action at StepKey \"" . $key . "\"" + "\nException occurred executing action at StepKey \"" . $key . "\"" ); } From 20a0ceffa1c3d1488161ea06834f1f6adeba2382 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Bajsarowicz?= Date: Tue, 7 Jan 2020 23:02:17 +0100 Subject: [PATCH 127/888] Code Review changes --- .../Util/TestGenerator.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 89120a83e..c87d0ad55 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1778,8 +1778,6 @@ private function addDollarSign($input) return sprintf("$%s", ltrim($this->stripQuotes($input), '$')); } - // @codingStandardsIgnoreStart - /** * Wrap parameters into a function call. * @@ -1843,9 +1841,9 @@ private function wrapFunctionCallWithReturnValue($returnVariable, $actor, $actio return $output; } - // @codingStandardsIgnoreEnd - /** + * Closure returned is used as a callable for array_filter to remove null values from array + * * @return callable */ private function filterNullCallback() @@ -1857,6 +1855,7 @@ private function filterNullCallback() /** * Resolves {{_ENV.variable}} into getenv("variable") for test-runtime ENV referencing. + * * @param array $args * @param string $regex * @param string $func @@ -1926,6 +1925,8 @@ private function validateParameterArray($paramArray) } /** + * Verifies whether we have correctly wrapped array syntax + * * @param string $paramArray * @return boolean */ @@ -1972,6 +1973,8 @@ private function resolveValueByType($value = null, $type = null) } /** + * Determines correct scope based on parameter + * * @param string $generationScope * @return string */ @@ -2103,6 +2106,8 @@ private function printRuleErrorToConsole($key, $tagName, $attributes) } /** + * Wraps parameters array with opening and closing symbol. + * * @param string $value * @return string */ @@ -2112,6 +2117,8 @@ private function wrapParameterArray(string $value): string } /** + * Determines whether string provided contains decimal point characteristic for current locale + * * @param string $outStr * @return boolean */ From f83107a98f49e636c003cb8ba23f60f8c9e94e65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Bajsarowicz?= Date: Tue, 7 Jan 2020 23:50:06 +0100 Subject: [PATCH 128/888] Satisfy ridiculous Coding Standard --- .../FunctionalTestingFramework/Util/TestGenerator.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index c87d0ad55..2d7b99eee 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1781,10 +1781,9 @@ private function addDollarSign($input) /** * Wrap parameters into a function call. * - * @param string $actor + * @param string $actor * @param actionObject $action - * @param string $scope - * @param array ...$args + * @param array ...$args * @return string * @throws \Exception */ @@ -1816,7 +1815,7 @@ private function wrapFunctionCall($actor, $action, ...$args) * @param string $actor * @param string $action * @param string $scope - * @param array ...$args + * @param array ...$args * @return string * @throws \Exception */ From 771716dc4bc59921156d40254021a649e01e0b13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Bajsarowicz?= Date: Wed, 8 Jan 2020 00:07:13 +0100 Subject: [PATCH 129/888] ... Coding Standard --- src/Magento/FunctionalTestingFramework/Util/TestGenerator.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 2d7b99eee..66c11975c 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1814,7 +1814,6 @@ private function wrapFunctionCall($actor, $action, ...$args) * @param string $returnVariable * @param string $actor * @param string $action - * @param string $scope * @param array ...$args * @return string * @throws \Exception From 995016a42bee7a0043ae2331be968f1f7a91369b Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Wed, 8 Jan 2020 14:56:40 -0600 Subject: [PATCH 130/888] MQE-1713: Generate/run test in single suite context - added support for 'suite:test' syntax in generate and run:test command - minor fixes to exceptions in suite mechanisms --- .../Console/BaseGenerateCommandTest.php | 18 ++++++++++++++++++ .../Console/BaseGenerateCommand.php | 4 ++++ .../Suite/Handlers/SuiteObjectHandler.php | 3 ++- .../Suite/SuiteGenerator.php | 2 +- 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php index 1b1686ce2..234f677e8 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php @@ -156,6 +156,24 @@ public function testThreeTestOneSuiteOneGroupMix() $this->assertEquals($expected, $actual); } + public function testSuiteToTestSyntax() + { + $testOne = new TestObject('Test1', [], [], []); + $suiteOne = new SuiteObject( + 'Suite1', + ['Test1' => $testOne], + [], + [] + ); + + $testArray = ['Test1' => $testOne]; + $suiteArray = ['Suite1' => $suiteOne]; + $this->mockHandlers($testArray, $suiteArray); + $actual = json_decode($this->callTestConfig(['Suite1:Test1']), true); + $expected = ['tests' => null, 'suites' => ['Suite1' => ['Test1']]]; + $this->assertEquals($expected, $actual); + } + /** * Mock handlers to skip parsing * @param array $testArray diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index 0953e9d68..72cfc8578 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -87,6 +87,10 @@ protected function getTestAndSuiteConfiguration(array $tests) $suiteToTestPair = []; foreach($tests as $test) { + if (strpos($test, ':') !== null) { + $suiteToTestPair[] = $test; + continue; + } if (array_key_exists($test, $testsReferencedInSuites)) { $suites = $testsReferencedInSuites[$test]; foreach ($suites as $suite) { diff --git a/src/Magento/FunctionalTestingFramework/Suite/Handlers/SuiteObjectHandler.php b/src/Magento/FunctionalTestingFramework/Suite/Handlers/SuiteObjectHandler.php index 30a67c31d..bbaaf4379 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Handlers/SuiteObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Handlers/SuiteObjectHandler.php @@ -5,6 +5,7 @@ */ namespace Magento\FunctionalTestingFramework\Suite\Handlers; +use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\ObjectManager\ObjectHandlerInterface; use Magento\FunctionalTestingFramework\ObjectManagerFactory; @@ -73,7 +74,7 @@ public static function getInstance(): ObjectHandlerInterface public function getObject($objectName): SuiteObject { if (!array_key_exists($objectName, $this->suiteObjects)) { - trigger_error("Suite ${objectName} is not defined.", E_USER_ERROR); + throw new TestReferenceException("Suite ${objectName} is not defined in xml."); } return $this->suiteObjects[$objectName]; } diff --git a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php index 4df7daa75..077e6d1cc 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php @@ -178,7 +178,7 @@ private function validateTestsReferencedInSuite($suiteName, $testsReferenced, $o { $suiteRef = $originalSuiteName ?? $suiteName; $possibleTestRef = SuiteObjectHandler::getInstance()->getObject($suiteRef)->getTests(); - $errorMsg = "Cannot reference tests whcih are not declared as part of suite."; + $errorMsg = "Cannot reference tests which are not declared as part of suite."; $invalidTestRef = array_diff($testsReferenced, array_keys($possibleTestRef)); From 199391561191460956489c26d97afc39b83514a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Bajsarowicz?= Date: Wed, 8 Jan 2020 23:52:06 +0100 Subject: [PATCH 131/888] Add tests to cover new feature --- .../verification/TestModule/Test/BasicFunctionalTest.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dev/tests/verification/TestModule/Test/BasicFunctionalTest.xml b/dev/tests/verification/TestModule/Test/BasicFunctionalTest.xml index c23a3ce60..1ef25b43d 100644 --- a/dev/tests/verification/TestModule/Test/BasicFunctionalTest.xml +++ b/dev/tests/verification/TestModule/Test/BasicFunctionalTest.xml @@ -79,6 +79,9 @@ + + + @@ -143,4 +146,4 @@ - \ No newline at end of file + From f61897228498c1a2734bf75dd17891645c6fef4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Bajsarowicz?= Date: Thu, 9 Jan 2020 00:02:38 +0100 Subject: [PATCH 132/888] Add tests to cover new feature --- dev/tests/verification/Resources/BasicFunctionalTest.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dev/tests/verification/Resources/BasicFunctionalTest.txt b/dev/tests/verification/Resources/BasicFunctionalTest.txt index 5bcfd55dd..e78f1b49c 100644 --- a/dev/tests/verification/Resources/BasicFunctionalTest.txt +++ b/dev/tests/verification/Resources/BasicFunctionalTest.txt @@ -126,6 +126,12 @@ class BasicFunctionalTestCest $I->comment($magentoCli3); // stepKey: magentoCli3 $magentoCli4 = $I->magentoCLISecret("config:set somePath " . $I->getSecret("someKey"), 120); // stepKey: magentoCli4 $I->comment($magentoCli4); // stepKey: magentoCli4 + $cronAllGroups = $I->magentoCron("", 70); // stepKey: cronAllGroups + $I->comment($cronAllGroups); + $cronSingleGroup = $I->magentoCron("index", 70); // stepKey: cronSingleGroup + $I->comment($cronSingleGroup); + $cronMultipleGroups = $I->magentoCron("a b c", 70); // stepKey: cronMultipleGroups + $I->comment($cronMultipleGroups); $I->makeScreenshot("screenShotInput"); // stepKey: makeScreenshotKey1 $I->maximizeWindow(); // stepKey: maximizeWindowKey1 $I->moveBack(); // stepKey: moveBackKey1 From f3bb5c2cfadd35ed6c8f50dc8fac402b69118ca2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Bajsarowicz?= Date: Thu, 9 Jan 2020 00:18:02 +0100 Subject: [PATCH 133/888] Add documentation to `` command --- docs/test/actions.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/docs/test/actions.md b/docs/test/actions.md index c5dc83fdb..59fd12aa2 100644 --- a/docs/test/actions.md +++ b/docs/test/actions.md @@ -1274,6 +1274,29 @@ Attribute|Type|Use|Description ``` +### magentoCron + +Used to execute Magento Cron jobs. Groups may be provided optionally. Internal mechanism of `` ensures that Cron Job of single group is ran with 60 seconds interval. + +Attribute|Type|Use|Description +---|---|---|--- +`groups`|string |optional| Run only specified groups of Cron Jobs +`arguments`|string |optional| Unescaped arguments to be passed in with the CLI command. +`timeout`|string|optional| Number of seconds CLI command can run without outputting anything. +`stepKey`|string|required| A unique identifier of the action. +`before`|string|optional| `stepKey` of action that must be executed next. +`after`|string|optional| `stepKey` of preceding action. + + +#### Example +```xml + + + + + +``` + ### makeScreenshot See [makeScreenshot docs on codeception.com](http://codeception.com/docs/modules/WebDriver#makeScreenshot). From aea7e8d76bc24c69cb506370e8bd8c78ca06e0ac Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Thu, 9 Jan 2020 08:58:24 -0600 Subject: [PATCH 134/888] MQE-1713: Generate/run test in single suite contex - Fixed wrong comparison --- .../FunctionalTestingFramework/Console/BaseGenerateCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index 72cfc8578..a0d94b16e 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -87,7 +87,7 @@ protected function getTestAndSuiteConfiguration(array $tests) $suiteToTestPair = []; foreach($tests as $test) { - if (strpos($test, ':') !== null) { + if (strpos($test, ':') !== false) { $suiteToTestPair[] = $test; continue; } From af7c2fb9a4af3de4a9a401768bb6794f149ca711 Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Thu, 9 Jan 2020 09:03:40 -0600 Subject: [PATCH 135/888] MQE-1713: Generate/run test in single suite context - Documentation update --- docs/commands/mftf.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 2440428f9..642bbb1bd 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -42,6 +42,12 @@ vendor/bin/mftf generate:tests vendor/bin/mftf generate:tests AdminLoginTest StorefrontPersistedCustomerLoginTest ``` +### Generate test by test and suite name + +```bash +vendor/bin/mftf generate:tests LoginSuite:AdminLoginTest +``` + ### Generate and run the tests for a specified group ```bash @@ -58,6 +64,14 @@ vendor/bin/mftf run:test AdminLoginTest StorefrontPersistedCustomerLoginTest -r This command cleans up the previously generated tests; generates and runs the `LoginAsAdminTest` and `LoginAsCustomerTest` tests. +### Generate and run particular test in a specific suite's context + +```bash +vendor/bin/mftf run:test LoginSuite:AdminLoginTest -r +``` + +This command cleans up previously generated tests; generates and run `AdminLoginTest` within the context of the `LoginSuite`. + ### Generate and run a testManifest.txt file ```bash From ffec377dd2d8b3d091dcc20c33c1354eed89836d Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Fri, 10 Jan 2020 14:44:00 -0600 Subject: [PATCH 136/888] MQE-1918: MFTF AWS Secrets Manager - Local Use --- composer.json | 3 + composer.lock | 148 ++++++++++++++++- .../AwsSecretManagerStorageTest.php | 65 ++++++++ docs/configuration.md | 22 +++ docs/credentials.md | 67 +++++++- etc/config/.env.example | 6 +- .../Handlers/CredentialStore.php | 27 ++- .../SecretStorage/AwsSecretManagerStorage.php | 155 ++++++++++++++++++ .../Handlers/SecretStorage/VaultStorage.php | 2 +- 9 files changed, 483 insertions(+), 12 deletions(-) create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/AwsSecretManagerStorageTest.php create mode 100644 src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/AwsSecretManagerStorage.php diff --git a/composer.json b/composer.json index 158287fbf..ca1c02572 100755 --- a/composer.json +++ b/composer.json @@ -11,7 +11,10 @@ "require": { "php": "7.0.2||7.0.4||~7.0.6||~7.1.0||~7.2.0||~7.3.0", "ext-curl": "*", + "ext-json": "*", + "ext-openssl": "*", "allure-framework/allure-codeception": "~1.3.0", + "aws/aws-sdk-php": "^3.132", "codeception/codeception": "~2.4.5", "composer/composer": "^1.4", "consolidation/robo": "^1.0.0", diff --git a/composer.lock b/composer.lock index 8f2fcb8e9..6bfc30ab9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "59e95cc1ae6311e93111bd7ced180d29", + "content-hash": "2325a3a38edb33b24f6e33bd3009fd8a", "packages": [ { "name": "allure-framework/allure-codeception", @@ -109,6 +109,90 @@ ], "time": "2016-12-07T12:15:46+00:00" }, + { + "name": "aws/aws-sdk-php", + "version": "3.132.2", + "source": { + "type": "git", + "url": "https://github.com/aws/aws-sdk-php.git", + "reference": "f890689c6db27625522ea2e7e9b8420b6fccb063" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/f890689c6db27625522ea2e7e9b8420b6fccb063", + "reference": "f890689c6db27625522ea2e7e9b8420b6fccb063", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-pcre": "*", + "ext-simplexml": "*", + "guzzlehttp/guzzle": "^5.3.3|^6.2.1|^7.0", + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.4.1", + "mtdowling/jmespath.php": "^2.5", + "php": ">=5.5" + }, + "require-dev": { + "andrewsville/php-token-reflection": "^1.4", + "aws/aws-php-sns-message-validator": "~1.0", + "behat/behat": "~3.0", + "doctrine/cache": "~1.4", + "ext-dom": "*", + "ext-openssl": "*", + "ext-pcntl": "*", + "ext-sockets": "*", + "nette/neon": "^2.3", + "phpunit/phpunit": "^4.8.35|^5.4.3", + "psr/cache": "^1.0", + "psr/simple-cache": "^1.0", + "sebastian/comparator": "^1.2.3" + }, + "suggest": { + "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications", + "doctrine/cache": "To use the DoctrineCacheAdapter", + "ext-curl": "To send requests using cURL", + "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages", + "ext-sockets": "To use client-side monitoring" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Aws\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Amazon Web Services", + "homepage": "http://aws.amazon.com" + } + ], + "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project", + "homepage": "http://aws.amazon.com/sdkforphp", + "keywords": [ + "amazon", + "aws", + "cloud", + "dynamodb", + "ec2", + "glacier", + "s3", + "sdk" + ], + "time": "2020-01-09T19:09:31+00:00" + }, { "name": "behat/gherkin", "version": "v4.4.5", @@ -2542,8 +2626,66 @@ "bcmath", "math" ], + "abandoned": "brick/math", "time": "2017-02-16T16:54:46+00:00" }, + { + "name": "mtdowling/jmespath.php", + "version": "2.5.0", + "source": { + "type": "git", + "url": "https://github.com/jmespath/jmespath.php.git", + "reference": "52168cb9472de06979613d365c7f1ab8798be895" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/52168cb9472de06979613d365c7f1ab8798be895", + "reference": "52168cb9472de06979613d365c7f1ab8798be895", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "symfony/polyfill-mbstring": "^1.4" + }, + "require-dev": { + "composer/xdebug-handler": "^1.2", + "phpunit/phpunit": "^4.8.36|^7.5.15" + }, + "bin": [ + "bin/jp.php" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.5-dev" + } + }, + "autoload": { + "psr-4": { + "JmesPath\\": "src/" + }, + "files": [ + "src/JmesPath.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Declaratively specify how to extract elements from a JSON document", + "keywords": [ + "json", + "jsonpath" + ], + "time": "2019-12-30T18:03:34+00:00" + }, { "name": "mustache/mustache", "version": "v2.12.0", @@ -6542,7 +6684,9 @@ "prefer-lowest": false, "platform": { "php": "7.0.2||7.0.4||~7.0.6||~7.1.0||~7.2.0||~7.3.0", - "ext-curl": "*" + "ext-curl": "*", + "ext-json": "*", + "ext-openssl": "*" }, "platform-dev": [] } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/AwsSecretManagerStorageTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/AwsSecretManagerStorageTest.php new file mode 100644 index 000000000..015c7a009 --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/AwsSecretManagerStorageTest.php @@ -0,0 +1,65 @@ + 'mftf/magento/' . $testShortKey, + 'SecretString' => json_encode([$testShortKey => $testValue]) + ]; + /** @var Result */ + $result = new Result($data); + + $mockClient = $this->getMockBuilder(SecretsManagerClient::class) + ->disableOriginalConstructor() + ->setMethods(['__call']) + ->getMock(); + + $mockClient->expects($this->once()) + ->method('__call') + ->willReturnCallback(function($name, $args) use ($result) { + return $result; + }); + + /** @var SecretsManagerClient */ + $credentialStorage = new AwsSecretManagerStorage($testRegion, $testProfile); + $reflection = new ReflectionClass($credentialStorage); + $reflection_property = $reflection->getProperty('client'); + $reflection_property->setAccessible(true); + $reflection_property->setValue($credentialStorage, $mockClient); + + // Test getEncryptedValue() + $encryptedCred = $credentialStorage->getEncryptedValue($testLongKey); + + // Assert the value we've gotten is in fact not identical to our test value + $this->assertNotEquals($testValue, $encryptedCred); + + // Test getDecryptedValue() + $actualValue = $credentialStorage->getDecryptedValue($encryptedCred); + + // Assert that we are able to successfully decrypt our secret value + $this->assertEquals($testValue, $actualValue); + } +} diff --git a/docs/configuration.md b/docs/configuration.md index 5140c01e7..f89090c06 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -277,6 +277,28 @@ Example: CREDENTIAL_VAULT_SECRET_BASE_PATH=secret ``` +### CREDENTIAL_AWS_SECRET_MANAGER_REGION + +The region that Aws Secret Manager is located. + +Example: + +```conf +# Region of Aws Secret Manager +CREDENTIAL_AWS_SECRET_MANAGER_REGION=us-east-1 +``` + +### CREDENTIAL_AWS_SECRET_MANAGER_PROFILE + +The profile used to connect to Aws Secret Manager. + +Example: + +```conf +# Profile used to connect to Aws Secret Manager. +CREDENTIAL_AWS_SECRET_MANAGER_PROFILE=default +``` + ### ENABLE_BROWSER_LOG Enables addition of browser logs to Allure steps diff --git a/docs/credentials.md b/docs/credentials.md index a2850cfe8..6ca9900cb 100644 --- a/docs/credentials.md +++ b/docs/credentials.md @@ -3,10 +3,11 @@ When you test functionality that involves external services such as UPS, FedEx, PayPal, or SignifyD, use the MFTF credentials feature to hide sensitive [data][] like integration tokens and API keys. -Currently the MFTF supports two types of credential storage: +Currently the MFTF supports three types of credential storage: - **.credentials file** -- **HashiCorp vault** +- **HashiCorp Vault** +- **Aws Secret Manager** ## Configure File Storage @@ -135,11 +136,64 @@ CREDENTIAL_VAULT_ADDRESS=http://127.0.0.1:8200 CREDENTIAL_VAULT_SECRET_BASE_PATH=secret ``` -## Configure both File Storage and Vault Storage +## Configure Aws Secret Manager -It is possible and sometimes useful to setup and use both `.credentials` file and vault for secret storage at the same time. -In this case, the MFTF tests are able to read secret data at runtime from both storage options, but the local `.credentials` file will take precedence. +Aws Secrets Manager offers secret management that supports: +- Secret rotation with built-in integration for Amazon RDS, Amazon Redshift, and Amazon DocumentDB +- Fine-grained policies and permissions +- Audit secret rotation centrally for resources in the AWS Cloud, third-party services, and on-premises +### Prerequisites +- AWS account +- AWS Secret Manger is created and configured +- IAM User or Role is created + +### Store secrets in Aws Secret Manager + +#### Secrets format +`Secret Name`, `Secret Key`, `Secret Value` are three key pieces of information to construct an Aws Secret. +`Secret Key` and `Secret Value` can be any content you want to secure, `Secret Name` must follow the format: + +```conf +mftf// +``` + +```conf +# Secret name for carriers_usps_userid +mftf/magento/carriers_usps_userid + +# Secret key for carriers_usps_userid +carriers_usps_userid + +# Secret name for carriers_usps_password +mftf/magento/carriers_usps_password + +# Secret key for carriers_usps_password +carriers_usps_password +``` + +### Setup MFTF to use Aws Secret Manager + +To use Aws Secret Manager, the Aws region to connect to is required. You can set it through environment variable [`CREDENTIAL_AWS_SECRET_MANAGER_REGION`][] in `.env`. + +MFTF uses the recommended [Default Credential Provider Chain][credential chain] to establish connection to Aws Secret Manager service. +You can setup credentials according to [Default Credential Provider Chain][credential chain] and there is no MFTF specific setup required. +Optionally, however, you can explicitly set Aws profile through environment variable [`CREDENTIAL_AWS_SECRET_MANAGER_PROFILE`][] in `.env`. + +```conf +# Sample Aws Secret Manager configuration +CREDENTIAL_AWS_SECRET_MANAGER_REGION=us-east-1 +CREDENTIAL_AWS_SECRET_MANAGER_PROFILE=default +``` + +## Configure multiple credential storage + +It is possible and sometimes useful to setup and use multiple credential storage at the same time. +In this case, the MFTF tests are able to read secret data at runtime from all storage options, in this case MFTF use the following precedence: + +``` +.credentials File > HashiCorp Vault > Aws Secret Manager +``` ## Use credentials in a test @@ -183,3 +237,6 @@ The MFTF tests delivered with Magento application do not use credentials and do [Vault KV2]: https://www.vaultproject.io/docs/secrets/kv/kv-v2.html [`CREDENTIAL_VAULT_ADDRESS`]: configuration.md#credential_vault_address [`CREDENTIAL_VAULT_SECRET_BASE_PATH`]: configuration.md#credential_vault_secret_base_path +[credential chain]: https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/guide_credentials.html +[`CREDENTIAL_AWS_SECRET_MANAGER_PROFILE`]: configuration.md#credential_aws_secret_manager_profile +[`CREDENTIAL_AWS_SECRET_MANAGER_REGION`]: configuration.md#credential_aws_secret_manager_region \ No newline at end of file diff --git a/etc/config/.env.example b/etc/config/.env.example index 7320d8b8b..a772b1e9e 100644 --- a/etc/config/.env.example +++ b/etc/config/.env.example @@ -30,10 +30,14 @@ BROWSER=chrome #MAGENTO_RESTAPI_SERVER_PORT=8080 #MAGENTO_RESTAPI_SERVER_PROTOCOL=https -#*** Uncomment and set vault address and secret base path if you want to use vault to manage _CREDS secrets ***# +#*** To use HashiCorp Vault to manage _CREDS secrets, uncomment and set vault address and secret base path ***# #CREDENTIAL_VAULT_ADDRESS=http://127.0.0.1:8200 #CREDENTIAL_VAULT_SECRET_BASE_PATH=secret +#*** To use AWS Secret Manager to manage _CREDS secrets, uncomment and set region, profile is optional, when omitted, AWS default credential provider chain will be used ***# +#CREDENTIAL_AWS_SECRET_MANAGER_PROFILE=default +#CREDENTIAL_AWS_SECRET_MANAGER_REGION=us-east-1 + #*** Uncomment these properties to set up a dev environment with symlinked projects ***# #TESTS_BP= #FW_BP= diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php index 94ff40069..bff3e9b00 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php @@ -9,12 +9,18 @@ use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\SecretStorage\FileStorage; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\SecretStorage\VaultStorage; +use Magento\FunctionalTestingFramework\DataGenerator\Handlers\SecretStorage\AwsSecretManagerStorage; use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; class CredentialStore { const ARRAY_KEY_FOR_VAULT = 'vault'; const ARRAY_KEY_FOR_FILE = 'file'; + const ARRAY_KEY_FOR_AWS_SECRET_MANAGER = 'aws'; + + const CREDENTIAL_STORAGE_INFO = 'MFTF uses Credential Storage in the following precedence: ' + . '.credentials file, HashiCorp Vault and AWS Secret Manager. ' + . 'You need to configure at least one to use _CREDS in tests.'; /** * Credential storage array @@ -71,9 +77,25 @@ private function __construct() } } + // Initialize AWS secret manager storage + $awsRegion = getenv('CREDENTIAL_AWS_SECRET_MANAGER_REGION'); + $awsProfile = getenv('CREDENTIAL_AWS_SECRET_MANAGER_PROFILE'); + if ($awsRegion !== false) { + if ($awsProfile === false) { + $awsProfile = null; + } + try { + $this->credStorage[self::ARRAY_KEY_FOR_AWS_SECRET_MANAGER] = new AwsSecretManagerStorage( + $awsRegion, + $awsProfile + ); + } catch (TestFrameworkException $e) { + } + } + if (empty($this->credStorage)) { throw new TestFrameworkException( - "No credential storage is properly configured. Please configure vault or .credentials file." + 'Invalid Credential Storage. ' . self::CREDENTIAL_STORAGE_INFO ); } } @@ -97,8 +119,7 @@ public function getSecret($key) } throw new TestFrameworkException( - "\"{$key}\" not defined in vault or .credentials file, " - . "please provide a value in order to use this secret in a test." + "{$key} not found. " . self::CREDENTIAL_STORAGE_INFO . ' And make sure key/value exists.' ); } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/AwsSecretManagerStorage.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/AwsSecretManagerStorage.php new file mode 100644 index 000000000..c617f1cac --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/AwsSecretManagerStorage.php @@ -0,0 +1,155 @@ +createAwsSecretManagerClient($region, $profile); + } + + /** + * Returns the value of a secret based on corresponding key + * + * @param string $key + * @return string|null + * @throws Exception + */ + public function getEncryptedValue($key) + { + // Check if secret is in cached array + if (null !== ($value = parent::getEncryptedValue($key))) { + return $value; + } + + if (MftfApplicationConfig::getConfig()->verboseEnabled()) { + LoggingUtil::getInstance()->getLogger(VaultStorage::class)->debug( + "Retrieving secret for key name {$key} from AWS Secret Manager" + ); + } + + $reValue = null; + try { + // Split vendor/key to construct secret id + list($vendor, $key) = explode('/', trim($key, '/'), 2); + $secretId = self::MFTF_PATH + . '/' + . $vendor + . '/' + . $key; + // Read value by id from AWS Secret Manager, and parse the result + $value = $this->parseAwsSecretResult( + $this->client->getSecretValue(['SecretId' => $secretId]), + $key + ); + // Encrypt value for return + $reValue = openssl_encrypt($value, parent::ENCRYPTION_ALGO, parent::$encodedKey, 0, parent::$iv); + parent::$cachedSecretData[$key] = $reValue; + } catch (AwsException $e) { + $error = $e->getAwsErrorCode(); + if (MftfApplicationConfig::getConfig()->verboseEnabled()) { + LoggingUtil::getInstance()->getLogger(VaultStorage::class)->debug( + "AWS error code: {$error}. Unable to read secret for key {$key} from AWS Secret Manager" + ); + } + } catch (\Exception $e) { + if (MftfApplicationConfig::getConfig()->verboseEnabled()) { + LoggingUtil::getInstance()->getLogger(VaultStorage::class)->debug( + "Unable to read secret for key {$key} from AWS Secret Manager" + ); + } + } + return $reValue; + } + + /** + * Parse AWS result object and return secret for key + * + * @param Result $awsResult + * @param string $key + * @return string + * @throws TestFrameworkException + */ + private function parseAwsSecretResult($awsResult, $key) + { + // Return secret from the associated KMS CMK + if (isset($awsResult['SecretString'])) { + $rawSecret = $awsResult['SecretString']; + } else { + throw new TestFrameworkException("Error parsing AWS secret result"); + } + $secret = json_decode($rawSecret, true); + if (isset($secret[$key])) { + return $secret[$key]; + } + throw new TestFrameworkException("Error parsing AWS secret result"); + } + + /** + * Create Aws Secret Manager client + * + * @param string $region + * @param string $profile + * @throws TestFrameworkException + * @throws InvalidArgumentException + */ + private function createAwsSecretManagerClient($region, $profile) + { + if (null !== $this->client) { + return; + } + + // Create AWS Secret Manager client + $this->client = new SecretsManagerClient([ + 'profile' => $profile, + 'region' => $region, + 'version' => self::LATEST_VERSION + ]); + + if ($this->client === null) { + throw new TestFrameworkException("Unable to create AWS Secret Manager client"); + } + } +} diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/VaultStorage.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/VaultStorage.php index 6a9e9f0cf..798ac660c 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/VaultStorage.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/VaultStorage.php @@ -67,7 +67,7 @@ class VaultStorage extends BaseStorage private $secretBasePath; /** - * CredentialVault constructor + * VaultStorage constructor * * @param string $baseUrl * @param string $secretBasePath From 579c96d82c9786392cf85b78162947d42f686802 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Fri, 10 Jan 2020 14:49:15 -0600 Subject: [PATCH 137/888] MQE-1918: MFTF AWS Secrets Manager - Local Use --- .../Handlers/SecretStorage/AwsSecretManagerStorageTest.php | 2 +- .../Handlers/SecretStorage/AwsSecretManagerStorage.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/AwsSecretManagerStorageTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/AwsSecretManagerStorageTest.php index 015c7a009..f11d14920 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/AwsSecretManagerStorageTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/AwsSecretManagerStorageTest.php @@ -39,7 +39,7 @@ public function testEncryptAndDecrypt() $mockClient->expects($this->once()) ->method('__call') - ->willReturnCallback(function($name, $args) use ($result) { + ->willReturnCallback(function ($name, $args) use ($result) { return $result; }); diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/AwsSecretManagerStorage.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/AwsSecretManagerStorage.php index c617f1cac..0c10c53c4 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/AwsSecretManagerStorage.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/AwsSecretManagerStorage.php @@ -132,6 +132,7 @@ private function parseAwsSecretResult($awsResult, $key) * * @param string $region * @param string $profile + * @return void * @throws TestFrameworkException * @throws InvalidArgumentException */ From d210dcd60e42bf81c0e9105400b44b48e0e37075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Bajsarowicz?= Date: Sat, 11 Jan 2020 14:59:47 +0100 Subject: [PATCH 138/888] #55 Throw Exception when cannot resolve URL attribute --- .../Test/Objects/ActionObject.php | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php index 53743330e..caa5b2113 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php @@ -404,6 +404,14 @@ private function resolveUrlReference() $url = $this->actionAttributes[ActionObject::ACTION_ATTRIBUTE_URL]; $replacement = $this->findAndReplaceReferences(PageObjectHandler::getInstance(), $url); + + $missingReferences = $this->getMissingReferences($replacement); + if (!empty($missingReferences)) { + throw new TestReferenceException( + sprintf('Can not resolve replacements: "%s"', implode('", "', $missingReferences)) + ); + } + if ($replacement) { $this->resolvedCustomAttributes[ActionObject::ACTION_ATTRIBUTE_URL] = $replacement; $allPages = PageObjectHandler::getInstance()->getAllObjects(); @@ -417,6 +425,20 @@ private function resolveUrlReference() } } + /** + * Returns array of missing references + * + * @param $replacement + * @return array + */ + private function getMissingReferences($replacement): array + { + $mustachePattern = '/({{[\w]+}})|({{[\w]+\.[\w\[\]]+}})|({{[\w]+\.[\w]+\((?(?!}}).)+\)}})/'; + preg_match_all($mustachePattern, $replacement, $matches); + + return array_filter($matches[1], function($match) { return false === strpos($match, '_ENV.'); }); + } + /** * Look up the value for EntityDataObjectName.Key and set it as the corresponding attribute in the resolved custom * attributes. From e06c1883d6f12097383ade28c08773b54690f043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Bajsarowicz?= Date: Sat, 11 Jan 2020 15:13:53 +0100 Subject: [PATCH 139/888] Amend PHPUnit tests and Static tests --- .../Test/Objects/ActionObjectTest.php | 15 +++------------ .../Test/Objects/ActionObject.php | 6 ++++-- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php index 511c9748f..4954cea19 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php @@ -227,7 +227,7 @@ public function testResolveUrl() } /** - * {{PageObject}} should not be replaced and should elicit a warning in console + * {{PageObject}} should not be replaced and should throw an exception! * * @throws /Exception */ @@ -248,18 +248,9 @@ public function testResolveUrlWithNoAttribute() // Call the method under test $actionObject->resolveReferences(); - // Expect this warning to get generated - TestLoggingUtil::getInstance()->validateMockLogStatement( - "warning", - "page url attribute not found and is required", - ['action' => $actionObject->getType(), 'url' => '{{PageObject}}', 'stepKey' => $actionObject->getStepKey()] - ); + $this->expectExceptionMessage('Can not resolve replacements: "{{PageObject}}"'); - // Verify - $expected = [ - 'url' => '{{PageObject}}' - ]; - $this->assertEquals($expected, $actionObject->getCustomActionAttributes()); + $actionObject->getCustomActionAttributes(); } /** diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php index caa5b2113..67a57031e 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php @@ -428,7 +428,7 @@ private function resolveUrlReference() /** * Returns array of missing references * - * @param $replacement + * @param string $replacement * @return array */ private function getMissingReferences($replacement): array @@ -436,7 +436,9 @@ private function getMissingReferences($replacement): array $mustachePattern = '/({{[\w]+}})|({{[\w]+\.[\w\[\]]+}})|({{[\w]+\.[\w]+\((?(?!}}).)+\)}})/'; preg_match_all($mustachePattern, $replacement, $matches); - return array_filter($matches[1], function($match) { return false === strpos($match, '_ENV.'); }); + return array_filter($matches[1], function ($match) { + return false === strpos($match, '_ENV.'); + }); } /** From 15d61bbd36812a780c9fafc214571d0bfd50a756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Bajsarowicz?= Date: Sat, 11 Jan 2020 17:29:36 +0100 Subject: [PATCH 140/888] Change Unit Tests to cover the change (including Exception thrown) --- .../Test/Objects/ActionObjectTest.php | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php index 4954cea19..890083d51 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php @@ -24,6 +24,8 @@ */ class ActionObjectTest extends MagentoTestCase { + const STUB_PAGE_URL_WITH_NO_ATTRIBUTE = '{{PageObject}}/some/path'; + /** * Before test functionality * @return void @@ -233,10 +235,11 @@ public function testResolveUrl() */ public function testResolveUrlWithNoAttribute() { - // Set up mocks + // Given $actionObject = new ActionObject('merge123', 'amOnPage', [ - 'url' => '{{PageObject}}' + 'url' => self::STUB_PAGE_URL_WITH_NO_ATTRIBUTE ]); + $pageObject = new PageObject('PageObject', '/replacement/url.html', 'Test', [], false, "test"); $pageObjectList = ["PageObject" => $pageObject]; $instance = AspectMock::double( @@ -245,12 +248,15 @@ public function testResolveUrlWithNoAttribute() )->make(); // bypass the private constructor AspectMock::double(PageObjectHandler::class, ['getInstance' => $instance]); - // Call the method under test - $actionObject->resolveReferences(); - + // Expect $this->expectExceptionMessage('Can not resolve replacements: "{{PageObject}}"'); + $expected = [ + 'url' => self::STUB_PAGE_URL_WITH_NO_ATTRIBUTE + ]; - $actionObject->getCustomActionAttributes(); + // When + $actionObject->resolveReferences(); + $this->assertEquals($expected, $actionObject->getCustomActionAttributes()); } /** From fd19fb574c1f4d90a0e6cb7b4232d45e6268022c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Bajsarowicz?= Date: Sat, 11 Jan 2020 18:03:37 +0100 Subject: [PATCH 141/888] Amend PHPUnit tests --- .../FunctionalTestingFramework/Test/Objects/ActionObject.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php index 67a57031e..cf78fe522 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php @@ -437,7 +437,7 @@ private function getMissingReferences($replacement): array preg_match_all($mustachePattern, $replacement, $matches); return array_filter($matches[1], function ($match) { - return false === strpos($match, '_ENV.'); + return !empty($match) && false === strpos($match, '_ENV.'); }); } From 3f7df8b25609c811c2823895d38d63ee051a2950 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Bajsarowicz?= Date: Sun, 12 Jan 2020 01:22:33 +0100 Subject: [PATCH 142/888] Update ActionGroups documentation --- docs/test/action-groups.md | 111 ++++++++++++++++++++----------------- 1 file changed, 61 insertions(+), 50 deletions(-) diff --git a/docs/test/action-groups.md b/docs/test/action-groups.md index 0743481f6..5fdfbb522 100644 --- a/docs/test/action-groups.md +++ b/docs/test/action-groups.md @@ -10,8 +10,10 @@ The following diagram shows the structure of an MFTF action group: The following conventions apply to MFTF action groups: -- All action groups are declared in XML files and stored in the `/ActionGroup/` directory. -- Every file name ends with `ActionGroup`, such as `LoginToAdminActionGroup`. +- All action groups are declared in XML files and stored in the `/Test/Mftf/ActionGroup/` directory. +- Every file name ends with `ActionGroup` suffix. For exampe `LoginAsAdminActionGroup.xml`. +- Action group name should be the same as file name without extension. +- Single file should contain only one `` node The XML format for the `actionGroups` declaration is: @@ -34,32 +36,31 @@ The XML format for the `actionGroups` declaration is: These examples build a declaration for a group of actions that grant authorization to the Admin area, and use the declaration in a test. -The _Backend/ActionGroup/LoginToAdminActionGroup.xml_ `` relates to the functionality of the _Backend_ module. -In [test][], the name and identifier of the `` is used as a reference in the `ref` parameter, such as `ref="LoginToAdminActionGroup"`. +The _Magento/Backend/Test/Mftf/ActionGroup/LoginAsAdminActionGroup.xml_ `` relates to the functionality of the _Magento_Backend_ module. + +In [test][], the name and identifier of the `` is used as a reference in the `ref` parameter, such as `ref="LoginAsAdminActionGroup"`. ### Create an action group declaration To create the `` declaration: -1. Begin with a _Backend/ActionGroup/LoginToAdminActionGroup.xml_ template for the ``: +1. Begin with a template for the ``: ```xml - - ... + + ``` - - 1. Add actions to the `actionGroup` arguments: ```xml - + @@ -81,14 +82,20 @@ To create the `` declaration: - - - - - - - - + + + Login to Backend Admin using provided User Data. PLEASE NOTE: This Action Group does NOT validate that you are Logged In. + + + + + + + + + + + ``` @@ -97,23 +104,23 @@ To create the `` declaration: In this test example, we want to add the following set of actions: ```xml - - - + + + ``` -Instead of adding this set of actions, use the _LoginToAdminActionGroup_ `` declaration in tests: +Instead of adding this set of actions, use the _LoginAsAdminActionGroup_ `` declaration in tests: -1. Reference the `LoginToAdminActionGroup` action group: +1. Reference the `LoginAsAdminActionGroup` action group: ```xml - + ``` 1. Update the argument name/value pair to `adminUser` and `CustomAdminUser`: ```xml - + ``` @@ -196,30 +203,34 @@ Starting with an action group such as: ``` It can be reworked into more manageable pieces, as below. These smaller steps are easier to read, update, and reuse. - -```xml - - - - - - - - - - - - - - - - - - - - - -``` +* GoToCategoryGridAndAddNewCategory + ```xml + + + + + + ``` +* FillInBasicCategoryFields + ```xml + + + + + + + + + ``` +* SaveAndVerifyCategoryCreation + ```xml + + + + + + + ``` @@ -261,4 +272,4 @@ Attribute|Type|Use|Description [actions]: ./actions.md [test]: ../test.md [`argument`]: #argument-tag -[created]: ../data.md#persist-data \ No newline at end of file +[created]: ../data.md#persist-data From 2d67ec9961abf24e720e34a4a9e6ff5d612761fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Bajsarowicz?= Date: Sun, 12 Jan 2020 01:33:48 +0100 Subject: [PATCH 143/888] Update Best Practices --- docs/best-practices.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/best-practices.md b/docs/best-practices.md index a3e5f2629..95677e78a 100644 --- a/docs/best-practices.md +++ b/docs/best-practices.md @@ -5,12 +5,12 @@ Check out our best practices below to ensure you are getting the absolute most o ## Action group 1. [Action group] names should be sufficiently descriptive to inform a test writer of what the action group does and when it should be used. - Add additional explanation in comments if needed. + Add additional explanation in annotations if needed. 2. Provide default values for the arguments that apply to your most common case scenarios. ## `actionGroups` vs `extends` -Use an action group to wraps a set of actions to reuse them multiple times. +Use an action group to wrap a set of actions to reuse them multiple times. Use an [extension] when a test or action group needs to be repeated with the exception of a few steps. @@ -64,6 +64,12 @@ Format: {_Admin_ or _Storefront_}{Functionality}_Test.xml_, where Functionality Example: _StorefrontCreateCustomerTest.xml_. +#### Action Group file name + +Format: {_Admin_ or _Storefront_}{Action Group Summary}ActionGroup.xml`, where Action Group Summary describes with a few words what we can expect from it. + +Example: _AdminCreateStoreActionGroup.xml_ + #### Section file name Format: {_Admin_ or _Storefront_}{UI Description}_Section.xml_, where UI Description briefly describes the testing UI. @@ -97,6 +103,7 @@ Use a lower case first letter for: - Data keys. Example: ``. - Element names. Examples: ``. +- Step keys. For example: `` ## Page object From 22e1f48404a6fc2a68d152aec749db246d1a3428 Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Tue, 14 Jan 2020 09:46:50 -0600 Subject: [PATCH 144/888] MQE-1713: Generate/run test in single suite context - New Unit test for SuiteGenerator - Better message for exception in SuiteGenerator --- .../Suite/SuiteGeneratorTest.php | 45 +++++++++++++++++++ .../Suite/SuiteGenerator.php | 6 ++- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php index 29158b0f5..eded50b41 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php @@ -6,6 +6,7 @@ namespace Tests\unit\Magento\FunctionalTestFramework\Suite; use AspectMock\Test as AspectMock; +use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\ObjectManager\ObjectManager; use Magento\FunctionalTestingFramework\ObjectManagerFactory; use Magento\FunctionalTestingFramework\Suite\SuiteGenerator; @@ -17,6 +18,7 @@ use Magento\FunctionalTestingFramework\Test\Parsers\TestDataParser; use Magento\FunctionalTestingFramework\Util\Manifest\DefaultTestManifest; use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use Magento\FunctionalTestingFramework\Util\Manifest\TestManifestFactory; use tests\unit\Util\SuiteDataArrayBuilder; use tests\unit\Util\TestDataArrayBuilder; use tests\unit\Util\TestLoggingUtil; @@ -143,6 +145,49 @@ public function testGenerateEmptySuite() $mockSuiteGenerator->generateSuite("basicTestSuite"); } + public function testInvalidTestRef() + { + // Mock Suite1 => Test1 and Suite2 => Test2 + $suiteDataArrayBuilder = new SuiteDataArrayBuilder(); + $mockData = $suiteDataArrayBuilder + ->withName('Suite1') + ->includeGroups(['group1']) + ->build(); + $suiteDataArrayBuilder = new SuiteDataArrayBuilder(); + $mockData2 = $suiteDataArrayBuilder + ->withName('Suite2') + ->includeGroups(['group2']) + ->build(); + $mockSuiteData = array_merge_recursive($mockData, $mockData2); + + $testDataArrayBuilder = new TestDataArrayBuilder(); + $mockSimpleTest = $testDataArrayBuilder + ->withName('Test1') + ->withAnnotations(['group' => [['value' => 'group1']]]) + ->withTestActions() + ->build(); + $testDataArrayBuilder = new TestDataArrayBuilder(); + $mockSimpleTest2 = $testDataArrayBuilder + ->withName('Test2') + ->withAnnotations(['group' => [['value' => 'group2']]]) + ->withTestActions() + ->build(); + $mockTestData = ['tests' => array_merge($mockSimpleTest, $mockSimpleTest2)]; + $this->setMockTestAndSuiteParserOutput($mockTestData, $mockSuiteData); + + // Make invalid manifest + $suiteConfig = ['Suite2' => ['Test1']]; + $manifest = TestManifestFactory::makeManifest('default', $suiteConfig); + + // Set up Expected Exception + $this->expectException(TestReferenceException::class); + $this->expectExceptionMessageRegExp('(Suite: "Suite2" Tests: "Test1")'); + + // parse and generate suite object with mocked data and manifest + $mockSuiteGenerator = SuiteGenerator::getInstance(); + $mockSuiteGenerator->generateAllSuites($manifest); + } + /** * Function used to set mock for parser return and force init method to run between tests. * diff --git a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php index 077e6d1cc..e3da10497 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php @@ -178,12 +178,14 @@ private function validateTestsReferencedInSuite($suiteName, $testsReferenced, $o { $suiteRef = $originalSuiteName ?? $suiteName; $possibleTestRef = SuiteObjectHandler::getInstance()->getObject($suiteRef)->getTests(); - $errorMsg = "Cannot reference tests which are not declared as part of suite."; + $errorMsg = "Cannot reference tests which are not declared as part of suite"; $invalidTestRef = array_diff($testsReferenced, array_keys($possibleTestRef)); if (!empty($invalidTestRef)) { - throw new TestReferenceException($errorMsg, ['suite' => $suiteRef, 'test' => $invalidTestRef]); + $testList = implode("\", \"", $invalidTestRef); + $fullError = $errorMsg . " (Suite: \"{$suiteRef}\" Tests: \"{$testList}\")"; + throw new TestReferenceException($fullError, ['suite' => $suiteRef, 'test' => $invalidTestRef]); } } From 46eabbf80dc84fe37981ba8487ac53a6bfae76ec Mon Sep 17 00:00:00 2001 From: Donald Booth Date: Tue, 14 Jan 2020 10:21:46 -0600 Subject: [PATCH 145/888] Added raw tags --- docs/best-practices.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/docs/best-practices.md b/docs/best-practices.md index 95677e78a..0b95b1c41 100644 --- a/docs/best-practices.md +++ b/docs/best-practices.md @@ -58,6 +58,8 @@ The following pattern is used when merging with `extends`: Name files according to the following patterns to make searching in future more easy: + + #### Test file name Format: {_Admin_ or _Storefront_}{Functionality}_Test.xml_, where Functionality briefly describes the testing functionality. @@ -80,6 +82,8 @@ Example: _AdminNavbarSection.xml_. Format: {Type}_Data.xml_, where Type represents the entity type. + + Example: _ProductData.xml_. ### Object names @@ -91,18 +95,18 @@ Use the _Foo.camelCase_ naming convention, which is similar to _Classes_ and _cl Use an upper case first letter for: - File names. Example: _StorefrontCreateCustomerTest.xml_ -- Test name attributes. Example: ``. -- Data entity names. Example: ``. -- Page name. Example: ``. -- Section name. Example: `
`. -- Action group name. Example: ``. +- Test name attributes. Example: `` +- Data entity names. Example: `` +- Page name. Example: `` +- Section name. Example: `
` +- Action group name. Example: `` #### Lower case Use a lower case first letter for: -- Data keys. Example: ``. -- Element names. Examples: ``. +- Data keys. Example: `` +- Element names. Examples: `` - Step keys. For example: `` ## Page object From ce8b333b0d4cd115b69f42b9f2a2f5e08b3eef89 Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Tue, 14 Jan 2020 11:11:26 -0600 Subject: [PATCH 146/888] MQE-1713: Generate/run test in single suite context - Added unit test for different exception message --- .../Suite/SuiteGeneratorTest.php | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php index eded50b41..e3f820ede 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php @@ -145,7 +145,7 @@ public function testGenerateEmptySuite() $mockSuiteGenerator->generateSuite("basicTestSuite"); } - public function testInvalidTestRef() + public function testInvalidSuiteTestPair() { // Mock Suite1 => Test1 and Suite2 => Test2 $suiteDataArrayBuilder = new SuiteDataArrayBuilder(); @@ -188,6 +188,30 @@ public function testInvalidTestRef() $mockSuiteGenerator->generateAllSuites($manifest); } + public function testNonExistentSuiteTestPair() + { + $testDataArrayBuilder = new TestDataArrayBuilder(); + $mockSimpleTest = $testDataArrayBuilder + ->withName('Test1') + ->withAnnotations(['group' => [['value' => 'group1']]]) + ->withTestActions() + ->build(); + $mockTestData = ['tests' => array_merge($mockSimpleTest)]; + $this->setMockTestAndSuiteParserOutput($mockTestData, []); + + // Make invalid manifest + $suiteConfig = ['Suite3' => ['Test1']]; + $manifest = TestManifestFactory::makeManifest('default', $suiteConfig); + + // Set up Expected Exception + $this->expectException(TestReferenceException::class); + $this->expectExceptionMessageRegExp('#Suite3 is not defined#'); + + // parse and generate suite object with mocked data and manifest + $mockSuiteGenerator = SuiteGenerator::getInstance(); + $mockSuiteGenerator->generateAllSuites($manifest); + } + /** * Function used to set mock for parser return and force init method to run between tests. * From c8a8ba915d977dbe51f1cc6ce49bb1ec06ca3268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Bajsarowicz?= Date: Tue, 14 Jan 2020 18:40:43 +0100 Subject: [PATCH 147/888] Improve readability of mustache patterns --- .../Test/Objects/ActionObject.php | 37 ++++++++++++++++--- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php index cf78fe522..b9e3a3465 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php @@ -76,6 +76,9 @@ class ActionObject const ACTION_ATTRIBUTE_USERINPUT = 'userInput'; const ACTION_TYPE_COMMENT = 'comment'; const INVISIBLE_STEP_ACTIONS = ['retrieveEntityField', 'getSecret']; + const REGEX_SINGLE_GROUP = '[\w]+'; + const REGEX_WITH_INDEX = '[\w]+\.[\w\[\]]+'; + const REGEX_WITH_PARAM = '[\w]+\.[\w]+\((?(?!}}).)+\)'; /** * The unique identifier for the action @@ -433,8 +436,13 @@ private function resolveUrlReference() */ private function getMissingReferences($replacement): array { - $mustachePattern = '/({{[\w]+}})|({{[\w]+\.[\w\[\]]+}})|({{[\w]+\.[\w]+\((?(?!}}).)+\)}})/'; - preg_match_all($mustachePattern, $replacement, $matches); + $matchPatterns = [ + self::REGEX_SINGLE_GROUP, + self::REGEX_WITH_INDEX, + self::REGEX_WITH_PARAM + ]; + + preg_match_all($this->getMustachePattern($matchPatterns), $replacement, $matches); return array_filter($matches[1], function ($match) { return !empty($match) && false === strpos($match, '_ENV.'); @@ -534,10 +542,12 @@ private function stripAndReturnParameters($reference) */ private function findAndReplaceReferences($objectHandler, $inputString) { - //look for parameter area, if so use different regex - $regex = ActionObject::ACTION_ATTRIBUTE_VARIABLE_REGEX_PATTERN; + $matchPatterns = [ + self::REGEX_WITH_INDEX, + self::REGEX_WITH_PARAM + ]; - preg_match_all($regex, $inputString, $matches); + preg_match_all($this->getMustachePattern($matchPatterns), $inputString, $matches); $outputString = $inputString; @@ -720,7 +730,11 @@ private function resolveParameterization($isParameterized, $replacement, $match, */ private function matchParameterReferences($reference, $parameters) { - preg_match_all('/{{[\w.]+}}/', $reference, $varMatches); + $matchPatterns = [ + self::REGEX_SINGLE_GROUP + ]; + + preg_match_all($this->getMustachePattern($matchPatterns), $reference, $varMatches); $varMatches[0] = array_unique($varMatches[0]); $this->checkParameterCount($varMatches[0], $parameters, $reference); @@ -790,4 +804,15 @@ private function checkParameterCount($matches, $parameters, $reference) ); } } + + /** + * Returns Mustache regex pattern + * + * @param array|null $patterns + * @return string + */ + private function getMustachePattern(array $patterns = []): string + { + return '/({{' .implode('}})|({{', $patterns).'}})/'; + } } From d0d98051488658d8325b7e2e0fe3a969c9cd45ee Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Tue, 14 Jan 2020 15:36:30 -0600 Subject: [PATCH 148/888] MQE-1918: MFTF AWS Secrets Manager - Local Use --- ...t.php => AwsSecretsManagerStorageTest.php} | 8 ++--- docs/configuration.md | 16 ++++----- docs/credentials.md | 34 +++++++++---------- etc/config/.env.example | 6 ++-- .../Handlers/CredentialStore.php | 18 +++++----- ...orage.php => AwsSecretsManagerStorage.php} | 34 +++++++++---------- 6 files changed, 58 insertions(+), 58 deletions(-) rename dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/{AwsSecretManagerStorageTest.php => AwsSecretsManagerStorageTest.php} (88%) rename src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/{AwsSecretManagerStorage.php => AwsSecretsManagerStorage.php} (75%) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/AwsSecretManagerStorageTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/AwsSecretsManagerStorageTest.php similarity index 88% rename from dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/AwsSecretManagerStorageTest.php rename to dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/AwsSecretsManagerStorageTest.php index f11d14920..e1f4e4879 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/AwsSecretManagerStorageTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/AwsSecretsManagerStorageTest.php @@ -7,15 +7,15 @@ namespace tests\unit\Magento\FunctionalTestFramework\DataGenerator\Handlers\SecretStorage; use Aws\SecretsManager\SecretsManagerClient; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\SecretStorage\AwsSecretManagerStorage; +use Magento\FunctionalTestingFramework\DataGenerator\Handlers\SecretStorage\AwsSecretsManagerStorage; use Aws\Result; use Magento\FunctionalTestingFramework\Util\MagentoTestCase; use ReflectionClass; -class AwsSecretManagerStorageTest extends MagentoTestCase +class AwsSecretsManagerStorageTest extends MagentoTestCase { /** - * Test encryption/decryption functionality in AwsSecretManagerStorage class. + * Test encryption/decryption functionality in AwsSecretsManagerStorage class. */ public function testEncryptAndDecrypt() { @@ -44,7 +44,7 @@ public function testEncryptAndDecrypt() }); /** @var SecretsManagerClient */ - $credentialStorage = new AwsSecretManagerStorage($testRegion, $testProfile); + $credentialStorage = new AwsSecretsManagerStorage($testRegion, $testProfile); $reflection = new ReflectionClass($credentialStorage); $reflection_property = $reflection->getProperty('client'); $reflection_property->setAccessible(true); diff --git a/docs/configuration.md b/docs/configuration.md index f89090c06..9466f2bcc 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -277,26 +277,26 @@ Example: CREDENTIAL_VAULT_SECRET_BASE_PATH=secret ``` -### CREDENTIAL_AWS_SECRET_MANAGER_REGION +### CREDENTIAL_AWS_SECRETS_MANAGER_REGION -The region that Aws Secret Manager is located. +The region that AWS Secrets Manager is located. Example: ```conf -# Region of Aws Secret Manager -CREDENTIAL_AWS_SECRET_MANAGER_REGION=us-east-1 +# Region of AWS Secrets Manager +CREDENTIAL_AWS_SECRETS_MANAGER_REGION=us-east-1 ``` -### CREDENTIAL_AWS_SECRET_MANAGER_PROFILE +### CREDENTIAL_AWS_SECRETS_MANAGER_PROFILE -The profile used to connect to Aws Secret Manager. +The profile used to connect to AWS Secrets Manager. Example: ```conf -# Profile used to connect to Aws Secret Manager. -CREDENTIAL_AWS_SECRET_MANAGER_PROFILE=default +# Profile used to connect to AWS Secrets Manager. +CREDENTIAL_AWS_SECRETS_MANAGER_PROFILE=default ``` ### ENABLE_BROWSER_LOG diff --git a/docs/credentials.md b/docs/credentials.md index 6ca9900cb..4b20e68dc 100644 --- a/docs/credentials.md +++ b/docs/credentials.md @@ -7,7 +7,7 @@ Currently the MFTF supports three types of credential storage: - **.credentials file** - **HashiCorp Vault** -- **Aws Secret Manager** +- **AWS Secrets Manager** ## Configure File Storage @@ -136,22 +136,22 @@ CREDENTIAL_VAULT_ADDRESS=http://127.0.0.1:8200 CREDENTIAL_VAULT_SECRET_BASE_PATH=secret ``` -## Configure Aws Secret Manager +## Configure AWS Secrets Manager -Aws Secrets Manager offers secret management that supports: +AWS Secrets Manager offers secret management that supports: - Secret rotation with built-in integration for Amazon RDS, Amazon Redshift, and Amazon DocumentDB - Fine-grained policies and permissions - Audit secret rotation centrally for resources in the AWS Cloud, third-party services, and on-premises ### Prerequisites - AWS account -- AWS Secret Manger is created and configured -- IAM User or Role is created +- AWS Secrets Manger is created and configured +- IAM User or Role is created with appropriate AWS Secrets Manger access permission -### Store secrets in Aws Secret Manager +### Store secrets in AWS Secrets Manager #### Secrets format -`Secret Name`, `Secret Key`, `Secret Value` are three key pieces of information to construct an Aws Secret. +`Secret Name`, `Secret Key`, `Secret Value` are three key pieces of information to construct an AWS Secret. `Secret Key` and `Secret Value` can be any content you want to secure, `Secret Name` must follow the format: ```conf @@ -172,18 +172,18 @@ mftf/magento/carriers_usps_password carriers_usps_password ``` -### Setup MFTF to use Aws Secret Manager +### Setup MFTF to use AWS Secrets Manager -To use Aws Secret Manager, the Aws region to connect to is required. You can set it through environment variable [`CREDENTIAL_AWS_SECRET_MANAGER_REGION`][] in `.env`. +To use AWS Secrets Manager, the AWS region to connect to is required. You can set it through environment variable [`CREDENTIAL_AWS_SECRETS_MANAGER_REGION`][] in `.env`. -MFTF uses the recommended [Default Credential Provider Chain][credential chain] to establish connection to Aws Secret Manager service. +MFTF uses the recommended [Default Credential Provider Chain][credential chain] to establish connection to AWS Secrets Manager service. You can setup credentials according to [Default Credential Provider Chain][credential chain] and there is no MFTF specific setup required. -Optionally, however, you can explicitly set Aws profile through environment variable [`CREDENTIAL_AWS_SECRET_MANAGER_PROFILE`][] in `.env`. +Optionally, however, you can explicitly set AWS profile through environment variable [`CREDENTIAL_AWS_SECRETS_MANAGER_PROFILE`][] in `.env`. ```conf -# Sample Aws Secret Manager configuration -CREDENTIAL_AWS_SECRET_MANAGER_REGION=us-east-1 -CREDENTIAL_AWS_SECRET_MANAGER_PROFILE=default +# Sample AWS Secrets Manager configuration +CREDENTIAL_AWS_SECRETS_MANAGER_REGION=us-east-1 +CREDENTIAL_AWS_SECRETS_MANAGER_PROFILE=default ``` ## Configure multiple credential storage @@ -192,7 +192,7 @@ It is possible and sometimes useful to setup and use multiple credential storage In this case, the MFTF tests are able to read secret data at runtime from all storage options, in this case MFTF use the following precedence: ``` -.credentials File > HashiCorp Vault > Aws Secret Manager +.credentials File > HashiCorp Vault > AWS Secrets Manager ``` @@ -238,5 +238,5 @@ The MFTF tests delivered with Magento application do not use credentials and do [`CREDENTIAL_VAULT_ADDRESS`]: configuration.md#credential_vault_address [`CREDENTIAL_VAULT_SECRET_BASE_PATH`]: configuration.md#credential_vault_secret_base_path [credential chain]: https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/guide_credentials.html -[`CREDENTIAL_AWS_SECRET_MANAGER_PROFILE`]: configuration.md#credential_aws_secret_manager_profile -[`CREDENTIAL_AWS_SECRET_MANAGER_REGION`]: configuration.md#credential_aws_secret_manager_region \ No newline at end of file +[`CREDENTIAL_AWS_SECRETS_MANAGER_PROFILE`]: configuration.md#credential_aws_secrets_manager_profile +[`CREDENTIAL_AWS_SECRETS_MANAGER_REGION`]: configuration.md#credential_aws_secrets_manager_region \ No newline at end of file diff --git a/etc/config/.env.example b/etc/config/.env.example index a772b1e9e..f5b6ef40e 100644 --- a/etc/config/.env.example +++ b/etc/config/.env.example @@ -34,9 +34,9 @@ BROWSER=chrome #CREDENTIAL_VAULT_ADDRESS=http://127.0.0.1:8200 #CREDENTIAL_VAULT_SECRET_BASE_PATH=secret -#*** To use AWS Secret Manager to manage _CREDS secrets, uncomment and set region, profile is optional, when omitted, AWS default credential provider chain will be used ***# -#CREDENTIAL_AWS_SECRET_MANAGER_PROFILE=default -#CREDENTIAL_AWS_SECRET_MANAGER_REGION=us-east-1 +#*** To use AWS Secrets Manager to manage _CREDS secrets, uncomment and set region, profile is optional, when omitted, AWS default credential provider chain will be used ***# +#CREDENTIAL_AWS_SECRETS_MANAGER_PROFILE=default +#CREDENTIAL_AWS_SECRETS_MANAGER_REGION=us-east-1 #*** Uncomment these properties to set up a dev environment with symlinked projects ***# #TESTS_BP= diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php index bff3e9b00..76560bcf1 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php @@ -9,17 +9,17 @@ use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\SecretStorage\FileStorage; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\SecretStorage\VaultStorage; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\SecretStorage\AwsSecretManagerStorage; +use Magento\FunctionalTestingFramework\DataGenerator\Handlers\SecretStorage\AwsSecretsManagerStorage; use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; class CredentialStore { const ARRAY_KEY_FOR_VAULT = 'vault'; const ARRAY_KEY_FOR_FILE = 'file'; - const ARRAY_KEY_FOR_AWS_SECRET_MANAGER = 'aws'; + const ARRAY_KEY_FOR_AWS_SECRETS_MANAGER = 'aws'; const CREDENTIAL_STORAGE_INFO = 'MFTF uses Credential Storage in the following precedence: ' - . '.credentials file, HashiCorp Vault and AWS Secret Manager. ' + . '.credentials file, HashiCorp Vault and AWS Secrets Manager. ' . 'You need to configure at least one to use _CREDS in tests.'; /** @@ -77,15 +77,15 @@ private function __construct() } } - // Initialize AWS secret manager storage - $awsRegion = getenv('CREDENTIAL_AWS_SECRET_MANAGER_REGION'); - $awsProfile = getenv('CREDENTIAL_AWS_SECRET_MANAGER_PROFILE'); + // Initialize AWS Secrets Manager storage + $awsRegion = getenv('CREDENTIAL_AWS_SECRETS_MANAGER_REGION'); + $awsProfile = getenv('CREDENTIAL_AWS_SECRETS_MANAGER_PROFILE'); if ($awsRegion !== false) { if ($awsProfile === false) { $awsProfile = null; } try { - $this->credStorage[self::ARRAY_KEY_FOR_AWS_SECRET_MANAGER] = new AwsSecretManagerStorage( + $this->credStorage[self::ARRAY_KEY_FOR_AWS_SECRETS_MANAGER] = new AwsSecretsManagerStorage( $awsRegion, $awsProfile ); @@ -109,8 +109,8 @@ private function __construct() */ public function getSecret($key) { - // Get secret data from storage according to the order they are stored - // File storage is preferred over vault storage to allow local secret value overriding remote secret value + // Get secret data from storage according to the order they are stored which follows this precedence: + // FileStorage > VaultStorage > AwsSecretsManagerStorage foreach ($this->credStorage as $storage) { $value = $storage->getEncryptedValue($key); if (null !== $value) { diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/AwsSecretManagerStorage.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/AwsSecretsManagerStorage.php similarity index 75% rename from src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/AwsSecretManagerStorage.php rename to src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/AwsSecretsManagerStorage.php index 0c10c53c4..e7a858254 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/AwsSecretManagerStorage.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/AwsSecretsManagerStorage.php @@ -15,7 +15,7 @@ use InvalidArgumentException; use Exception; -class AwsSecretManagerStorage extends BaseStorage +class AwsSecretsManagerStorage extends BaseStorage { /** * Mftf project path @@ -23,7 +23,7 @@ class AwsSecretManagerStorage extends BaseStorage const MFTF_PATH = 'mftf'; /** - * AWS Secret Manager version + * AWS Secrets Manager version * * Last tested version '2017-10-17' */ @@ -37,7 +37,7 @@ class AwsSecretManagerStorage extends BaseStorage private $client = null; /** - * AwsSecretManagerStorage constructor + * AwsSecretsManagerStorage constructor * * @param string $region * @param string $profile @@ -47,7 +47,7 @@ class AwsSecretManagerStorage extends BaseStorage public function __construct($region, $profile = null) { parent::__construct(); - $this->createAwsSecretManagerClient($region, $profile); + $this->createAwsSecretsManagerClient($region, $profile); } /** @@ -65,8 +65,8 @@ public function getEncryptedValue($key) } if (MftfApplicationConfig::getConfig()->verboseEnabled()) { - LoggingUtil::getInstance()->getLogger(VaultStorage::class)->debug( - "Retrieving secret for key name {$key} from AWS Secret Manager" + LoggingUtil::getInstance()->getLogger(AwsSecretsManagerStorage::class)->debug( + "Retrieving value for key name {$key} from AWS Secrets Manager" ); } @@ -79,7 +79,7 @@ public function getEncryptedValue($key) . $vendor . '/' . $key; - // Read value by id from AWS Secret Manager, and parse the result + // Read value by id from AWS Secrets Manager, and parse the result $value = $this->parseAwsSecretResult( $this->client->getSecretValue(['SecretId' => $secretId]), $key @@ -90,14 +90,14 @@ public function getEncryptedValue($key) } catch (AwsException $e) { $error = $e->getAwsErrorCode(); if (MftfApplicationConfig::getConfig()->verboseEnabled()) { - LoggingUtil::getInstance()->getLogger(VaultStorage::class)->debug( - "AWS error code: {$error}. Unable to read secret for key {$key} from AWS Secret Manager" + LoggingUtil::getInstance()->getLogger(AwsSecretsManagerStorage::class)->debug( + "AWS error code: {$error}. Unable to read value for key {$key} from AWS Secrets Manager" ); } } catch (\Exception $e) { if (MftfApplicationConfig::getConfig()->verboseEnabled()) { - LoggingUtil::getInstance()->getLogger(VaultStorage::class)->debug( - "Unable to read secret for key {$key} from AWS Secret Manager" + LoggingUtil::getInstance()->getLogger(AwsSecretsManagerStorage::class)->debug( + "Unable to read value for key {$key} from AWS Secrets Manager" ); } } @@ -118,17 +118,17 @@ private function parseAwsSecretResult($awsResult, $key) if (isset($awsResult['SecretString'])) { $rawSecret = $awsResult['SecretString']; } else { - throw new TestFrameworkException("Error parsing AWS secret result"); + throw new TestFrameworkException("Error parsing result from AWS Secrets Manager"); } $secret = json_decode($rawSecret, true); if (isset($secret[$key])) { return $secret[$key]; } - throw new TestFrameworkException("Error parsing AWS secret result"); + throw new TestFrameworkException("Error parsing result from AWS Secrets Manager"); } /** - * Create Aws Secret Manager client + * Create Aws Secrets Manager client * * @param string $region * @param string $profile @@ -136,13 +136,13 @@ private function parseAwsSecretResult($awsResult, $key) * @throws TestFrameworkException * @throws InvalidArgumentException */ - private function createAwsSecretManagerClient($region, $profile) + private function createAwsSecretsManagerClient($region, $profile) { if (null !== $this->client) { return; } - // Create AWS Secret Manager client + // Create AWS Secrets Manager client $this->client = new SecretsManagerClient([ 'profile' => $profile, 'region' => $region, @@ -150,7 +150,7 @@ private function createAwsSecretManagerClient($region, $profile) ]); if ($this->client === null) { - throw new TestFrameworkException("Unable to create AWS Secret Manager client"); + throw new TestFrameworkException("Unable to create AWS Secrets Manager client"); } } } From bb62cfe317f88c7e18df7039d72c2bbbb78b1bf9 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Wed, 15 Jan 2020 10:07:44 -0600 Subject: [PATCH 149/888] MQE-1918: MFTF AWS Secrets Manager - Local Use --- .../DataGenerator/Handlers/CredentialStore.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php index 76560bcf1..84d58ade8 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php @@ -18,9 +18,8 @@ class CredentialStore const ARRAY_KEY_FOR_FILE = 'file'; const ARRAY_KEY_FOR_AWS_SECRETS_MANAGER = 'aws'; - const CREDENTIAL_STORAGE_INFO = 'MFTF uses Credential Storage in the following precedence: ' - . '.credentials file, HashiCorp Vault and AWS Secrets Manager. ' - . 'You need to configure at least one to use _CREDS in tests.'; + const CREDENTIAL_STORAGE_INFO = 'You need to configure at least one of these options: ' + . '.credentials file, HashiCorp Vault or AWS Secrets Manager correctly'; /** * Credential storage array @@ -95,7 +94,7 @@ private function __construct() if (empty($this->credStorage)) { throw new TestFrameworkException( - 'Invalid Credential Storage. ' . self::CREDENTIAL_STORAGE_INFO + 'Invalid Credential Storage. ' . self::CREDENTIAL_STORAGE_INFO . '.' ); } } @@ -119,7 +118,8 @@ public function getSecret($key) } throw new TestFrameworkException( - "{$key} not found. " . self::CREDENTIAL_STORAGE_INFO . ' And make sure key/value exists.' + "{$key} not found. " . self::CREDENTIAL_STORAGE_INFO + . ' and ensure key, value exists to use _CREDS in tests.' ); } From 350e8967cb971623f40c1b73d46230c1e5c47498 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Wed, 15 Jan 2020 11:59:56 -0600 Subject: [PATCH 150/888] MQE-1761: Allure reporting error for multiple suite run --- .../Console/RunTestGroupCommand.php | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php index 98d121d40..2c7aee1c1 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php @@ -94,21 +94,32 @@ protected function execute(InputInterface $input, OutputInterface $output): int $command->run(new ArrayInput($args), $output); } - $codeceptionCommand = realpath(PROJECT_ROOT . '/vendor/bin/codecept') . ' run functional --verbose --steps'; + $commandString = realpath(PROJECT_ROOT . '/vendor/bin/codecept') . ' run functional --verbose --steps'; + $exitCode = -1; + $returnCodes = []; foreach ($groups as $group) { - $codeceptionCommand .= " -g {$group}"; - } + $codeceptionCommandString = $commandString . " -g {$group}"; + + $process = new Process($codeceptionCommandString); + $process->setWorkingDirectory(TESTS_BP); + $process->setIdleTimeout(600); + $process->setTimeout(0); - $process = new Process($codeceptionCommand); - $process->setWorkingDirectory(TESTS_BP); - $process->setIdleTimeout(600); - $process->setTimeout(0); + $returnCodes[] = $process->run( + function ($type, $buffer) use ($output) { + $output->write($buffer); + } + ); + } - return $process->run( - function ($type, $buffer) use ($output) { - $output->write($buffer); + foreach ($returnCodes as $returnCode) { + if ($returnCode != 0) { + return $returnCode; } - ); + $exitCode = 0; + } + return $exitCode; + } } From eb68e89b195ba6eec1a511f06623332938fd7780 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Wed, 15 Jan 2020 12:16:37 -0600 Subject: [PATCH 151/888] MQE-1761: Allure reporting error for multiple suite run --- .../FunctionalTestingFramework/Console/RunTestGroupCommand.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php index 2c7aee1c1..6ea37785d 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php @@ -120,6 +120,5 @@ function ($type, $buffer) use ($output) { $exitCode = 0; } return $exitCode; - } } From 9a1fdd1530b8005dd2cf8f3d62edab612330adb9 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Thu, 16 Jan 2020 16:02:52 -0600 Subject: [PATCH 152/888] MQE-1919: MFTF AWS Secrets Manager - CI Use --- etc/config/.env.example | 2 ++ .../Handlers/CredentialStore.php | 7 ++++- .../AwsSecretsManagerStorage.php | 31 +++++++++++++++++-- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/etc/config/.env.example b/etc/config/.env.example index f5b6ef40e..7f988c9f0 100644 --- a/etc/config/.env.example +++ b/etc/config/.env.example @@ -37,6 +37,8 @@ BROWSER=chrome #*** To use AWS Secrets Manager to manage _CREDS secrets, uncomment and set region, profile is optional, when omitted, AWS default credential provider chain will be used ***# #CREDENTIAL_AWS_SECRETS_MANAGER_PROFILE=default #CREDENTIAL_AWS_SECRETS_MANAGER_REGION=us-east-1 +#*** If using non-default AWS account ***# +#CREDENTIAL_AWS_ACCOUNT_ID= #*** Uncomment these properties to set up a dev environment with symlinked projects ***# #TESTS_BP= diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php index 84d58ade8..7769decc6 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php @@ -79,14 +79,19 @@ private function __construct() // Initialize AWS Secrets Manager storage $awsRegion = getenv('CREDENTIAL_AWS_SECRETS_MANAGER_REGION'); $awsProfile = getenv('CREDENTIAL_AWS_SECRETS_MANAGER_PROFILE'); + $awsId = getenv('CREDENTIAL_AWS_ACCOUNT_ID'); if ($awsRegion !== false) { if ($awsProfile === false) { $awsProfile = null; } + if ($awsId === false) { + $awsId = null; + } try { $this->credStorage[self::ARRAY_KEY_FOR_AWS_SECRETS_MANAGER] = new AwsSecretsManagerStorage( $awsRegion, - $awsProfile + $awsProfile, + $awsId ); } catch (TestFrameworkException $e) { } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/AwsSecretsManagerStorage.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/AwsSecretsManagerStorage.php index e7a858254..1e58e3bee 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/AwsSecretsManagerStorage.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/AwsSecretsManagerStorage.php @@ -22,6 +22,11 @@ class AwsSecretsManagerStorage extends BaseStorage */ const MFTF_PATH = 'mftf'; + /** + * AWS Secrets Manager partial ARN + */ + const AWS_SM_PARTIAL_ARN = 'arn:aws:secretsmanager:'; + /** * AWS Secrets Manager version * @@ -36,18 +41,35 @@ class AwsSecretsManagerStorage extends BaseStorage */ private $client = null; + /** + * AWS account id + * + * @var string + */ + private $awsAccountId; + + /** + * AWS account region + * + * @var string + */ + private $region; + /** * AwsSecretsManagerStorage constructor * * @param string $region * @param string $profile + * @param string $accountId * @throws TestFrameworkException * @throws InvalidArgumentException */ - public function __construct($region, $profile = null) + public function __construct($region, $profile = null, $accountId = null) { parent::__construct(); $this->createAwsSecretsManagerClient($region, $profile); + $this->region = $region; + $this->awsAccountId = $accountId; } /** @@ -74,7 +96,12 @@ public function getEncryptedValue($key) try { // Split vendor/key to construct secret id list($vendor, $key) = explode('/', trim($key, '/'), 2); - $secretId = self::MFTF_PATH + // If AWS account id is specified, create and use full ARN, otherwise use partial ARN as secret id + $secretId = ''; + if (!empty($this->awsAccountId)) { + $secretId = self::AWS_SM_PARTIAL_ARN . $this->region . ':' . $this->awsAccountId . ':secret:'; + } + $secretId .= self::MFTF_PATH . '/' . $vendor . '/' From 458bddd9046070173dd23e1746b829c40862b694 Mon Sep 17 00:00:00 2001 From: Ajith Date: Mon, 20 Jan 2020 14:52:02 +0530 Subject: [PATCH 153/888] Remove extra spaces --- docs/extending.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/extending.md b/docs/extending.md index 91dc97c5d..5ebd5ab27 100644 --- a/docs/extending.md +++ b/docs/extending.md @@ -26,7 +26,7 @@ __Use case__: Create two similar tests with different `url` (`"{{AdminCategoryPa > Test with "extends": ```xml - + ... @@ -47,7 +47,7 @@ __Use case__: Create two similar tests with different `url` (`"{{AdminCategoryPa > Test without "extends": ```xml - + ... @@ -77,7 +77,7 @@ __Use case__: Create two similar tests where the second test contains two additi > Tests with "extends": ```xml - + @@ -95,7 +95,7 @@ __Use case__: Create two similar tests where the second test contains two additi > Tests without "extends": ```xml - + @@ -125,7 +125,7 @@ __Use case__: Create two similar tests where the second one contains two additio > Tests with "extends": ```xml - + @@ -147,7 +147,7 @@ __Use case__: Create two similar tests where the second one contains two additio > Tests without "extends": ```xml - + From eb7b6a3f59645bcb427ba749fc7e34f8e5899360 Mon Sep 17 00:00:00 2001 From: Ajith Date: Tue, 21 Jan 2020 07:16:37 +0530 Subject: [PATCH 154/888] Remove extra spaces --- docs/extending.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/extending.md b/docs/extending.md index 5ebd5ab27..064ed3208 100644 --- a/docs/extending.md +++ b/docs/extending.md @@ -295,7 +295,7 @@ __Use case__: Create an entity named `DivPanelGreen`, which is similar to the `D > Entities with "extends": ```xml - + Red 80px @@ -310,7 +310,7 @@ __Use case__: Create an entity named `DivPanelGreen`, which is similar to the `D > Entities without "extends": ```xml - + Red 80px @@ -331,7 +331,7 @@ __Use case__: Create an entity named `DivPanelGreen`, which is similar to the `D > Entities with "extends": ```xml - + Red 80px @@ -347,7 +347,7 @@ __Use case__: Create an entity named `DivPanelGreen`, which is similar to the `D > Entities without "extends": ```xml - + Red 80px From 93e221c4a99db73a129d05b3fd203942022617dc Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Tue, 21 Jan 2020 11:14:56 -0600 Subject: [PATCH 155/888] MQE-1919: MFTF AWS Secrets Manager - CI Use --- docs/credentials.md | 64 ++++++++--- etc/config/.env.example | 2 - .../Handlers/CredentialStore.php | 107 +++++++++++------- .../AwsSecretsManagerStorage.php | 42 ++++--- 4 files changed, 145 insertions(+), 70 deletions(-) diff --git a/docs/credentials.md b/docs/credentials.md index 4b20e68dc..1ea91a5c3 100644 --- a/docs/credentials.md +++ b/docs/credentials.md @@ -144,32 +144,54 @@ AWS Secrets Manager offers secret management that supports: - Audit secret rotation centrally for resources in the AWS Cloud, third-party services, and on-premises ### Prerequisites -- AWS account -- AWS Secrets Manger is created and configured + +#### Use AWS Secrets Manager from your own AWS account + +- AWS account with Secrets Manager service available - IAM User or Role is created with appropriate AWS Secrets Manger access permission +#### Use AWS Secrets Manager from other AWS account + +- AWS account ID where the AWS Secrets Manager service is hosted +- IAM User or Role with appropriate access permission + ### Store secrets in AWS Secrets Manager + #### Secrets format -`Secret Name`, `Secret Key`, `Secret Value` are three key pieces of information to construct an AWS Secret. -`Secret Key` and `Secret Value` can be any content you want to secure, `Secret Name` must follow the format: + +`Secret Name` and `Secret Value` are two key pieces of information for creating a secret. + +`Secret Value` can be either plaintext or key/value pairs in JSON format. + +`Secrets Name` must use the following format: ```conf -mftf// +mftf// ``` -```conf -# Secret name for carriers_usps_userid -mftf/magento/carriers_usps_userid +`Secrets Value` in plaintext format can be any content you want to secure. `Secrets Value` in key/value pairs format, however, the `key` must be same as the `Secret Name` with `mftf//` part removed. +e.g. in above example, `key` should be `` + +##### Create Secrets using AWS CLI -# Secret key for carriers_usps_userid -carriers_usps_userid +```bash +aws secretsmanager create-secret --name "mftf/magento/shipping/carriers_usps_userid" --description "Carriers USPS user id" --secret-string "1234567" +``` + +##### Create Secrets using AWS Console + +To save the same secret in key/value JSON format, you should use + +```conf +# Secret Name +mftf/magento/shipping/carriers_usps_userid -# Secret name for carriers_usps_password -mftf/magento/carriers_usps_password +# Secret Key +shipping/carriers_usps_userid -# Secret key for carriers_usps_password -carriers_usps_password +# Secret Value +1234567 ``` ### Setup MFTF to use AWS Secrets Manager @@ -186,6 +208,16 @@ CREDENTIAL_AWS_SECRETS_MANAGER_REGION=us-east-1 CREDENTIAL_AWS_SECRETS_MANAGER_PROFILE=default ``` +### Optionally set CREDENTIAL_AWS_ACCOUNT_ID environment variable + +Full AWS KMS ([Key Management Service][]) key ARN ([Amazon Resource Name][]) is required when accessing secrets stored in other AWS account. +If this is the case, you will also need to set `CREDENTIAL_AWS_ACCOUNT_ID` environment variable so that MFTF can construct the full ARN. +This is also commonly used in CI system. + +```bash +export CREDENTIAL_AWS_ACCOUNT_ID= +``` + ## Configure multiple credential storage It is possible and sometimes useful to setup and use multiple credential storage at the same time. @@ -239,4 +271,6 @@ The MFTF tests delivered with Magento application do not use credentials and do [`CREDENTIAL_VAULT_SECRET_BASE_PATH`]: configuration.md#credential_vault_secret_base_path [credential chain]: https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/guide_credentials.html [`CREDENTIAL_AWS_SECRETS_MANAGER_PROFILE`]: configuration.md#credential_aws_secrets_manager_profile -[`CREDENTIAL_AWS_SECRETS_MANAGER_REGION`]: configuration.md#credential_aws_secrets_manager_region \ No newline at end of file +[`CREDENTIAL_AWS_SECRETS_MANAGER_REGION`]: configuration.md#credential_aws_secrets_manager_region +[Key Management Service]: https://aws.amazon.com/kms/ +[Amazon Resource Name]: https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html \ No newline at end of file diff --git a/etc/config/.env.example b/etc/config/.env.example index 7f988c9f0..f5b6ef40e 100644 --- a/etc/config/.env.example +++ b/etc/config/.env.example @@ -37,8 +37,6 @@ BROWSER=chrome #*** To use AWS Secrets Manager to manage _CREDS secrets, uncomment and set region, profile is optional, when omitted, AWS default credential provider chain will be used ***# #CREDENTIAL_AWS_SECRETS_MANAGER_PROFILE=default #CREDENTIAL_AWS_SECRETS_MANAGER_REGION=us-east-1 -#*** If using non-default AWS account ***# -#CREDENTIAL_AWS_ACCOUNT_ID= #*** Uncomment these properties to set up a dev environment with symlinked projects ***# #TESTS_BP= diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php index 7769decc6..b66d19799 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php @@ -57,45 +57,10 @@ public static function getInstance() */ private function __construct() { - // Initialize file storage - try { - $this->credStorage[self::ARRAY_KEY_FOR_FILE] = new FileStorage(); - } catch (TestFrameworkException $e) { - } - - // Initialize vault storage - $cvAddress = getenv('CREDENTIAL_VAULT_ADDRESS'); - $cvSecretPath = getenv('CREDENTIAL_VAULT_SECRET_BASE_PATH'); - if ($cvAddress !== false && $cvSecretPath !== false) { - try { - $this->credStorage[self::ARRAY_KEY_FOR_VAULT] = new VaultStorage( - UrlFormatter::format($cvAddress, false), - '/' . trim($cvSecretPath, '/') - ); - } catch (TestFrameworkException $e) { - } - } - - // Initialize AWS Secrets Manager storage - $awsRegion = getenv('CREDENTIAL_AWS_SECRETS_MANAGER_REGION'); - $awsProfile = getenv('CREDENTIAL_AWS_SECRETS_MANAGER_PROFILE'); - $awsId = getenv('CREDENTIAL_AWS_ACCOUNT_ID'); - if ($awsRegion !== false) { - if ($awsProfile === false) { - $awsProfile = null; - } - if ($awsId === false) { - $awsId = null; - } - try { - $this->credStorage[self::ARRAY_KEY_FOR_AWS_SECRETS_MANAGER] = new AwsSecretsManagerStorage( - $awsRegion, - $awsProfile, - $awsId - ); - } catch (TestFrameworkException $e) { - } - } + // Initialize credential storage by defined order of precedence as the following + $this->initializeFileStorage(); + $this->initializeVaultStorage(); + $this->initializeAwsSecretsManagerStorage(); if (empty($this->credStorage)) { throw new TestFrameworkException( @@ -155,4 +120,68 @@ public function decryptAllSecretsInString($string) return $storage->getAllDecryptedValuesInString($string); } } + + /** + * Initialize file storage + * + * @return void + */ + private function initializeFileStorage() + { + // Initialize file storage + try { + $this->credStorage[self::ARRAY_KEY_FOR_FILE] = new FileStorage(); + } catch (TestFrameworkException $e) { + } + } + + /** + * Initialize Vault storage + * + * @return void + */ + private function initializeVaultStorage() + { + // Initialize vault storage + $cvAddress = getenv('CREDENTIAL_VAULT_ADDRESS'); + $cvSecretPath = getenv('CREDENTIAL_VAULT_SECRET_BASE_PATH'); + if ($cvAddress !== false && $cvSecretPath !== false) { + try { + $this->credStorage[self::ARRAY_KEY_FOR_VAULT] = new VaultStorage( + UrlFormatter::format($cvAddress, false), + '/' . trim($cvSecretPath, '/') + ); + } catch (TestFrameworkException $e) { + } + } + } + + /** + * Initialize AWS Secrets Manager storage + * + * @return void + */ + private function initializeAwsSecretsManagerStorage() + { + // Initialize AWS Secrets Manager storage + $awsRegion = getenv('CREDENTIAL_AWS_SECRETS_MANAGER_REGION'); + $awsProfile = getenv('CREDENTIAL_AWS_SECRETS_MANAGER_PROFILE'); + $awsId = getenv('CREDENTIAL_AWS_ACCOUNT_ID'); + if (!empty($awsRegion)) { + if (empty($awsProfile)) { + $awsProfile = null; + } + if (empty($awsId)) { + $awsId = null; + } + try { + $this->credStorage[self::ARRAY_KEY_FOR_AWS_SECRETS_MANAGER] = new AwsSecretsManagerStorage( + $awsRegion, + $awsProfile, + $awsId + ); + } catch (TestFrameworkException $e) { + } + } + } } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/AwsSecretsManagerStorage.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/AwsSecretsManagerStorage.php index 1e58e3bee..bb6044c7f 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/AwsSecretsManagerStorage.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/AwsSecretsManagerStorage.php @@ -115,17 +115,18 @@ public function getEncryptedValue($key) $reValue = openssl_encrypt($value, parent::ENCRYPTION_ALGO, parent::$encodedKey, 0, parent::$iv); parent::$cachedSecretData[$key] = $reValue; } catch (AwsException $e) { - $error = $e->getAwsErrorCode(); + $errMessage = "\nAWS Exception:\n" . $e->getAwsErrorMessage() + . "\nUnable to read value for key {$key} from AWS Secrets Manager\n"; + print_r($errMessage); if (MftfApplicationConfig::getConfig()->verboseEnabled()) { - LoggingUtil::getInstance()->getLogger(AwsSecretsManagerStorage::class)->debug( - "AWS error code: {$error}. Unable to read value for key {$key} from AWS Secrets Manager" - ); + LoggingUtil::getInstance()->getLogger(AwsSecretsManagerStorage::class)->debug($errMessage); } } catch (\Exception $e) { + $errMessage = "\nException:\n" . $e->getMessage() + . "\nUnable to read value for key {$key} from AWS Secrets Manager\n"; + print_r($errMessage); if (MftfApplicationConfig::getConfig()->verboseEnabled()) { - LoggingUtil::getInstance()->getLogger(AwsSecretsManagerStorage::class)->debug( - "Unable to read value for key {$key} from AWS Secrets Manager" - ); + LoggingUtil::getInstance()->getLogger(AwsSecretsManagerStorage::class)->debug($errMessage); } } return $reValue; @@ -145,13 +146,22 @@ private function parseAwsSecretResult($awsResult, $key) if (isset($awsResult['SecretString'])) { $rawSecret = $awsResult['SecretString']; } else { - throw new TestFrameworkException("Error parsing result from AWS Secrets Manager"); + throw new TestFrameworkException( + "'SecretString' field is not set in AWS Result. Error parsing result from AWS Secrets Manager" + ); } + + // Secrets are saved as JSON structures of key/value pairs if using AWS Secrets Manager console, and + // Secrets are saved as plain text if using AWS CLI. We need to handle both cases. $secret = json_decode($rawSecret, true); if (isset($secret[$key])) { return $secret[$key]; + } elseif (is_string($rawSecret)) { + return $rawSecret; } - throw new TestFrameworkException("Error parsing result from AWS Secrets Manager"); + throw new TestFrameworkException( + "$key not found or value is not string . Error parsing result from AWS Secrets Manager" + ); } /** @@ -169,13 +179,17 @@ private function createAwsSecretsManagerClient($region, $profile) return; } - // Create AWS Secrets Manager client - $this->client = new SecretsManagerClient([ - 'profile' => $profile, + $options = [ 'region' => $region, - 'version' => self::LATEST_VERSION - ]); + 'version' => self::LATEST_VERSION, + ]; + if (!empty($profile)) { + $options['profile'] = $profile; + } + + // Create AWS Secrets Manager client + $this->client = new SecretsManagerClient($options); if ($this->client === null) { throw new TestFrameworkException("Unable to create AWS Secrets Manager client"); } From 0331f7eec902b9c04780129c905b30e0416abf2f Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Wed, 22 Jan 2020 09:01:30 -0600 Subject: [PATCH 156/888] MQE-1676: Add a static-check that ensures action groups do not have unused arguments --- .../StaticCheck/StaticChecksList.php | 1 + .../StaticCheck/UnusedArgumentsCheck.php | 212 ++++++++++++++++++ .../Handlers/ActionGroupObjectHandler.php | 5 +- 3 files changed, 216 insertions(+), 2 deletions(-) create mode 100644 src/Magento/FunctionalTestingFramework/StaticCheck/UnusedArgumentsCheck.php diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php b/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php index f3cf20739..83f06225e 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php @@ -29,6 +29,7 @@ public function __construct(array $checks = []) { $this->checks = [ 'testDependencies' => new TestDependencyCheck(), + 'unusedArgumentsCheck' => new UnusedArgumentsCheck(), ] + $checks; } diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/UnusedArgumentsCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/UnusedArgumentsCheck.php new file mode 100644 index 000000000..0dc74171c --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/UnusedArgumentsCheck.php @@ -0,0 +1,212 @@ +initActionGroups(); + + $unusedArgumentList = $this->buildUnusedArgumentList($actionGroups); + + $this->errors += $this->setErrorOutput($unusedArgumentList); + + $this->output = $this->printErrorsToFile(); + + } + + /** + * Return array containing all errors found after running the execute() function. + * @return array + */ + public function getErrors() + { + return $this->errors; + } + + /** + * Return string of a short human readable result of the check. For example: "No unused arguments found." + * @return string + */ + public function getOutput() + { + return $this->output; + } + + /** + * Builds array of action groups => unused arguments + * @param $actionGroups + * @return array + */ + private function buildUnusedArgumentList($actionGroups) { + + $actionGroupToArguments = []; + + foreach ($actionGroups as $actionGroup) { + $unusedArguments = $this->findUnusedArguments($actionGroup); + if(!empty($unusedArguments)) { + $actionGroupToArguments[$actionGroup->getFilename()][$actionGroup->getName()] = $unusedArguments; + } + } + return $actionGroupToArguments; + } + + /** + * Returns unused arguments in an action group. + * @param $actionGroup + * @return array + */ + private function findUnusedArguments($actionGroup) { + + $unusedArguments = []; + //extract all action attribute values + $actionAttributeValues = $this->getAllActionAttributeValues($actionGroup); + $argumentList = $actionGroup->getArguments(); + foreach ($argumentList as $argument) { + $argumentName = $argument->getName(); + //pattern to match all argument references + $pattern = '(.*\.*[\W]+(?getName(); + } + return $unusedArguments; + } + + /** + * Returns array of all action attribute values in an action group. + * @param $actionGroup + * @return array + */ + private function getAllActionAttributeValues($actionGroup) { + + $allAttributeValues = []; + $actions = $actionGroup->getActions(); + foreach ($actions as $action) { + $actionAttributeValues = $this->extractAttributeValues($action); + $allAttributeValues = array_merge($allAttributeValues, $actionAttributeValues); + } + return array_unique($allAttributeValues); + } + + + /** + * Builds and returns flattened attribute value list for an action. + * @param $action + * @return array + */ + private function extractAttributeValues($action) { + + $flattenedAttributeValues = []; + $actionAttributes = $action->getCustomActionAttributes(); + //check if action has nodes eg. expectedResult, actualResult and flatten array + foreach ($actionAttributes as $attributeName => $attributeValue) { + if (is_array($attributeValue)) { + $flattenedAttributeValues = array_merge($flattenedAttributeValues, array_values($attributeValue)); + } + else { + $flattenedAttributeValues[] = $attributeValue; + } + } + return $flattenedAttributeValues; + } + + /** + * Builds and returns error output for unused arguments + * + * @param array $unusedArgumentList + * @return mixed + */ + private function setErrorOutput($unusedArgumentList) + { + $testErrors = []; + + if (!empty($unusedArgumentList)) { + // Build error output + foreach ($unusedArgumentList as $path => $actionGroupToArguments) { + + $errorOutput = "\nFile \"{$path}\""; + $errorOutput .= "\ncontains action group(s) with unused arguments.\n\t\t"; + + foreach ($actionGroupToArguments as $actionGroup => $arguments) { + $errorOutput .= "\n\t {$actionGroup} has unused argument(s): " . implode(", ", $arguments); + } + $testErrors[$path][] = $errorOutput; + } + } + return $testErrors; + } + + /** + * Prints out given errors to file, and returns summary result string + * @return string + */ + private function printErrorsToFile() + { + $errors = $this->getErrors(); + + if (empty($errors)) { + return "No unused arguments found."; + } + + $outputPath = getcwd() . DIRECTORY_SEPARATOR . "mftf-arguments-checks.txt"; + $fileResource = fopen($outputPath, 'w'); + $header = "MFTF ActionGroup Arguments Check:\n"; + fwrite($fileResource, $header); + + foreach ($errors as $test => $error) { + fwrite($fileResource, $error[0] . PHP_EOL); + } + + fclose($fileResource); + $errorCount = count($errors); + $output = "Unused arguments found across {$errorCount} actionGroup(s). Error details output to {$outputPath}"; + + return $output; + } + +} diff --git a/src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php b/src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php index 131ae0a26..91f1f2b0d 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php @@ -99,10 +99,10 @@ public function getAllObjects(): array /** * Method which populates field array with objects from parsed action_group.xml * - * @return void + * @return array * @SuppressWarnings(PHPMD.UnusedPrivateMethod) */ - private function initActionGroups() + public function initActionGroups() { $actionGroupParser = ObjectManagerFactory::getObjectManager()->create(ActionGroupDataParser::class); $parsedActionGroups = $actionGroupParser->readActionGroupData(); @@ -118,6 +118,7 @@ private function initActionGroups() $this->actionGroups[$actionGroupName] = $actionGroupObjectExtractor->extractActionGroup($actionGroupData); } + return $this->actionGroups; } /** From 4a4fc38df8dc59f10a3ee2228a04f8ebad238685 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Wed, 22 Jan 2020 10:59:29 -0600 Subject: [PATCH 157/888] MQE-1676: Add a static-check that ensures action groups do not have unused arguments modified regex, merged develop, fixed static checks --- .../StaticCheck/UnusedArgumentsCheck.php | 45 +++++++++---------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/UnusedArgumentsCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/UnusedArgumentsCheck.php index 0dc74171c..ffec45487 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/UnusedArgumentsCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/UnusedArgumentsCheck.php @@ -8,6 +8,8 @@ use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\Test\Handlers\ActionGroupObjectHandler; +use Magento\FunctionalTestingFramework\Test\Objects\ActionGroupObject; +use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Symfony\Component\Console\Input\InputInterface; use Exception; @@ -35,7 +37,7 @@ class UnusedArgumentsCheck implements StaticCheckInterface * Checks unused arguments in action groups and prints out error to file. * * @param InputInterface $input - * @return string + * @return void * @throws Exception; */ public function execute(InputInterface $input) @@ -55,7 +57,6 @@ public function execute(InputInterface $input) $this->errors += $this->setErrorOutput($unusedArgumentList); $this->output = $this->printErrorsToFile(); - } /** @@ -78,16 +79,16 @@ public function getOutput() /** * Builds array of action groups => unused arguments - * @param $actionGroups - * @return array + * @param array $actionGroups + * @return array $actionGroupToArguments */ - private function buildUnusedArgumentList($actionGroups) { - + private function buildUnusedArgumentList($actionGroups) + { $actionGroupToArguments = []; foreach ($actionGroups as $actionGroup) { $unusedArguments = $this->findUnusedArguments($actionGroup); - if(!empty($unusedArguments)) { + if (!empty($unusedArguments)) { $actionGroupToArguments[$actionGroup->getFilename()][$actionGroup->getName()] = $unusedArguments; } } @@ -96,11 +97,11 @@ private function buildUnusedArgumentList($actionGroups) { /** * Returns unused arguments in an action group. - * @param $actionGroup - * @return array + * @param ActionGroupObject $actionGroup + * @return array $unusedArguments */ - private function findUnusedArguments($actionGroup) { - + private function findUnusedArguments($actionGroup) + { $unusedArguments = []; //extract all action attribute values $actionAttributeValues = $this->getAllActionAttributeValues($actionGroup); @@ -108,7 +109,7 @@ private function findUnusedArguments($actionGroup) { foreach ($argumentList as $argument) { $argumentName = $argument->getName(); //pattern to match all argument references - $pattern = '(.*\.*[\W]+(?getActions(); foreach ($actions as $action) { @@ -133,22 +134,20 @@ private function getAllActionAttributeValues($actionGroup) { return array_unique($allAttributeValues); } - /** * Builds and returns flattened attribute value list for an action. - * @param $action - * @return array + * @param ActionObject $action + * @return array $flattenedAttributeValues */ - private function extractAttributeValues($action) { - + private function extractAttributeValues($action) + { $flattenedAttributeValues = []; $actionAttributes = $action->getCustomActionAttributes(); //check if action has nodes eg. expectedResult, actualResult and flatten array foreach ($actionAttributes as $attributeName => $attributeValue) { if (is_array($attributeValue)) { $flattenedAttributeValues = array_merge($flattenedAttributeValues, array_values($attributeValue)); - } - else { + } else { $flattenedAttributeValues[] = $attributeValue; } } @@ -158,7 +157,7 @@ private function extractAttributeValues($action) { /** * Builds and returns error output for unused arguments * - * @param array $unusedArgumentList + * @param array $unusedArgumentList * @return mixed */ private function setErrorOutput($unusedArgumentList) @@ -168,7 +167,6 @@ private function setErrorOutput($unusedArgumentList) if (!empty($unusedArgumentList)) { // Build error output foreach ($unusedArgumentList as $path => $actionGroupToArguments) { - $errorOutput = "\nFile \"{$path}\""; $errorOutput .= "\ncontains action group(s) with unused arguments.\n\t\t"; @@ -208,5 +206,4 @@ private function printErrorsToFile() return $output; } - } From 58f0da61520522b01f3eadb2161fb4035bdc6435 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Wed, 22 Jan 2020 11:08:57 -0600 Subject: [PATCH 158/888] MQE-1676: Add a static-check that ensures action groups do not have unused arguments Documentation + fixed static checks --- docs/commands/mftf.md | 1 + .../StaticCheck/UnusedArgumentsCheck.php | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 642bbb1bd..bb0cca3fb 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -468,6 +468,7 @@ Runs all MFTF static-checks on the test codebase that MFTF is currently attached #### Existing static checks * Test Dependency: Checks that test dependencies do not violate Magento module's composer dependencies. +* Unused Arguments: Checks that action groups do not have unused arguments. #### Usage diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/UnusedArgumentsCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/UnusedArgumentsCheck.php index ffec45487..b0a20959a 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/UnusedArgumentsCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/UnusedArgumentsCheck.php @@ -120,8 +120,8 @@ private function findUnusedArguments($actionGroup) /** * Returns array of all action attribute values in an action group. - * @param $actionGroup - * @return array + * @param ActionGroupObject $actionGroup + * @return array $allAttributeValues */ private function getAllActionAttributeValues($actionGroup) { From 9bd0651bb39ca7db68fb2a175fdda0c8bb5cac7b Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Wed, 22 Jan 2020 10:55:19 -0600 Subject: [PATCH 159/888] MQE-1959: Static-checks command can be configured --- docs/commands/mftf.md | 29 ++++++- .../Console/StaticChecksCommand.php | 82 +++++++++++++++++-- 2 files changed, 98 insertions(+), 13 deletions(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 642bbb1bd..cf1260b6a 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -463,18 +463,39 @@ The example parameters are taken from the `etc/config/.env.example` file. ### `static-checks` -Runs all MFTF static-checks on the test codebase that MFTF is currently attached to. +Runs all or specific MFTF static-checks on the test codebase that MFTF is currently attached to. +If no script name argument is specified, all existing static check scripts will run. -#### Existing static checks +#### Usage -* Test Dependency: Checks that test dependencies do not violate Magento module's composer dependencies. +```bash +vendor/bin/mftf static-checks []... +``` -#### Usage +#### Examples + +To check what existing static check scripts are available + +```bash +vendor/bin/mftf static-checks --help +``` + +To run all existing static check scripts ```bash vendor/bin/mftf static-checks ``` +To run specific static check scripts + +```bash +vendor/bin/mftf static-checks testDependencies +``` + +#### Existing static checks + +* Test Dependency: Checks that test dependencies do not violate Magento module's composer dependencies. + ### `upgrade:tests` Applies all the MFTF major version upgrade scripts to test components in the given path (`test.xml`, `data.xml`, etc). diff --git a/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php b/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php index 9757f494e..30c9cd600 100644 --- a/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php @@ -8,10 +8,12 @@ namespace Magento\FunctionalTestingFramework\Console; +use Magento\FunctionalTestingFramework\StaticCheck\StaticCheckInterface; use Magento\FunctionalTestingFramework\StaticCheck\StaticChecksList; -use Magento\FunctionalTestingFramework\StaticCheck\StaticCheckListInterface; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Exception; @@ -19,11 +21,18 @@ class StaticChecksCommand extends Command { /** - * Pool of static check scripts to run + * Pool of all existing static check objects * - * @var StaticCheckListInterface + * @var StaticCheckInterface[] */ - private $staticChecksList; + private $allStaticCheckObjects; + + /** + * Static checks to run + * + * @var StaticCheckInterface[] + */ + private $staticCheckObjects; /** * Configures the current command. @@ -32,13 +41,22 @@ class StaticChecksCommand extends Command */ protected function configure() { + $list = new StaticChecksList(); + $this->allStaticCheckObjects = $list->getStaticChecks(); + $staticCheckNames = implode(', ', array_keys($this->allStaticCheckObjects)); + $description = "This command will run all static checks on xml test materials. " + . "Available static check scripts are:\n{$staticCheckNames}"; $this->setName('static-checks') - ->setDescription('This command will run all static checks on xml test materials.'); - $this->staticChecksList = new StaticChecksList(); + ->setDescription($description) + ->addArgument( + 'names', + InputArgument::OPTIONAL | InputArgument::IS_ARRAY, + 'name(s) of specific static check script(s) to run' + ); } /** - * + * Run required static check scripts * * @param InputInterface $input * @param OutputInterface $output @@ -47,11 +65,23 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output) { - $staticCheckObjects = $this->staticChecksList->getStaticChecks(); + try { + $this->validateInputArguments($input, $output); + } catch (InvalidArgumentException $e) { + LoggingUtil::getInstance()->getLogger(StaticChecksCommand::class)->error($e->getMessage()); + $output->writeln($e->getMessage() . " Please fix input arguments and rerun."); + return 1; + } $errors = []; + foreach ($this->staticCheckObjects as $name => $staticCheck) { + LoggingUtil::getInstance()->getLogger(get_class($staticCheck))->info( + "\nRunning static check script for: " . $name + ); + $output->writeln( + "\nRunning static check script for: " . $name + ); - foreach ($staticCheckObjects as $staticCheck) { $staticCheck->execute($input); $staticOutput = $staticCheck->getOutput(); @@ -66,4 +96,38 @@ protected function execute(InputInterface $input, OutputInterface $output) return 1; } } + + /** + * Validate input arguments + * + * @param InputInterface $input + * @return void + * @throws InvalidArgumentException + */ + private function validateInputArguments(InputInterface $input) + { + $this->staticCheckObjects = []; + $requiredChecksNames = $input->getArgument('names'); + $invalidCheckNames = []; + // Found user required static check script(s) to run, + // If no static check name is supplied, run all static check scripts + if (empty($requiredChecksNames)) { + $this->staticCheckObjects = $this->allStaticCheckObjects; + } else { + for ($index = 0; $index < count($requiredChecksNames); $index++) { + if (in_array($requiredChecksNames[$index], array_keys($this->allStaticCheckObjects))) { + $this->staticCheckObjects[$requiredChecksNames[$index]] = + $this->allStaticCheckObjects[$requiredChecksNames[$index]]; + } else { + $invalidCheckNames[] = $requiredChecksNames[$index]; + } + } + } + + if (!empty($invalidCheckNames)) { + throw new InvalidArgumentException( + "Invalid static check script(s): " . implode(', ', $invalidCheckNames) . "." + ); + } + } } From cc3601ae1f9262228a56415a09816fbb18fab024 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Fri, 24 Jan 2020 08:58:35 -0600 Subject: [PATCH 160/888] MQE-1676: Add a static-check that ensures action groups do not have unused arguments Refactoring + added logic to exclude arguments found in parent action group --- ...heck.php => ActionGroupArgumentsCheck.php} | 78 ++++++++++--------- .../StaticCheck/StaticCheckHelper.php | 36 +++++++++ .../StaticCheck/StaticChecksList.php | 2 +- .../StaticCheck/TestDependencyCheck.php | 35 ++------- 4 files changed, 84 insertions(+), 67 deletions(-) rename src/Magento/FunctionalTestingFramework/StaticCheck/{UnusedArgumentsCheck.php => ActionGroupArgumentsCheck.php} (75%) create mode 100644 src/Magento/FunctionalTestingFramework/StaticCheck/StaticCheckHelper.php diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/UnusedArgumentsCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php similarity index 75% rename from src/Magento/FunctionalTestingFramework/StaticCheck/UnusedArgumentsCheck.php rename to src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php index b0a20959a..709d35341 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/UnusedArgumentsCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php @@ -14,12 +14,13 @@ use Exception; /** - * Class UnusedArgumentsCheck + * Class ActionGroupArgumentsCheck * @package Magento\FunctionalTestingFramework\StaticCheck - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class UnusedArgumentsCheck implements StaticCheckInterface +class ActionGroupArgumentsCheck implements StaticCheckInterface { + const ERROR_LOG_FILENAME = 'mftf-arguments-checks'; + const ERROR_LOG_MESSAGE = 'MFTF Unused Arguments Check'; /** * Array containing all errors found after running the execute() function. @@ -38,10 +39,11 @@ class UnusedArgumentsCheck implements StaticCheckInterface * * @param InputInterface $input * @return void - * @throws Exception; + * @throws Exception */ public function execute(InputInterface $input) { + MftfApplicationConfig::create( true, MftfApplicationConfig::UNIT_TEST_PHASE, @@ -56,7 +58,8 @@ public function execute(InputInterface $input) $this->errors += $this->setErrorOutput($unusedArgumentList); - $this->output = $this->printErrorsToFile(); + $this->output = StaticCheckHelper::printErrorsToFile($this->errors, + self::ERROR_LOG_FILENAME, self::ERROR_LOG_MESSAGE); } /** @@ -109,15 +112,45 @@ private function findUnusedArguments($actionGroup) foreach ($argumentList as $argument) { $argumentName = $argument->getName(); //pattern to match all argument references - $pattern = '(.*[\W]+(?getName(); + //exclude arguments that are also defined in parent action group for extending action groups + if ($this->isParentActionGroupArgument($argument, $actionGroup)) { + continue; + } + $unusedArguments[] = $argumentName; } return $unusedArguments; } + /** + * Checks if the argument is also defined in the parent for extending action groups. + * @param string $argument + * @param ActionGroupObject $actionGroup + * @return bool + */ + private function isParentActionGroupArgument($argument, $actionGroup) { + + if ($actionGroup->getParentName() !== null) { + $parentActionGroup = ActionGroupObjectHandler::getInstance()->getObject($actionGroup->getParentName()); + $parentArguments = $parentActionGroup->getArguments(); + if ($parentArguments !== null) { + return in_array($argument, $parentArguments); + } + return false; + } + } + /** * Returns array of all action attribute values in an action group. * @param ActionGroupObject $actionGroup @@ -163,7 +196,6 @@ private function extractAttributeValues($action) private function setErrorOutput($unusedArgumentList) { $testErrors = []; - if (!empty($unusedArgumentList)) { // Build error output foreach ($unusedArgumentList as $path => $actionGroupToArguments) { @@ -178,32 +210,4 @@ private function setErrorOutput($unusedArgumentList) } return $testErrors; } - - /** - * Prints out given errors to file, and returns summary result string - * @return string - */ - private function printErrorsToFile() - { - $errors = $this->getErrors(); - - if (empty($errors)) { - return "No unused arguments found."; - } - - $outputPath = getcwd() . DIRECTORY_SEPARATOR . "mftf-arguments-checks.txt"; - $fileResource = fopen($outputPath, 'w'); - $header = "MFTF ActionGroup Arguments Check:\n"; - fwrite($fileResource, $header); - - foreach ($errors as $test => $error) { - fwrite($fileResource, $error[0] . PHP_EOL); - } - - fclose($fileResource); - $errorCount = count($errors); - $output = "Unused arguments found across {$errorCount} actionGroup(s). Error details output to {$outputPath}"; - - return $output; - } } diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticCheckHelper.php b/src/Magento/FunctionalTestingFramework/StaticCheck/StaticCheckHelper.php new file mode 100644 index 000000000..dc8803ceb --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/StaticCheckHelper.php @@ -0,0 +1,36 @@ + $error) { + fwrite($fileResource, $error[0] . PHP_EOL); + } + + fclose($fileResource); + $errorCount = count($errors); + $output = $message . ": Errors found across {$errorCount} file(s). Error details output to {$outputPath}"; + + return $output; + } +} diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php b/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php index 83f06225e..ffa63389d 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php @@ -29,7 +29,7 @@ public function __construct(array $checks = []) { $this->checks = [ 'testDependencies' => new TestDependencyCheck(), - 'unusedArgumentsCheck' => new UnusedArgumentsCheck(), + 'actionGroupArguments' => new ActionGroupArgumentsCheck(), ] + $checks; } diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php index 19725dc18..dff24b0ed 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php @@ -6,6 +6,7 @@ namespace Magento\FunctionalTestingFramework\StaticCheck; +use Magento\FunctionalTestingFramework\StaticCheck\StaticCheckHelper; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; @@ -32,6 +33,9 @@ class TestDependencyCheck implements StaticCheckInterface const ACTIONGROUP_REGEX_PATTERN = '/ref=["\']([^\'"]*)/'; const ACTIONGROUP_ARGUMENT_REGEX_PATTERN = '/]*name="([^"\']*)/'; + const ERROR_LOG_FILENAME = 'mftf-dependency-checks'; + const ERROR_LOG_MESSAGE = 'MFTF File Dependency Check'; + /** * Array of FullModuleName => [dependencies] * @var array @@ -123,7 +127,8 @@ public function execute(InputInterface $input) $this->errors += $this->findErrorsInFileSet($dataXmlFiles); // hold on to the output and print any errors to a file - $this->output = $this->printErrorsToFile(); + $this->output = StaticCheckHelper::printErrorsToFile($this->errors, + self::ERROR_LOG_FILENAME, self::ERROR_LOG_MESSAGE); } /** @@ -461,32 +466,4 @@ private function findEntity($name) } return null; } - - /** - * Prints out given errors to file, and returns summary result string - * @return string - */ - private function printErrorsToFile() - { - $errors = $this->getErrors(); - - if (empty($errors)) { - return "No Dependency errors found."; - } - - $outputPath = getcwd() . DIRECTORY_SEPARATOR . "mftf-dependency-checks.txt"; - $fileResource = fopen($outputPath, 'w'); - $header = "MFTF File Dependency Check:\n"; - fwrite($fileResource, $header); - - foreach ($errors as $test => $error) { - fwrite($fileResource, $error[0] . PHP_EOL); - } - - fclose($fileResource); - $errorCount = count($errors); - $output = "Dependency errors found across {$errorCount} file(s). Error details output to {$outputPath}"; - - return $output; - } } From 4a306c265d4b29e11c23414f1edb674a51e843a3 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Fri, 24 Jan 2020 09:43:04 -0600 Subject: [PATCH 161/888] MQE-1676: Add a static-check that ensures action groups do not have unused arguments fixing unit tests --- .../StaticCheck/ActionGroupArgumentsCheck.php | 15 +++++++++------ .../StaticCheck/TestDependencyCheck.php | 7 +++++-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php index 709d35341..705b2103d 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php @@ -58,8 +58,11 @@ public function execute(InputInterface $input) $this->errors += $this->setErrorOutput($unusedArgumentList); - $this->output = StaticCheckHelper::printErrorsToFile($this->errors, - self::ERROR_LOG_FILENAME, self::ERROR_LOG_MESSAGE); + $this->output = StaticCheckHelper::printErrorsToFile( + $this->errors, + self::ERROR_LOG_FILENAME, + self::ERROR_LOG_MESSAGE + ); } /** @@ -135,12 +138,12 @@ private function findUnusedArguments($actionGroup) /** * Checks if the argument is also defined in the parent for extending action groups. - * @param string $argument + * @param string $argument * @param ActionGroupObject $actionGroup - * @return bool + * @return boolean */ - private function isParentActionGroupArgument($argument, $actionGroup) { - + private function isParentActionGroupArgument($argument, $actionGroup) + { if ($actionGroup->getParentName() !== null) { $parentActionGroup = ActionGroupObjectHandler::getInstance()->getObject($actionGroup->getParentName()); $parentArguments = $parentActionGroup->getArguments(); diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php index dff24b0ed..2b309c015 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php @@ -127,8 +127,11 @@ public function execute(InputInterface $input) $this->errors += $this->findErrorsInFileSet($dataXmlFiles); // hold on to the output and print any errors to a file - $this->output = StaticCheckHelper::printErrorsToFile($this->errors, - self::ERROR_LOG_FILENAME, self::ERROR_LOG_MESSAGE); + $this->output = StaticCheckHelper::printErrorsToFile( + $this->errors, + self::ERROR_LOG_FILENAME, + self::ERROR_LOG_MESSAGE + ); } /** From f4b2d955f2ab8687b4d92721a5a6fc59196fbc7b Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Fri, 24 Jan 2020 10:04:55 -0600 Subject: [PATCH 162/888] MQE-1676: Add a static-check that ensures action groups do not have unused arguments fixing unit tests --- .../StaticCheck/StaticCheckHelper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticCheckHelper.php b/src/Magento/FunctionalTestingFramework/StaticCheck/StaticCheckHelper.php index dc8803ceb..5e3e8520d 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticCheckHelper.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/StaticCheckHelper.php @@ -9,7 +9,7 @@ class StaticCheckHelper { /** * Prints out given errors to file, and returns summary result string - * @param array $errors + * @param array $errors * @param string $filename * @param string $message * @return string From bb3871940026e5a4adeee8d921f4018ad3722839 Mon Sep 17 00:00:00 2001 From: Ken Hicks <46905350+hickskenh@users.noreply.github.com> Date: Fri, 24 Jan 2020 11:54:58 -0600 Subject: [PATCH 163/888] updated Contribution Guidelines link original .github/CONTRIBUTING.html link produces 404 error. changed link to https://github.com/magento/magento2-functional-testing-framework/blob/develop/.github/CONTRIBUTING.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b95a7afc4..fc42f0603 100755 --- a/README.md +++ b/README.md @@ -70,11 +70,11 @@ See the license [here][] or contact [license@magentocommerce.com][] for a copy. [Getting Started]: docs/getting-started.md -[Contribution Guidelines]: .github/CONTRIBUTING.html +[Contribution Guidelines]: https://github.com/magento/magento2-functional-testing-framework/blob/develop/.github/CONTRIBUTING.md [DevDocs Contributing]: https://github.com/magento/devdocs/blob/master/.github/CONTRIBUTING.md [security@magento.com]: mailto:security@magento.com [encryption key]: https://info2.magento.com/rs/magentoenterprise/images/security_at_magento.asc [here]: https://magento.com/security/reporting-magento-security-issue [Security Alert Notifications]: https://magento.com/security/sign-up [here]: LICENSE_AGPL3.txt -[license@magentocommerce.com]: mailto:license@magentocommerce.com \ No newline at end of file +[license@magentocommerce.com]: mailto:license@magentocommerce.com From 3166af84d0c42039ace17ecd9c09299ebaefee53 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk Date: Fri, 24 Jan 2020 19:24:01 -0600 Subject: [PATCH 164/888] MFTF deprecation notice attributes --- .../MFTF/DevDocs/Section/ContentSection.xml | 1 + .../tests/MFTF/DevDocs/Test/DevDocsTest.xml | 2 +- .../Allure/Adapter/MagentoAllureAdapter.php | 1 + .../Codeception/Subscriber/Console.php | 30 ++++++++++ .../Handlers/DataObjectHandler.php | 13 ++++- .../OperationDefinitionObjectHandler.php | 12 +++- .../Objects/EntityDataObject.php | 30 ++++++++-- .../Objects/OperationDefinitionObject.php | 22 +++++++- .../Persist/DataPersistenceHandler.php | 5 +- .../DataGenerator/Util/DataExtensionUtil.php | 3 +- .../DataGenerator/etc/dataOperation.xsd | 7 +++ .../DataGenerator/etc/dataProfileSchema.xsd | 8 +++ .../Page/Handlers/PageObjectHandler.php | 11 +++- .../Page/Handlers/SectionObjectHandler.php | 29 +++++++++- .../Page/Objects/ElementObject.php | 20 ++++++- .../Page/Objects/PageObject.php | 45 ++++++++++++--- .../Page/Objects/SectionObject.php | 25 ++++++++- .../Page/etc/PageObject.xsd | 8 +++ .../Page/etc/SectionObject.xsd | 14 +++++ .../Suite/etc/suiteSchema.xsd | 7 +++ .../Test/Objects/ActionGroupObject.php | 55 ++++++++++++++++--- .../Test/Objects/ActionObject.php | 47 ++++++++++++++-- .../Test/Util/ActionGroupObjectExtractor.php | 16 +++++- .../Test/Util/ActionMergeUtil.php | 3 +- .../Test/Util/TestObjectExtractor.php | 39 +++++++++---- .../Test/etc/actionGroupSchema.xsd | 7 +++ .../Test/etc/mergedTestSchema.xsd | 7 +++ .../Util/TestGenerator.php | 46 +++++++++++++++- 28 files changed, 452 insertions(+), 61 deletions(-) diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Section/ContentSection.xml b/dev/tests/functional/tests/MFTF/DevDocs/Section/ContentSection.xml index cf82b69e9..15af0fa39 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Section/ContentSection.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/Section/ContentSection.xml @@ -10,5 +10,6 @@ xsi:noNamespaceSchemaLocation="../../../../../../../src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd">
+
diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml b/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml index 3bdeeb9e8..c6b2575b9 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml @@ -21,6 +21,6 @@ - +
diff --git a/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php b/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php index e9e1c344c..97335726a 100644 --- a/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php +++ b/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php @@ -5,6 +5,7 @@ */ namespace Magento\FunctionalTestingFramework\Allure\Adapter; +use Codeception\Event\TestEvent; use Codeception\Step\Comment; use Magento\FunctionalTestingFramework\Suite\Handlers\SuiteObjectHandler; use Magento\FunctionalTestingFramework\Test\Objects\ActionGroupObject; diff --git a/src/Magento/FunctionalTestingFramework/Codeception/Subscriber/Console.php b/src/Magento/FunctionalTestingFramework/Codeception/Subscriber/Console.php index 8c50f0670..01b385133 100644 --- a/src/Magento/FunctionalTestingFramework/Codeception/Subscriber/Console.php +++ b/src/Magento/FunctionalTestingFramework/Codeception/Subscriber/Console.php @@ -7,17 +7,24 @@ namespace Magento\FunctionalTestingFramework\Codeception\Subscriber; use Codeception\Event\StepEvent; +use Codeception\Event\TestEvent; use Codeception\Lib\Console\Message; use Codeception\Step; use Codeception\Step\Comment; use Codeception\Test\Interfaces\ScenarioDriven; use Magento\FunctionalTestingFramework\Test\Objects\ActionGroupObject; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; +use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; use Magento\FunctionalTestingFramework\Util\TestGenerator; use Symfony\Component\Console\Formatter\OutputFormatter; class Console extends \Codeception\Subscriber\Console { + /** + * Regular expresion to find deprecated notices. + */ + const DEPRECATED_NOTICE = '/
  • (?.*?)<\/li>/m'; + /** * Test files cache. * @@ -53,6 +60,29 @@ public function __construct($extensionOptions = [], $options = []) parent::__construct($options); } + public function startTest(TestEvent $e) + { + $test = $e->getTest()->getTestClass(); + try { + $testReflection = new \ReflectionClass($test); + $isDeprecated = preg_match_all(self::DEPRECATED_NOTICE, $testReflection->getDocComment(), $match); + if ($isDeprecated) { + $this->message('DEPRECATION NOTICE(S): ') + ->style('debug') + ->writeln(); + foreach ($match['deprecatedMessage'] as $deprecatedMessage) { + $this->message(' - ' . $deprecatedMessage) + ->style('debug') + ->writeln(); + } + } + } catch (\ReflectionException $e) { + LoggingUtil::getInstance()->getLogger(self::class)->error($e->getMessage(), $e->getTrace()); + } + + return parent::startTest($e); + } + /** * Printing stepKey in before step action. * diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php index 95a2b8b93..0a7ae8ff2 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php @@ -13,6 +13,8 @@ use Magento\FunctionalTestingFramework\ObjectManager\ObjectHandlerInterface; use Magento\FunctionalTestingFramework\ObjectManagerFactory; use Magento\FunctionalTestingFramework\DataGenerator\Util\DataExtensionUtil; +use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; +use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; class DataObjectHandler implements ObjectHandlerInterface { @@ -163,6 +165,14 @@ private function processParserOutput($parserOutput) $parentEntity = $rawEntity[self::_EXTENDS]; } + if (array_key_exists('deprecated', $rawEntity)) { + $deprecated = $rawEntity['deprecated']; + LoggingUtil::getInstance()->getLogger(self::class)->deprecation( + $deprecated, + ["dataName" => $filename, "deprecatedEntity" => $deprecated] + ); + } + $entityDataObject = new EntityDataObject( $name, $type, @@ -171,7 +181,8 @@ private function processParserOutput($parserOutput) $uniquenessData, $vars, $parentEntity, - $filename + $filename, + $deprecated ); $entityDataObjects[$entityDataObject->getName()] = $entityDataObject; diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php index b768d9bd8..7fbfe0be7 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php @@ -11,6 +11,7 @@ use Magento\FunctionalTestingFramework\DataGenerator\Util\OperationElementExtractor; use Magento\FunctionalTestingFramework\ObjectManager\ObjectHandlerInterface; use Magento\FunctionalTestingFramework\ObjectManagerFactory; +use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; class OperationDefinitionObjectHandler implements ObjectHandlerInterface { @@ -145,6 +146,7 @@ private function initialize() $auth = $opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH] ?? null; $successRegex = $opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_SUCCESS_REGEX] ?? null; $returnRegex = $opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_RETURN_REGEX] ?? null; + $deprecated = $opDefArray['deprecated'] ?? null; $returnIndex = $opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_RETURN_INDEX] ?? 0; $contentType = $opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_CONTENT_TYPE][0]['value'] ?? null; @@ -205,6 +207,13 @@ private function initialize() } } + if ($deprecated !== null) { + LoggingUtil::getInstance()->getLogger(self::class)->deprecation( + $deprecated, + ["operationName" => $dataDefName, "deprecatedOperation" => $deprecated] + ); + } + $this->operationDefinitionObjects[$operation . $dataType] = new OperationDefinitionObject( $dataDefName, $operation, @@ -219,7 +228,8 @@ private function initialize() $removeBackend, $successRegex, $returnRegex, - $returnIndex + $returnIndex, + $deprecated ); } } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/EntityDataObject.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/EntityDataObject.php index 47a966f84..a41ee03d8 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/EntityDataObject.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/EntityDataObject.php @@ -80,17 +80,25 @@ class EntityDataObject */ private $filename; + /** + * Deprecated message. + * + * @var string + */ + private $deprecated; + /** * Constructor * - * @param string $name - * @param string $type + * @param string $name + * @param string $type * @param string[] $data * @param string[] $linkedEntities * @param string[] $uniquenessData * @param string[] $vars - * @param string $parentEntity - * @param string $filename + * @param string $parentEntity + * @param string $filename + * @param string|null $deprecated */ public function __construct( $name, @@ -100,7 +108,8 @@ public function __construct( $uniquenessData, $vars = [], $parentEntity = null, - $filename = null + $filename = null, + $deprecated = null ) { $this->name = $name; $this->type = $type; @@ -113,6 +122,17 @@ public function __construct( $this->vars = $vars; $this->parentEntity = $parentEntity; $this->filename = $filename; + $this->deprecated = $deprecated; + } + + /** + * Getter for the deprecated attr of the section. + * + * @return string + */ + public function getDeprecated() + { + return $this->deprecated; } /** diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/OperationDefinitionObject.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/OperationDefinitionObject.php index 721a9dcc9..a294ea1fd 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/OperationDefinitionObject.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/OperationDefinitionObject.php @@ -117,6 +117,13 @@ class OperationDefinitionObject */ private $removeBackend; + /** + * Deprecated message. + * + * @var string + */ + private $deprecated; + /** * OperationDefinitionObject constructor. * @param string $name @@ -133,6 +140,7 @@ class OperationDefinitionObject * @param string $successRegex * @param string $returnRegex * @param string $returnIndex + * @param string|null $deprecated * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -149,7 +157,8 @@ public function __construct( $removeBackend, $successRegex = null, $returnRegex = null, - $returnIndex = null + $returnIndex = null, + $deprecated = null ) { $this->name = $name; $this->operation = $operation; @@ -164,6 +173,7 @@ public function __construct( $this->returnRegex = $returnRegex; $this->returnIndex = $returnIndex; $this->removeBackend = $removeBackend; + $this->deprecated = $deprecated; $this->apiUrl = null; if (!empty($contentType)) { @@ -176,6 +186,16 @@ public function __construct( $this->headers[] = self::HTTP_CONTENT_TYPE_HEADER . ': ' . $this->contentType; } + /** + * Getter for the deprecated attr of the section + * + * @return string + */ + public function getDeprecated() + { + return $this->deprecated; + } + /** * Getter for data's data type * diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/DataPersistenceHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/DataPersistenceHandler.php index dcb9d158a..73ee2be19 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/DataPersistenceHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/DataPersistenceHandler.php @@ -59,7 +59,10 @@ public function __construct($entityObject, $dependentObjects = [], $customFields array_merge($entityObject->getAllData(), $customFields), $entityObject->getLinkedEntities(), $this->stripCustomFieldsFromUniquenessData($entityObject->getUniquenessData(), $customFields), - $entityObject->getVarReferences() + $entityObject->getVarReferences(), + $entityObject->getParentName(), + $entityObject->getFilename(), + $entityObject->getDeprecated() ); } else { $this->entityObject = clone $entityObject; diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Util/DataExtensionUtil.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Util/DataExtensionUtil.php index 2766b39a0..3a12bdce1 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Util/DataExtensionUtil.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Util/DataExtensionUtil.php @@ -93,7 +93,8 @@ public function extendEntity($entityObject) $newUniqueReferences, $newVarReferences, $entityObject->getParentName(), - $entityObject->getFilename() + $entityObject->getFilename(), + $entityObject->getDeprecated() ); return $extendedEntity; } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd b/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd index 8b59ccae0..58fad8d8b 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd @@ -22,6 +22,13 @@ + + + + Message and flag which shows that entity is deprecated. + + + diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd b/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd index aec157309..9d0d8bb35 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd @@ -69,6 +69,14 @@ + + + + Message and flag which shows that entity is deprecated. + + + + diff --git a/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php b/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php index d9eec1af1..a9c3b7cfb 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php @@ -9,6 +9,7 @@ use Magento\FunctionalTestingFramework\ObjectManager\ObjectHandlerInterface; use Magento\FunctionalTestingFramework\ObjectManagerFactory; use Magento\FunctionalTestingFramework\Page\Objects\PageObject; +use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; use Magento\FunctionalTestingFramework\XmlParser\PageParser; use Magento\FunctionalTestingFramework\Exceptions\XmlException; @@ -68,9 +69,17 @@ private function __construct() $sectionNames = array_keys($pageData[self::SECTION] ?? []); $parameterized = $pageData[self::PARAMETERIZED] ?? false; $filename = $pageData[self::FILENAME] ?? null; + $deprecated = $pageData['deprecated'] ?? null; + + if ($deprecated !== null) { + LoggingUtil::getInstance()->getLogger(self::class)->deprecation( + $deprecated, + ["pageName" => $filename, "deprecatedPage" => $deprecated] + ); + } $this->pageObjects[$pageName] = - new PageObject($pageName, $url, $module, $sectionNames, $parameterized, $area, $filename); + new PageObject($pageName, $url, $module, $sectionNames, $parameterized, $area, $filename, $deprecated); } } diff --git a/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php b/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php index e77e4c502..a827eac22 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php @@ -10,6 +10,8 @@ use Magento\FunctionalTestingFramework\ObjectManagerFactory; use Magento\FunctionalTestingFramework\Page\Objects\ElementObject; use Magento\FunctionalTestingFramework\Page\Objects\SectionObject; +use Magento\FunctionalTestingFramework\Test\Util\TestObjectExtractor; +use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; use Magento\FunctionalTestingFramework\XmlParser\SectionParser; use Magento\FunctionalTestingFramework\Exceptions\XmlException; @@ -73,14 +75,21 @@ private function __construct() $elementLocatorFunc = $elementData[SectionObjectHandler::LOCATOR_FUNCTION] ?? null; $elementTimeout = $elementData[SectionObjectHandler::TIMEOUT] ?? null; $elementParameterized = $elementData[SectionObjectHandler::PARAMETERIZED] ?? false; - + $elementDeprecated = $elementData['deprecated'] ?? null; + if ($elementDeprecated !== null) { + LoggingUtil::getInstance()->getLogger(ElementObject::class)->deprecation( + $elementDeprecated, + ["elementName" => $elementName, "deprecatedElement" => $elementDeprecated] + ); + } $elements[$elementName] = new ElementObject( $elementName, $elementType, $elementSelector, $elementLocatorFunc, $elementTimeout, - $elementParameterized + $elementParameterized, + $elementDeprecated ); } } catch (XmlException $exception) { @@ -88,7 +97,21 @@ private function __construct() } $filename = $sectionData[self::FILENAME] ?? null; - $this->sectionObjects[$sectionName] = new SectionObject($sectionName, $elements, $filename); + $sectionDeprecated = $sectionData['deprecated'] ?? null; + + if ($sectionDeprecated !== null) { + LoggingUtil::getInstance()->getLogger(ElementObject::class)->deprecation( + $sectionDeprecated, + ["sectionName" => $filename, "deprecatedSection" => $sectionDeprecated] + ); + } + + $this->sectionObjects[$sectionName] = new SectionObject( + $sectionName, + $elements, + $filename, + $sectionDeprecated + ); } } diff --git a/src/Magento/FunctionalTestingFramework/Page/Objects/ElementObject.php b/src/Magento/FunctionalTestingFramework/Page/Objects/ElementObject.php index 6b0626f10..567872fc7 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Objects/ElementObject.php +++ b/src/Magento/FunctionalTestingFramework/Page/Objects/ElementObject.php @@ -56,6 +56,13 @@ class ElementObject */ private $parameterized; + /** + * Deprecated message. + * + * @var string + */ + private $deprecated; + /** * ElementObject constructor. * @param string $name @@ -66,7 +73,7 @@ class ElementObject * @param boolean $parameterized * @throws XmlException */ - public function __construct($name, $type, $selector, $locatorFunction, $timeout, $parameterized) + public function __construct($name, $type, $selector, $locatorFunction, $timeout, $parameterized, $deprecated = null) { if ($selector != null && $locatorFunction != null) { throw new XmlException("Element '{$name}' cannot have both a selector and a locatorFunction."); @@ -83,6 +90,17 @@ public function __construct($name, $type, $selector, $locatorFunction, $timeout, } $this->timeout = $timeout; $this->parameterized = $parameterized; + $this->deprecated = $deprecated; + } + + /** + * Getter for the deprecated attr + * + * @return string + */ + public function getDeprecated() + { + return $this->deprecated; } /** diff --git a/src/Magento/FunctionalTestingFramework/Page/Objects/PageObject.php b/src/Magento/FunctionalTestingFramework/Page/Objects/PageObject.php index d99c40240..19525a415 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Objects/PageObject.php +++ b/src/Magento/FunctionalTestingFramework/Page/Objects/PageObject.php @@ -65,18 +65,34 @@ class PageObject */ private $filename; + /** + * Deprecated message. + * + * @var string + */ + private $deprecated; + /** * PageObject constructor. - * @param string $name - * @param string $url - * @param string $module - * @param array $sections + * @param string $name + * @param string $url + * @param string $module + * @param array $sections * @param boolean $parameterized - * @param string $area - * @param string $filename - */ - public function __construct($name, $url, $module, $sections, $parameterized, $area, $filename = null) - { + * @param string $area + * @param string|null $filename + * @param string|null $deprecated + */ + public function __construct( + $name, + $url, + $module, + $sections, + $parameterized, + $area, + $filename = null, + $deprecated = null + ) { $this->name = $name; $this->url = $url; $this->module = $module; @@ -84,6 +100,17 @@ public function __construct($name, $url, $module, $sections, $parameterized, $ar $this->parameterized = $parameterized; $this->area = $area; $this->filename = $filename; + $this->deprecated = $deprecated; + } + + /** + * Getter for the deprecated attr of the section + * + * @return string + */ + public function getDeprecated() + { + return $this->deprecated; } /** diff --git a/src/Magento/FunctionalTestingFramework/Page/Objects/SectionObject.php b/src/Magento/FunctionalTestingFramework/Page/Objects/SectionObject.php index 8c1cac326..57883e393 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Objects/SectionObject.php +++ b/src/Magento/FunctionalTestingFramework/Page/Objects/SectionObject.php @@ -32,17 +32,26 @@ class SectionObject */ private $filename; + /** + * Deprecated message. + * + * @var string + */ + private $deprecated; + /** * SectionObject constructor. * @param string $name - * @param array $elements - * @param string $filename + * @param array $elements + * @param string|null $filename + * @param string|null $deprecated */ - public function __construct($name, $elements, $filename = null) + public function __construct($name, $elements, $filename = null, $deprecated = null) { $this->name = $name; $this->elements = $elements; $this->filename = $filename; + $this->deprecated = $deprecated; } /** @@ -55,6 +64,16 @@ public function getName() return $this->name; } + /** + * Getter for the deprecated attr of the section + * + * @return string + */ + public function getDeprecated() + { + return $this->deprecated; + } + /** * Getter for the Section Filename * diff --git a/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd b/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd index c6f399a67..65ac8290d 100644 --- a/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd +++ b/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd @@ -48,6 +48,14 @@ + + + + Message and flag which shows that entity is deprecated. + + + + diff --git a/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd b/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd index 44e057369..1b5b44ddd 100644 --- a/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd +++ b/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd @@ -44,6 +44,13 @@ + + + + Message and flag which shows that entity is deprecated. + + + @@ -58,6 +65,13 @@ + + + + Message and flag which shows that entity is deprecated. + + + diff --git a/src/Magento/FunctionalTestingFramework/Suite/etc/suiteSchema.xsd b/src/Magento/FunctionalTestingFramework/Suite/etc/suiteSchema.xsd index 34ef37594..b36e35517 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/etc/suiteSchema.xsd +++ b/src/Magento/FunctionalTestingFramework/Suite/etc/suiteSchema.xsd @@ -61,6 +61,13 @@ + + + + Message and flag which shows that entity is deprecated. + + + diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php index fc38a7fce..1a1e93dab 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php @@ -94,18 +94,33 @@ class ActionGroupObject */ private $cachedStepKeys = null; + /** + * Deprecation message. + * + * @var string|null + */ + private $deprecated; + /** * ActionGroupObject constructor. * - * @param string $name - * @param array $annotations + * @param string $name + * @param array $annotations * @param ArgumentObject[] $arguments - * @param array $actions - * @param string $parentActionGroup - * @param string $filename + * @param array $actions + * @param string $parentActionGroup + * @param string $filename + * @param $deprecated */ - public function __construct($name, $annotations, $arguments, $actions, $parentActionGroup, $filename = null) - { + public function __construct( + $name, + $annotations, + $arguments, + $actions, + $parentActionGroup, + $filename = null, + $deprecated = null + ) { $this->varAttributes = array_merge( ActionObject::SELECTOR_ENABLED_ATTRIBUTES, ActionObject::DATA_ENABLED_ATTRIBUTES @@ -117,6 +132,17 @@ public function __construct($name, $annotations, $arguments, $actions, $parentAc $this->parsedActions = $actions; $this->parentActionGroup = $parentActionGroup; $this->filename = $filename; + $this->deprecated = $deprecated; + } + + /** + * Returns deprecated messages. + * + * @return string|null + */ + public function getDeprecated() + { + return $this->deprecated; } /** @@ -213,7 +239,8 @@ private function getResolvedActionsWithArgs($arguments, $actionReferenceKey) $action->getLinkedAction() == null ? null : $action->getLinkedAction() . ucfirst($actionReferenceKey), $orderOffset, [self::ACTION_GROUP_ORIGIN_NAME => $this->name, - self::ACTION_GROUP_ORIGIN_TEST_REF => $actionReferenceKey] + self::ACTION_GROUP_ORIGIN_TEST_REF => $actionReferenceKey], + $action->getDeprecatedUsages() ); } @@ -543,10 +570,20 @@ private function addContextCommentsToActionList($actionList, $actionReferenceKey { $actionStartComment = self::ACTION_GROUP_CONTEXT_START . "[" . $actionReferenceKey . "] " . $this->name; $actionEndComment = self::ACTION_GROUP_CONTEXT_END . "[" . $actionReferenceKey . "] " . $this->name; + + $deprecationNotices = []; + if ($this->getDeprecated() !== null) { + $deprecationNotices[] = "DEPRECATED ACTION GROUP in Test: " . $this->name . ' ' . $this->getDeprecated(); + } + $startAction = new ActionObject( $actionStartComment, ActionObject::ACTION_TYPE_COMMENT, - [ActionObject::ACTION_ATTRIBUTE_USERINPUT => $actionStartComment] + [ActionObject::ACTION_ATTRIBUTE_USERINPUT => $actionStartComment], + null, + ActionObject::MERGE_ACTION_ORDER_BEFORE, + null, + $deprecationNotices ); $endAction = new ActionObject( $actionEndComment, diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php index 53743330e..207d05bc7 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php @@ -84,6 +84,14 @@ class ActionObject */ private $stepKey; + + /** + * Array of deprecated entities used in action. + * + * @var array + */ + private $deprecatedUsage = []; + /** * The type of action (e.g. fillField, createData, etc) * @@ -136,12 +144,13 @@ class ActionObject /** * ActionObject constructor. * - * @param string $stepKey - * @param string $type - * @param array $actionAttributes + * @param string $stepKey + * @param string $type + * @param array $actionAttributes * @param string|null $linkedAction - * @param string $order - * @param array $actionOrigin + * @param string $order + * @param array $actionOrigin + * @param array $deprecatedUsage */ public function __construct( $stepKey, @@ -149,13 +158,15 @@ public function __construct( $actionAttributes, $linkedAction = null, $order = ActionObject::MERGE_ACTION_ORDER_BEFORE, - $actionOrigin = null + $actionOrigin = null, + $deprecatedUsage = [] ) { $this->stepKey = $stepKey; $this->type = $type === self::COMMENT_ACTION ? self::ACTION_TYPE_COMMENT : $type; $this->actionAttributes = $actionAttributes; $this->linkedAction = $linkedAction; $this->actionOrigin = $actionOrigin; + $this->deprecatedUsage = $deprecatedUsage; if ($order === ActionObject::MERGE_ACTION_ORDER_AFTER) { $this->orderOffset = 1; @@ -534,11 +545,18 @@ private function findAndReplaceReferences($objectHandler, $inputString) $replacement = null; $parameterized = false; } elseif (get_class($obj) == PageObject::class) { + if ($obj->getDeprecated() !== null) { + $this->deprecatedUsage[] = "DEPRECATED PAGE in Test: " . $match . ' ' . $obj->getDeprecated(); + } $this->validateUrlAreaAgainstActionType($obj); $replacement = $obj->getUrl(); $parameterized = $obj->isParameterized(); } elseif (get_class($obj) == SectionObject::class) { + if ($obj->getDeprecated() !== null) { + $this->deprecatedUsage[] = "DEPRECATED SECTION in Test: " . $match . ' ' . $obj->getDeprecated(); + } list(,$objField) = $this->stripAndSplitReference($match); + if ($obj->getElement($objField) == null) { throw new TestReferenceException( "Could not resolve entity reference \"{$inputString}\" " @@ -549,7 +567,14 @@ private function findAndReplaceReferences($objectHandler, $inputString) $parameterized = $obj->getElement($objField)->isParameterized(); $replacement = $obj->getElement($objField)->getPrioritizedSelector(); $this->setTimeout($obj->getElement($objField)->getTimeout()); + if ($obj->getElement($objField)->getDeprecated() !== null) { + $this->deprecatedUsage[] = "DEPRECATED ELEMENT in Test: " . $match . ' ' + . $obj->getElement($objField)->getDeprecated(); + } } elseif (get_class($obj) == EntityDataObject::class) { + if ($obj->getDeprecated() !== null) { + $this->deprecatedUsage[] = "DEPRECATED DATA ENTITY in Test: " . $match . ' ' . $obj->getDeprecated(); + } $replacement = $this->resolveEntityDataObjectReference($obj, $match); if (is_array($replacement)) { @@ -766,4 +791,14 @@ private function checkParameterCount($matches, $parameters, $reference) ); } } + + /** + * Returns array of deprecated usages in Action. + * + * @return array + */ + public function getDeprecatedUsages() + { + return $this->deprecatedUsage; + } } diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/ActionGroupObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/ActionGroupObjectExtractor.php index e41329cb3..0b606c6d8 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/ActionGroupObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/ActionGroupObjectExtractor.php @@ -11,6 +11,8 @@ use Magento\FunctionalTestingFramework\Test\Objects\ActionGroupObject; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Magento\FunctionalTestingFramework\Test\Objects\ArgumentObject; +use Magento\FunctionalTestingFramework\Test\Objects\TestObject; +use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; /** * Class ActionGroupObjectExtractor @@ -58,7 +60,15 @@ public function __construct() public function extractActionGroup($actionGroupData) { $arguments = []; + $deprecated = null; + if (array_key_exists('deprecated', $actionGroupData)) { + $deprecated = $actionGroupData['deprecated']; + LoggingUtil::getInstance()->getLogger(ActionGroupObject::class)->deprecation( + $deprecated, + ["actionGroupName" => $actionGroupData[self::FILENAME], "deprecatedActionGroup" => $deprecated] + ); + } $actionGroupReference = $actionGroupData[self::EXTENDS_ACTION_GROUP] ?? null; $actionData = $this->stripDescriptorTags( $actionGroupData, @@ -69,7 +79,8 @@ public function extractActionGroup($actionGroupData) self::FILENAME, self::ACTION_GROUP_INSERT_BEFORE, self::ACTION_GROUP_INSERT_AFTER, - self::EXTENDS_ACTION_GROUP + self::EXTENDS_ACTION_GROUP, + 'deprecated' ); // TODO filename is now available to the ActionGroupObject, integrate this into debug and error statements @@ -99,7 +110,8 @@ public function extractActionGroup($actionGroupData) $arguments, $actions, $actionGroupReference, - $actionGroupData[self::FILENAME] + $actionGroupData[self::FILENAME], + $deprecated ); } diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/ActionMergeUtil.php b/src/Magento/FunctionalTestingFramework/Test/Util/ActionMergeUtil.php index cd81ade24..159822db1 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/ActionMergeUtil.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/ActionMergeUtil.php @@ -128,7 +128,8 @@ private function resolveSecretFieldAccess($resolvedActions) $action->getCustomActionAttributes(), $action->getLinkedAction(), $action->getOrderOffset(), - $action->getActionOrigin() + $action->getActionOrigin(), + $action->getDeprecatedUsages() ); $actions[$action->getStepKey()] = $action; diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php index d5420e355..c55e35b9a 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php @@ -8,8 +8,10 @@ use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Exceptions\XmlException; +use Magento\FunctionalTestingFramework\Page\Objects\ElementObject; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; +use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; use Magento\FunctionalTestingFramework\Util\ModulePathExtractor; use Magento\FunctionalTestingFramework\Util\Validation\NameValidationUtil; @@ -19,6 +21,7 @@ class TestObjectExtractor extends BaseObjectExtractor { const TEST_ANNOTATIONS = 'annotations'; + const TEST_DEPRECATED = 'deprecated'; const TEST_BEFORE_HOOK = 'before'; const TEST_AFTER_HOOK = 'after'; const TEST_FAILED_HOOK = 'failed'; @@ -95,7 +98,8 @@ public function extractTestData($testData) $fileNames = explode(",", $filename); $baseFileName = $fileNames[0]; $module = $this->modulePathExtractor->extractModuleName($baseFileName); - $testReference = $testData['extends'] ?? null; + $testReference = $testData['extends'] ?? null; + $deprecated = isset($testData[self::TEST_DEPRECATED]) ? $testData[self::TEST_DEPRECATED] : null; $testActions = $this->stripDescriptorTags( $testData, self::NODE_NAME, @@ -107,6 +111,7 @@ public function extractTestData($testData) self::TEST_INSERT_BEFORE, self::TEST_INSERT_AFTER, self::TEST_FILENAME, + self::TEST_DEPRECATED, 'extends' ); @@ -122,12 +127,19 @@ public function extractTestData($testData) // when $fileNames is not available if (!isset($testAnnotations["description"])) { $testAnnotations["description"] = []; + } else { + $testAnnotations["description"]['main'] = $testAnnotations["description"][0]; + unset($testAnnotations["description"][0]); + } + $testAnnotations["description"]['test_files'] = $this->appendFileNamesInDescriptionAnnotation($fileNames); + + if ($deprecated !== null) { + $testAnnotations["description"][self::TEST_DEPRECATED][] = $deprecated; + LoggingUtil::getInstance()->getLogger(TestObject::class)->deprecation( + $deprecated, + ["testName" => $filename, "deprecatedTest" => $deprecated] + ); } - $description = $testAnnotations["description"][0] ?? ''; - $testAnnotations["description"][0] = $this->appendFileNamesInDescriptionAnnotation( - $description, - $fileNames - ); // extract before if (array_key_exists(self::TEST_BEFORE_HOOK, $testData) && is_array($testData[self::TEST_BEFORE_HOOK])) { @@ -152,6 +164,10 @@ public function extractTestData($testData) ); } + if (!empty($testData[self::TEST_DEPRECATED])) { + $testAnnotations[self::TEST_DEPRECATED] = $testData[self::TEST_DEPRECATED]; + } + // TODO extract filename info and store try { return new TestObject( @@ -170,14 +186,13 @@ public function extractTestData($testData) /** * Append names of test files, including merge files, in description annotation * - * @param string $description - * @param array $fileNames + * @param array $fileNames * * @return string */ - private function appendFileNamesInDescriptionAnnotation($description, $fileNames) + private function appendFileNamesInDescriptionAnnotation(array $fileNames) { - $description .= '

    Test files

    '; + $filePaths = '

    Test files

    '; foreach ($fileNames as $fileName) { if (!empty($fileName) && realpath($fileName) !== false) { @@ -187,11 +202,11 @@ private function appendFileNamesInDescriptionAnnotation($description, $fileNames DIRECTORY_SEPARATOR ); if (!empty($relativeFileName)) { - $description .= $relativeFileName . '
    '; + $filePaths .= $relativeFileName . '
    '; } } } - return $description; + return $filePaths; } } diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd index 6e9e798f1..bd32ba879 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd @@ -43,6 +43,13 @@ + + + + Message and flag which shows that entity is deprecated. + + +
    diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/mergedTestSchema.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/mergedTestSchema.xsd index fe45945ee..6ded366bb 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/mergedTestSchema.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/mergedTestSchema.xsd @@ -86,6 +86,13 @@ + + + + Message and flag which shows that entity is deprecated. + + + diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index c67d8288f..e16c4cde6 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -112,6 +112,13 @@ class TestGenerator */ private $currentGenerationScope = TestGenerator::TEST_SCOPE; + /** + * Test deprecation messages. + * + * @var array + */ + private $deprecationMessages = []; + /** * Private constructor for Factory * @@ -244,7 +251,6 @@ public function createAllTestFiles($testManifest = null, $testsToIgnore = null) public function assembleTestPhp($testObject) { $usePhp = $this->generateUseStatementsPhp(); - $classAnnotationsPhp = $this->generateAnnotationsPhp($testObject->getAnnotations()); $className = $testObject->getCodeceptionName(); try { @@ -257,6 +263,7 @@ public function assembleTestPhp($testObject) } catch (TestReferenceException $e) { throw new TestReferenceException($e->getMessage() . "\n" . $testObject->getFilename()); } + $classAnnotationsPhp = $this->generateAnnotationsPhp($testObject->getAnnotations()); $cestPhp = "exportDirName . "\Backend;\n\n"; @@ -456,7 +463,7 @@ private function generateMethodAnnotations($annotationType = null, $annotationNa * Method which return formatted class level annotations based on type and name(s). * * @param string $annotationType - * @param string $annotationName + * @param array $annotationName * @return null|string * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ @@ -470,7 +477,8 @@ private function generateClassAnnotations($annotationType, $annotationName) break; case "description": - $annotationToAppend = sprintf(" * @Description(\"%s\")\n", $annotationName[0]); + $template = " * @Description(\"%s\")\n"; + $annotationToAppend = sprintf($template, $this->generateDescriptionAnnotation($annotationName)); break; case "testCaseId": @@ -491,6 +499,36 @@ private function generateClassAnnotations($annotationType, $annotationName) return $annotationToAppend; } + /** + * Generates Description + * + * @param array $descriptions + * @return string + */ + private function generateDescriptionAnnotation(array $descriptions) + { + $descriptionText = ""; + + $descriptionText .= $descriptions["main"]; + if (!empty($descriptions[TestObjectExtractor::TEST_DEPRECATED])) { + $deprecatedMessages = array_merge( + $descriptions[TestObjectExtractor::TEST_DEPRECATED], + $this->deprecationMessages + ); + + $descriptionText .= "

    Deprecated Notice(s):

    "; + $descriptionText .= "
      "; + + foreach ($deprecatedMessages as $deprecatedMessage) { + $descriptionText .= "
    • " . $deprecatedMessage . "
    • "; + } + $descriptionText .= "
    "; + } + $descriptionText .= $descriptions["test_files"]; + + return $descriptionText; + } + /** * Creates a PHP string for the actions contained withing a block. * Since nearly half of all Codeception methods don't share the same signature I had to setup a massive Case @@ -511,8 +549,10 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $testSteps = ''; $this->actor = $actor; $this->currentGenerationScope = $generationScope; + $this->deprecationMessages = []; foreach ($actionObjects as $actionObject) { + $this->deprecationMessages = array_merge($this->deprecationMessages, $actionObject->getDeprecatedUsages()); $stepKey = $actionObject->getStepKey(); $customActionAttributes = $actionObject->getCustomActionAttributes(); $attribute = null; From ffbde82ea8a3139701fe7f1bf1531d5424f190f2 Mon Sep 17 00:00:00 2001 From: Ajith Date: Sun, 26 Jan 2020 00:49:37 +0530 Subject: [PATCH 165/888] Example added for grapValueFrom element --- docs/data.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/data.md b/docs/data.md index 2a1b845d4..df3e89479 100644 --- a/docs/data.md +++ b/docs/data.md @@ -85,6 +85,16 @@ The following example shows the usage of `grabValueFrom` in testing, where the r ``` +Below is an example used in Magento/Catalog/Test/Mftf/ActionGroup/AssertDiscountsPercentageOfProductsActionGroup.xml test. + +```xml + + + {{amount}} + $grabProductTierPriceInput + +``` + ## Hard-coded data input The data to operate against can be included as literals in a test. Hard-coded data input can be useful in assertions. From 731a7703e298d12cfd7208eaf5047bc830675a2b Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Sun, 26 Jan 2020 22:12:42 -0600 Subject: [PATCH 166/888] MQE-1676: Add a static-check that ensures action groups do not have unused arguments Refactored to read xml content from files directly to avoid flagging arguments due to step removals during merging/extensions. --- .../StaticCheck/ActionGroupArgumentsCheck.php | 145 ++++++++---------- .../StaticCheck/StaticCheckHelper.php | 21 +++ .../StaticCheck/TestDependencyCheck.php | 25 +-- .../Handlers/ActionGroupObjectHandler.php | 5 +- 4 files changed, 94 insertions(+), 102 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php index 705b2103d..8e630bd63 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php @@ -9,8 +9,9 @@ use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\Test\Handlers\ActionGroupObjectHandler; use Magento\FunctionalTestingFramework\Test\Objects\ActionGroupObject; -use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Symfony\Component\Console\Input\InputInterface; +use Magento\FunctionalTestingFramework\Util\ModuleResolver; +use Symfony\Component\Finder\Finder; use Exception; /** @@ -19,6 +20,11 @@ */ class ActionGroupArgumentsCheck implements StaticCheckInterface { + + const ACTIONGROUP_XML_REGEX_PATTERN = '/).)*/mxs'; + const ACTIONGROUP_ARGUMENT_REGEX_PATTERN = '/]*name="([^"\']*)/mxs'; + const ACTIONGROUP_NAME_REGEX_PATTERN = '/initActionGroups(); + $allModules = ModuleResolver::getInstance()->getModulesPath(); - $unusedArgumentList = $this->buildUnusedArgumentList($actionGroups); + $actionGroupXmlFiles = StaticCheckHelper::buildFileList( + $allModules, + DIRECTORY_SEPARATOR . 'ActionGroup' . DIRECTORY_SEPARATOR + ); - $this->errors += $this->setErrorOutput($unusedArgumentList); + $this->errors = $this->findErrorsInFileSet($actionGroupXmlFiles); $this->output = StaticCheckHelper::printErrorsToFile( $this->errors, @@ -84,7 +92,24 @@ public function getOutput() } /** - * Builds array of action groups => unused arguments + * Finds all unused arguments in given set of actionGroup files + * @param Finder $files + * @return array $testErrors + */ + private function findErrorsInFileSet($files) + { + $actionGroupErrors = []; + foreach ($files as $filePath) { + $contents = file_get_contents($filePath); + preg_match_all(self::ACTIONGROUP_XML_REGEX_PATTERN, $contents, $actionGroups); + $actionGroupToArguments = $this->buildUnusedArgumentList($actionGroups[0]); + $actionGroupErrors += $this->setErrorOutput($actionGroupToArguments, $filePath); + } + return $actionGroupErrors; + } + + /** + * Builds array of action group => unused arguments * @param array $actionGroups * @return array $actionGroupToArguments */ @@ -92,46 +117,48 @@ private function buildUnusedArgumentList($actionGroups) { $actionGroupToArguments = []; - foreach ($actionGroups as $actionGroup) { - $unusedArguments = $this->findUnusedArguments($actionGroup); + foreach ($actionGroups as $actionGroupXml) { + preg_match(self::ACTIONGROUP_NAME_REGEX_PATTERN, $actionGroupXml, $actionGroupName); + $unusedArguments = $this->findUnusedArguments($actionGroupXml); if (!empty($unusedArguments)) { - $actionGroupToArguments[$actionGroup->getFilename()][$actionGroup->getName()] = $unusedArguments; + $actionGroupToArguments[$actionGroupName[1]] = $unusedArguments; } } return $actionGroupToArguments; } /** - * Returns unused arguments in an action group. - * @param ActionGroupObject $actionGroup - * @return array $unusedArguments + * @param $actionGroupXml + * @return array */ - private function findUnusedArguments($actionGroup) + private function findUnusedArguments($actionGroupXml) { $unusedArguments = []; - //extract all action attribute values - $actionAttributeValues = $this->getAllActionAttributeValues($actionGroup); - $argumentList = $actionGroup->getArguments(); - foreach ($argumentList as $argument) { - $argumentName = $argument->getName(); + + preg_match_all(self::ACTIONGROUP_ARGUMENT_REGEX_PATTERN, $actionGroupXml, $arguments); + preg_match(self::ACTIONGROUP_NAME_REGEX_PATTERN, $actionGroupXml, $actionGroupName); + + $actionGroup = ActionGroupObjectHandler::getInstance()->getObject($actionGroupName[1]); + + foreach ($arguments[1] as $argument) { //pattern to match all argument references $patterns = [ - '(\{{2}' . $argumentName . '(\.[a-zA-Z0-9_\[\]\(\).,\'\/ ]+)?}{2})', - '([(,\s\']' . $argumentName . '(\.[a-zA-Z0-9_\[\]]+)?[),\s\'])' + '(\{{2}' . $argument . '(\.[a-zA-Z0-9_\[\]\(\).,\'\/ ]+)?}{2})', + '([(,\s\']' . $argument . '(\.[a-zA-Z0-9_\[\]]+)?[),\s\'])' ]; // matches entity references - if (preg_grep($patterns[0], $actionAttributeValues)) { + if (preg_match($patterns[0], $actionGroupXml)) { continue; } //matches parametrized references - if (preg_grep($patterns[1], $actionAttributeValues)) { + if (preg_match($patterns[1], $actionGroupXml)) { continue; } - //exclude arguments that are also defined in parent action group for extending action groups + //for extending action groups, exclude arguments that are also defined in parent action group if ($this->isParentActionGroupArgument($argument, $actionGroup)) { continue; } - $unusedArguments[] = $argumentName; + $unusedArguments[] = $argument; } return $unusedArguments; } @@ -147,70 +174,34 @@ private function isParentActionGroupArgument($argument, $actionGroup) if ($actionGroup->getParentName() !== null) { $parentActionGroup = ActionGroupObjectHandler::getInstance()->getObject($actionGroup->getParentName()); $parentArguments = $parentActionGroup->getArguments(); - if ($parentArguments !== null) { - return in_array($argument, $parentArguments); - } - return false; - } - } - - /** - * Returns array of all action attribute values in an action group. - * @param ActionGroupObject $actionGroup - * @return array $allAttributeValues - */ - private function getAllActionAttributeValues($actionGroup) - { - $allAttributeValues = []; - $actions = $actionGroup->getActions(); - foreach ($actions as $action) { - $actionAttributeValues = $this->extractAttributeValues($action); - $allAttributeValues = array_merge($allAttributeValues, $actionAttributeValues); - } - return array_unique($allAttributeValues); - } - - /** - * Builds and returns flattened attribute value list for an action. - * @param ActionObject $action - * @return array $flattenedAttributeValues - */ - private function extractAttributeValues($action) - { - $flattenedAttributeValues = []; - $actionAttributes = $action->getCustomActionAttributes(); - //check if action has nodes eg. expectedResult, actualResult and flatten array - foreach ($actionAttributes as $attributeName => $attributeValue) { - if (is_array($attributeValue)) { - $flattenedAttributeValues = array_merge($flattenedAttributeValues, array_values($attributeValue)); - } else { - $flattenedAttributeValues[] = $attributeValue; + foreach ($parentArguments as $parentArgument) { + if ($argument === $parentArgument->getName()) { + return true; + } } } - return $flattenedAttributeValues; + return false; } /** - * Builds and returns error output for unused arguments + * Builds and returns error output for violating references * - * @param array $unusedArgumentList + * @param array $actionGroupToArguments + * @param string $path * @return mixed */ - private function setErrorOutput($unusedArgumentList) + private function setErrorOutput($actionGroupToArguments, $path) { - $testErrors = []; - if (!empty($unusedArgumentList)) { + $actionGroupErrors = []; + if (!empty($actionGroupToArguments)) { // Build error output - foreach ($unusedArgumentList as $path => $actionGroupToArguments) { - $errorOutput = "\nFile \"{$path}\""; - $errorOutput .= "\ncontains action group(s) with unused arguments.\n\t\t"; - - foreach ($actionGroupToArguments as $actionGroup => $arguments) { - $errorOutput .= "\n\t {$actionGroup} has unused argument(s): " . implode(", ", $arguments); - } - $testErrors[$path][] = $errorOutput; + $errorOutput = "\nFile \"{$path->getRealPath()}\""; + $errorOutput .= "\ncontains action group(s) with unused arguments.\n\t\t"; + foreach ($actionGroupToArguments as $actionGroup => $arguments) { + $errorOutput .= "\n\t {$actionGroup} has unused argument(s): " . implode(", ", $arguments); } + $actionGroupErrors[$path->getRealPath()][] = $errorOutput; } - return $testErrors; + return $actionGroupErrors; } } diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticCheckHelper.php b/src/Magento/FunctionalTestingFramework/StaticCheck/StaticCheckHelper.php index 5e3e8520d..6430774d4 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticCheckHelper.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/StaticCheckHelper.php @@ -5,6 +5,8 @@ */ namespace Magento\FunctionalTestingFramework\StaticCheck; +use Symfony\Component\Finder\Finder; + class StaticCheckHelper { /** @@ -33,4 +35,23 @@ public static function printErrorsToFile($errors, $filename, $message) return $output; } + + /** + * Builds list of all XML files in given modulePaths + path given + * @param array $modulePaths + * @param string $path + * @return Finder + */ + public static function buildFileList($modulePaths, $path) + { + $finder = new Finder(); + foreach ($modulePaths as $modulePath) { + if (!realpath($modulePath . $path)) { + continue; + } + $finder->files()->in($modulePath . $path)->name("*.xml"); + } + return $finder->files(); + } + } diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php index 2b309c015..3c3ed6a37 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php @@ -6,7 +6,6 @@ namespace Magento\FunctionalTestingFramework\StaticCheck; -use Magento\FunctionalTestingFramework\StaticCheck\StaticCheckHelper; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; @@ -117,9 +116,9 @@ public function execute(InputInterface $input) DIRECTORY_SEPARATOR . 'Data' . DIRECTORY_SEPARATOR, ]; // These files can contain references to other modules. - $testXmlFiles = $this->buildFileList($allModules, $filePaths[0]); - $actionGroupXmlFiles = $this->buildFileList($allModules, $filePaths[1]); - $dataXmlFiles= $this->buildFileList($allModules, $filePaths[2]); + $testXmlFiles = StaticCheckHelper::buildFileList($allModules, $filePaths[0]); + $actionGroupXmlFiles = StaticCheckHelper::buildFileList($allModules, $filePaths[1]); + $dataXmlFiles= StaticCheckHelper::buildFileList($allModules, $filePaths[2]); $this->errors = []; $this->errors += $this->findErrorsInFileSet($testXmlFiles); @@ -421,24 +420,6 @@ private function getModuleDependenciesFromReferences($array) return $filenames; } - /** - * Builds list of all XML files in given modulePaths + path given - * @param string $modulePaths - * @param string $path - * @return Finder - */ - private function buildFileList($modulePaths, $path) - { - $finder = new Finder(); - foreach ($modulePaths as $modulePath) { - if (!realpath($modulePath . $path)) { - continue; - } - $finder->files()->in($modulePath . $path)->name("*.xml"); - } - return $finder->files(); - } - /** * Attempts to find any MFTF entity by its name. Returns null if none are found. * @param string $name diff --git a/src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php b/src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php index 91f1f2b0d..131ae0a26 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php @@ -99,10 +99,10 @@ public function getAllObjects(): array /** * Method which populates field array with objects from parsed action_group.xml * - * @return array + * @return void * @SuppressWarnings(PHPMD.UnusedPrivateMethod) */ - public function initActionGroups() + private function initActionGroups() { $actionGroupParser = ObjectManagerFactory::getObjectManager()->create(ActionGroupDataParser::class); $parsedActionGroups = $actionGroupParser->readActionGroupData(); @@ -118,7 +118,6 @@ public function initActionGroups() $this->actionGroups[$actionGroupName] = $actionGroupObjectExtractor->extractActionGroup($actionGroupData); } - return $this->actionGroups; } /** From 089b88d9d777318b0748b1536345b34e63057494 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan Date: Sun, 26 Jan 2020 22:31:29 -0600 Subject: [PATCH 167/888] MQE-1676: Add a static-check that ensures action groups do not have unused arguments fixed unit tests --- .../StaticCheck/ActionGroupArgumentsCheck.php | 8 +++++--- .../StaticCheck/StaticCheckHelper.php | 3 +-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php index 8e630bd63..6c5c34203 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php @@ -128,7 +128,8 @@ private function buildUnusedArgumentList($actionGroups) } /** - * @param $actionGroupXml + * Returns unused arguments in an action group + * @param string $actionGroupXml * @return array */ private function findUnusedArguments($actionGroupXml) @@ -171,8 +172,9 @@ private function findUnusedArguments($actionGroupXml) */ private function isParentActionGroupArgument($argument, $actionGroup) { - if ($actionGroup->getParentName() !== null) { - $parentActionGroup = ActionGroupObjectHandler::getInstance()->getObject($actionGroup->getParentName()); + $parentActionGroupName = $actionGroup->getParentName(); + if ($parentActionGroupName !== null) { + $parentActionGroup = ActionGroupObjectHandler::getInstance()->getObject($parentActionGroupName); $parentArguments = $parentActionGroup->getArguments(); foreach ($parentArguments as $parentArgument) { if ($argument === $parentArgument->getName()) { diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticCheckHelper.php b/src/Magento/FunctionalTestingFramework/StaticCheck/StaticCheckHelper.php index 6430774d4..f534544fc 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticCheckHelper.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/StaticCheckHelper.php @@ -38,7 +38,7 @@ public static function printErrorsToFile($errors, $filename, $message) /** * Builds list of all XML files in given modulePaths + path given - * @param array $modulePaths + * @param array $modulePaths * @param string $path * @return Finder */ @@ -53,5 +53,4 @@ public static function buildFileList($modulePaths, $path) } return $finder->files(); } - } From c0a885cbc5e75e67925736152dc592105021563d Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Fri, 24 Jan 2020 13:21:26 -0600 Subject: [PATCH 168/888] MQE-1919: MFTF AWS Secrets Manager - CI Use --- docs/credentials.md | 32 ++-- .../Handlers/CredentialStore.php | 155 +++++++++++++++--- .../Handlers/PersistedObjectHandler.php | 8 +- .../AwsSecretsManagerStorage.php | 15 ++ .../Handlers/SecretStorage/BaseStorage.php | 24 ++- .../Handlers/SecretStorage/VaultStorage.php | 18 +- .../Util/RuntimeDataReferenceResolver.php | 6 +- .../Collector/ExceptionCollector.php | 20 +++ .../Module/MagentoWebDriver.php | 6 + 9 files changed, 231 insertions(+), 53 deletions(-) diff --git a/docs/credentials.md b/docs/credentials.md index 1ea91a5c3..402030985 100644 --- a/docs/credentials.md +++ b/docs/credentials.md @@ -147,31 +147,33 @@ AWS Secrets Manager offers secret management that supports: #### Use AWS Secrets Manager from your own AWS account -- AWS account with Secrets Manager service available -- IAM User or Role is created with appropriate AWS Secrets Manger access permission +- An AWS account with Secrets Manager service +- An IAM user with AWS Secrets Manager access permission -#### Use AWS Secrets Manager from other AWS account +#### Use AWS Secrets Manager in CI/CD - AWS account ID where the AWS Secrets Manager service is hosted -- IAM User or Role with appropriate access permission +- Authorized CI/CD EC2 instances with AWS Secrets Manager service access IAM role attached ### Store secrets in AWS Secrets Manager - #### Secrets format `Secret Name` and `Secret Value` are two key pieces of information for creating a secret. `Secret Value` can be either plaintext or key/value pairs in JSON format. -`Secrets Name` must use the following format: +`Secret Name` must use the following format: ```conf mftf// ``` -`Secrets Value` in plaintext format can be any content you want to secure. `Secrets Value` in key/value pairs format, however, the `key` must be same as the `Secret Name` with `mftf//` part removed. -e.g. in above example, `key` should be `` +`Secret Value` can be stored in two different formats: plaintext or key/value pairs. + +For plaintext format, `Secret Value` can be any string you want to secure. + +For key/value pairs format, `Secret Value` is a key/value pair with `key` the same as `Secret Name` without `mftf//` prefix, which is ``, and value can be any string you want to secure. ##### Create Secrets using AWS CLI @@ -181,8 +183,11 @@ aws secretsmanager create-secret --name "mftf/magento/shipping/carriers_usps_use ##### Create Secrets using AWS Console -To save the same secret in key/value JSON format, you should use - +- Sign in to the AWS Secrets Manager console +- Choose Store a new secret +- In the Select secret type section, specify "Other type of secret" +- For `Secret Name`, `Secret Key` and `Secret Value` field, for example, to save the same secret in key/value JSON format, you should use + ```conf # Secret Name mftf/magento/shipping/carriers_usps_userid @@ -210,9 +215,8 @@ CREDENTIAL_AWS_SECRETS_MANAGER_PROFILE=default ### Optionally set CREDENTIAL_AWS_ACCOUNT_ID environment variable -Full AWS KMS ([Key Management Service][]) key ARN ([Amazon Resource Name][]) is required when accessing secrets stored in other AWS account. -If this is the case, you will also need to set `CREDENTIAL_AWS_ACCOUNT_ID` environment variable so that MFTF can construct the full ARN. -This is also commonly used in CI system. +In case AWS credentials cannot resolve to a valid AWS account, full AWS KMS ([Key Management Service][]) key ARN ([Amazon Resource Name][]) is required. +You will also need to set `CREDENTIAL_AWS_ACCOUNT_ID` environment variable so that MFTF can construct the full ARN. This is mostly used for CI/CD. ```bash export CREDENTIAL_AWS_ACCOUNT_ID= @@ -236,7 +240,7 @@ Define the value as a reference to the corresponding key in the credentials file - `_CREDS` is an environment constant pointing to the `.credentials` file - `my_data_key` is a key in the the `.credentials` file or vault that contains the value to be used in a test step - - for File Storage, ensure your key contains the vendor prefix, i.e. `vendor/my_data_key` + - for File Storage, ensure your key contains the vendor prefix, which is `vendor/my_data_key` For example, to reference secret data in the [`fillField`][] action, use the `userInput` attribute using a typical File Storage: diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php index b66d19799..d6e6b9a69 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php @@ -6,7 +6,9 @@ namespace Magento\FunctionalTestingFramework\DataGenerator\Handlers; +use Magento\FunctionalTestingFramework\Exceptions\Collector\ExceptionCollector; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\DataGenerator\Handlers\SecretStorage\BaseStorage; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\SecretStorage\FileStorage; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\SecretStorage\VaultStorage; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\SecretStorage\AwsSecretsManagerStorage; @@ -24,10 +26,17 @@ class CredentialStore /** * Credential storage array * - * @var array + * @var BaseStorage[] */ private $credStorage = []; + /** + * Boolean to indicate if credential storage have been initialized + * + * @var boolean + */ + private $initialized; + /** * Singleton instance * @@ -35,11 +44,17 @@ class CredentialStore */ private static $INSTANCE = null; + /** + * Exception contexts + * + * @var ExceptionCollector + */ + private $exceptionContexts; + /** * Static singleton getter for CredentialStore Instance * * @return CredentialStore - * @throws TestFrameworkException */ public static function getInstance() { @@ -52,21 +67,11 @@ public static function getInstance() /** * CredentialStore constructor - * - * @throws TestFrameworkException */ private function __construct() { - // Initialize credential storage by defined order of precedence as the following - $this->initializeFileStorage(); - $this->initializeVaultStorage(); - $this->initializeAwsSecretsManagerStorage(); - - if (empty($this->credStorage)) { - throw new TestFrameworkException( - 'Invalid Credential Storage. ' . self::CREDENTIAL_STORAGE_INFO . '.' - ); - } + $this->initialized = false; + $this->exceptionContexts = new ExceptionCollector(); } /** @@ -78,6 +83,9 @@ private function __construct() */ public function getSecret($key) { + // Initialize credential storage if it's not been done + $this->initializeCredentialStorage(); + // Get secret data from storage according to the order they are stored which follows this precedence: // FileStorage > VaultStorage > AwsSecretsManagerStorage foreach ($this->credStorage as $storage) { @@ -87,9 +95,12 @@ public function getSecret($key) } } + $exceptionContexts = $this->getExceptionContexts(); + $this->resetExceptionContext(); throw new TestFrameworkException( "{$key} not found. " . self::CREDENTIAL_STORAGE_INFO - . ' and ensure key, value exists to use _CREDS in tests.' + . " and ensure key, value exists to use _CREDS in tests." + . $exceptionContexts ); } @@ -97,28 +108,112 @@ public function getSecret($key) * Return decrypted input value * * @param string $value - * @return string + * @return string|false The decrypted string on success or false on failure + * @throws TestFrameworkException */ public function decryptSecretValue($value) { - // Loop through storage to decrypt value - foreach ($this->credStorage as $storage) { - return $storage->getDecryptedValue($value); - } + // Initialize credential storage if it's not been done + $this->initializeCredentialStorage(); + + // Decrypt secret value + return BaseStorage::getDecryptedValue($value); } /** * Return decrypted values for all occurrences from input string * * @param string $string - * @return mixed + * @return string|false The decrypted string on success or false on failure + * @throws TestFrameworkException */ public function decryptAllSecretsInString($string) { - // Loop through storage to decrypt all occurrences from input string - foreach ($this->credStorage as $storage) { - return $storage->getAllDecryptedValuesInString($string); + // Initialize credential storage if it's not been done + $this->initializeCredentialStorage(); + + // Decrypt all secret values in string + return BaseStorage::getAllDecryptedValuesInString($string); + } + + /** + * Setter for exception contexts + * + * @param string $type + * @param string $context + * @return void + */ + public function setExceptionContexts($type, $context) + { + $typeArray = [self::ARRAY_KEY_FOR_FILE, self::ARRAY_KEY_FOR_VAULT, self::ARRAY_KEY_FOR_AWS_SECRETS_MANAGER]; + if (in_array($type, $typeArray) && !empty($context)) { + $this->exceptionContexts->addError($type, $context); + } + } + + /** + * Return collected exception contexts + * + * @return string + */ + private function getExceptionContexts() + { + // Gather all exceptions collected + $exceptionMessage = "\n"; + foreach ($this->exceptionContexts->getErrors() as $type => $exceptions) { + $exceptionMessage .= "\nException from "; + if ($type == self::ARRAY_KEY_FOR_FILE) { + $exceptionMessage .= "File Storage: \n"; + } + if ($type == self::ARRAY_KEY_FOR_VAULT) { + $exceptionMessage .= "Vault Storage: \n"; + } + if ($type == self::ARRAY_KEY_FOR_AWS_SECRETS_MANAGER) { + $exceptionMessage .= "AWS Secrets Manager Storage: \n"; + } + + if (is_array($exceptions)) { + $exceptionMessage .= implode("\n", $exceptions) . "\n"; + } else { + $exceptionMessage .= $exceptions . "\n"; + } + } + return $exceptionMessage; + } + + /** + * Reset exception contexts to empty array + * + * @return void + */ + private function resetExceptionContext() + { + $this->exceptionContexts->reset(); + } + + /** + * Initialize all available credential storage + * + * @return void + * @throws TestFrameworkException + */ + private function initializeCredentialStorage() + { + if (!$this->initialized) { + // Initialize credential storage by defined order of precedence as the following + $this->initializeFileStorage(); + $this->initializeVaultStorage(); + $this->initializeAwsSecretsManagerStorage(); + $this->initialized = true; + } + + if (empty($this->credStorage)) { + throw new TestFrameworkException( + 'Invalid Credential Storage. ' . self::CREDENTIAL_STORAGE_INFO + . '.' . $this->getExceptionContexts() + ); } + $this->resetExceptionContext(); } /** @@ -132,6 +227,10 @@ private function initializeFileStorage() try { $this->credStorage[self::ARRAY_KEY_FOR_FILE] = new FileStorage(); } catch (TestFrameworkException $e) { + // Print error message in console + print_r($e->getMessage()); + // Save to exception context for Allure report + $this->setExceptionContexts(self::ARRAY_KEY_FOR_FILE, $e->getMessage()); } } @@ -152,6 +251,10 @@ private function initializeVaultStorage() '/' . trim($cvSecretPath, '/') ); } catch (TestFrameworkException $e) { + // Print error message in console + print_r($e->getMessage()); + // Save to exception context for Allure report + $this->setExceptionContexts(self::ARRAY_KEY_FOR_VAULT, $e->getMessage()); } } } @@ -181,6 +284,10 @@ private function initializeAwsSecretsManagerStorage() $awsId ); } catch (TestFrameworkException $e) { + // Print error message in console + print_r($e->getMessage()); + // Save to exception context for Allure report + $this->setExceptionContexts(self::ARRAY_KEY_FOR_AWS_SECRETS_MANAGER, $e->getMessage()); } } } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php index 00353856b..927c0ab4e 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php @@ -89,10 +89,12 @@ public function createEntity( foreach ($overrideFields as $index => $field) { try { - $overrideFields[$index] = CredentialStore::getInstance()->decryptAllSecretsInString($field); + $decrptedField = CredentialStore::getInstance()->decryptAllSecretsInString($field); + if ($decrptedField !== false) { + $overrideFields[$index] = $decrptedField; + } } catch (TestFrameworkException $e) { - //do not rethrow if Credentials are not defined - $overrideFields[$index] = $field; + //catch exception if Credentials are not defined } } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/AwsSecretsManagerStorage.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/AwsSecretsManagerStorage.php index bb6044c7f..6bd1ff144 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/AwsSecretsManagerStorage.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/AwsSecretsManagerStorage.php @@ -7,6 +7,7 @@ namespace Magento\FunctionalTestingFramework\DataGenerator\Handlers\SecretStorage; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; use Aws\SecretsManager\SecretsManagerClient; @@ -117,17 +118,31 @@ public function getEncryptedValue($key) } catch (AwsException $e) { $errMessage = "\nAWS Exception:\n" . $e->getAwsErrorMessage() . "\nUnable to read value for key {$key} from AWS Secrets Manager\n"; + // Print error message in console print_r($errMessage); + // Add error message in mftf log if verbose is enable if (MftfApplicationConfig::getConfig()->verboseEnabled()) { LoggingUtil::getInstance()->getLogger(AwsSecretsManagerStorage::class)->debug($errMessage); } + // Save to exception context for Allure report + CredentialStore::getInstance()->setExceptionContexts( + CredentialStore::ARRAY_KEY_FOR_AWS_SECRETS_MANAGER, + $errMessage + ); } catch (\Exception $e) { $errMessage = "\nException:\n" . $e->getMessage() . "\nUnable to read value for key {$key} from AWS Secrets Manager\n"; + // Print error message in console print_r($errMessage); + // Add error message in mftf log if verbose is enable if (MftfApplicationConfig::getConfig()->verboseEnabled()) { LoggingUtil::getInstance()->getLogger(AwsSecretsManagerStorage::class)->debug($errMessage); } + // Save to exception context for Allure report + CredentialStore::getInstance()->setExceptionContexts( + CredentialStore::ARRAY_KEY_FOR_AWS_SECRETS_MANAGER, + $errMessage + ); } return $reValue; } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/BaseStorage.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/BaseStorage.php index cb892a545..6eb7fa7e8 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/BaseStorage.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/BaseStorage.php @@ -58,30 +58,38 @@ public function getEncryptedValue($key) /** * Takes a value encrypted at runtime and decrypts it using the object's initial vector + * return the decrypted string on success or false on failure * * @param string $value - * @return string + * @return string|false The decrypted string on success or false on failure */ - public function getDecryptedValue($value) + public static function getDecryptedValue($value) { return openssl_decrypt($value, self::ENCRYPTION_ALGO, self::$encodedKey, 0, self::$iv); } /** * Takes a string that contains encrypted data at runtime and decrypts each value + * return false if no decryption happens or a failure occurs * * @param string $string - * @return mixed + * @return string|false The decrypted string on success or false on failure */ - public function getAllDecryptedValuesInString($string) + public static function getAllDecryptedValuesInString($string) { - $newString = $string; + $decrypted = false; foreach (self::$cachedSecretData as $key => $secretValue) { - if (strpos($newString, $secretValue) !== false) { + if (strpos($string, $secretValue) !== false) { $decryptedValue = self::getDecryptedValue($secretValue); - $newString = str_replace($secretValue, $decryptedValue, $newString); + if ($decryptedValue === false) { + return false; + } + if (!$decrypted) { + $decrypted = true; + } + $string = str_replace($secretValue, $decryptedValue, $string); } } - return $newString; + return $decrypted ? $string : false; } } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/VaultStorage.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/VaultStorage.php index 798ac660c..39839e8f9 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/VaultStorage.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/VaultStorage.php @@ -7,6 +7,7 @@ namespace Magento\FunctionalTestingFramework\DataGenerator\Handlers\SecretStorage; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; use Vault\Client; @@ -123,10 +124,14 @@ public function getEncryptedValue($key) $reValue = openssl_encrypt($value, parent::ENCRYPTION_ALGO, parent::$encodedKey, 0, parent::$iv); parent::$cachedSecretData[$key] = $reValue; } catch (\Exception $e) { + $errMessage = "\nUnable to read secret for key name {$key} from vault." . $e->getMessage(); + // Print error message in console + print_r($errMessage); + // Save to exception context for Allure report + CredentialStore::getInstance()->setExceptionContexts('vault', $errMessage); + // Add error message in mftf log if verbose is enable if (MftfApplicationConfig::getConfig()->verboseEnabled()) { - LoggingUtil::getInstance()->getLogger(VaultStorage::class)->debug( - "Unable to read secret for key name {$key} from vault" - ); + LoggingUtil::getInstance()->getLogger(VaultStorage::class)->debug($errMessage); } } return $reValue; @@ -149,6 +154,13 @@ private function authenticated() return true; } } catch (\Exception $e) { + // Print error message in console + print_r($e->getMessage()); + // Save to exception context for Allure report + CredentialStore::getInstance()->setExceptionContexts( + CredentialStore::ARRAY_KEY_FOR_VAULT, + $e->getMessage() + ); } return false; } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Util/RuntimeDataReferenceResolver.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Util/RuntimeDataReferenceResolver.php index a09afd01a..220d4ab7f 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Util/RuntimeDataReferenceResolver.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Util/RuntimeDataReferenceResolver.php @@ -9,6 +9,7 @@ use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; /** @@ -23,7 +24,7 @@ class RuntimeDataReferenceResolver implements DataReferenceResolverInterface * @param string $originalDataEntity * @return array|false|string|null * @throws TestReferenceException - * @throws \Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException + * @throws TestFrameworkException */ public function getDataReference(string $data, string $originalDataEntity) { @@ -43,6 +44,9 @@ public function getDataReference(string $data, string $originalDataEntity) case ActionObject::__CREDS: $value = CredentialStore::getInstance()->getSecret($var); $result = CredentialStore::getInstance()->decryptSecretValue($value); + if ($result === false) { + throw new TestFrameworkException("\nFailed to decrypt value {$value}\n"); + } $result = str_replace($matches['reference'], $result, $data); break; default: diff --git a/src/Magento/FunctionalTestingFramework/Exceptions/Collector/ExceptionCollector.php b/src/Magento/FunctionalTestingFramework/Exceptions/Collector/ExceptionCollector.php index c1e023ef4..f64b35446 100644 --- a/src/Magento/FunctionalTestingFramework/Exceptions/Collector/ExceptionCollector.php +++ b/src/Magento/FunctionalTestingFramework/Exceptions/Collector/ExceptionCollector.php @@ -43,6 +43,26 @@ public function throwException() throw new \Exception("\n" . $errorMsg); } + /** + * Return all errors + * + * @return array + */ + public function getErrors() + { + return $this->errors ?? []; + } + + /** + * Reset error to empty array + * + * @return void + */ + public function reset() + { + $this->errors = []; + } + /** * If there are multiple exceptions for a single file, the function flattens the array so they can be printed * as separate messages. diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index f44d7e1a0..cd2768a06 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -769,6 +769,9 @@ public function fillSecretField($field, $value) // decrypted value $decryptedValue = CredentialStore::getInstance()->decryptSecretValue($value); + if ($decryptedValue === false) { + throw new TestFrameworkException("\nFailed to decrypt value {$value} for field {$field}\n"); + } $this->fillField($field, $decryptedValue); } @@ -788,6 +791,9 @@ public function magentoCLISecret($command, $timeout = null, $arguments = null) // decrypted value $decryptedCommand = CredentialStore::getInstance()->decryptAllSecretsInString($command); + if ($decryptedCommand === false) { + throw new TestFrameworkException("\nFailed to decrypt magentoCLI command {$command}\n"); + } return $this->magentoCLI($decryptedCommand, $timeout, $arguments); } From 6ff290a11305768719c3a02d4d8eb578bef9593c Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk Date: Mon, 27 Jan 2020 10:45:58 -0600 Subject: [PATCH 169/888] MFTF deprecation notice attributes - fix failing tests --- .../DeprecatedCommentActionGroup.xml | 13 +++++++++ .../DevDocs/Data/DeprecatedMessageData.xml | 14 +++++++++ .../tests/MFTF/DevDocs/Data/MessageData.xml | 14 +++++++++ .../DevDocs/Page/DeprecatedMFTFDocPage.xml | 14 +++++++++ .../Section/DeprecatedContentSection.xml | 14 +++++++++ .../DevDocs/Test/DeprecatedDevDocsTest.xml | 27 +++++++++++++++++ .../Test/Handlers/TestObjectHandlerTest.php | 2 +- .../ActionGroupContainsStepKeyInArgText.txt | 2 +- .../ActionGroupMergedViaInsertAfter.txt | 2 +- .../ActionGroupMergedViaInsertBefore.txt | 2 +- .../Resources/ActionGroupSkipReadiness.txt | 2 +- .../Resources/ActionGroupToExtend.txt | 2 +- .../Resources/ActionGroupUsingCreateData.txt | 2 +- .../ActionGroupUsingNestedArgument.txt | 2 +- .../ActionGroupWithDataOverrideTest.txt | 2 +- .../Resources/ActionGroupWithDataTest.txt | 2 +- ...hDefaultArgumentAndStringSelectorParam.txt | 2 +- ...eParameterSelectorsFromDefaultArgument.txt | 2 +- .../Resources/ActionGroupWithNoArguments.txt | 2 +- .../ActionGroupWithNoDefaultTest.txt | 2 +- ...roupWithParameterizedElementWithHyphen.txt | 2 +- ...meterizedElementsWithStepKeyReferences.txt | 2 +- ...thPassedArgumentAndStringSelectorParam.txt | 2 +- .../ActionGroupWithPersistedData.txt | 2 +- ...tionGroupWithSectionAndDataAsArguments.txt | 2 +- ...WithSimpleDataUsageFromDefaultArgument.txt | 2 +- ...pWithSimpleDataUsageFromPassedArgument.txt | 2 +- ...leParameterSelectorFromDefaultArgument.txt | 2 +- ...gleParameterSelectorFromPassedArgument.txt | 2 +- .../ActionGroupWithStepKeyReferences.txt | 2 +- .../ActionGroupWithTopLevelPersistedData.txt | 2 +- .../ArgumentWithSameNameAsElement.txt | 2 +- .../verification/Resources/AssertTest.txt | 2 +- .../Resources/BasicActionGroupTest.txt | 2 +- .../Resources/BasicFunctionalTest.txt | 2 +- .../verification/Resources/BasicMergeTest.txt | 2 +- .../Resources/CharacterReplacementTest.txt | 2 +- .../Resources/ChildExtendedTestAddHooks.txt | 2 +- .../Resources/ChildExtendedTestMerging.txt | 2 +- .../Resources/ChildExtendedTestNoParent.txt | 2 +- .../ChildExtendedTestRemoveAction.txt | 2 +- .../ChildExtendedTestRemoveHookAction.txt | 2 +- .../Resources/ChildExtendedTestReplace.txt | 2 +- .../ChildExtendedTestReplaceHook.txt | 2 +- .../Resources/DataActionsTest.txt | 2 +- .../Resources/DataReplacementTest.txt | 2 +- .../Resources/ExecuteInSeleniumTest.txt | 2 +- .../Resources/ExecuteJsEscapingTest.txt | 2 +- .../Resources/ExtendParentDataTest.txt | 2 +- .../Resources/ExtendedActionGroup.txt | 2 +- .../ExtendedChildTestInSuiteCest.txt | 2 +- .../Resources/ExtendedChildTestNotInSuite.txt | 2 +- .../Resources/ExtendedRemoveActionGroup.txt | 2 +- .../Resources/ExtendingSkippedTest.txt | 2 +- .../Resources/HookActionsTest.txt | 2 +- .../Resources/LocatorFunctionTest.txt | 2 +- .../Resources/MergeMassViaInsertAfter.txt | 2 +- .../Resources/MergeMassViaInsertBefore.txt | 2 +- .../verification/Resources/MergeSkip.txt | 2 +- .../Resources/MergedActionGroupTest.txt | 2 +- .../Resources/MergedReferencesTest.txt | 2 +- .../Resources/MultipleActionGroupsTest.txt | 2 +- .../Resources/PageReplacementTest.txt | 2 +- .../Resources/ParameterArrayTest.txt | 2 +- .../Resources/ParentExtendedTest.txt | 2 +- .../PersistedAndXmlEntityArguments.txt | 2 +- .../Resources/PersistedReplacementTest.txt | 2 +- .../PersistenceActionGroupAppendingTest.txt | 2 +- .../Resources/PersistenceCustomFieldsTest.txt | 2 +- .../Resources/SectionReplacementTest.txt | 2 +- .../verification/Resources/SkippedTest.txt | 2 +- .../Resources/SkippedTestNoIssues.txt | 2 +- .../Resources/SkippedTestTwoIssues.txt | 2 +- .../Resources/SkippedTestWithHooks.txt | 2 +- .../Resources/XmlCommentedActionGroupTest.txt | 2 +- .../Resources/XmlCommentedTest.txt | 2 +- .../Allure/Adapter/MagentoAllureAdapter.php | 1 - .../Codeception/Subscriber/Console.php | 12 +++++++- .../Handlers/DataObjectHandler.php | 3 +- .../OperationDefinitionObjectHandler.php | 4 +-- .../Objects/EntityDataObject.php | 16 +++++----- .../Objects/OperationDefinitionObject.php | 29 ++++++++++--------- .../Page/Objects/PageObject.php | 12 ++++---- .../Page/Objects/SectionObject.php | 4 +-- .../Test/Objects/ActionGroupObject.php | 12 ++++---- .../Test/Objects/ActionObject.php | 16 +++++----- .../Test/Util/TestObjectExtractor.php | 2 ++ .../Util/TestGenerator.php | 6 ++-- 88 files changed, 230 insertions(+), 123 deletions(-) create mode 100644 dev/tests/functional/tests/MFTF/DevDocs/ActionGroup/DeprecatedCommentActionGroup.xml create mode 100644 dev/tests/functional/tests/MFTF/DevDocs/Data/DeprecatedMessageData.xml create mode 100644 dev/tests/functional/tests/MFTF/DevDocs/Data/MessageData.xml create mode 100644 dev/tests/functional/tests/MFTF/DevDocs/Page/DeprecatedMFTFDocPage.xml create mode 100644 dev/tests/functional/tests/MFTF/DevDocs/Section/DeprecatedContentSection.xml create mode 100644 dev/tests/functional/tests/MFTF/DevDocs/Test/DeprecatedDevDocsTest.xml diff --git a/dev/tests/functional/tests/MFTF/DevDocs/ActionGroup/DeprecatedCommentActionGroup.xml b/dev/tests/functional/tests/MFTF/DevDocs/ActionGroup/DeprecatedCommentActionGroup.xml new file mode 100644 index 000000000..908808a8c --- /dev/null +++ b/dev/tests/functional/tests/MFTF/DevDocs/ActionGroup/DeprecatedCommentActionGroup.xml @@ -0,0 +1,13 @@ + + + + + + + diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Data/DeprecatedMessageData.xml b/dev/tests/functional/tests/MFTF/DevDocs/Data/DeprecatedMessageData.xml new file mode 100644 index 000000000..5835a78af --- /dev/null +++ b/dev/tests/functional/tests/MFTF/DevDocs/Data/DeprecatedMessageData.xml @@ -0,0 +1,14 @@ + + + + + + Introduction to the Magento Functional Testing Framework + + diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Data/MessageData.xml b/dev/tests/functional/tests/MFTF/DevDocs/Data/MessageData.xml new file mode 100644 index 000000000..eb77e73bc --- /dev/null +++ b/dev/tests/functional/tests/MFTF/DevDocs/Data/MessageData.xml @@ -0,0 +1,14 @@ + + + + + + Introduction to the Magento Functional Testing Framework + + diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Page/DeprecatedMFTFDocPage.xml b/dev/tests/functional/tests/MFTF/DevDocs/Page/DeprecatedMFTFDocPage.xml new file mode 100644 index 000000000..ee47fe954 --- /dev/null +++ b/dev/tests/functional/tests/MFTF/DevDocs/Page/DeprecatedMFTFDocPage.xml @@ -0,0 +1,14 @@ + + + + + +
    + + diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Section/DeprecatedContentSection.xml b/dev/tests/functional/tests/MFTF/DevDocs/Section/DeprecatedContentSection.xml new file mode 100644 index 000000000..cc316d6ed --- /dev/null +++ b/dev/tests/functional/tests/MFTF/DevDocs/Section/DeprecatedContentSection.xml @@ -0,0 +1,14 @@ + + + + +
    + +
    +
    diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Test/DeprecatedDevDocsTest.xml b/dev/tests/functional/tests/MFTF/DevDocs/Test/DeprecatedDevDocsTest.xml new file mode 100644 index 000000000..bf0078df4 --- /dev/null +++ b/dev/tests/functional/tests/MFTF/DevDocs/Test/DeprecatedDevDocsTest.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + <description value="[Deprecated] Magento Functional Testing Framework Documentation is available."/> + <severity value="CRITICAL"/> + <group value="mftf"/> + </annotations> + + <!-- Open MFTF DevDocs Page --> + <amOnPage stepKey="openMFTFDevDocPage" url="{{DeprecatedMFTFDocPage.url}}" /> + <see stepKey="verifyPageIntroText" selector="{{DeprecatedContentSection.pageIntro}}" userInput="{{DeprecatedMessageData.message}}" /> + <actionGroup ref="DeprecatedCommentActionGroup" stepKey="commentActionGroup" /> + </test> +</tests> diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php index 39e80d556..67f6f2b43 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php @@ -92,7 +92,7 @@ public function testGetTestObject() [ 'features' => ['NO MODULE DETECTED'], 'group' => ['test'], - 'description' => ['<br><br><b><font size=+0.9>Test files</font></b><br><br>'] + 'description' => ['test_files' => '<h3>Test files</h3>', 'deprecated' => []] ], [ TestObjectExtractor::TEST_BEFORE_HOOK => $expectedBeforeHookObject, diff --git a/dev/tests/verification/Resources/ActionGroupContainsStepKeyInArgText.txt b/dev/tests/verification/Resources/ActionGroupContainsStepKeyInArgText.txt index 1eb3d6566..23e0f0b69 100644 --- a/dev/tests/verification/Resources/ActionGroupContainsStepKeyInArgText.txt +++ b/dev/tests/verification/Resources/ActionGroupContainsStepKeyInArgText.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") */ class ActionGroupContainsStepKeyInArgTextCest { diff --git a/dev/tests/verification/Resources/ActionGroupMergedViaInsertAfter.txt b/dev/tests/verification/Resources/ActionGroupMergedViaInsertAfter.txt index b4745e0c0..da3d84daf 100644 --- a/dev/tests/verification/Resources/ActionGroupMergedViaInsertAfter.txt +++ b/dev/tests/verification/Resources/ActionGroupMergedViaInsertAfter.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") */ class ActionGroupMergedViaInsertAfterCest { diff --git a/dev/tests/verification/Resources/ActionGroupMergedViaInsertBefore.txt b/dev/tests/verification/Resources/ActionGroupMergedViaInsertBefore.txt index b27328275..22e8148d9 100644 --- a/dev/tests/verification/Resources/ActionGroupMergedViaInsertBefore.txt +++ b/dev/tests/verification/Resources/ActionGroupMergedViaInsertBefore.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") */ class ActionGroupMergedViaInsertBeforeCest { diff --git a/dev/tests/verification/Resources/ActionGroupSkipReadiness.txt b/dev/tests/verification/Resources/ActionGroupSkipReadiness.txt index 11025fefe..efd5a8cb5 100644 --- a/dev/tests/verification/Resources/ActionGroupSkipReadiness.txt +++ b/dev/tests/verification/Resources/ActionGroupSkipReadiness.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") */ class ActionGroupSkipReadinessCest { diff --git a/dev/tests/verification/Resources/ActionGroupToExtend.txt b/dev/tests/verification/Resources/ActionGroupToExtend.txt index 133c9fb9b..29d08c0b6 100644 --- a/dev/tests/verification/Resources/ActionGroupToExtend.txt +++ b/dev/tests/verification/Resources/ActionGroupToExtend.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") */ class ActionGroupToExtendCest { diff --git a/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt b/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt index fb76b4f44..b64822cf6 100644 --- a/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt +++ b/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") */ class ActionGroupUsingCreateDataCest { diff --git a/dev/tests/verification/Resources/ActionGroupUsingNestedArgument.txt b/dev/tests/verification/Resources/ActionGroupUsingNestedArgument.txt index 5814e85e0..5eb67f577 100644 --- a/dev/tests/verification/Resources/ActionGroupUsingNestedArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupUsingNestedArgument.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") */ class ActionGroupUsingNestedArgumentCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt b/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt index a455d98e0..bb6404315 100644 --- a/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt +++ b/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @group functional - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") */ class ActionGroupWithDataOverrideTestCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithDataTest.txt b/dev/tests/verification/Resources/ActionGroupWithDataTest.txt index 7ac32f550..6b22f83e0 100644 --- a/dev/tests/verification/Resources/ActionGroupWithDataTest.txt +++ b/dev/tests/verification/Resources/ActionGroupWithDataTest.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @group functional - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") */ class ActionGroupWithDataTestCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithDefaultArgumentAndStringSelectorParam.txt b/dev/tests/verification/Resources/ActionGroupWithDefaultArgumentAndStringSelectorParam.txt index 289bbe4e1..ca5f72cc0 100644 --- a/dev/tests/verification/Resources/ActionGroupWithDefaultArgumentAndStringSelectorParam.txt +++ b/dev/tests/verification/Resources/ActionGroupWithDefaultArgumentAndStringSelectorParam.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: Action Group With Default Argument Value and Hardcoded Value in Param") - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") */ class ActionGroupWithDefaultArgumentAndStringSelectorParamCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.txt b/dev/tests/verification/Resources/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.txt index 4e94978ad..f3ad492b0 100644 --- a/dev/tests/verification/Resources/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: Action Group With Passed Argument Value and Multiple Argument Values in Param") - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") */ class ActionGroupWithMultipleParameterSelectorsFromDefaultArgumentCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithNoArguments.txt b/dev/tests/verification/Resources/ActionGroupWithNoArguments.txt index 6158b5af7..0f69c40e8 100644 --- a/dev/tests/verification/Resources/ActionGroupWithNoArguments.txt +++ b/dev/tests/verification/Resources/ActionGroupWithNoArguments.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: Action Group With No Argument") - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") */ class ActionGroupWithNoArgumentsCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt b/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt index ca6474a7b..533e14b9d 100644 --- a/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt +++ b/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @group functional - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") */ class ActionGroupWithNoDefaultTestCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithParameterizedElementWithHyphen.txt b/dev/tests/verification/Resources/ActionGroupWithParameterizedElementWithHyphen.txt index 52dc8bd1b..acc6aa58a 100644 --- a/dev/tests/verification/Resources/ActionGroupWithParameterizedElementWithHyphen.txt +++ b/dev/tests/verification/Resources/ActionGroupWithParameterizedElementWithHyphen.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") */ class ActionGroupWithParameterizedElementWithHyphenCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithParameterizedElementsWithStepKeyReferences.txt b/dev/tests/verification/Resources/ActionGroupWithParameterizedElementsWithStepKeyReferences.txt index b0758e679..ac20299a8 100644 --- a/dev/tests/verification/Resources/ActionGroupWithParameterizedElementsWithStepKeyReferences.txt +++ b/dev/tests/verification/Resources/ActionGroupWithParameterizedElementsWithStepKeyReferences.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") */ class ActionGroupWithParameterizedElementsWithStepKeyReferencesCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithPassedArgumentAndStringSelectorParam.txt b/dev/tests/verification/Resources/ActionGroupWithPassedArgumentAndStringSelectorParam.txt index 254fbe0f2..e816da90b 100644 --- a/dev/tests/verification/Resources/ActionGroupWithPassedArgumentAndStringSelectorParam.txt +++ b/dev/tests/verification/Resources/ActionGroupWithPassedArgumentAndStringSelectorParam.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: Action Group With Passed Argument Value and Hardcoded Value in Param") - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") */ class ActionGroupWithPassedArgumentAndStringSelectorParamCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt b/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt index e8eb29996..7d0bb58e9 100644 --- a/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt +++ b/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @group functional - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") */ class ActionGroupWithPersistedDataCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithSectionAndDataAsArguments.txt b/dev/tests/verification/Resources/ActionGroupWithSectionAndDataAsArguments.txt index ec6111062..f629f32f1 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSectionAndDataAsArguments.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSectionAndDataAsArguments.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") */ class ActionGroupWithSectionAndDataAsArgumentsCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromDefaultArgument.txt b/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromDefaultArgument.txt index f4faf0773..10206867a 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromDefaultArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromDefaultArgument.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: Action Group With Simple Data Usage From Default Argument") - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") */ class ActionGroupWithSimpleDataUsageFromDefaultArgumentCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromPassedArgument.txt b/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromPassedArgument.txt index 86791407d..54aec35a7 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromPassedArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromPassedArgument.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: Action Group With Simple Data Usage From Passed Argument") - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") */ class ActionGroupWithSimpleDataUsageFromPassedArgumentCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromDefaultArgument.txt b/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromDefaultArgument.txt index 5d8298108..c23b99cab 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromDefaultArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromDefaultArgument.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: Action Group With Default Argument Value and Argument Value in Param") - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") */ class ActionGroupWithSingleParameterSelectorFromDefaultArgumentCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromPassedArgument.txt b/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromPassedArgument.txt index 283a9fdd7..4a0932b99 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromPassedArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromPassedArgument.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: Action Group With Passed Argument Value and Argument Value in Param") - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") */ class ActionGroupWithSingleParameterSelectorFromPassedArgumentCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt b/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt index 2ee5b4bf9..8098142fd 100644 --- a/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt +++ b/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") */ class ActionGroupWithStepKeyReferencesCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt b/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt index ca8325402..a8f80eae6 100644 --- a/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt +++ b/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @group functional - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") */ class ActionGroupWithTopLevelPersistedDataCest { diff --git a/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt b/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt index 44a00dbd9..e45207249 100644 --- a/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt +++ b/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @group functional - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") */ class ArgumentWithSameNameAsElementCest { diff --git a/dev/tests/verification/Resources/AssertTest.txt b/dev/tests/verification/Resources/AssertTest.txt index e7f24b605..bb29759d5 100644 --- a/dev/tests/verification/Resources/AssertTest.txt +++ b/dev/tests/verification/Resources/AssertTest.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/AssertTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/AssertTest.xml<br>") */ class AssertTestCest { diff --git a/dev/tests/verification/Resources/BasicActionGroupTest.txt b/dev/tests/verification/Resources/BasicActionGroupTest.txt index 02915d1a8..7d8c40f0b 100644 --- a/dev/tests/verification/Resources/BasicActionGroupTest.txt +++ b/dev/tests/verification/Resources/BasicActionGroupTest.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @group functional - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") */ class BasicActionGroupTestCest { diff --git a/dev/tests/verification/Resources/BasicFunctionalTest.txt b/dev/tests/verification/Resources/BasicFunctionalTest.txt index e78f1b49c..ac42f395e 100644 --- a/dev/tests/verification/Resources/BasicFunctionalTest.txt +++ b/dev/tests/verification/Resources/BasicFunctionalTest.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: A Functional Cest") * @group functional - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/BasicFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/BasicFunctionalTest.xml<br>") */ class BasicFunctionalTestCest { diff --git a/dev/tests/verification/Resources/BasicMergeTest.txt b/dev/tests/verification/Resources/BasicMergeTest.txt index c6fb58e3a..8171cd892 100644 --- a/dev/tests/verification/Resources/BasicMergeTest.txt +++ b/dev/tests/verification/Resources/BasicMergeTest.txt @@ -16,7 +16,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; * @Title("[NO TESTCASEID]: BasicMergeTest") * @group functional * @group mergeTest - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/MergeFunctionalTest.xml<br>verification/TestModuleMerged/Test/MergeFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/MergeFunctionalTest.xml<br>verification/TestModuleMerged/Test/MergeFunctionalTest.xml<br>") */ class BasicMergeTestCest { diff --git a/dev/tests/verification/Resources/CharacterReplacementTest.txt b/dev/tests/verification/Resources/CharacterReplacementTest.txt index 61729cc8b..24d8e2ab1 100644 --- a/dev/tests/verification/Resources/CharacterReplacementTest.txt +++ b/dev/tests/verification/Resources/CharacterReplacementTest.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/CharacterReplacementTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/CharacterReplacementTest.xml<br>") */ class CharacterReplacementTestCest { diff --git a/dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt b/dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt index 8362cf513..86d81f848 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: ChildExtendedTestAddHooks") * @group Parent - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") */ class ChildExtendedTestAddHooksCest { diff --git a/dev/tests/verification/Resources/ChildExtendedTestMerging.txt b/dev/tests/verification/Resources/ChildExtendedTestMerging.txt index 590ba6003..08345bd86 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestMerging.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestMerging.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: ChildExtendedTestMerging") * @group Child - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") */ class ChildExtendedTestMergingCest { diff --git a/dev/tests/verification/Resources/ChildExtendedTestNoParent.txt b/dev/tests/verification/Resources/ChildExtendedTestNoParent.txt index 5d72176c5..4cca6ec06 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestNoParent.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestNoParent.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: ChildExtendedTestNoParent") * @group Child - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") * @group skip */ class ChildExtendedTestNoParentCest diff --git a/dev/tests/verification/Resources/ChildExtendedTestRemoveAction.txt b/dev/tests/verification/Resources/ChildExtendedTestRemoveAction.txt index 766bfd331..370ffe404 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestRemoveAction.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestRemoveAction.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: ChildExtendedTestRemoveAction") * @group Child - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") */ class ChildExtendedTestRemoveActionCest { diff --git a/dev/tests/verification/Resources/ChildExtendedTestRemoveHookAction.txt b/dev/tests/verification/Resources/ChildExtendedTestRemoveHookAction.txt index 8497c29af..50b6e030d 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestRemoveHookAction.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestRemoveHookAction.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: ChildExtendedTestRemoveHookAction") * @group Child - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") */ class ChildExtendedTestRemoveHookActionCest { diff --git a/dev/tests/verification/Resources/ChildExtendedTestReplace.txt b/dev/tests/verification/Resources/ChildExtendedTestReplace.txt index 3b2e9d369..ce32f6af1 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestReplace.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestReplace.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: ChildExtendedTestReplace") * @group Child - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") */ class ChildExtendedTestReplaceCest { diff --git a/dev/tests/verification/Resources/ChildExtendedTestReplaceHook.txt b/dev/tests/verification/Resources/ChildExtendedTestReplaceHook.txt index 53ae22361..bbb6c5ef9 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestReplaceHook.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestReplaceHook.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: ChildExtendedTestReplaceHook") * @group Child - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") */ class ChildExtendedTestReplaceHookCest { diff --git a/dev/tests/verification/Resources/DataActionsTest.txt b/dev/tests/verification/Resources/DataActionsTest.txt index c3f8400b3..84a94174a 100644 --- a/dev/tests/verification/Resources/DataActionsTest.txt +++ b/dev/tests/verification/Resources/DataActionsTest.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/DataActionsTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/DataActionsTest.xml<br>") */ class DataActionsTestCest { diff --git a/dev/tests/verification/Resources/DataReplacementTest.txt b/dev/tests/verification/Resources/DataReplacementTest.txt index 2912ee8a2..b75d93f0d 100644 --- a/dev/tests/verification/Resources/DataReplacementTest.txt +++ b/dev/tests/verification/Resources/DataReplacementTest.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/DataReplacementTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/DataReplacementTest.xml<br>") */ class DataReplacementTestCest { diff --git a/dev/tests/verification/Resources/ExecuteInSeleniumTest.txt b/dev/tests/verification/Resources/ExecuteInSeleniumTest.txt index cfd7a14ce..bbed61691 100644 --- a/dev/tests/verification/Resources/ExecuteInSeleniumTest.txt +++ b/dev/tests/verification/Resources/ExecuteInSeleniumTest.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ExecuteInSeleniumTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ExecuteInSeleniumTest.xml<br>") */ class ExecuteInSeleniumTestCest { diff --git a/dev/tests/verification/Resources/ExecuteJsEscapingTest.txt b/dev/tests/verification/Resources/ExecuteJsEscapingTest.txt index d0b7acc83..ad3696e00 100644 --- a/dev/tests/verification/Resources/ExecuteJsEscapingTest.txt +++ b/dev/tests/verification/Resources/ExecuteJsEscapingTest.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ExecuteJsTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ExecuteJsTest.xml<br>") */ class ExecuteJsEscapingTestCest { diff --git a/dev/tests/verification/Resources/ExtendParentDataTest.txt b/dev/tests/verification/Resources/ExtendParentDataTest.txt index d26d91b08..70cb6b70b 100644 --- a/dev/tests/verification/Resources/ExtendParentDataTest.txt +++ b/dev/tests/verification/Resources/ExtendParentDataTest.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ExtendedDataTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedDataTest.xml<br>") */ class ExtendParentDataTestCest { diff --git a/dev/tests/verification/Resources/ExtendedActionGroup.txt b/dev/tests/verification/Resources/ExtendedActionGroup.txt index 3158161d9..8996526ba 100644 --- a/dev/tests/verification/Resources/ExtendedActionGroup.txt +++ b/dev/tests/verification/Resources/ExtendedActionGroup.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") */ class ExtendedActionGroupCest { diff --git a/dev/tests/verification/Resources/ExtendedChildTestInSuiteCest.txt b/dev/tests/verification/Resources/ExtendedChildTestInSuiteCest.txt index bde2ce2b3..e4a006c8f 100644 --- a/dev/tests/verification/Resources/ExtendedChildTestInSuiteCest.txt +++ b/dev/tests/verification/Resources/ExtendedChildTestInSuiteCest.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: ExtendedChildTestInSuite") * @group ExtendedTestInSuite - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") */ class ExtendedChildTestInSuiteCest { diff --git a/dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt b/dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt index fc67be840..1d5af7d3e 100644 --- a/dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt +++ b/dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: ExtendedChildTestNotInSuite") - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") */ class ExtendedChildTestNotInSuiteCest { diff --git a/dev/tests/verification/Resources/ExtendedRemoveActionGroup.txt b/dev/tests/verification/Resources/ExtendedRemoveActionGroup.txt index 5ba7a3cce..fde8842e7 100644 --- a/dev/tests/verification/Resources/ExtendedRemoveActionGroup.txt +++ b/dev/tests/verification/Resources/ExtendedRemoveActionGroup.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") */ class ExtendedRemoveActionGroupCest { diff --git a/dev/tests/verification/Resources/ExtendingSkippedTest.txt b/dev/tests/verification/Resources/ExtendingSkippedTest.txt index 73a1c89d7..93e9b6a60 100644 --- a/dev/tests/verification/Resources/ExtendingSkippedTest.txt +++ b/dev/tests/verification/Resources/ExtendingSkippedTest.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: ChildExtendedTestSkippedParent") * @group Child - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") */ class ExtendingSkippedTestCest { diff --git a/dev/tests/verification/Resources/HookActionsTest.txt b/dev/tests/verification/Resources/HookActionsTest.txt index c61cc86e2..0b77325c1 100644 --- a/dev/tests/verification/Resources/HookActionsTest.txt +++ b/dev/tests/verification/Resources/HookActionsTest.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/HookActionsTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/HookActionsTest.xml<br>") */ class HookActionsTestCest { diff --git a/dev/tests/verification/Resources/LocatorFunctionTest.txt b/dev/tests/verification/Resources/LocatorFunctionTest.txt index f00392778..76c48a921 100644 --- a/dev/tests/verification/Resources/LocatorFunctionTest.txt +++ b/dev/tests/verification/Resources/LocatorFunctionTest.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/LocatorFunctionTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/LocatorFunctionTest.xml<br>") */ class LocatorFunctionTestCest { diff --git a/dev/tests/verification/Resources/MergeMassViaInsertAfter.txt b/dev/tests/verification/Resources/MergeMassViaInsertAfter.txt index 90c8c5373..a57ca4471 100644 --- a/dev/tests/verification/Resources/MergeMassViaInsertAfter.txt +++ b/dev/tests/verification/Resources/MergeMassViaInsertAfter.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/BasicFunctionalTest.xml<br>verification/TestModule/Test/MergeFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/BasicFunctionalTest.xml<br>verification/TestModule/Test/MergeFunctionalTest.xml<br>") */ class MergeMassViaInsertAfterCest { diff --git a/dev/tests/verification/Resources/MergeMassViaInsertBefore.txt b/dev/tests/verification/Resources/MergeMassViaInsertBefore.txt index df569d66b..7c6fdc906 100644 --- a/dev/tests/verification/Resources/MergeMassViaInsertBefore.txt +++ b/dev/tests/verification/Resources/MergeMassViaInsertBefore.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/BasicFunctionalTest.xml<br>verification/TestModule/Test/MergeFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/BasicFunctionalTest.xml<br>verification/TestModule/Test/MergeFunctionalTest.xml<br>") */ class MergeMassViaInsertBeforeCest { diff --git a/dev/tests/verification/Resources/MergeSkip.txt b/dev/tests/verification/Resources/MergeSkip.txt index bf5903065..b2a1b8918 100644 --- a/dev/tests/verification/Resources/MergeSkip.txt +++ b/dev/tests/verification/Resources/MergeSkip.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/MergeFunctionalTest.xml<br>verification/TestModuleMerged/Test/MergeFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/MergeFunctionalTest.xml<br>verification/TestModuleMerged/Test/MergeFunctionalTest.xml<br>") */ class MergeSkipCest { diff --git a/dev/tests/verification/Resources/MergedActionGroupTest.txt b/dev/tests/verification/Resources/MergedActionGroupTest.txt index e0067b479..a9c740127 100644 --- a/dev/tests/verification/Resources/MergedActionGroupTest.txt +++ b/dev/tests/verification/Resources/MergedActionGroupTest.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @group functional - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") */ class MergedActionGroupTestCest { diff --git a/dev/tests/verification/Resources/MergedReferencesTest.txt b/dev/tests/verification/Resources/MergedReferencesTest.txt index c4cc7276e..b3fc29966 100644 --- a/dev/tests/verification/Resources/MergedReferencesTest.txt +++ b/dev/tests/verification/Resources/MergedReferencesTest.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: MergedReferencesTest") * @group functional - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/MergeFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/MergeFunctionalTest.xml<br>") */ class MergedReferencesTestCest { diff --git a/dev/tests/verification/Resources/MultipleActionGroupsTest.txt b/dev/tests/verification/Resources/MultipleActionGroupsTest.txt index 8e5ea542e..5f1db5081 100644 --- a/dev/tests/verification/Resources/MultipleActionGroupsTest.txt +++ b/dev/tests/verification/Resources/MultipleActionGroupsTest.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @group functional - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") */ class MultipleActionGroupsTestCest { diff --git a/dev/tests/verification/Resources/PageReplacementTest.txt b/dev/tests/verification/Resources/PageReplacementTest.txt index f90a4fda7..cda119999 100644 --- a/dev/tests/verification/Resources/PageReplacementTest.txt +++ b/dev/tests/verification/Resources/PageReplacementTest.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/PageReplacementTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/PageReplacementTest.xml<br>") */ class PageReplacementTestCest { diff --git a/dev/tests/verification/Resources/ParameterArrayTest.txt b/dev/tests/verification/Resources/ParameterArrayTest.txt index af47657ea..8918bb619 100644 --- a/dev/tests/verification/Resources/ParameterArrayTest.txt +++ b/dev/tests/verification/Resources/ParameterArrayTest.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ParameterArrayTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ParameterArrayTest.xml<br>") */ class ParameterArrayTestCest { diff --git a/dev/tests/verification/Resources/ParentExtendedTest.txt b/dev/tests/verification/Resources/ParentExtendedTest.txt index 5662da744..8c756f010 100644 --- a/dev/tests/verification/Resources/ParentExtendedTest.txt +++ b/dev/tests/verification/Resources/ParentExtendedTest.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: ParentExtendedTest") * @group Parent - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") */ class ParentExtendedTestCest { diff --git a/dev/tests/verification/Resources/PersistedAndXmlEntityArguments.txt b/dev/tests/verification/Resources/PersistedAndXmlEntityArguments.txt index 2f86f0af7..f6956f5d9 100644 --- a/dev/tests/verification/Resources/PersistedAndXmlEntityArguments.txt +++ b/dev/tests/verification/Resources/PersistedAndXmlEntityArguments.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") */ class PersistedAndXmlEntityArgumentsCest { diff --git a/dev/tests/verification/Resources/PersistedReplacementTest.txt b/dev/tests/verification/Resources/PersistedReplacementTest.txt index 009a8eac2..eb1c9995d 100644 --- a/dev/tests/verification/Resources/PersistedReplacementTest.txt +++ b/dev/tests/verification/Resources/PersistedReplacementTest.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/PersistedReplacementTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/PersistedReplacementTest.xml<br>") */ class PersistedReplacementTestCest { diff --git a/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt b/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt index 118db353a..426003bc2 100644 --- a/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt +++ b/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/PersistenceActionGroupAppendingTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/PersistenceActionGroupAppendingTest.xml<br>") */ class PersistenceActionGroupAppendingTestCest { diff --git a/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt b/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt index 221373be1..41251d2fb 100644 --- a/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt +++ b/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/PersistenceCustomFieldsTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/PersistenceCustomFieldsTest.xml<br>") */ class PersistenceCustomFieldsTestCest { diff --git a/dev/tests/verification/Resources/SectionReplacementTest.txt b/dev/tests/verification/Resources/SectionReplacementTest.txt index 2b2a8bcd6..109c198eb 100644 --- a/dev/tests/verification/Resources/SectionReplacementTest.txt +++ b/dev/tests/verification/Resources/SectionReplacementTest.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/SectionReplacementTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/SectionReplacementTest.xml<br>") */ class SectionReplacementTestCest { diff --git a/dev/tests/verification/Resources/SkippedTest.txt b/dev/tests/verification/Resources/SkippedTest.txt index dcad67e83..95783ca66 100644 --- a/dev/tests/verification/Resources/SkippedTest.txt +++ b/dev/tests/verification/Resources/SkippedTest.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: skippedTest") - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/SkippedTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/SkippedTest.xml<br>") */ class SkippedTestCest { diff --git a/dev/tests/verification/Resources/SkippedTestNoIssues.txt b/dev/tests/verification/Resources/SkippedTestNoIssues.txt index 3a7ca6f59..e8f4726d9 100644 --- a/dev/tests/verification/Resources/SkippedTestNoIssues.txt +++ b/dev/tests/verification/Resources/SkippedTestNoIssues.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: skippedNoIssuesTest") - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/SkippedTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/SkippedTest.xml<br>") * @group skip */ class SkippedTestNoIssuesCest diff --git a/dev/tests/verification/Resources/SkippedTestTwoIssues.txt b/dev/tests/verification/Resources/SkippedTestTwoIssues.txt index d3859978f..4a801856e 100644 --- a/dev/tests/verification/Resources/SkippedTestTwoIssues.txt +++ b/dev/tests/verification/Resources/SkippedTestTwoIssues.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: skippedMultipleIssuesTest") - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/SkippedTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/SkippedTest.xml<br>") */ class SkippedTestTwoIssuesCest { diff --git a/dev/tests/verification/Resources/SkippedTestWithHooks.txt b/dev/tests/verification/Resources/SkippedTestWithHooks.txt index 667be6747..ad59d48c3 100644 --- a/dev/tests/verification/Resources/SkippedTestWithHooks.txt +++ b/dev/tests/verification/Resources/SkippedTestWithHooks.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: skippedTestWithHooks") - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/SkippedTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/SkippedTest.xml<br>") */ class SkippedTestWithHooksCest { diff --git a/dev/tests/verification/Resources/XmlCommentedActionGroupTest.txt b/dev/tests/verification/Resources/XmlCommentedActionGroupTest.txt index 480e35b73..0eb546335 100644 --- a/dev/tests/verification/Resources/XmlCommentedActionGroupTest.txt +++ b/dev/tests/verification/Resources/XmlCommentedActionGroupTest.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: Action Group With comment block in arguments and action group body") - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/XmlCommentedActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/XmlCommentedActionGroupTest.xml<br>") */ class XmlCommentedActionGroupTestCest { diff --git a/dev/tests/verification/Resources/XmlCommentedTest.txt b/dev/tests/verification/Resources/XmlCommentedTest.txt index 5b8057099..47d984d9e 100644 --- a/dev/tests/verification/Resources/XmlCommentedTest.txt +++ b/dev/tests/verification/Resources/XmlCommentedTest.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: Test With comment blocks in root element 'tests', in annotations and in test body.") - * @Description("<br><br><b><font size=+0.9>Test files</font></b><br><br>verification/TestModule/Test/XmlCommentedTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/XmlCommentedTest.xml<br>") */ class XmlCommentedTestCest { diff --git a/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php b/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php index 97335726a..e9e1c344c 100644 --- a/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php +++ b/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php @@ -5,7 +5,6 @@ */ namespace Magento\FunctionalTestingFramework\Allure\Adapter; -use Codeception\Event\TestEvent; use Codeception\Step\Comment; use Magento\FunctionalTestingFramework\Suite\Handlers\SuiteObjectHandler; use Magento\FunctionalTestingFramework\Test\Objects\ActionGroupObject; diff --git a/src/Magento/FunctionalTestingFramework/Codeception/Subscriber/Console.php b/src/Magento/FunctionalTestingFramework/Codeception/Subscriber/Console.php index 01b385133..90f04abae 100644 --- a/src/Magento/FunctionalTestingFramework/Codeception/Subscriber/Console.php +++ b/src/Magento/FunctionalTestingFramework/Codeception/Subscriber/Console.php @@ -18,6 +18,9 @@ use Magento\FunctionalTestingFramework\Util\TestGenerator; use Symfony\Component\Console\Formatter\OutputFormatter; +/** + * @SuppressWarnings(PHPMD) + */ class Console extends \Codeception\Subscriber\Console { /** @@ -60,6 +63,13 @@ public function __construct($extensionOptions = [], $options = []) parent::__construct($options); } + /** + * Triggered event before each test. + * + * @param TestEvent $e + * @return void + * @throws \Exception + */ public function startTest(TestEvent $e) { $test = $e->getTest()->getTestClass(); @@ -80,7 +90,7 @@ public function startTest(TestEvent $e) LoggingUtil::getInstance()->getLogger(self::class)->error($e->getMessage(), $e->getTrace()); } - return parent::startTest($e); + parent::startTest($e); } /** diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php index 0a7ae8ff2..0a188c6d0 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php @@ -13,7 +13,6 @@ use Magento\FunctionalTestingFramework\ObjectManager\ObjectHandlerInterface; use Magento\FunctionalTestingFramework\ObjectManagerFactory; use Magento\FunctionalTestingFramework\DataGenerator\Util\DataExtensionUtil; -use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; class DataObjectHandler implements ObjectHandlerInterface @@ -121,6 +120,7 @@ public function getAllObjects() * @param string[] $parserOutput Primitive array output from the Magento parser. * @return EntityDataObject[] * @throws XmlException + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ private function processParserOutput($parserOutput) { @@ -134,6 +134,7 @@ private function processParserOutput($parserOutput) $type = $rawEntity[self::_TYPE] ?? null; $data = []; + $deprecated = null; $linkedEntities = []; $uniquenessData = []; $vars = []; diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php index 7fbfe0be7..7181bc994 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php @@ -129,9 +129,7 @@ public function getOperationDefinition($operation, $dataType) * @return void * @throws \Exception * - * @SuppressWarnings(PHPMD.NPathComplexity) - * @SuppressWarnings(PHPMD.UnusedPrivateMethod) - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + * @SuppressWarnings(PHPMD) */ private function initialize() { diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/EntityDataObject.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/EntityDataObject.php index a41ee03d8..2204364f5 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/EntityDataObject.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/EntityDataObject.php @@ -90,14 +90,14 @@ class EntityDataObject /** * Constructor * - * @param string $name - * @param string $type - * @param string[] $data - * @param string[] $linkedEntities - * @param string[] $uniquenessData - * @param string[] $vars - * @param string $parentEntity - * @param string $filename + * @param string $name + * @param string $type + * @param string[] $data + * @param string[] $linkedEntities + * @param string[] $uniquenessData + * @param string[] $vars + * @param string $parentEntity + * @param string $filename * @param string|null $deprecated */ public function __construct( diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/OperationDefinitionObject.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/OperationDefinitionObject.php index a294ea1fd..67fe48300 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/OperationDefinitionObject.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/OperationDefinitionObject.php @@ -8,6 +8,7 @@ /** * Class OperationDefinitionObject + * @SuppressWarnings(PHPMD) */ class OperationDefinitionObject { @@ -126,20 +127,20 @@ class OperationDefinitionObject /** * OperationDefinitionObject constructor. - * @param string $name - * @param string $operation - * @param string $dataType - * @param string $apiMethod - * @param string $apiUri - * @param string $auth - * @param array $headers - * @param array $params - * @param array $metaData - * @param string $contentType - * @param boolean $removeBackend - * @param string $successRegex - * @param string $returnRegex - * @param string $returnIndex + * @param string $name + * @param string $operation + * @param string $dataType + * @param string $apiMethod + * @param string $apiUri + * @param string $auth + * @param array $headers + * @param array $params + * @param array $metaData + * @param string $contentType + * @param boolean $removeBackend + * @param string $successRegex + * @param string $returnRegex + * @param string $returnIndex * @param string|null $deprecated * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ diff --git a/src/Magento/FunctionalTestingFramework/Page/Objects/PageObject.php b/src/Magento/FunctionalTestingFramework/Page/Objects/PageObject.php index 19525a415..e4a1acdc0 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Objects/PageObject.php +++ b/src/Magento/FunctionalTestingFramework/Page/Objects/PageObject.php @@ -74,12 +74,12 @@ class PageObject /** * PageObject constructor. - * @param string $name - * @param string $url - * @param string $module - * @param array $sections - * @param boolean $parameterized - * @param string $area + * @param string $name + * @param string $url + * @param string $module + * @param array $sections + * @param boolean $parameterized + * @param string $area * @param string|null $filename * @param string|null $deprecated */ diff --git a/src/Magento/FunctionalTestingFramework/Page/Objects/SectionObject.php b/src/Magento/FunctionalTestingFramework/Page/Objects/SectionObject.php index 57883e393..3674eea16 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Objects/SectionObject.php +++ b/src/Magento/FunctionalTestingFramework/Page/Objects/SectionObject.php @@ -41,8 +41,8 @@ class SectionObject /** * SectionObject constructor. - * @param string $name - * @param array $elements + * @param string $name + * @param array $elements * @param string|null $filename * @param string|null $deprecated */ diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php index 1a1e93dab..dc1b158e1 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php @@ -104,13 +104,13 @@ class ActionGroupObject /** * ActionGroupObject constructor. * - * @param string $name - * @param array $annotations + * @param string $name + * @param array $annotations * @param ArgumentObject[] $arguments - * @param array $actions - * @param string $parentActionGroup - * @param string $filename - * @param $deprecated + * @param array $actions + * @param string $parentActionGroup + * @param string $filename + * @param string|null $deprecated */ public function __construct( $name, diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php index 207d05bc7..44bc8726f 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php @@ -84,7 +84,6 @@ class ActionObject */ private $stepKey; - /** * Array of deprecated entities used in action. * @@ -144,13 +143,13 @@ class ActionObject /** * ActionObject constructor. * - * @param string $stepKey - * @param string $type - * @param array $actionAttributes + * @param string $stepKey + * @param string $type + * @param array $actionAttributes * @param string|null $linkedAction - * @param string $order - * @param array $actionOrigin - * @param array $deprecatedUsage + * @param string $order + * @param array $actionOrigin + * @param array $deprecatedUsage */ public function __construct( $stepKey, @@ -573,7 +572,8 @@ private function findAndReplaceReferences($objectHandler, $inputString) } } elseif (get_class($obj) == EntityDataObject::class) { if ($obj->getDeprecated() !== null) { - $this->deprecatedUsage[] = "DEPRECATED DATA ENTITY in Test: " . $match . ' ' . $obj->getDeprecated(); + $this->deprecatedUsage[] = "DEPRECATED DATA ENTITY in Test: " + . $match . ' ' . $obj->getDeprecated(); } $replacement = $this->resolveEntityDataObjectReference($obj, $match); diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php index c55e35b9a..68b9b4c50 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php @@ -17,6 +17,7 @@ /** * Class TestObjectExtractor + * @SuppressWarnings(PHPMD) */ class TestObjectExtractor extends BaseObjectExtractor { @@ -133,6 +134,7 @@ public function extractTestData($testData) } $testAnnotations["description"]['test_files'] = $this->appendFileNamesInDescriptionAnnotation($fileNames); + $testAnnotations["description"][self::TEST_DEPRECATED] = []; if ($deprecated !== null) { $testAnnotations["description"][self::TEST_DEPRECATED][] = $deprecated; LoggingUtil::getInstance()->getLogger(TestObject::class)->deprecation( diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index e16c4cde6..e4e1c34c7 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -463,7 +463,7 @@ private function generateMethodAnnotations($annotationType = null, $annotationNa * Method which return formatted class level annotations based on type and name(s). * * @param string $annotationType - * @param array $annotationName + * @param array $annotationName * @return null|string * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ @@ -509,8 +509,8 @@ private function generateDescriptionAnnotation(array $descriptions) { $descriptionText = ""; - $descriptionText .= $descriptions["main"]; - if (!empty($descriptions[TestObjectExtractor::TEST_DEPRECATED])) { + $descriptionText .= $descriptions["main"] ?? ''; + if (!empty($descriptions[TestObjectExtractor::TEST_DEPRECATED]) || !empty($this->deprecationMessages)) { $deprecatedMessages = array_merge( $descriptions[TestObjectExtractor::TEST_DEPRECATED], $this->deprecationMessages From 3e86d4f8dca940416985fcfbf1ab0f5bf0597f22 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 27 Jan 2020 11:43:22 -0600 Subject: [PATCH 170/888] MFTF deprecation notice attributes - fix review comments --- .../DataGenerator/Handlers/DataObjectHandler.php | 4 ++-- .../Handlers/OperationDefinitionObjectHandler.php | 2 +- .../ObjectManager/ObjectHandlerInterface.php | 2 ++ .../Page/Handlers/PageObjectHandler.php | 2 +- .../Page/Handlers/SectionObjectHandler.php | 4 ++-- .../Test/Util/ActionGroupObjectExtractor.php | 4 ++-- .../Test/Util/BaseObjectExtractor.php | 1 + .../Test/Util/TestObjectExtractor.php | 13 ++++++------- .../Util/TestGenerator.php | 10 +++------- 9 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php index 0a188c6d0..a210710db 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php @@ -166,8 +166,8 @@ private function processParserOutput($parserOutput) $parentEntity = $rawEntity[self::_EXTENDS]; } - if (array_key_exists('deprecated', $rawEntity)) { - $deprecated = $rawEntity['deprecated']; + if (array_key_exists(self::OBJ_DEPRECATED, $rawEntity)) { + $deprecated = $rawEntity[self::OBJ_DEPRECATED]; LoggingUtil::getInstance()->getLogger(self::class)->deprecation( $deprecated, ["dataName" => $filename, "deprecatedEntity" => $deprecated] diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php index 7181bc994..8c2ec7b0a 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php @@ -144,7 +144,7 @@ private function initialize() $auth = $opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH] ?? null; $successRegex = $opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_SUCCESS_REGEX] ?? null; $returnRegex = $opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_RETURN_REGEX] ?? null; - $deprecated = $opDefArray['deprecated'] ?? null; + $deprecated = $opDefArray[ObjectHandlerInterface::OBJ_DEPRECATED] ?? null; $returnIndex = $opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_RETURN_INDEX] ?? 0; $contentType = $opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_CONTENT_TYPE][0]['value'] ?? null; diff --git a/src/Magento/FunctionalTestingFramework/ObjectManager/ObjectHandlerInterface.php b/src/Magento/FunctionalTestingFramework/ObjectManager/ObjectHandlerInterface.php index 1bc79cbbb..94147dc08 100644 --- a/src/Magento/FunctionalTestingFramework/ObjectManager/ObjectHandlerInterface.php +++ b/src/Magento/FunctionalTestingFramework/ObjectManager/ObjectHandlerInterface.php @@ -11,6 +11,8 @@ */ interface ObjectHandlerInterface { + const OBJ_DEPRECATED = 'deprecated'; + /** * Function to enforce singleton design pattern * diff --git a/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php b/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php index a9c3b7cfb..c310b9bef 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php @@ -69,7 +69,7 @@ private function __construct() $sectionNames = array_keys($pageData[self::SECTION] ?? []); $parameterized = $pageData[self::PARAMETERIZED] ?? false; $filename = $pageData[self::FILENAME] ?? null; - $deprecated = $pageData['deprecated'] ?? null; + $deprecated = $pageData[self::OBJ_DEPRECATED] ?? null; if ($deprecated !== null) { LoggingUtil::getInstance()->getLogger(self::class)->deprecation( diff --git a/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php b/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php index a827eac22..15c4fdd9e 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php @@ -75,7 +75,7 @@ private function __construct() $elementLocatorFunc = $elementData[SectionObjectHandler::LOCATOR_FUNCTION] ?? null; $elementTimeout = $elementData[SectionObjectHandler::TIMEOUT] ?? null; $elementParameterized = $elementData[SectionObjectHandler::PARAMETERIZED] ?? false; - $elementDeprecated = $elementData['deprecated'] ?? null; + $elementDeprecated = $elementData[self::OBJ_DEPRECATED] ?? null; if ($elementDeprecated !== null) { LoggingUtil::getInstance()->getLogger(ElementObject::class)->deprecation( $elementDeprecated, @@ -97,7 +97,7 @@ private function __construct() } $filename = $sectionData[self::FILENAME] ?? null; - $sectionDeprecated = $sectionData['deprecated'] ?? null; + $sectionDeprecated = $sectionData[self::OBJ_DEPRECATED] ?? null; if ($sectionDeprecated !== null) { LoggingUtil::getInstance()->getLogger(ElementObject::class)->deprecation( diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/ActionGroupObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/ActionGroupObjectExtractor.php index 0b606c6d8..618cddc09 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/ActionGroupObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/ActionGroupObjectExtractor.php @@ -62,8 +62,8 @@ public function extractActionGroup($actionGroupData) $arguments = []; $deprecated = null; - if (array_key_exists('deprecated', $actionGroupData)) { - $deprecated = $actionGroupData['deprecated']; + if (array_key_exists(self::OBJ_DEPRECATED, $actionGroupData)) { + $deprecated = $actionGroupData[self::OBJ_DEPRECATED]; LoggingUtil::getInstance()->getLogger(ActionGroupObject::class)->deprecation( $deprecated, ["actionGroupName" => $actionGroupData[self::FILENAME], "deprecatedActionGroup" => $deprecated] diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/BaseObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/BaseObjectExtractor.php index 26644937d..516f79d14 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/BaseObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/BaseObjectExtractor.php @@ -13,6 +13,7 @@ class BaseObjectExtractor { const NODE_NAME = 'nodeName'; const NAME = 'name'; + const OBJ_DEPRECATED = 'deprecated'; /** * BaseObjectExtractor constructor. diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php index 68b9b4c50..a25db0935 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php @@ -22,7 +22,6 @@ class TestObjectExtractor extends BaseObjectExtractor { const TEST_ANNOTATIONS = 'annotations'; - const TEST_DEPRECATED = 'deprecated'; const TEST_BEFORE_HOOK = 'before'; const TEST_AFTER_HOOK = 'after'; const TEST_FAILED_HOOK = 'failed'; @@ -100,7 +99,7 @@ public function extractTestData($testData) $baseFileName = $fileNames[0]; $module = $this->modulePathExtractor->extractModuleName($baseFileName); $testReference = $testData['extends'] ?? null; - $deprecated = isset($testData[self::TEST_DEPRECATED]) ? $testData[self::TEST_DEPRECATED] : null; + $deprecated = isset($testData[self::OBJ_DEPRECATED]) ? $testData[self::OBJ_DEPRECATED] : null; $testActions = $this->stripDescriptorTags( $testData, self::NODE_NAME, @@ -112,7 +111,7 @@ public function extractTestData($testData) self::TEST_INSERT_BEFORE, self::TEST_INSERT_AFTER, self::TEST_FILENAME, - self::TEST_DEPRECATED, + self::OBJ_DEPRECATED, 'extends' ); @@ -134,9 +133,9 @@ public function extractTestData($testData) } $testAnnotations["description"]['test_files'] = $this->appendFileNamesInDescriptionAnnotation($fileNames); - $testAnnotations["description"][self::TEST_DEPRECATED] = []; + $testAnnotations["description"][self::OBJ_DEPRECATED] = []; if ($deprecated !== null) { - $testAnnotations["description"][self::TEST_DEPRECATED][] = $deprecated; + $testAnnotations["description"][self::OBJ_DEPRECATED][] = $deprecated; LoggingUtil::getInstance()->getLogger(TestObject::class)->deprecation( $deprecated, ["testName" => $filename, "deprecatedTest" => $deprecated] @@ -166,8 +165,8 @@ public function extractTestData($testData) ); } - if (!empty($testData[self::TEST_DEPRECATED])) { - $testAnnotations[self::TEST_DEPRECATED] = $testData[self::TEST_DEPRECATED]; + if (!empty($testData[self::OBJ_DEPRECATED])) { + $testAnnotations[self::OBJ_DEPRECATED] = $testData[self::OBJ_DEPRECATED]; } // TODO extract filename info and store diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index e4e1c34c7..e40f60dcf 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -7,7 +7,6 @@ namespace Magento\FunctionalTestingFramework\Util; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; @@ -17,14 +16,11 @@ use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; use Magento\FunctionalTestingFramework\Test\Objects\ActionGroupObject; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; use Magento\FunctionalTestingFramework\Test\Objects\TestHookObject; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; -use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; +use Magento\FunctionalTestingFramework\Test\Util\BaseObjectExtractor; use Magento\FunctionalTestingFramework\Util\Manifest\BaseTestManifest; -use Magento\FunctionalTestingFramework\Util\Manifest\TestManifestFactory; use Magento\FunctionalTestingFramework\Test\Util\ActionObjectExtractor; -use Magento\FunctionalTestingFramework\Test\Util\TestObjectExtractor; use Magento\FunctionalTestingFramework\Util\Filesystem\DirSetupUtil; use Magento\FunctionalTestingFramework\Test\Util\ActionMergeUtil; use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; @@ -510,9 +506,9 @@ private function generateDescriptionAnnotation(array $descriptions) $descriptionText = ""; $descriptionText .= $descriptions["main"] ?? ''; - if (!empty($descriptions[TestObjectExtractor::TEST_DEPRECATED]) || !empty($this->deprecationMessages)) { + if (!empty($descriptions[BaseObjectExtractor::OBJ_DEPRECATED]) || !empty($this->deprecationMessages)) { $deprecatedMessages = array_merge( - $descriptions[TestObjectExtractor::TEST_DEPRECATED], + $descriptions[BaseObjectExtractor::OBJ_DEPRECATED], $this->deprecationMessages ); From 9775b5eec21d75f791531bf3f1baabddceda1406 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 27 Jan 2020 12:59:24 -0600 Subject: [PATCH 171/888] MFTF deprecation notice attributes - add verification test --- .../verification/Resources/DeprecatedTest.txt | 34 +++++++++++++++++++ .../ActionGroup/DeprecatedActionGroup.xml | 13 +++++++ .../TestModule/Data/DeprecatedData.xml | 14 ++++++++ .../TestModule/Page/DeprecatedPage.xml | 14 ++++++++ .../TestModule/Section/DeprecatedSection.xml | 14 ++++++++ .../TestModule/Test/DeprecatedTest.xml | 15 ++++++++ .../verification/Tests/DeprecatedTest.php | 22 ++++++++++++ 7 files changed, 126 insertions(+) create mode 100644 dev/tests/verification/Resources/DeprecatedTest.txt create mode 100644 dev/tests/verification/TestModule/ActionGroup/DeprecatedActionGroup.xml create mode 100644 dev/tests/verification/TestModule/Data/DeprecatedData.xml create mode 100644 dev/tests/verification/TestModule/Page/DeprecatedPage.xml create mode 100644 dev/tests/verification/TestModule/Section/DeprecatedSection.xml create mode 100644 dev/tests/verification/TestModule/Test/DeprecatedTest.xml create mode 100644 dev/tests/verification/Tests/DeprecatedTest.php diff --git a/dev/tests/verification/Resources/DeprecatedTest.txt b/dev/tests/verification/Resources/DeprecatedTest.txt new file mode 100644 index 000000000..845d13912 --- /dev/null +++ b/dev/tests/verification/Resources/DeprecatedTest.txt @@ -0,0 +1,34 @@ +<?php +namespace Magento\AcceptanceTest\_default\Backend; + +use Magento\FunctionalTestingFramework\AcceptanceTester; +use \Codeception\Util\Locator; +use Yandex\Allure\Adapter\Annotation\Features; +use Yandex\Allure\Adapter\Annotation\Stories; +use Yandex\Allure\Adapter\Annotation\Title; +use Yandex\Allure\Adapter\Annotation\Description; +use Yandex\Allure\Adapter\Annotation\Parameter; +use Yandex\Allure\Adapter\Annotation\Severity; +use Yandex\Allure\Adapter\Model\SeverityLevel; +use Yandex\Allure\Adapter\Annotation\TestCaseId; + +/** + * @Description("<h3 class='y-label y-label_status_broken'>Deprecated Notice(s):</h3><ul><li>Test is deprecated</li><li>DEPRECATED ACTION GROUP in Test: DeprecatedActionGroup Deprecated action group</li><li>DEPRECATED SECTION in Test: {{DeprecatedSection.deprecatedElement}} Deprecated section</li><li>DEPRECATED ELEMENT in Test: {{DeprecatedSection.deprecatedElement}} Deprecated element</li><li>DEPRECATED DATA ENTITY in Test: {{DeprecatedData.field}} Data entity deprecated</li><li>DEPRECATED PAGE in Test: {{DeprecatedPage.url}} Deprecated page</li></ul><h3>Test files</h3>verification/TestModule/Test/DeprecatedTest.xml<br>") + */ +class DeprecatedTestCest +{ + /** + * @Features({"TestModule"}) + * @Parameter(name = "AcceptanceTester", value="$I") + * @param AcceptanceTester $I + * @return void + * @throws \Exception + */ + public function DeprecatedTest(AcceptanceTester $I) + { + $I->comment("Entering Action Group [deprecatedActionGroup] DeprecatedActionGroup"); + $I->see("deprecated", "#element"); // stepKey: deprecatedSeeDeprecatedActionGroup + $I->comment("Exiting Action Group [deprecatedActionGroup] DeprecatedActionGroup"); + $I->amOnPage("/test.html"); // stepKey: amOnPage + } +} diff --git a/dev/tests/verification/TestModule/ActionGroup/DeprecatedActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/DeprecatedActionGroup.xml new file mode 100644 index 000000000..8f0341c09 --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/DeprecatedActionGroup.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <actionGroup name="DeprecatedActionGroup" deprecated="Deprecated action group"> + <see stepKey="deprecatedSee" userInput="{{DeprecatedData.field}}" selector="{{DeprecatedSection.deprecatedElement}}" /> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/Data/DeprecatedData.xml b/dev/tests/verification/TestModule/Data/DeprecatedData.xml new file mode 100644 index 000000000..060752419 --- /dev/null +++ b/dev/tests/verification/TestModule/Data/DeprecatedData.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="DeprecatedData" deprecated="Data entity deprecated"> + <data key="field">deprecated</data> + </entity> +</entities> diff --git a/dev/tests/verification/TestModule/Page/DeprecatedPage.xml b/dev/tests/verification/TestModule/Page/DeprecatedPage.xml new file mode 100644 index 000000000..316b8b1d7 --- /dev/null +++ b/dev/tests/verification/TestModule/Page/DeprecatedPage.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + <page name="DeprecatedPage" url="/test.html" area="storefront" module="UnknownVendor_TestModule" deprecated="Deprecated page"> + <section name="SampleSection"/> + </page> +</pages> diff --git a/dev/tests/verification/TestModule/Section/DeprecatedSection.xml b/dev/tests/verification/TestModule/Section/DeprecatedSection.xml new file mode 100644 index 000000000..a9ed20d98 --- /dev/null +++ b/dev/tests/verification/TestModule/Section/DeprecatedSection.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="DeprecatedSection" deprecated="Deprecated section"> + <element name="deprecatedElement" type="button" selector="#element" deprecated="Deprecated element"/> + </section> +</sections> diff --git a/dev/tests/verification/TestModule/Test/DeprecatedTest.xml b/dev/tests/verification/TestModule/Test/DeprecatedTest.xml new file mode 100644 index 000000000..cc5ae4994 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/DeprecatedTest.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="DeprecatedTest" deprecated="Test is deprecated"> + <actionGroup ref="DeprecatedActionGroup" stepKey="deprecatedActionGroup" /> + <amOnPage url="{{DeprecatedPage.url}}" stepKey="amOnPage" /> + </test> +</tests> diff --git a/dev/tests/verification/Tests/DeprecatedTest.php b/dev/tests/verification/Tests/DeprecatedTest.php new file mode 100644 index 000000000..dbbe78ea9 --- /dev/null +++ b/dev/tests/verification/Tests/DeprecatedTest.php @@ -0,0 +1,22 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace tests\verification\Tests; + +use tests\util\MftfTestCase; + +class DeprecatedTest extends MftfTestCase +{ + /** + * Tests flat generation of a deprecated test which uses deprecated entities. + * + * @throws \Exception + * @throws \Magento\FunctionalTestingFramework\Exceptions\TestReferenceException + */ + public function testDeprecatedTestEntitiesGeneration() + { + $this->generateAndCompareTest('DeprecatedTest'); + } +} From 28fe7572e30fe0f48a08587f2325d85edc4fa835 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Mon, 27 Jan 2020 13:47:45 -0600 Subject: [PATCH 172/888] MQE-1676: Add a static-check that ensures action groups do not have unused arguments added exception catch for incorrect action group definition --- docs/commands/mftf.md | 7 +++++-- .../StaticCheck/ActionGroupArgumentsCheck.php | 8 +++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 83c48507e..b2c36dae4 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -494,12 +494,15 @@ vendor/bin/mftf static-checks testDependencies ```bash vendor/bin/mftf static-checks actionGroupArguments ``` +```bash +vendor/bin/mftf static-checks testDependencies actionGroupArguments +``` #### Existing static checks * Test Dependency: Checks that test dependencies do not violate Magento module's composer dependencies. -* Unused Arguments: Checks that action groups do not have unused arguments. - +* Action Group Unused Arguments: Checks that action groups do not have unused arguments. + ### `upgrade:tests` Applies all the MFTF major version upgrade scripts to test components in the given path (`test.xml`, `data.xml`, etc). diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php index 6c5c34203..2b25fcf65 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php @@ -7,6 +7,7 @@ namespace Magento\FunctionalTestingFramework\StaticCheck; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Test\Handlers\ActionGroupObjectHandler; use Magento\FunctionalTestingFramework\Test\Objects\ActionGroupObject; use Symfony\Component\Console\Input\InputInterface; @@ -138,9 +139,10 @@ private function findUnusedArguments($actionGroupXml) preg_match_all(self::ACTIONGROUP_ARGUMENT_REGEX_PATTERN, $actionGroupXml, $arguments); preg_match(self::ACTIONGROUP_NAME_REGEX_PATTERN, $actionGroupXml, $actionGroupName); - - $actionGroup = ActionGroupObjectHandler::getInstance()->getObject($actionGroupName[1]); - + try { + $actionGroup = ActionGroupObjectHandler::getInstance()->getObject($actionGroupName[1]); + } catch (XmlException $e){ + } foreach ($arguments[1] as $argument) { //pattern to match all argument references $patterns = [ From 27ca94d76491ff14f4562461a6a30e6d12717a66 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 27 Jan 2020 13:52:57 -0600 Subject: [PATCH 173/888] MFTF deprecation notice attributes - added 1 more verification test - reduce cli output of deprecated entities --- .../Resources/DeprecatedEntitiesTest.txt | 34 +++++++++++++++++++ .../Test/DeprecatedEntitiesTest.xml | 15 ++++++++ .../verification/Tests/DeprecatedTest.php | 11 ++++++ .../Config/Reader/Filesystem.php | 3 +- .../Test/Objects/ActionObject.php | 3 +- .../Util/ActionGroupAnnotationExtractor.php | 3 +- .../Test/Util/AnnotationExtractor.php | 3 +- .../Util/Logger/MftfLogger.php | 20 ++++++----- 8 files changed, 80 insertions(+), 12 deletions(-) create mode 100644 dev/tests/verification/Resources/DeprecatedEntitiesTest.txt create mode 100644 dev/tests/verification/TestModule/Test/DeprecatedEntitiesTest.xml diff --git a/dev/tests/verification/Resources/DeprecatedEntitiesTest.txt b/dev/tests/verification/Resources/DeprecatedEntitiesTest.txt new file mode 100644 index 000000000..489cb66ea --- /dev/null +++ b/dev/tests/verification/Resources/DeprecatedEntitiesTest.txt @@ -0,0 +1,34 @@ +<?php +namespace Magento\AcceptanceTest\_default\Backend; + +use Magento\FunctionalTestingFramework\AcceptanceTester; +use \Codeception\Util\Locator; +use Yandex\Allure\Adapter\Annotation\Features; +use Yandex\Allure\Adapter\Annotation\Stories; +use Yandex\Allure\Adapter\Annotation\Title; +use Yandex\Allure\Adapter\Annotation\Description; +use Yandex\Allure\Adapter\Annotation\Parameter; +use Yandex\Allure\Adapter\Annotation\Severity; +use Yandex\Allure\Adapter\Model\SeverityLevel; +use Yandex\Allure\Adapter\Annotation\TestCaseId; + +/** + * @Description("<h3 class='y-label y-label_status_broken'>Deprecated Notice(s):</h3><ul><li>DEPRECATED ACTION GROUP in Test: DeprecatedActionGroup Deprecated action group</li><li>DEPRECATED SECTION in Test: {{DeprecatedSection.deprecatedElement}} Deprecated section</li><li>DEPRECATED ELEMENT in Test: {{DeprecatedSection.deprecatedElement}} Deprecated element</li><li>DEPRECATED DATA ENTITY in Test: {{DeprecatedData.field}} Data entity deprecated</li><li>DEPRECATED PAGE in Test: {{DeprecatedPage.url}} Deprecated page</li></ul><h3>Test files</h3>verification/TestModule/Test/DeprecatedEntitiesTest.xml<br>") + */ +class DeprecatedEntitiesTestCest +{ + /** + * @Features({"TestModule"}) + * @Parameter(name = "AcceptanceTester", value="$I") + * @param AcceptanceTester $I + * @return void + * @throws \Exception + */ + public function DeprecatedEntitiesTest(AcceptanceTester $I) + { + $I->comment("Entering Action Group [deprecatedActionGroup] DeprecatedActionGroup"); + $I->see("deprecated", "#element"); // stepKey: deprecatedSeeDeprecatedActionGroup + $I->comment("Exiting Action Group [deprecatedActionGroup] DeprecatedActionGroup"); + $I->amOnPage("/test.html"); // stepKey: amOnPage + } +} diff --git a/dev/tests/verification/TestModule/Test/DeprecatedEntitiesTest.xml b/dev/tests/verification/TestModule/Test/DeprecatedEntitiesTest.xml new file mode 100644 index 000000000..733a34e80 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/DeprecatedEntitiesTest.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="DeprecatedEntitiesTest"> + <actionGroup ref="DeprecatedActionGroup" stepKey="deprecatedActionGroup" /> + <amOnPage url="{{DeprecatedPage.url}}" stepKey="amOnPage" /> + </test> +</tests> diff --git a/dev/tests/verification/Tests/DeprecatedTest.php b/dev/tests/verification/Tests/DeprecatedTest.php index dbbe78ea9..78e3326b9 100644 --- a/dev/tests/verification/Tests/DeprecatedTest.php +++ b/dev/tests/verification/Tests/DeprecatedTest.php @@ -19,4 +19,15 @@ public function testDeprecatedTestEntitiesGeneration() { $this->generateAndCompareTest('DeprecatedTest'); } + + /** + * Tests flat generation of a test which uses deprecated entities. + * + * @throws \Exception + * @throws \Magento\FunctionalTestingFramework\Exceptions\TestReferenceException + */ + public function testDeprecatedEntitiesOnlyGeneration() + { + $this->generateAndCompareTest('DeprecatedEntitiesTest'); + } } diff --git a/src/Magento/FunctionalTestingFramework/Config/Reader/Filesystem.php b/src/Magento/FunctionalTestingFramework/Config/Reader/Filesystem.php index 2f2cb8ad3..db96b010c 100644 --- a/src/Magento/FunctionalTestingFramework/Config/Reader/Filesystem.php +++ b/src/Magento/FunctionalTestingFramework/Config/Reader/Filesystem.php @@ -235,7 +235,8 @@ protected function validateSchema($configMerger, $filename = null) $error = str_replace(PHP_EOL, "", $error); LoggingUtil::getInstance()->getLogger(Filesystem::class)->criticalFailure( "Schema validation error ", - ($filename ? [ "file"=> $filename, "error" => $error]: ["error" => $error]) + ($filename ? [ "file"=> $filename, "error" => $error]: ["error" => $error]), + true ); } throw new \Exception("Schema validation errors found in xml file(s)" . $filename); diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php index 44bc8726f..45b5db69d 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php @@ -314,7 +314,8 @@ public function trimAssertionAttributes() if ($appConfig->getPhase() == MftfApplicationConfig::GENERATION_PHASE && $appConfig->verboseEnabled()) { LoggingUtil::getInstance()->getLogger(ActionObject::class)->deprecation( "use of one line Assertion actions will be deprecated in MFTF 3.0.0, please use nested syntax", - ["action" => $this->type, "stepKey" => $this->stepKey] + ["action" => $this->type, "stepKey" => $this->stepKey], + true ); } return; diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/ActionGroupAnnotationExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/ActionGroupAnnotationExtractor.php index 44b004105..9d3a9877e 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/ActionGroupAnnotationExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/ActionGroupAnnotationExtractor.php @@ -64,7 +64,8 @@ private function validateMissingAnnotations($annotationObjects, $filename) $message = "Action Group File {$filename} is missing required annotations."; LoggingUtil::getInstance()->getLogger(ActionObject::class)->deprecation( $message, - ["actionGroup" => $filename, "missingAnnotations" => implode(", ", $missingAnnotations)] + ["actionGroup" => $filename, "missingAnnotations" => implode(", ", $missingAnnotations)], + true ); } } diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php index d30ed351e..1859f3195 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php @@ -164,7 +164,8 @@ private function validateMissingAnnotations($annotationObjects, $filename) $message = "Test {$filename} is missing required annotations."; LoggingUtil::getInstance()->getLogger(ActionObject::class)->deprecation( $message, - ["testName" => $filename, "missingAnnotations" => implode(", ", $missingAnnotations)] + ["testName" => $filename, "missingAnnotations" => implode(", ", $missingAnnotations)], + true ); } } diff --git a/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php b/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php index 0a52f6b6b..7306aab67 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php +++ b/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php @@ -15,15 +15,17 @@ class MftfLogger extends Logger /** * Prints a deprecation warning, as well as adds a log at the WARNING level. * - * @param string $message The log message. - * @param array $context The log context. + * @param string $message The log message. + * @param array $context The log context. + * @param bool $verbose * @return void + * @throws \Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException */ - public function deprecation($message, array $context = []) + public function deprecation($message, array $context = [], $verbose = false) { $message = "DEPRECATION: " . $message; // Suppress print during unit testing - if (MftfApplicationConfig::getConfig()->getPhase() !== MftfApplicationConfig::UNIT_TEST_PHASE) { + if (MftfApplicationConfig::getConfig()->getPhase() !== MftfApplicationConfig::UNIT_TEST_PHASE && $verbose) { print ($message . json_encode($context) . "\n"); } parent::warning($message, $context); @@ -32,15 +34,17 @@ public function deprecation($message, array $context = []) /** * Prints a critical failure, as well as adds a log at the CRITICAL level. * - * @param string $message The log message. - * @param array $context The log context. + * @param string $message The log message. + * @param array $context The log context. + * @param bool $verbose * @return void + * @throws \Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException */ - public function criticalFailure($message, array $context = []) + public function criticalFailure($message, array $context = [], $verbose = false) { $message = "FAILURE: " . $message; // Suppress print during unit testing - if (MftfApplicationConfig::getConfig()->getPhase() !== MftfApplicationConfig::UNIT_TEST_PHASE) { + if (MftfApplicationConfig::getConfig()->getPhase() !== MftfApplicationConfig::UNIT_TEST_PHASE && $verbose) { print ($message . implode("\n", $context) . "\n"); } parent::critical($message, $context); From 6e9aeca43780844991858d58b7e728a2663b54b3 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 27 Jan 2020 14:04:36 -0600 Subject: [PATCH 174/888] MFTF deprecation notice attributes --- .../Page/Handlers/SectionObjectHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php b/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php index 15c4fdd9e..2736100fd 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php @@ -100,7 +100,7 @@ private function __construct() $sectionDeprecated = $sectionData[self::OBJ_DEPRECATED] ?? null; if ($sectionDeprecated !== null) { - LoggingUtil::getInstance()->getLogger(ElementObject::class)->deprecation( + LoggingUtil::getInstance()->getLogger(SectionObject::class)->deprecation( $sectionDeprecated, ["sectionName" => $filename, "deprecatedSection" => $sectionDeprecated] ); From a30065ad18d82fae4b9bcda5137076425cd1d1b9 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 27 Jan 2020 14:13:21 -0600 Subject: [PATCH 175/888] MFTF deprecation notice attributes --- .../FunctionalTestingFramework/Util/Logger/MftfLogger.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php b/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php index 7306aab67..9e3510ab7 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php +++ b/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php @@ -16,8 +16,8 @@ class MftfLogger extends Logger * Prints a deprecation warning, as well as adds a log at the WARNING level. * * @param string $message The log message. - * @param array $context The log context. - * @param bool $verbose + * @param array $context The log context. + * @param bool $verbose * @return void * @throws \Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException */ @@ -35,8 +35,8 @@ public function deprecation($message, array $context = [], $verbose = false) * Prints a critical failure, as well as adds a log at the CRITICAL level. * * @param string $message The log message. - * @param array $context The log context. - * @param bool $verbose + * @param array $context The log context. + * @param bool $verbose * @return void * @throws \Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException */ From 64b6bdf6e135f6e19ff744fec6298fd25bde698e Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 27 Jan 2020 14:24:56 -0600 Subject: [PATCH 176/888] MFTF deprecation notice attributes --- .../Util/Logger/MftfLogger.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php b/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php index 9e3510ab7..3983a755a 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php +++ b/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php @@ -15,9 +15,9 @@ class MftfLogger extends Logger /** * Prints a deprecation warning, as well as adds a log at the WARNING level. * - * @param string $message The log message. - * @param array $context The log context. - * @param bool $verbose + * @param string $message The log message. + * @param array $context The log context. + * @param boolean $verbose * @return void * @throws \Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException */ @@ -34,9 +34,9 @@ public function deprecation($message, array $context = [], $verbose = false) /** * Prints a critical failure, as well as adds a log at the CRITICAL level. * - * @param string $message The log message. - * @param array $context The log context. - * @param bool $verbose + * @param string $message The log message. + * @param array $context The log context. + * @param boolean $verbose * @return void * @throws \Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException */ From 1c7c6ced5563b36416e028384bdef909d497a887 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Mon, 27 Jan 2020 14:30:31 -0600 Subject: [PATCH 177/888] MQE-1676: Add a static-check that ensures action groups do not have unused arguments included $$argument.name$$ pattern + fixed unit tests --- .../StaticCheck/ActionGroupArgumentsCheck.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php index 2b25fcf65..32c7661fe 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php @@ -27,7 +27,7 @@ class ActionGroupArgumentsCheck implements StaticCheckInterface const ACTIONGROUP_NAME_REGEX_PATTERN = '/<actionGroup name=["\']([^\'"]*)/'; const ERROR_LOG_FILENAME = 'mftf-arguments-checks'; - const ERROR_LOG_MESSAGE = 'MFTF Unused Arguments Check'; + const ERROR_LOG_MESSAGE = 'MFTF Action Group Unused Arguments Check'; /** * Array containing all errors found after running the execute() function. @@ -141,13 +141,13 @@ private function findUnusedArguments($actionGroupXml) preg_match(self::ACTIONGROUP_NAME_REGEX_PATTERN, $actionGroupXml, $actionGroupName); try { $actionGroup = ActionGroupObjectHandler::getInstance()->getObject($actionGroupName[1]); - } catch (XmlException $e){ + } catch (XmlException $e) { } foreach ($arguments[1] as $argument) { //pattern to match all argument references $patterns = [ '(\{{2}' . $argument . '(\.[a-zA-Z0-9_\[\]\(\).,\'\/ ]+)?}{2})', - '([(,\s\']' . $argument . '(\.[a-zA-Z0-9_\[\]]+)?[),\s\'])' + '([(,\s\'$$]' . $argument . '(\.[a-zA-Z0-9_$\[\]]+)?[),\s\'])' ]; // matches entity references if (preg_match($patterns[0], $actionGroupXml)) { From 031b0a74c411f903035a5bdeeaabbe6db60d9f1d Mon Sep 17 00:00:00 2001 From: Ajith <ajithkumar.maragathavel@ziffity.com> Date: Tue, 28 Jan 2020 23:12:10 +0530 Subject: [PATCH 178/888] cache clean command added --- docs/getting-started.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/getting-started.md b/docs/getting-started.md index a6706769d..20a24adff 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -74,6 +74,12 @@ or via command line: bin/magento config:set cms/wysiwyg/enabled disabled ``` +Clean the cache after changing the configuration values + +```bash +bin/magento cache:clean config full_page +``` + <div class="bs-callout bs-callout-tip"> When you want to test the WYSIWYG functionality, re-enable WYSIWYG in your test suite. </div> @@ -97,6 +103,12 @@ bin/magento config:set admin/security/admin_account_sharing 1 bin/magento config:set admin/security/use_form_key 0 ``` +Clean the cache after changing the configuration values + +```bash +bin/magento cache:clean config full_page +``` + ### Webserver configuration {#web-server-configuration} The MFTF does not support executing CLI commands if your web server points to `<MAGE_ROOT_DIR>/pub` directory as recommended in the [Installation Guide][Installation Guide docroot]. For the MFTF to execute the CLI commands, the web server must point to the Magento root directory. From bb1e73214a6b98095a7e99904e5d9fa7f810e94d Mon Sep 17 00:00:00 2001 From: Ajith <ajithkumar.maragathavel@ziffity.com> Date: Tue, 28 Jan 2020 23:21:20 +0530 Subject: [PATCH 179/888] Configuration path altered and information added --- docs/getting-started.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 20a24adff..92f456cfd 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -115,9 +115,9 @@ The MFTF does not support executing CLI commands if your web server points to `< ### Nginx settings {#nginx-settings} -If Nginx Web server is used on your development environment then **Use Web Server Rewrites** setting in **Stores** > Settings > **Configuration** > **Web** > **Search Engine Optimization** must be set to **Yes**. +If Nginx Web server is used on your development environment then **Use Web Server Rewrites** setting in **Stores** > Settings > **Configuration** > **General** > **Web** > **Search Engine Optimization** must be set to **Yes**. -To be able to run Magento command line commands in tests add the following location block to Nginx configuration file: +To be able to run Magento command line commands in tests add the following location block to Nginx configuration file in the Magento root directory: ```conf location ~* ^/dev/tests/acceptance/utils($|/) { From 826674886bd015a6d499ced36fa7037cd439a9b0 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 30 Jan 2020 10:04:34 -0600 Subject: [PATCH 180/888] MQE-1969: Updated CHANGELOG.md and bumped MFTF package version --- CHANGELOG.md | 34 ++++++++++++++++++++++++++++++++++ composer.json | 2 +- composer.lock | 3 ++- 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8c4ca9b8..558b3be13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,39 @@ Magento Functional Testing Framework Changelog ================================================ + +2.6.0 +----- + +* Traceability + * MFTF generated cest files are fully compatible for Codeception `dry-run`. +* Modularity + * `mftf generate:tests` and `mftf run:test` commands now accept suite scoped test names in format `[<suitename:>testname]...`. +* Maintainability + * Support `deprecated` syntax for the following test entities: + * Test + * Action Group + * Data + * Page + * Section + * Section Element + * Suite + + See DevDocs for details + * Improved `mftf static-checks` command to allow executing all or specific static checks. + * Added a new static check that checks and reports unused arguments in action groups. +* Customizability + * AWS Secrets Manager is added as an additional credential storage. + * See DevDocs for details + +### Fixes +* Fixed missing before, after, failed steps in cest file when generating tests with `--allow-skipped` option. +* Fixed suites and tests display issue in Allure `Suites` page after `mftf run:group` command. +* `createData` action now shows a meaningful error message at runtime when the entity does not exist. + +### GitHub Issues/Pull requests: +* [#537](https://github.com/magento/magento2-functional-testing-framework/pull/537) -- Refactor of TestGenerator class +* [#538](https://github.com/magento/magento2-functional-testing-framework/pull/538) -- FEATURE: <magentoCron> command to execute Cron Jobs + 2.5.4 ----- [Demo Video](https://www.youtube.com/watch?v=tguvkw1HWKg) diff --git a/composer.json b/composer.json index ca1c02572..e6d081114 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "2.5.4", + "version": "2.6.0", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index 6bfc30ab9..051ab6441 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "2325a3a38edb33b24f6e33bd3009fd8a", + "content-hash": "859ddf6506836faaabb056ae7b377c63", "packages": [ { "name": "allure-framework/allure-codeception", @@ -1710,6 +1710,7 @@ "selenium", "webdriver" ], + "abandoned": "php-webdriver/webdriver", "time": "2018-05-16T17:37:13+00:00" }, { From a1adbc1655749a1de114f907ee9f26ae5fd03bf4 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 30 Jan 2020 10:29:09 -0600 Subject: [PATCH 181/888] MQE-1969: Updated CHANGELOG.md and bumped MFTF package version --- CHANGELOG.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 558b3be13..5910e8b38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ Magento Functional Testing Framework Changelog * Traceability * MFTF generated cest files are fully compatible for Codeception `dry-run`. * Modularity - * `mftf generate:tests` and `mftf run:test` commands now accept suite scoped test names in format `[<suitename:>testname]...`. + * `mftf generate:tests` and `mftf run:test` commands now accept suite scoped test names in format `[suitename:testname]...`. * Maintainability * Support `deprecated` syntax for the following test entities: * Test @@ -17,12 +17,11 @@ Magento Functional Testing Framework Changelog * Section * Section Element * Suite - - See DevDocs for details + * See DevDocs for details * Improved `mftf static-checks` command to allow executing all or specific static checks. * Added a new static check that checks and reports unused arguments in action groups. * Customizability - * AWS Secrets Manager is added as an additional credential storage. + * AWS Secrets Manager has been added as an additional credential storage. * See DevDocs for details ### Fixes From ac9f32c3f13ebd3d1894247f5a735c72ccd77668 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 30 Jan 2020 10:32:50 -0600 Subject: [PATCH 182/888] MQE-1969: Updated CHANGELOG.md and bumped MFTF package version --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5910e8b38..fe6bd9822 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,10 +13,10 @@ Magento Functional Testing Framework Changelog * Test * Action Group * Data + * Metadata * Page * Section * Section Element - * Suite * See DevDocs for details * Improved `mftf static-checks` command to allow executing all or specific static checks. * Added a new static check that checks and reports unused arguments in action groups. From 2284db92585e26f9b1193dcfaf1608e7bbc225cf Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Fri, 31 Jan 2020 12:19:20 -0600 Subject: [PATCH 183/888] Fix include --- docs/mftf-tests.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/mftf-tests.md b/docs/mftf-tests.md index 4505975a9..cb1941053 100644 --- a/docs/mftf-tests.md +++ b/docs/mftf-tests.md @@ -12,7 +12,7 @@ dl dt{ The Magento Functional Testing Framework runs tests on every Module within Magento. These files are stored within each Module folder in the Magento repo. This page lists all those tests so that developers can have a good sense of what is covered. -{% include mftf/mftf_data.md %} +{% include mftf/functional_data.md %} {% for item in mftf %} From a31b49cf06fe9875e74c5ac35907a0501dca5207 Mon Sep 17 00:00:00 2001 From: Lukasz Bajsarowicz <lukasz.bajsarowicz@gmail.com> Date: Fri, 31 Jan 2020 19:24:32 +0100 Subject: [PATCH 184/888] #544 Log Request sent even if Response failed --- .../DataGenerator/Persist/CurlHandler.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php index 05178c915..efdc17ab9 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php @@ -134,6 +134,8 @@ public function executeRequest($dependentEntities) false ); + AllureHelper::addAttachmentToCurrentStep(json_encode($this->requestData, JSON_PRETTY_PRINT), 'Request Body'); + if (($contentType === 'application/json') && ($authorization === 'adminOauth')) { $this->isJson = true; $executor = new WebapiExecutor($this->storeCode); @@ -169,7 +171,6 @@ public function executeRequest($dependentEntities) $response = $executor->read($successRegex, $returnRegex, $returnIndex); $executor->close(); - AllureHelper::addAttachmentToCurrentStep(json_encode($this->requestData, JSON_PRETTY_PRINT), 'Request Body'); AllureHelper::addAttachmentToCurrentStep( json_encode(json_decode($response, true), JSON_PRETTY_PRINT+JSON_UNESCAPED_UNICODE+JSON_UNESCAPED_SLASHES), 'Response Data' @@ -229,7 +230,7 @@ private function resolveUrlReference($urlIn, $entityObjects) foreach ($entityObjects as $entityObject) { $param = null; - if ($paramEntityParent === "" || $entityObject->getType() == $paramEntityParent) { + if ($paramEntityParent === "" || $entityObject->getType() === $paramEntityParent) { $param = $entityObject->getDataByName( $dataItem, EntityDataObject::CEST_UNIQUE_VALUE From 93fda6b0fc4bbf4f6a76a86a0265761bd101eeb9 Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Fri, 31 Jan 2020 13:23:13 -0600 Subject: [PATCH 185/888] Adding raw tag. --- docs/test/action-groups.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/test/action-groups.md b/docs/test/action-groups.md index 5fdfbb522..e036073a8 100644 --- a/docs/test/action-groups.md +++ b/docs/test/action-groups.md @@ -8,6 +8,8 @@ The following diagram shows the structure of an MFTF action group: ## Principles +{% raw %} + The following conventions apply to MFTF action groups: - All action groups are declared in XML files and stored in the `<module>/Test/Mftf/ActionGroup/` directory. From 80ee17c85b3e71cb3d2ae30fa15ea0c9da0f2807 Mon Sep 17 00:00:00 2001 From: Lukasz Bajsarowicz <lukasz.bajsarowicz@gmail.com> Date: Fri, 31 Jan 2020 20:35:49 +0100 Subject: [PATCH 186/888] #568 Project-based URN path generation + add consistency of misc.xml path --- .../Console/GenerateDevUrnCommand.php | 91 +++++++++++++++---- 1 file changed, 71 insertions(+), 20 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateDevUrnCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateDevUrnCommand.php index f953deb16..bca72421b 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateDevUrnCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateDevUrnCommand.php @@ -4,7 +4,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -declare(strict_types = 1); +declare(strict_types=1); namespace Magento\FunctionalTestingFramework\Console; @@ -19,6 +19,14 @@ class GenerateDevUrnCommand extends Command { + /** + * Argument for the path to IDE config file + */ + const IDE_FILE_PATH_ARGUMENT = 'path'; + + const PROJECT_PATH_IDENTIFIER = '$PROJECT_DIR$'; + const MFTF_SRC_PATH = 'src/Magento/FunctionalTestingFramework/'; + /** * Configures the current command. * @@ -27,8 +35,12 @@ class GenerateDevUrnCommand extends Command protected function configure() { $this->setName('generate:urn-catalog') - ->setDescription('This command generates an URN catalog to enable PHPStorm to recognize and highlight URNs.') - ->addArgument('path', InputArgument::REQUIRED, 'path to PHPStorm misc.xml file (typically located in [ProjectRoot]/.idea/misc.xml)') + ->setDescription('Generates the catalog of URNs to *.xsd mappings for the IDE to highlight xml.') + ->addArgument( + self::IDE_FILE_PATH_ARGUMENT, + InputArgument::REQUIRED, + 'Path to file to output the catalog. For PhpStorm use .idea/misc.xml' + ) ->addOption( "force", 'f', @@ -47,7 +59,7 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output) { - $miscXmlFilePath = $input->getArgument('path') . DIRECTORY_SEPARATOR . "misc.xml"; + $miscXmlFilePath = $input->getArgument(self::IDE_FILE_PATH_ARGUMENT); $miscXmlFile = realpath($miscXmlFilePath); $force = $input->getOption('force'); @@ -71,7 +83,7 @@ protected function execute(InputInterface $input, OutputInterface $output) //Locate ProjectResources node, create one if none are found. $nodeForWork = null; - foreach($dom->getElementsByTagName('component') as $child) { + foreach ($dom->getElementsByTagName('component') as $child) { if ($child->getAttribute('name') === 'ProjectResources') { $nodeForWork = $child; } @@ -109,35 +121,74 @@ protected function execute(InputInterface $input, OutputInterface $output) /** * Generates urn => location array for all MFTF schema. + * * @return array - * @throws TestFrameworkException */ private function generateResourcesArray() { $resourcesArray = [ 'urn:magento:mftf:DataGenerator/etc/dataOperation.xsd' => - realpath(FilePathFormatter::format(FW_BP) - . 'src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd'), + $this->getResourcePath('DataGenerator/etc/dataOperation.xsd'), 'urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd' => - realpath(FilePathFormatter::format(FW_BP) - . 'src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd'), + $this->getResourcePath('DataGenerator/etc/dataProfileSchema.xsd'), 'urn:magento:mftf:Page/etc/PageObject.xsd' => - realpath(FilePathFormatter::format(FW_BP) - . 'src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd'), + $this->getResourcePath('Page/etc/PageObject.xsd'), 'urn:magento:mftf:Page/etc/SectionObject.xsd' => - realpath(FilePathFormatter::format(FW_BP) - . 'src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd'), + $this->getResourcePath('Page/etc/SectionObject.xsd'), 'urn:magento:mftf:Test/etc/actionGroupSchema.xsd' => - realpath(FilePathFormatter::format(FW_BP) - . 'src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd'), + $this->getResourcePath('Test/etc/actionGroupSchema.xsd'), 'urn:magento:mftf:Test/etc/testSchema.xsd' => - realpath(FilePathFormatter::format(FW_BP) - . 'src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd'), + $this->getResourcePath('Test/etc/testSchema.xsd'), 'urn:magento:mftf:Suite/etc/suiteSchema.xsd' => - realpath(FilePathFormatter::format(FW_BP) - . 'src/Magento/FunctionalTestingFramework/Suite/etc/suiteSchema.xsd') + $this->getResourcePath('Suite/etc/suiteSchema.xsd') ]; return $resourcesArray; } + /** + * Returns path (full or PhpStorm project-based) to XSD file + * + * @param $relativePath + * @return string + * @throws TestFrameworkException + */ + private function getResourcePath($relativePath) + { + $urnPath = realpath(FilePathFormatter::format(FW_BP) . self::MFTF_SRC_PATH . $relativePath); + $projectRoot = $this->getProjectRootPath(); + + if ($projectRoot !== null) { + return str_replace($projectRoot, self::PROJECT_PATH_IDENTIFIER, $urnPath); + } + + return $urnPath; + } + + /** + * Returns Project root directory absolute path + * @TODO Find out how to detect other types of installation + * + * @return string|null + */ + private function getProjectRootPath() + { + $frameworkRoot = realpath(__DIR__); + + if ($this->isInstalledByComposer($frameworkRoot)) { + return strstr($frameworkRoot, '/vendor/', true); + } + + return null; + } + + /** + * Determines whether MFTF was installed using Composer + * + * @param string $frameworkRoot + * @return bool + */ + private function isInstalledByComposer($frameworkRoot) + { + return false !== strpos($frameworkRoot, '/vendor/'); + } } From c8bb2de7bb84e7f82f01f01038b14fc745e3083b Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Fri, 31 Jan 2020 15:28:56 -0600 Subject: [PATCH 187/888] Adding deprecation attribute info --- docs/data.md | 1 + docs/page.md | 2 ++ docs/section.md | 2 ++ docs/section/locator-functions.md | 1 - docs/test.md | 1 + docs/test/action-groups.md | 1 + 6 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/data.md b/docs/data.md index 2a1b845d4..bb4ae57f0 100644 --- a/docs/data.md +++ b/docs/data.md @@ -208,6 +208,7 @@ Attributes|Type|Use|Description ---|---|---|--- `key`|string|optional|Key attribute of data/value pair. `unique`|enum: `"prefix"`, `"suffix"`|optional|Add suite or test wide unique sequence as "prefix" or "suffix" to the data value if specified. +`deprecated`|string|optional|Used to warn about the future deprecation of the data entity. String will appear in Allure reports and console output at runtime. ### var {#var-tag} diff --git a/docs/page.md b/docs/page.md index 705a94294..d776edc6c 100644 --- a/docs/page.md +++ b/docs/page.md @@ -145,6 +145,7 @@ Attributes|Type|Use|Description `area`|string|required|The area where this page lives. Three possible values: `admin` prepends `BACKEND_NAME` to `url`, `storefront` does not prepend anything to `url`, `external` flags the page for use with `amOnUrl`. The `url` provided must be a full URL, such as `http://myFullUrl.com/`, instead of the URL for a Magento page. `parameterized`|boolean |optional|Include and set to `"true"` if the `url` for this page has parameters that need to be replaced for proper use. `remove`|boolean|optional|The default value is `"false"`. Set to `"true"` to remove this element during parsing. +`deprecated`|string|optional|Used to warn about the future deprecation of the page. String will appear in Allure reports and console output at runtime. `<page>` may contain several [`<section>`] elements. @@ -157,6 +158,7 @@ A section is a reusable piece or part of a page. Attributes|Type|Use|Description ---|---|---|--- +`deprecated`|string|optional|Used to warn about the future deprecation of the section. String will appear in Allure reports and console output at runtime. `name`|string|required|Unique section name identifier. `remove`|boolean|optional|The default value is `"false"`. Set to `"true"` to remove this element during parsing. diff --git a/docs/section.md b/docs/section.md index 98221ec44..aa3555dc4 100644 --- a/docs/section.md +++ b/docs/section.md @@ -89,6 +89,7 @@ The following is an example of a call in test: Attributes|Type|Use|Description ---|---|---|--- `name`|string|required|Unique section name identifier. +`deprecated`|string|optional|Used to warn about the future deprecation of the section. String will appear in Allure reports and console output at runtime. `remove`|boolean|optional|The default is `false`. Set to `true` to remove this element during parsing. ### element {#element-tag} @@ -103,6 +104,7 @@ Attributes|Type|Use|Description `locatorFunction`|string|optional|[Locator function][] declaration to be used in lieu of a selector. `timeout`|string|optional|The timeout after interaction with the element (in seconds). The default is _none_. `parameterized`|boolean|optional|Include and set to `true` if the `selector` for this element has parameters that need to be replaced for proper use. Learn more in [Parameterized selectors][]. +`deprecated`|string|optional|Used to warn about the future deprecation of the element. String will appear in Allure reports and console output at runtime. `remove`|boolean|optional|The default is `false`. Set to `true` to remove this element during parsing. #### `timeout` attribute {#timeout-attribute} diff --git a/docs/section/locator-functions.md b/docs/section/locator-functions.md index d52c2fc72..1e3dffd24 100644 --- a/docs/section/locator-functions.md +++ b/docs/section/locator-functions.md @@ -1,6 +1,5 @@ # Locator functions - ## Define Locator::functions in elements Codeception has a set of very useful [Locator functions][] that may be used by elements inside a [section][]. diff --git a/docs/test.md b/docs/test.md index dcda0ba50..363732fd7 100644 --- a/docs/test.md +++ b/docs/test.md @@ -73,6 +73,7 @@ Attribute|Type|Use|Description `remove`|boolean|optional|Set `true` to remove the test when merging. `insertBefore`|string|optional| This option is used for [merging]. It enables you to add all test actions contained in the original test into a test with the same name BEFORE the test step with `stepKey` that you assigned in `insertBefore`. `insertAfter`|string|optional| Set `stepKey` of the test step after which you want to insert the test when [merging]. +`deprecated`|string|optional|Used to warn about the future deprecation of the test. String will appear in Allure reports and console output at runtime. `extends`|string|optional|A name of the parent test to [extend]. `<test>` may also contain [`<annotations>`], [`<before>`], [`<after>`], any [action][actions], or [`<actionGroup>`]. diff --git a/docs/test/action-groups.md b/docs/test/action-groups.md index e036073a8..162ac0541 100644 --- a/docs/test/action-groups.md +++ b/docs/test/action-groups.md @@ -255,6 +255,7 @@ Attribute|Type|Use|Description ---|---|---|--- `name`|string|required|Identifier of the action group. `extends`|string|optional|Identifies the action group to extend. +`deprecated`|string|optional|Used to warn about the future deprecation of the actionGroup. String will appear in Allure reports and console output at runtime. It may contain `<arguments>`. From a2b0cdd0d5ae090d9cd8c7bae32a443151d73da3 Mon Sep 17 00:00:00 2001 From: Ajith <ajithkumar.maragathavel@ziffity.com> Date: Sun, 2 Feb 2020 23:26:53 +0530 Subject: [PATCH 188/888] added missing node --- docs/metadata.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/metadata.md b/docs/metadata.md index 795c8a038..5a2ad4371 100644 --- a/docs/metadata.md +++ b/docs/metadata.md @@ -61,6 +61,7 @@ The following diagram demonstrates the XML structure of a metadata file: </array> </object> </operation> +</operations> ``` ## Principles {#principles} From 016cee6b4b35e23b6cbe3c7d74be0d6bb26bf152 Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Mon, 3 Feb 2020 10:49:44 -0600 Subject: [PATCH 189/888] Moving def to correct table --- docs/data.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data.md b/docs/data.md index bb4ae57f0..8705bf7ba 100644 --- a/docs/data.md +++ b/docs/data.md @@ -197,6 +197,7 @@ Attributes|Type|Use|Description ---|---|---|--- `name`|string|optional|Name of the `<entity>`. `type`|string|optional|Node containing the exact name of `<entity>` type. Used later to find specific Persistence Layer Model class. `type` in `<data>` can be whatever the user wants; There are no constraints. It is important when persisting data, depending on the `type` given, as it will try to match a metadata definition with the operation being done. Example: A `myCustomer` entity with `type="customer"`, calling `<createData entity="myCustomer"/>`, will try to find a metadata entry with the following attributes: `<operation dataType="customer" type="create">`. +`deprecated`|string|optional|Used to warn about the future deprecation of the data entity. String will appear in Allure reports and console output at runtime. `<entity>` may contain one or more [`<data>`][], [`<var>`][], [`<required-entities>`][], or [`<array>`][] elements in any sequence. @@ -208,7 +209,6 @@ Attributes|Type|Use|Description ---|---|---|--- `key`|string|optional|Key attribute of data/value pair. `unique`|enum: `"prefix"`, `"suffix"`|optional|Add suite or test wide unique sequence as "prefix" or "suffix" to the data value if specified. -`deprecated`|string|optional|Used to warn about the future deprecation of the data entity. String will appear in Allure reports and console output at runtime. ### var {#var-tag} From 1b0cf43dd2420b6930d217b327795026d63aaff5 Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Mon, 3 Feb 2020 10:50:45 -0600 Subject: [PATCH 190/888] Fixed table --- docs/page.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/page.md b/docs/page.md index d776edc6c..1d72b16c9 100644 --- a/docs/page.md +++ b/docs/page.md @@ -145,7 +145,6 @@ Attributes|Type|Use|Description `area`|string|required|The area where this page lives. Three possible values: `admin` prepends `BACKEND_NAME` to `url`, `storefront` does not prepend anything to `url`, `external` flags the page for use with `amOnUrl`. The `url` provided must be a full URL, such as `http://myFullUrl.com/`, instead of the URL for a Magento page. `parameterized`|boolean |optional|Include and set to `"true"` if the `url` for this page has parameters that need to be replaced for proper use. `remove`|boolean|optional|The default value is `"false"`. Set to `"true"` to remove this element during parsing. -`deprecated`|string|optional|Used to warn about the future deprecation of the page. String will appear in Allure reports and console output at runtime. `<page>` may contain several [`<section>`] elements. From 7560bc3d0c804c3ab6c7c0adba9df8ca87a8dc61 Mon Sep 17 00:00:00 2001 From: Lukasz Bajsarowicz <lukasz.bajsarowicz@gmail.com> Date: Tue, 4 Feb 2020 18:20:58 +0100 Subject: [PATCH 191/888] First cron run may fail when no Group provided. --- .../FunctionalTestingFramework/Module/MagentoWebDriver.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index cd2768a06..26c66acd1 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -601,6 +601,10 @@ private function notifyCronFinished(array $cronGroups = []) */ private function getLastCronExecution(array $cronGroups = []) { + if (empty($this->cronExecution)) { + return 0; + } + if (empty($cronGroups)) { return (int)max($this->cronExecution); } @@ -1060,7 +1064,7 @@ public function getSecret($key) /** * Waits proper amount of time to perform Cron execution * - * @param string $cronGroups + * @param array $cronGroups * @param integer $timeout * @param string $arguments * @return string From 62c3a58e2832182a07ed6d94c50dd1db0153eca8 Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Tue, 4 Feb 2020 11:25:04 -0600 Subject: [PATCH 192/888] Removing attribute --- docs/page.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/page.md b/docs/page.md index 1d72b16c9..705a94294 100644 --- a/docs/page.md +++ b/docs/page.md @@ -157,7 +157,6 @@ A section is a reusable piece or part of a page. Attributes|Type|Use|Description ---|---|---|--- -`deprecated`|string|optional|Used to warn about the future deprecation of the section. String will appear in Allure reports and console output at runtime. `name`|string|required|Unique section name identifier. `remove`|boolean|optional|The default value is `"false"`. Set to `"true"` to remove this element during parsing. From f2d09057017daf514a9537d22ee2e4ab3ef46fa0 Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Tue, 4 Feb 2020 11:28:34 -0600 Subject: [PATCH 193/888] Added `deprecated` to metadata topic --- docs/metadata.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/metadata.md b/docs/metadata.md index 795c8a038..d99a37346 100644 --- a/docs/metadata.md +++ b/docs/metadata.md @@ -421,6 +421,7 @@ Root element that points to the corresponding XML Schema. | `returnIndex` | string | optional | Specifies index at which the value will be returned when `returnRegex` matches multiple values | | `removeBackend` | boolean | optional | Removes backend name from requested URL. Applicable when `auth="adminFormKey"`. | | `filename` | string | optional | | +|`deprecated`|string|optional|Used to warn about the future deprecation of the test. String will appear in Allure reports and console output at runtime.| - \*`url` - full URL is a concatenation of _ENV.baseUrl_ + `/rest/` + _url_. To reuse data of a required entity or returned response use a field key wrapped in curly braces such as `{sku}`. From 96413c402ea0c3f48e72981a1a8be87768632b3e Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Tue, 4 Feb 2020 11:39:13 -0600 Subject: [PATCH 194/888] Added attribute. --- docs/page.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/page.md b/docs/page.md index 705a94294..cf8448dd8 100644 --- a/docs/page.md +++ b/docs/page.md @@ -145,6 +145,7 @@ Attributes|Type|Use|Description `area`|string|required|The area where this page lives. Three possible values: `admin` prepends `BACKEND_NAME` to `url`, `storefront` does not prepend anything to `url`, `external` flags the page for use with `amOnUrl`. The `url` provided must be a full URL, such as `http://myFullUrl.com/`, instead of the URL for a Magento page. `parameterized`|boolean |optional|Include and set to `"true"` if the `url` for this page has parameters that need to be replaced for proper use. `remove`|boolean|optional|The default value is `"false"`. Set to `"true"` to remove this element during parsing. +`deprecated`|string|optional|Used to warn about the future deprecation of the data entity. String will appear in Allure reports and console output at runtime. `<page>` may contain several [`<section>`] elements. From 309a1f256f24f599355dcddcf3b5364206119692 Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Tue, 4 Feb 2020 15:00:06 -0600 Subject: [PATCH 195/888] Remove ref files from repo. --- docs/actiongroup-list.md | 6 ------ docs/mftf-tests.md | 30 ------------------------------ 2 files changed, 36 deletions(-) delete mode 100644 docs/actiongroup-list.md delete mode 100644 docs/mftf-tests.md diff --git a/docs/actiongroup-list.md b/docs/actiongroup-list.md deleted file mode 100644 index 7b469f4ed..000000000 --- a/docs/actiongroup-list.md +++ /dev/null @@ -1,6 +0,0 @@ -# MFTF action group reference - -Action groups are important building blocks for quickly creating tests for the Magento Functional Testing Framework. -This page lists all current action groups so developers can see what is available to them. - -{% include mftf/actiongroup_data.md %} diff --git a/docs/mftf-tests.md b/docs/mftf-tests.md deleted file mode 100644 index cb1941053..000000000 --- a/docs/mftf-tests.md +++ /dev/null @@ -1,30 +0,0 @@ -<style> -.mftf-dl { - margin-bottom: 2.5em; -} -dl dt{ - font-weight:400; -} -</style> - -# MFTF functional test reference - -The Magento Functional Testing Framework runs tests on every Module within Magento. These files are stored within each Module folder in the Magento repo. -This page lists all those tests so that developers can have a good sense of what is covered. - -{% include mftf/functional_data.md %} - -{% for item in mftf %} - -### {{ item.name }} -{% for file in item.items %} -#### [{{ file.filename }}]({{file.repo}}) -{: .mftf-test-link} - -{% for test in file.tests %} -{{test.testname}} - : {{test.description}} -{: .mftf-dl} -{% endfor %} -{% endfor %} -{% endfor %} From 8905616c082c85db857aaba5c5738d071d9feeff Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Tue, 4 Feb 2020 15:24:24 -0600 Subject: [PATCH 196/888] Grammar and formatting --- docs/getting-started.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 92f456cfd..e2a16ff49 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -2,11 +2,11 @@ <div class="bs-callout bs-callout-info" markdown="1"> [Find your MFTF version][] of the MFTF. -The latest Magento 2.3.x release supports MFTF 2.4.5. +The latest Magento 2.3.x release supports MFTF 2.6.0. The latest Magento 2.2.x release supports MFTF 2.4.5. </div> -## Prepare environment {#prepare-environment} +## Prepare environment {#prepare-environment} Make sure that you have the following software installed and configured on your development environment: @@ -53,11 +53,11 @@ Install the Magento application. composer install ``` -## Prepare Magento {#prepare-magento} +## Prepare Magento {#prepare-magento} Configure the following settings in Magento as described below. -### WYSIWYG settings {#wysiwyg-settings} +### WYSIWYG settings {#wysiwyg-settings} A Selenium web driver cannot enter data to fields with WYSIWYG. @@ -74,7 +74,7 @@ or via command line: bin/magento config:set cms/wysiwyg/enabled disabled ``` -Clean the cache after changing the configuration values +Clean the cache after changing the configuration values: ```bash bin/magento cache:clean config full_page @@ -103,7 +103,7 @@ bin/magento config:set admin/security/admin_account_sharing 1 bin/magento config:set admin/security/use_form_key 0 ``` -Clean the cache after changing the configuration values +Clean the cache after changing the configuration values: ```bash bin/magento cache:clean config full_page @@ -115,9 +115,9 @@ The MFTF does not support executing CLI commands if your web server points to `< ### Nginx settings {#nginx-settings} -If Nginx Web server is used on your development environment then **Use Web Server Rewrites** setting in **Stores** > Settings > **Configuration** > **General** > **Web** > **Search Engine Optimization** must be set to **Yes**. +If the Nginx Web server is used on your development environment, then **Use Web Server Rewrites** setting in **Stores** > Settings > **Configuration** > **General** > **Web** > **Search Engine Optimization** must be set to **Yes**. -To be able to run Magento command line commands in tests add the following location block to Nginx configuration file in the Magento root directory: +To be able to run Magento command line commands in tests, add the following location block to the Nginx configuration file in the Magento root directory: ```conf location ~* ^/dev/tests/acceptance/utils($|/) { From f60c044728502e22c290ea8fbc5fd568bcd4538f Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Tue, 4 Feb 2020 15:27:00 -0600 Subject: [PATCH 197/888] Updated version number --- docs/getting-started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index e2a16ff49..89d228df9 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -2,7 +2,7 @@ <div class="bs-callout bs-callout-info" markdown="1"> [Find your MFTF version][] of the MFTF. -The latest Magento 2.3.x release supports MFTF 2.6.0. +The latest Magento 2.3.x release supports MFTF 2.5.3. The latest Magento 2.2.x release supports MFTF 2.4.5. </div> From 15f8304112cc040cafa758a5d1d649354626e976 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Tue, 4 Feb 2020 15:15:07 -0600 Subject: [PATCH 198/888] Bump MFTF dependencies --- composer.lock | 1223 ++++++++++------- .../Util/OperationElementExtractor.php | 6 +- 2 files changed, 705 insertions(+), 524 deletions(-) diff --git a/composer.lock b/composer.lock index 051ab6441..ac510665e 100644 --- a/composer.lock +++ b/composer.lock @@ -59,25 +59,26 @@ }, { "name": "allure-framework/allure-php-api", - "version": "1.1.4", + "version": "1.1.6", "source": { "type": "git", - "url": "https://github.com/allure-framework/allure-php-adapter-api.git", - "reference": "a462a0da121681577033e13c123b6cc4e89cdc64" + "url": "https://github.com/allure-framework/allure-php-commons.git", + "reference": "2c62a70d60eca190253a6b80e9aa4c2ebc2e6e7f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/allure-framework/allure-php-adapter-api/zipball/a462a0da121681577033e13c123b6cc4e89cdc64", - "reference": "a462a0da121681577033e13c123b6cc4e89cdc64", + "url": "https://api.github.com/repos/allure-framework/allure-php-commons/zipball/2c62a70d60eca190253a6b80e9aa4c2ebc2e6e7f", + "reference": "2c62a70d60eca190253a6b80e9aa4c2ebc2e6e7f", "shasum": "" }, "require": { - "jms/serializer": ">=0.16.0", - "moontoast/math": ">=1.1.0", + "jms/serializer": "^0.16 || ^1.0", "php": ">=5.4.0", - "phpunit/phpunit": ">=4.0.0", - "ramsey/uuid": ">=3.0.0", - "symfony/http-foundation": ">=2.0" + "ramsey/uuid": "^3.0", + "symfony/http-foundation": "^2.0 || ^3.0 || ^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0.0" }, "type": "library", "autoload": { @@ -107,20 +108,20 @@ "php", "report" ], - "time": "2016-12-07T12:15:46+00:00" + "time": "2020-01-09T10:26:09+00:00" }, { "name": "aws/aws-sdk-php", - "version": "3.132.2", + "version": "3.133.7", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "f890689c6db27625522ea2e7e9b8420b6fccb063" + "reference": "cd6fb07aed2cc68088251e3c572d111d67d558a3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/f890689c6db27625522ea2e7e9b8420b6fccb063", - "reference": "f890689c6db27625522ea2e7e9b8420b6fccb063", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/cd6fb07aed2cc68088251e3c572d111d67d558a3", + "reference": "cd6fb07aed2cc68088251e3c572d111d67d558a3", "shasum": "" }, "require": { @@ -191,20 +192,20 @@ "s3", "sdk" ], - "time": "2020-01-09T19:09:31+00:00" + "time": "2020-02-04T19:11:15+00:00" }, { "name": "behat/gherkin", - "version": "v4.4.5", + "version": "v4.6.0", "source": { "type": "git", "url": "https://github.com/Behat/Gherkin.git", - "reference": "5c14cff4f955b17d20d088dec1bde61c0539ec74" + "reference": "ab0a02ea14893860bca00f225f5621d351a3ad07" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Behat/Gherkin/zipball/5c14cff4f955b17d20d088dec1bde61c0539ec74", - "reference": "5c14cff4f955b17d20d088dec1bde61c0539ec74", + "url": "https://api.github.com/repos/Behat/Gherkin/zipball/ab0a02ea14893860bca00f225f5621d351a3ad07", + "reference": "ab0a02ea14893860bca00f225f5621d351a3ad07", "shasum": "" }, "require": { @@ -212,8 +213,8 @@ }, "require-dev": { "phpunit/phpunit": "~4.5|~5", - "symfony/phpunit-bridge": "~2.7|~3", - "symfony/yaml": "~2.3|~3" + "symfony/phpunit-bridge": "~2.7|~3|~4", + "symfony/yaml": "~2.3|~3|~4" }, "suggest": { "symfony/yaml": "If you want to parse features, represented in YAML files" @@ -250,7 +251,7 @@ "gherkin", "parser" ], - "time": "2016-10-30T11:50:56+00:00" + "time": "2019-01-16T14:22:17+00:00" }, { "name": "cache/cache", @@ -334,7 +335,7 @@ { "name": "Tobias Nyholm", "email": "tobias.nyholm@gmail.com", - "homepage": "https://github.com/nyholm" + "homepage": "https://github.com/Nyholm" } ], "description": "Library of all the php-cache adapters", @@ -438,16 +439,16 @@ }, { "name": "codeception/phpunit-wrapper", - "version": "6.7.0", + "version": "6.8.0", "source": { "type": "git", "url": "https://github.com/Codeception/phpunit-wrapper.git", - "reference": "93f59e028826464eac086052fa226e58967f6907" + "reference": "20e054e9cee8de0523322367bcccde8e6a3db263" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/phpunit-wrapper/zipball/93f59e028826464eac086052fa226e58967f6907", - "reference": "93f59e028826464eac086052fa226e58967f6907", + "url": "https://api.github.com/repos/Codeception/phpunit-wrapper/zipball/20e054e9cee8de0523322367bcccde8e6a3db263", + "reference": "20e054e9cee8de0523322367bcccde8e6a3db263", "shasum": "" }, "require": { @@ -480,7 +481,7 @@ } ], "description": "PHPUnit classes used by Codeception", - "time": "2019-08-18T15:43:35+00:00" + "time": "2020-01-03T08:01:16+00:00" }, { "name": "codeception/stub", @@ -514,16 +515,16 @@ }, { "name": "composer/ca-bundle", - "version": "1.2.4", + "version": "1.2.6", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "10bb96592168a0f8e8f6dcde3532d9fa50b0b527" + "reference": "47fe531de31fca4a1b997f87308e7d7804348f7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/10bb96592168a0f8e8f6dcde3532d9fa50b0b527", - "reference": "10bb96592168a0f8e8f6dcde3532d9fa50b0b527", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/47fe531de31fca4a1b997f87308e7d7804348f7e", + "reference": "47fe531de31fca4a1b997f87308e7d7804348f7e", "shasum": "" }, "require": { @@ -534,7 +535,7 @@ "require-dev": { "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8", "psr/log": "^1.0", - "symfony/process": "^2.5 || ^3.0 || ^4.0" + "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0" }, "type": "library", "extra": { @@ -566,20 +567,20 @@ "ssl", "tls" ], - "time": "2019-08-30T08:44:50+00:00" + "time": "2020-01-13T10:02:55+00:00" }, { "name": "composer/composer", - "version": "1.9.1", + "version": "1.9.3", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "bb01f2180df87ce7992b8331a68904f80439dd2f" + "reference": "1291a16ce3f48bfdeca39d64fca4875098af4d7b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/bb01f2180df87ce7992b8331a68904f80439dd2f", - "reference": "bb01f2180df87ce7992b8331a68904f80439dd2f", + "url": "https://api.github.com/repos/composer/composer/zipball/1291a16ce3f48bfdeca39d64fca4875098af4d7b", + "reference": "1291a16ce3f48bfdeca39d64fca4875098af4d7b", "shasum": "" }, "require": { @@ -646,28 +647,27 @@ "dependency", "package" ], - "time": "2019-11-01T16:20:17+00:00" + "time": "2020-02-04T11:58:49+00:00" }, { "name": "composer/semver", - "version": "1.5.0", + "version": "1.5.1", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "46d9139568ccb8d9e7cdd4539cab7347568a5e2e" + "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/46d9139568ccb8d9e7cdd4539cab7347568a5e2e", - "reference": "46d9139568ccb8d9e7cdd4539cab7347568a5e2e", + "url": "https://api.github.com/repos/composer/semver/zipball/c6bea70230ef4dd483e6bbcab6005f682ed3a8de", + "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de", "shasum": "" }, "require": { "php": "^5.3.2 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "^4.5 || ^5.0.5", - "phpunit/phpunit-mock-objects": "2.3.0 || ^3.0" + "phpunit/phpunit": "^4.5 || ^5.0.5" }, "type": "library", "extra": { @@ -708,7 +708,7 @@ "validation", "versioning" ], - "time": "2019-03-19T17:25:45+00:00" + "time": "2020-01-13T12:06:48+00:00" }, { "name": "composer/spdx-licenses", @@ -772,24 +772,24 @@ }, { "name": "composer/xdebug-handler", - "version": "1.3.3", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "46867cbf8ca9fb8d60c506895449eb799db1184f" + "reference": "cbe23383749496fe0f373345208b79568e4bc248" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/46867cbf8ca9fb8d60c506895449eb799db1184f", - "reference": "46867cbf8ca9fb8d60c506895449eb799db1184f", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/cbe23383749496fe0f373345208b79568e4bc248", + "reference": "cbe23383749496fe0f373345208b79568e4bc248", "shasum": "" }, "require": { - "php": "^5.3.2 || ^7.0", + "php": "^5.3.2 || ^7.0 || ^8.0", "psr/log": "^1.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" + "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8" }, "type": "library", "autoload": { @@ -807,43 +807,87 @@ "email": "john-stevenson@blueyonder.co.uk" } ], - "description": "Restarts a process without xdebug.", + "description": "Restarts a process without Xdebug.", "keywords": [ "Xdebug", "performance" ], - "time": "2019-05-27T17:52:04+00:00" + "time": "2019-11-06T16:40:04+00:00" }, { "name": "consolidation/annotated-command", - "version": "2.9.1", + "version": "2.12.0", "source": { "type": "git", "url": "https://github.com/consolidation/annotated-command.git", - "reference": "4bdbb8fa149e1cc1511bd77b0bc4729fd66bccac" + "reference": "512a2e54c98f3af377589de76c43b24652bcb789" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/annotated-command/zipball/4bdbb8fa149e1cc1511bd77b0bc4729fd66bccac", - "reference": "4bdbb8fa149e1cc1511bd77b0bc4729fd66bccac", + "url": "https://api.github.com/repos/consolidation/annotated-command/zipball/512a2e54c98f3af377589de76c43b24652bcb789", + "reference": "512a2e54c98f3af377589de76c43b24652bcb789", "shasum": "" }, "require": { - "consolidation/output-formatters": "^3.1.12", - "php": ">=5.4.0", + "consolidation/output-formatters": "^3.4", + "php": ">=5.4.5", "psr/log": "^1", "symfony/console": "^2.8|^3|^4", "symfony/event-dispatcher": "^2.5|^3|^4", "symfony/finder": "^2.5|^3|^4" }, "require-dev": { - "g1a/composer-test-scenarios": "^2", + "g1a/composer-test-scenarios": "^3", + "php-coveralls/php-coveralls": "^1", "phpunit/phpunit": "^6", - "satooshi/php-coveralls": "^2", "squizlabs/php_codesniffer": "^2.7" }, "type": "library", "extra": { + "scenarios": { + "symfony4": { + "require": { + "symfony/console": "^4.0" + }, + "config": { + "platform": { + "php": "7.1.3" + } + } + }, + "symfony2": { + "require": { + "symfony/console": "^2.8" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.36" + }, + "remove": [ + "php-coveralls/php-coveralls" + ], + "config": { + "platform": { + "php": "5.4.8" + } + }, + "scenario-options": { + "create-lockfile": "false" + } + }, + "phpunit4": { + "require-dev": { + "phpunit/phpunit": "^4.8.36" + }, + "remove": [ + "php-coveralls/php-coveralls" + ], + "config": { + "platform": { + "php": "5.4.8" + } + } + } + }, "branch-alias": { "dev-master": "2.x-dev" } @@ -864,20 +908,20 @@ } ], "description": "Initialize Symfony Console commands from annotated command class methods.", - "time": "2018-09-19T17:47:18+00:00" + "time": "2019-03-08T16:55:03+00:00" }, { "name": "consolidation/config", - "version": "1.1.1", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/consolidation/config.git", - "reference": "925231dfff32f05b787e1fddb265e789b939cf4c" + "reference": "cac1279bae7efb5c7fb2ca4c3ba4b8eb741a96c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/config/zipball/925231dfff32f05b787e1fddb265e789b939cf4c", - "reference": "925231dfff32f05b787e1fddb265e789b939cf4c", + "url": "https://api.github.com/repos/consolidation/config/zipball/cac1279bae7efb5c7fb2ca4c3ba4b8eb741a96c1", + "reference": "cac1279bae7efb5c7fb2ca4c3ba4b8eb741a96c1", "shasum": "" }, "require": { @@ -886,9 +930,9 @@ "php": ">=5.4.0" }, "require-dev": { - "g1a/composer-test-scenarios": "^1", + "g1a/composer-test-scenarios": "^3", + "php-coveralls/php-coveralls": "^1", "phpunit/phpunit": "^5", - "satooshi/php-coveralls": "^1.0", "squizlabs/php_codesniffer": "2.*", "symfony/console": "^2.5|^3|^4", "symfony/yaml": "^2.8.11|^3|^4" @@ -898,6 +942,33 @@ }, "type": "library", "extra": { + "scenarios": { + "symfony4": { + "require-dev": { + "symfony/console": "^4.0" + }, + "config": { + "platform": { + "php": "7.1.3" + } + } + }, + "symfony2": { + "require-dev": { + "symfony/console": "^2.8", + "symfony/event-dispatcher": "^2.8", + "phpunit/phpunit": "^4.8.36" + }, + "remove": [ + "php-coveralls/php-coveralls" + ], + "config": { + "platform": { + "php": "5.4.8" + } + } + } + }, "branch-alias": { "dev-master": "1.x-dev" } @@ -918,35 +989,76 @@ } ], "description": "Provide configuration services for a commandline tool.", - "time": "2018-10-24T17:55:35+00:00" + "time": "2019-03-03T19:37:04+00:00" }, { "name": "consolidation/log", - "version": "1.0.6", + "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/consolidation/log.git", - "reference": "dfd8189a771fe047bf3cd669111b2de5f1c79395" + "reference": "b2e887325ee90abc96b0a8b7b474cd9e7c896e3a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/log/zipball/dfd8189a771fe047bf3cd669111b2de5f1c79395", - "reference": "dfd8189a771fe047bf3cd669111b2de5f1c79395", + "url": "https://api.github.com/repos/consolidation/log/zipball/b2e887325ee90abc96b0a8b7b474cd9e7c896e3a", + "reference": "b2e887325ee90abc96b0a8b7b474cd9e7c896e3a", "shasum": "" }, "require": { - "php": ">=5.5.0", - "psr/log": "~1.0", + "php": ">=5.4.5", + "psr/log": "^1.0", "symfony/console": "^2.8|^3|^4" }, "require-dev": { - "g1a/composer-test-scenarios": "^1", - "phpunit/phpunit": "4.*", - "satooshi/php-coveralls": "^2", - "squizlabs/php_codesniffer": "2.*" + "g1a/composer-test-scenarios": "^3", + "php-coveralls/php-coveralls": "^1", + "phpunit/phpunit": "^6", + "squizlabs/php_codesniffer": "^2" }, "type": "library", "extra": { + "scenarios": { + "symfony4": { + "require": { + "symfony/console": "^4.0" + }, + "config": { + "platform": { + "php": "7.1.3" + } + } + }, + "symfony2": { + "require": { + "symfony/console": "^2.8" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.36" + }, + "remove": [ + "php-coveralls/php-coveralls" + ], + "config": { + "platform": { + "php": "5.4.8" + } + } + }, + "phpunit4": { + "require-dev": { + "phpunit/phpunit": "^4.8.36" + }, + "remove": [ + "php-coveralls/php-coveralls" + ], + "config": { + "platform": { + "php": "5.4.8" + } + } + } + }, "branch-alias": { "dev-master": "1.x-dev" } @@ -967,20 +1079,20 @@ } ], "description": "Improved Psr-3 / Psr\\Log logger based on Symfony Console components.", - "time": "2018-05-25T18:14:39+00:00" + "time": "2019-01-01T17:30:51+00:00" }, { "name": "consolidation/output-formatters", - "version": "3.4.0", + "version": "3.5.0", "source": { "type": "git", "url": "https://github.com/consolidation/output-formatters.git", - "reference": "a942680232094c4a5b21c0b7e54c20cce623ae19" + "reference": "99ec998ffb697e0eada5aacf81feebfb13023605" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/output-formatters/zipball/a942680232094c4a5b21c0b7e54c20cce623ae19", - "reference": "a942680232094c4a5b21c0b7e54c20cce623ae19", + "url": "https://api.github.com/repos/consolidation/output-formatters/zipball/99ec998ffb697e0eada5aacf81feebfb13023605", + "reference": "99ec998ffb697e0eada5aacf81feebfb13023605", "shasum": "" }, "require": { @@ -990,11 +1102,10 @@ "symfony/finder": "^2.5|^3|^4" }, "require-dev": { - "g1a/composer-test-scenarios": "^2", + "g1a/composer-test-scenarios": "^3", + "php-coveralls/php-coveralls": "^1", "phpunit/phpunit": "^5.7.27", - "satooshi/php-coveralls": "^2", "squizlabs/php_codesniffer": "^2.7", - "symfony/console": "3.2.3", "symfony/var-dumper": "^2.8|^3|^4", "victorjonsson/markdowndocs": "^1.3" }, @@ -1003,6 +1114,52 @@ }, "type": "library", "extra": { + "scenarios": { + "symfony4": { + "require": { + "symfony/console": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^6" + }, + "config": { + "platform": { + "php": "7.1.3" + } + } + }, + "symfony3": { + "require": { + "symfony/console": "^3.4", + "symfony/finder": "^3.4", + "symfony/var-dumper": "^3.4" + }, + "config": { + "platform": { + "php": "5.6.32" + } + } + }, + "symfony2": { + "require": { + "symfony/console": "^2.8" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.36" + }, + "remove": [ + "php-coveralls/php-coveralls" + ], + "config": { + "platform": { + "php": "5.4.8" + } + }, + "scenario-options": { + "create-lockfile": "false" + } + } + }, "branch-alias": { "dev-master": "3.x-dev" } @@ -1023,29 +1180,28 @@ } ], "description": "Format text by applying transformations provided by plug-in formatters.", - "time": "2018-10-19T22:35:38+00:00" + "time": "2019-05-30T23:16:01+00:00" }, { "name": "consolidation/robo", - "version": "1.3.1", + "version": "1.4.11", "source": { "type": "git", "url": "https://github.com/consolidation/Robo.git", - "reference": "31f2d2562c4e1dcde70f2659eefd59aa9c7f5b2d" + "reference": "5fa1d901776a628167a325baa9db95d8edf13a80" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/Robo/zipball/31f2d2562c4e1dcde70f2659eefd59aa9c7f5b2d", - "reference": "31f2d2562c4e1dcde70f2659eefd59aa9c7f5b2d", + "url": "https://api.github.com/repos/consolidation/Robo/zipball/5fa1d901776a628167a325baa9db95d8edf13a80", + "reference": "5fa1d901776a628167a325baa9db95d8edf13a80", "shasum": "" }, "require": { - "consolidation/annotated-command": "^2.8.2", - "consolidation/config": "^1.0.10", + "consolidation/annotated-command": "^2.11.0", + "consolidation/config": "^1.2", "consolidation/log": "~1", "consolidation/output-formatters": "^3.1.13", "consolidation/self-update": "^1", - "g1a/composer-test-scenarios": "^2", "grasmash/yaml-expander": "^1.3", "league/container": "^2.2", "php": ">=5.5.0", @@ -1062,14 +1218,16 @@ "codeception/aspect-mock": "^1|^2.1.1", "codeception/base": "^2.3.7", "codeception/verify": "^0.3.2", + "g1a/composer-test-scenarios": "^3", "goaop/framework": "~2.1.2", "goaop/parser-reflection": "^1.1.0", "natxet/cssmin": "3.0.4", "nikic/php-parser": "^3.1.5", "patchwork/jsqueeze": "~2", - "pear/archive_tar": "^1.4.2", + "pear/archive_tar": "^1.4.4", + "php-coveralls/php-coveralls": "^1", "phpunit/php-code-coverage": "~2|~4", - "satooshi/php-coveralls": "^2", + "sebastian/comparator": "^1.2.4", "squizlabs/php_codesniffer": "^2.8" }, "suggest": { @@ -1083,9 +1241,36 @@ ], "type": "library", "extra": { + "scenarios": { + "symfony4": { + "require": { + "symfony/console": "^4" + }, + "config": { + "platform": { + "php": "7.1.3" + } + } + }, + "symfony2": { + "require": { + "symfony/console": "^2.8" + }, + "remove": [ + "goaop/framework" + ], + "config": { + "platform": { + "php": "5.5.9" + } + }, + "scenario-options": { + "create-lockfile": "false" + } + } + }, "branch-alias": { - "dev-master": "1.x-dev", - "dev-state": "1.x-dev" + "dev-master": "2.x-dev" } }, "autoload": { @@ -1104,7 +1289,7 @@ } ], "description": "Modern task runner", - "time": "2018-08-17T18:44:18+00:00" + "time": "2019-10-29T15:50:02+00:00" }, { "name": "consolidation/self-update", @@ -1654,16 +1839,16 @@ }, { "name": "facebook/webdriver", - "version": "1.6.0", + "version": "1.7.1", "source": { "type": "git", "url": "https://github.com/facebook/php-webdriver.git", - "reference": "bd8c740097eb9f2fc3735250fc1912bc811a954e" + "reference": "e43de70f3c7166169d0f14a374505392734160e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/bd8c740097eb9f2fc3735250fc1912bc811a954e", - "reference": "bd8c740097eb9f2fc3735250fc1912bc811a954e", + "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/e43de70f3c7166169d0f14a374505392734160e5", + "reference": "e43de70f3c7166169d0f14a374505392734160e5", "shasum": "" }, "require": { @@ -1711,20 +1896,20 @@ "webdriver" ], "abandoned": "php-webdriver/webdriver", - "time": "2018-05-16T17:37:13+00:00" + "time": "2019-06-13T08:02:18+00:00" }, { "name": "flow/jsonpath", - "version": "0.4.0", + "version": "0.5.0", "source": { "type": "git", "url": "https://github.com/FlowCommunications/JSONPath.git", - "reference": "f0222818d5c938e4ab668ab2e2c079bd51a27112" + "reference": "b9738858c75d008c1211612b973e9510f8b7f8ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FlowCommunications/JSONPath/zipball/f0222818d5c938e4ab668ab2e2c079bd51a27112", - "reference": "f0222818d5c938e4ab668ab2e2c079bd51a27112", + "url": "https://api.github.com/repos/FlowCommunications/JSONPath/zipball/b9738858c75d008c1211612b973e9510f8b7f8ea", + "reference": "b9738858c75d008c1211612b973e9510f8b7f8ea", "shasum": "" }, "require": { @@ -1732,7 +1917,7 @@ }, "require-dev": { "peekmo/jsonpath": "dev-master", - "phpunit/phpunit": "^4.0" + "phpunit/phpunit": "^7.0" }, "type": "library", "autoload": { @@ -1752,20 +1937,20 @@ } ], "description": "JSONPath implementation for parsing, searching and flattening arrays", - "time": "2018-03-04T16:39:47+00:00" + "time": "2019-07-15T17:23:22+00:00" }, { "name": "fzaninotto/faker", - "version": "v1.8.0", + "version": "v1.9.1", "source": { "type": "git", "url": "https://github.com/fzaninotto/Faker.git", - "reference": "f72816b43e74063c8b10357394b6bba8cb1c10de" + "reference": "fc10d778e4b84d5bd315dad194661e091d307c6f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/f72816b43e74063c8b10357394b6bba8cb1c10de", - "reference": "f72816b43e74063c8b10357394b6bba8cb1c10de", + "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/fc10d778e4b84d5bd315dad194661e091d307c6f", + "reference": "fc10d778e4b84d5bd315dad194661e091d307c6f", "shasum": "" }, "require": { @@ -1774,12 +1959,12 @@ "require-dev": { "ext-intl": "*", "phpunit/phpunit": "^4.8.35 || ^5.7", - "squizlabs/php_codesniffer": "^1.5" + "squizlabs/php_codesniffer": "^2.9.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8-dev" + "dev-master": "1.9-dev" } }, "autoload": { @@ -1802,40 +1987,7 @@ "faker", "fixtures" ], - "time": "2018-07-12T10:23:15+00:00" - }, - { - "name": "g1a/composer-test-scenarios", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/g1a/composer-test-scenarios.git", - "reference": "a166fd15191aceab89f30c097e694b7cf3db4880" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/g1a/composer-test-scenarios/zipball/a166fd15191aceab89f30c097e694b7cf3db4880", - "reference": "a166fd15191aceab89f30c097e694b7cf3db4880", - "shasum": "" - }, - "bin": [ - "scripts/create-scenario", - "scripts/dependency-licenses", - "scripts/install-scenario" - ], - "type": "library", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Greg Anderson", - "email": "greg.1.anderson@greenknowe.org" - } - ], - "description": "Useful scripts for testing multiple sets of Composer dependencies.", - "time": "2018-08-08T23:37:23+00:00" + "time": "2019-12-12T13:22:17+00:00" }, { "name": "grasmash/expander", @@ -1934,44 +2086,46 @@ }, { "name": "guzzlehttp/guzzle", - "version": "6.3.3", + "version": "6.5.2", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba" + "reference": "43ece0e75098b7ecd8d13918293029e555a50f82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba", - "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/43ece0e75098b7ecd8d13918293029e555a50f82", + "reference": "43ece0e75098b7ecd8d13918293029e555a50f82", "shasum": "" }, "require": { + "ext-json": "*", "guzzlehttp/promises": "^1.0", - "guzzlehttp/psr7": "^1.4", + "guzzlehttp/psr7": "^1.6.1", "php": ">=5.5" }, "require-dev": { "ext-curl": "*", "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", - "psr/log": "^1.0" + "psr/log": "^1.1" }, "suggest": { + "ext-intl": "Required for Internationalized Domain Name (IDN) support", "psr/log": "Required for using the Log middleware" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "6.3-dev" + "dev-master": "6.5-dev" } }, "autoload": { - "files": [ - "src/functions_include.php" - ], "psr-4": { "GuzzleHttp\\": "src/" - } + }, + "files": [ + "src/functions_include.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -1995,7 +2149,7 @@ "rest", "web service" ], - "time": "2018-04-22T15:46:56+00:00" + "time": "2019-12-23T11:57:10+00:00" }, { "name": "guzzlehttp/promises", @@ -2050,32 +2204,37 @@ }, { "name": "guzzlehttp/psr7", - "version": "1.4.2", + "version": "1.6.1", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c" + "reference": "239400de7a173fe9901b9ac7c06497751f00727a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c", - "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/239400de7a173fe9901b9ac7c06497751f00727a", + "reference": "239400de7a173fe9901b9ac7c06497751f00727a", "shasum": "" }, "require": { "php": ">=5.4.0", - "psr/http-message": "~1.0" + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" }, "provide": { "psr/http-message-implementation": "1.0" }, "require-dev": { - "phpunit/phpunit": "~4.0" + "ext-zlib": "*", + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8" + }, + "suggest": { + "zendframework/zend-httphandlerrunner": "Emit PSR-7 responses" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4-dev" + "dev-master": "1.6-dev" } }, "autoload": { @@ -2105,13 +2264,14 @@ "keywords": [ "http", "message", + "psr-7", "request", "response", "stream", "uri", "url" ], - "time": "2017-03-20T17:10:46+00:00" + "time": "2019-07-01T23:21:34+00:00" }, { "name": "jms/metadata", @@ -2420,16 +2580,16 @@ }, { "name": "league/flysystem", - "version": "1.0.53", + "version": "1.0.63", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "08e12b7628f035600634a5e76d95b5eb66cea674" + "reference": "8132daec326565036bc8e8d1876f77ec183a7bd6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/08e12b7628f035600634a5e76d95b5eb66cea674", - "reference": "08e12b7628f035600634a5e76d95b5eb66cea674", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/8132daec326565036bc8e8d1876f77ec183a7bd6", + "reference": "8132daec326565036bc8e8d1876f77ec183a7bd6", "shasum": "" }, "require": { @@ -2500,20 +2660,20 @@ "sftp", "storage" ], - "time": "2019-06-18T20:09:29+00:00" + "time": "2020-01-04T16:30:31+00:00" }, { "name": "monolog/monolog", - "version": "1.24.0", + "version": "1.25.3", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266" + "reference": "fa82921994db851a8becaf3787a9e73c5976b6f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266", - "reference": "bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fa82921994db851a8becaf3787a9e73c5976b6f1", + "reference": "fa82921994db851a8becaf3787a9e73c5976b6f1", "shasum": "" }, "require": { @@ -2578,57 +2738,7 @@ "logging", "psr-3" ], - "time": "2018-11-05T09:00:11+00:00" - }, - { - "name": "moontoast/math", - "version": "1.1.2", - "source": { - "type": "git", - "url": "https://github.com/ramsey/moontoast-math.git", - "reference": "c2792a25df5cad4ff3d760dd37078fc5b6fccc79" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ramsey/moontoast-math/zipball/c2792a25df5cad4ff3d760dd37078fc5b6fccc79", - "reference": "c2792a25df5cad4ff3d760dd37078fc5b6fccc79", - "shasum": "" - }, - "require": { - "ext-bcmath": "*", - "php": ">=5.3.3" - }, - "require-dev": { - "jakub-onderka/php-parallel-lint": "^0.9.0", - "phpunit/phpunit": "^4.7|>=5.0 <5.4", - "satooshi/php-coveralls": "^0.6.1", - "squizlabs/php_codesniffer": "^2.3" - }, - "type": "library", - "autoload": { - "psr-4": { - "Moontoast\\Math\\": "src/Moontoast/Math/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Ben Ramsey", - "email": "ben@benramsey.com", - "homepage": "https://benramsey.com" - } - ], - "description": "A mathematics library, providing functionality for large numbers", - "homepage": "https://github.com/ramsey/moontoast-math", - "keywords": [ - "bcmath", - "math" - ], - "abandoned": "brick/math", - "time": "2017-02-16T16:54:46+00:00" + "time": "2019-12-20T14:15:16+00:00" }, { "name": "mtdowling/jmespath.php", @@ -2689,16 +2799,16 @@ }, { "name": "mustache/mustache", - "version": "v2.12.0", + "version": "v2.13.0", "source": { "type": "git", "url": "https://github.com/bobthecow/mustache.php.git", - "reference": "fe8fe72e9d580591854de404cc59a1b83ca4d19e" + "reference": "e95c5a008c23d3151d59ea72484d4f72049ab7f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/mustache.php/zipball/fe8fe72e9d580591854de404cc59a1b83ca4d19e", - "reference": "fe8fe72e9d580591854de404cc59a1b83ca4d19e", + "url": "https://api.github.com/repos/bobthecow/mustache.php/zipball/e95c5a008c23d3151d59ea72484d4f72049ab7f4", + "reference": "e95c5a008c23d3151d59ea72484d4f72049ab7f4", "shasum": "" }, "require": { @@ -2731,7 +2841,7 @@ "mustache", "templating" ], - "time": "2017-07-11T12:54:05+00:00" + "time": "2019-11-23T21:40:31+00:00" }, { "name": "myclabs/deep-copy", @@ -3029,27 +3139,28 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "4.3.0", + "version": "4.3.4", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "94fd0001232e47129dd3504189fa1c7225010d08" + "reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08", - "reference": "94fd0001232e47129dd3504189fa1c7225010d08", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/da3fd972d6bafd628114f7e7e036f45944b62e9c", + "reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c", "shasum": "" }, "require": { "php": "^7.0", - "phpdocumentor/reflection-common": "^1.0.0", - "phpdocumentor/type-resolver": "^0.4.0", + "phpdocumentor/reflection-common": "^1.0.0 || ^2.0.0", + "phpdocumentor/type-resolver": "~0.4 || ^1.0.0", "webmozart/assert": "^1.0" }, "require-dev": { - "doctrine/instantiator": "~1.0.5", + "doctrine/instantiator": "^1.0.5", "mockery/mockery": "^1.0", + "phpdocumentor/type-resolver": "0.4.*", "phpunit/phpunit": "^6.4" }, "type": "library", @@ -3076,29 +3187,29 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2017-11-30T07:14:17+00:00" + "time": "2019-12-28T18:55:12+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "0.4.0", + "version": "0.5.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" + "reference": "cf842904952e64e703800d094cdf34e715a8a3ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", - "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/cf842904952e64e703800d094cdf34e715a8a3ae", + "reference": "cf842904952e64e703800d094cdf34e715a8a3ae", "shasum": "" }, "require": { - "php": "^5.5 || ^7.0", + "php": "^7.0", "phpdocumentor/reflection-common": "^1.0" }, "require-dev": { - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^5.2||^4.8.24" + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^6.4" }, "type": "library", "extra": { @@ -3108,9 +3219,7 @@ }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] + "phpDocumentor\\Reflection\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -3123,47 +3232,52 @@ "email": "me@mikevanriel.com" } ], - "time": "2017-07-14T14:27:02+00:00" + "time": "2017-12-30T13:23:38+00:00" }, { "name": "phpoption/phpoption", - "version": "1.5.0", + "version": "1.7.2", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "94e644f7d2051a5f0fcf77d81605f152eecff0ed" + "reference": "77f7c4d2e65413aff5b5a8cc8b3caf7a28d81959" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/94e644f7d2051a5f0fcf77d81605f152eecff0ed", - "reference": "94e644f7d2051a5f0fcf77d81605f152eecff0ed", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/77f7c4d2e65413aff5b5a8cc8b3caf7a28d81959", + "reference": "77f7c4d2e65413aff5b5a8cc8b3caf7a28d81959", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": "^5.5.9 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "4.7.*" + "bamarni/composer-bin-plugin": "^1.3", + "phpunit/phpunit": "^4.8.35 || ^5.0 || ^6.0 || ^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3-dev" + "dev-master": "1.7-dev" } }, "autoload": { - "psr-0": { - "PhpOption\\": "src/" + "psr-4": { + "PhpOption\\": "src/PhpOption/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "Apache2" + "Apache-2.0" ], "authors": [ { "name": "Johannes M. Schmitt", "email": "schmittjoh@gmail.com" + }, + { + "name": "Graham Campbell", + "email": "graham@alt-three.com" } ], "description": "Option Type for PHP", @@ -3173,42 +3287,42 @@ "php", "type" ], - "time": "2015-07-25T16:39:46+00:00" + "time": "2019-12-15T19:35:24+00:00" }, { "name": "phpspec/prophecy", - "version": "1.8.0", + "version": "v1.10.2", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06" + "reference": "b4400efc9d206e83138e2bb97ed7f5b14b831cd9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06", - "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/b4400efc9d206e83138e2bb97ed7f5b14b831cd9", + "reference": "b4400efc9d206e83138e2bb97ed7f5b14b831cd9", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", - "sebastian/comparator": "^1.1|^2.0|^3.0", - "sebastian/recursion-context": "^1.0|^2.0|^3.0" + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", + "sebastian/comparator": "^1.2.3|^2.0|^3.0|^4.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0|^4.0" }, "require-dev": { - "phpspec/phpspec": "^2.5|^3.2", + "phpspec/phpspec": "^2.5 || ^3.2", "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8.x-dev" + "dev-master": "1.10.x-dev" } }, "autoload": { - "psr-0": { - "Prophecy\\": "src/" + "psr-4": { + "Prophecy\\": "src/Prophecy" } }, "notification-url": "https://packagist.org/downloads/", @@ -3236,7 +3350,7 @@ "spy", "stub" ], - "time": "2018-08-05T17:53:17+00:00" + "time": "2020-01-20T15:57:02+00:00" }, { "name": "phpunit/php-code-coverage", @@ -3489,16 +3603,16 @@ }, { "name": "phpunit/phpunit", - "version": "6.5.13", + "version": "6.5.14", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "0973426fb012359b2f18d3bd1e90ef1172839693" + "reference": "bac23fe7ff13dbdb461481f706f0e9fe746334b7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0973426fb012359b2f18d3bd1e90ef1172839693", - "reference": "0973426fb012359b2f18d3bd1e90ef1172839693", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/bac23fe7ff13dbdb461481f706f0e9fe746334b7", + "reference": "bac23fe7ff13dbdb461481f706f0e9fe746334b7", "shasum": "" }, "require": { @@ -3569,7 +3683,7 @@ "testing", "xunit" ], - "time": "2018-09-08T15:10:43+00:00" + "time": "2019-02-01T05:22:47+00:00" }, { "name": "phpunit/phpunit-mock-objects", @@ -3778,16 +3892,16 @@ }, { "name": "psr/log", - "version": "1.0.2", + "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" + "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", - "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801", + "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801", "shasum": "" }, "require": { @@ -3796,7 +3910,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.1.x-dev" } }, "autoload": { @@ -3821,7 +3935,7 @@ "psr", "psr-3" ], - "time": "2016-10-10T12:19:37+00:00" + "time": "2019-11-01T11:05:21+00:00" }, { "name": "psr/simple-cache", @@ -3871,46 +3985,88 @@ ], "time": "2017-10-23T01:57:42+00:00" }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "time": "2019-03-08T08:55:37+00:00" + }, { "name": "ramsey/uuid", - "version": "3.8.0", + "version": "3.9.2", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "d09ea80159c1929d75b3f9c60504d613aeb4a1e3" + "reference": "7779489a47d443f845271badbdcedfe4df8e06fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/d09ea80159c1929d75b3f9c60504d613aeb4a1e3", - "reference": "d09ea80159c1929d75b3f9c60504d613aeb4a1e3", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/7779489a47d443f845271badbdcedfe4df8e06fb", + "reference": "7779489a47d443f845271badbdcedfe4df8e06fb", "shasum": "" }, "require": { - "paragonie/random_compat": "^1.0|^2.0|9.99.99", - "php": "^5.4 || ^7.0", + "ext-json": "*", + "paragonie/random_compat": "^1 | ^2 | 9.99.99", + "php": "^5.4 | ^7 | ^8", "symfony/polyfill-ctype": "^1.8" }, "replace": { "rhumsaa/uuid": "self.version" }, "require-dev": { - "codeception/aspect-mock": "^1.0 | ~2.0.0", - "doctrine/annotations": "~1.2.0", - "goaop/framework": "1.0.0-alpha.2 | ^1.0 | ~2.1.0", - "ircmaxell/random-lib": "^1.1", - "jakub-onderka/php-parallel-lint": "^0.9.0", - "mockery/mockery": "^0.9.9", + "codeception/aspect-mock": "^1 | ^2", + "doctrine/annotations": "^1.2", + "goaop/framework": "1.0.0-alpha.2 | ^1 | ^2.1", + "jakub-onderka/php-parallel-lint": "^1", + "mockery/mockery": "^0.9.11 | ^1", "moontoast/math": "^1.1", - "php-mock/php-mock-phpunit": "^0.3|^1.1", - "phpunit/phpunit": "^4.7|^5.0|^6.5", - "squizlabs/php_codesniffer": "^2.3" + "paragonie/random-lib": "^2", + "php-mock/php-mock-phpunit": "^0.3 | ^1.1", + "phpunit/phpunit": "^4.8 | ^5.4 | ^6.5", + "squizlabs/php_codesniffer": "^3.5" }, "suggest": { "ext-ctype": "Provides support for PHP Ctype functions", "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator", + "ext-openssl": "Provides the OpenSSL extension for use with the OpenSslGenerator", "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator", - "ircmaxell/random-lib": "Provides RandomLib for use with the RandomLibAdapter", "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).", + "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter", "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid", "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." }, @@ -3923,13 +4079,21 @@ "autoload": { "psr-4": { "Ramsey\\Uuid\\": "src/" - } + }, + "files": [ + "src/functions.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + }, { "name": "Marijn Huizendveld", "email": "marijn.huizendveld@gmail.com" @@ -3937,11 +4101,6 @@ { "name": "Thibaud Fabre", "email": "thibaud@aztech.io" - }, - { - "name": "Ben Ramsey", - "email": "ben@benramsey.com", - "homepage": "https://benramsey.com" } ], "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).", @@ -3951,7 +4110,7 @@ "identifier", "uuid" ], - "time": "2018-07-19T23:38:55+00:00" + "time": "2019-12-17T08:18:51+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -4166,16 +4325,16 @@ }, { "name": "sebastian/exporter", - "version": "3.1.0", + "version": "3.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "234199f4528de6d12aaa58b612e98f7d36adb937" + "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937", - "reference": "234199f4528de6d12aaa58b612e98f7d36adb937", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/68609e1261d215ea5b21b7987539cbfbe156ec3e", + "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e", "shasum": "" }, "require": { @@ -4202,6 +4361,10 @@ "BSD-3-Clause" ], "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, { "name": "Jeff Welch", "email": "whatthejeff@gmail.com" @@ -4210,17 +4373,13 @@ "name": "Volker Dusch", "email": "github@wallbash.com" }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, { "name": "Adam Harvey", "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" } ], "description": "Provides the functionality to export PHP variables for visualization", @@ -4229,7 +4388,7 @@ "export", "exporter" ], - "time": "2017-04-03T13:19:02+00:00" + "time": "2019-09-14T09:02:43+00:00" }, { "name": "sebastian/global-state", @@ -4514,16 +4673,16 @@ }, { "name": "seld/jsonlint", - "version": "1.7.1", + "version": "1.7.2", "source": { "type": "git", "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "d15f59a67ff805a44c50ea0516d2341740f81a38" + "reference": "e2e5d290e4d2a4f0eb449f510071392e00e10d19" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/d15f59a67ff805a44c50ea0516d2341740f81a38", - "reference": "d15f59a67ff805a44c50ea0516d2341740f81a38", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/e2e5d290e4d2a4f0eb449f510071392e00e10d19", + "reference": "e2e5d290e4d2a4f0eb449f510071392e00e10d19", "shasum": "" }, "require": { @@ -4559,20 +4718,20 @@ "parser", "validator" ], - "time": "2018-01-24T12:46:19+00:00" + "time": "2019-10-24T14:27:39+00:00" }, { "name": "seld/phar-utils", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/Seldaek/phar-utils.git", - "reference": "7009b5139491975ef6486545a39f3e6dad5ac30a" + "reference": "84715761c35808076b00908a20317a3a8a67d17e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/7009b5139491975ef6486545a39f3e6dad5ac30a", - "reference": "7009b5139491975ef6486545a39f3e6dad5ac30a", + "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/84715761c35808076b00908a20317a3a8a67d17e", + "reference": "84715761c35808076b00908a20317a3a8a67d17e", "shasum": "" }, "require": { @@ -4603,20 +4762,20 @@ "keywords": [ "phra" ], - "time": "2015-10-13T18:44:15+00:00" + "time": "2020-01-13T10:41:09+00:00" }, { "name": "symfony/browser-kit", - "version": "v3.4.18", + "version": "v3.4.37", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "f6668d1a6182d5a8dec65a1c863a4c1d963816c0" + "reference": "ede0c5fa204586e3fa51053fbea9cea8a5a3ee8b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/f6668d1a6182d5a8dec65a1c863a4c1d963816c0", - "reference": "f6668d1a6182d5a8dec65a1c863a4c1d963816c0", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/ede0c5fa204586e3fa51053fbea9cea8a5a3ee8b", + "reference": "ede0c5fa204586e3fa51053fbea9cea8a5a3ee8b", "shasum": "" }, "require": { @@ -4660,20 +4819,20 @@ ], "description": "Symfony BrowserKit Component", "homepage": "https://symfony.com", - "time": "2018-07-26T09:06:28+00:00" + "time": "2020-01-01T11:03:25+00:00" }, { "name": "symfony/console", - "version": "v3.4.18", + "version": "v3.4.37", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "1d228fb4602047d7b26a0554e0d3efd567da5803" + "reference": "7c5bdd346f9d90a2d22d4e1fe61e02dc19b98f12" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/1d228fb4602047d7b26a0554e0d3efd567da5803", - "reference": "1d228fb4602047d7b26a0554e0d3efd567da5803", + "url": "https://api.github.com/repos/symfony/console/zipball/7c5bdd346f9d90a2d22d4e1fe61e02dc19b98f12", + "reference": "7c5bdd346f9d90a2d22d4e1fe61e02dc19b98f12", "shasum": "" }, "require": { @@ -4685,6 +4844,9 @@ "symfony/dependency-injection": "<3.4", "symfony/process": "<3.3" }, + "provide": { + "psr/log-implementation": "1.0" + }, "require-dev": { "psr/log": "~1.0", "symfony/config": "~3.3|~4.0", @@ -4694,7 +4856,7 @@ "symfony/process": "~3.3|~4.0" }, "suggest": { - "psr/log-implementation": "For using the console logger", + "psr/log": "For using the console logger", "symfony/event-dispatcher": "", "symfony/lock": "", "symfony/process": "" @@ -4729,20 +4891,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2018-10-30T16:50:50+00:00" + "time": "2020-01-10T07:52:48+00:00" }, { "name": "symfony/css-selector", - "version": "v3.4.18", + "version": "v3.4.37", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "3503415d4aafabc31cd08c3a4ebac7f43fde8feb" + "reference": "e1b3e1a0621d6e48ee46092b4c7d8280f746b3c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/3503415d4aafabc31cd08c3a4ebac7f43fde8feb", - "reference": "3503415d4aafabc31cd08c3a4ebac7f43fde8feb", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/e1b3e1a0621d6e48ee46092b4c7d8280f746b3c5", + "reference": "e1b3e1a0621d6e48ee46092b4c7d8280f746b3c5", "shasum": "" }, "require": { @@ -4767,14 +4929,14 @@ "MIT" ], "authors": [ - { - "name": "Jean-François Simon", - "email": "jeanfrancois.simon@sensiolabs.com" - }, { "name": "Fabien Potencier", "email": "fabien@symfony.com" }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" @@ -4782,20 +4944,20 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "time": "2018-10-02T16:33:53+00:00" + "time": "2020-01-01T11:03:25+00:00" }, { "name": "symfony/debug", - "version": "v3.4.18", + "version": "v3.4.37", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "fe9793af008b651c5441bdeab21ede8172dab097" + "reference": "70dd18e93bb8bdf3c4db7fde832619fef9828cf8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/fe9793af008b651c5441bdeab21ede8172dab097", - "reference": "fe9793af008b651c5441bdeab21ede8172dab097", + "url": "https://api.github.com/repos/symfony/debug/zipball/70dd18e93bb8bdf3c4db7fde832619fef9828cf8", + "reference": "70dd18e93bb8bdf3c4db7fde832619fef9828cf8", "shasum": "" }, "require": { @@ -4838,20 +5000,20 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2018-10-31T09:06:03+00:00" + "time": "2020-01-08T16:36:15+00:00" }, { "name": "symfony/dom-crawler", - "version": "v3.4.18", + "version": "v3.4.37", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "c705bee03ade5b47c087807dd9ffaaec8dda2722" + "reference": "c6fcc96c530ef18dcb4e605e3e9a97c483a160e6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/c705bee03ade5b47c087807dd9ffaaec8dda2722", - "reference": "c705bee03ade5b47c087807dd9ffaaec8dda2722", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/c6fcc96c530ef18dcb4e605e3e9a97c483a160e6", + "reference": "c6fcc96c530ef18dcb4e605e3e9a97c483a160e6", "shasum": "" }, "require": { @@ -4895,20 +5057,20 @@ ], "description": "Symfony DomCrawler Component", "homepage": "https://symfony.com", - "time": "2018-10-02T12:28:39+00:00" + "time": "2020-01-01T11:03:25+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v3.4.18", + "version": "v3.4.37", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "db9e829c8f34c3d35cf37fcd4cdb4293bc4a2f14" + "reference": "79ede8f2836e5ec910ebb325bde40f987244baa8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/db9e829c8f34c3d35cf37fcd4cdb4293bc4a2f14", - "reference": "db9e829c8f34c3d35cf37fcd4cdb4293bc4a2f14", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/79ede8f2836e5ec910ebb325bde40f987244baa8", + "reference": "79ede8f2836e5ec910ebb325bde40f987244baa8", "shasum": "" }, "require": { @@ -4958,20 +5120,20 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2018-10-30T16:50:50+00:00" + "time": "2020-01-04T12:05:51+00:00" }, { "name": "symfony/filesystem", - "version": "v3.4.18", + "version": "v3.4.37", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "d69930fc337d767607267d57c20a7403d0a822a4" + "reference": "0a0d3b4bda11aa3a0464531c40e681e184e75628" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/d69930fc337d767607267d57c20a7403d0a822a4", - "reference": "d69930fc337d767607267d57c20a7403d0a822a4", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/0a0d3b4bda11aa3a0464531c40e681e184e75628", + "reference": "0a0d3b4bda11aa3a0464531c40e681e184e75628", "shasum": "" }, "require": { @@ -5008,20 +5170,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2018-10-02T12:28:39+00:00" + "time": "2020-01-17T08:50:08+00:00" }, { "name": "symfony/finder", - "version": "v3.4.18", + "version": "v3.4.37", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "54ba444dddc5bd5708a34bd095ea67c6eb54644d" + "reference": "a90a9d3b9f458a5cdeabfa4090b20c000ca3962f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/54ba444dddc5bd5708a34bd095ea67c6eb54644d", - "reference": "54ba444dddc5bd5708a34bd095ea67c6eb54644d", + "url": "https://api.github.com/repos/symfony/finder/zipball/a90a9d3b9f458a5cdeabfa4090b20c000ca3962f", + "reference": "a90a9d3b9f458a5cdeabfa4090b20c000ca3962f", "shasum": "" }, "require": { @@ -5057,20 +5219,20 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2018-10-03T08:46:40+00:00" + "time": "2020-01-01T11:03:25+00:00" }, { "name": "symfony/http-foundation", - "version": "v3.4.18", + "version": "v3.4.37", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "5aea7a86ca3203dd7a257e765b4b9c9cfd01c6c0" + "reference": "f3abd07a56111ebe6a1ad6f1cbc23e4f8983f8f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/5aea7a86ca3203dd7a257e765b4b9c9cfd01c6c0", - "reference": "5aea7a86ca3203dd7a257e765b4b9c9cfd01c6c0", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/f3abd07a56111ebe6a1ad6f1cbc23e4f8983f8f5", + "reference": "f3abd07a56111ebe6a1ad6f1cbc23e4f8983f8f5", "shasum": "" }, "require": { @@ -5111,20 +5273,20 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2018-10-31T08:57:11+00:00" + "time": "2020-01-04T12:05:51+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.11.0", + "version": "v1.13.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "82ebae02209c21113908c229e9883c419720738a" + "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/82ebae02209c21113908c229e9883c419720738a", - "reference": "82ebae02209c21113908c229e9883c419720738a", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", + "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", "shasum": "" }, "require": { @@ -5136,7 +5298,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.11-dev" + "dev-master": "1.13-dev" } }, "autoload": { @@ -5152,13 +5314,13 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - }, { "name": "Gert de Pagter", "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony polyfill for ctype functions", @@ -5169,20 +5331,20 @@ "polyfill", "portable" ], - "time": "2019-02-06T07:57:58+00:00" + "time": "2019-11-27T13:56:44+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.10.0", + "version": "v1.13.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "c79c051f5b3a46be09205c73b80b346e4153e494" + "reference": "7b4aab9743c30be783b73de055d24a39cf4b954f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/c79c051f5b3a46be09205c73b80b346e4153e494", - "reference": "c79c051f5b3a46be09205c73b80b346e4153e494", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7b4aab9743c30be783b73de055d24a39cf4b954f", + "reference": "7b4aab9743c30be783b73de055d24a39cf4b954f", "shasum": "" }, "require": { @@ -5194,7 +5356,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.9-dev" + "dev-master": "1.13-dev" } }, "autoload": { @@ -5228,20 +5390,20 @@ "portable", "shim" ], - "time": "2018-09-21T13:07:52+00:00" + "time": "2019-11-27T14:18:11+00:00" }, { "name": "symfony/polyfill-php70", - "version": "v1.10.0", + "version": "v1.13.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php70.git", - "reference": "6b88000cdd431cd2e940caa2cb569201f3f84224" + "reference": "af23c7bb26a73b850840823662dda371484926c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/6b88000cdd431cd2e940caa2cb569201f3f84224", - "reference": "6b88000cdd431cd2e940caa2cb569201f3f84224", + "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/af23c7bb26a73b850840823662dda371484926c4", + "reference": "af23c7bb26a73b850840823662dda371484926c4", "shasum": "" }, "require": { @@ -5251,7 +5413,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.9-dev" + "dev-master": "1.13-dev" } }, "autoload": { @@ -5287,20 +5449,20 @@ "portable", "shim" ], - "time": "2018-09-21T06:26:08+00:00" + "time": "2019-11-27T13:56:44+00:00" }, { "name": "symfony/process", - "version": "v3.4.18", + "version": "v3.4.37", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "35c2914a9f50519bd207164c353ae4d59182c2cb" + "reference": "5b9d2bcffe4678911a4c941c00b7c161252cf09a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/35c2914a9f50519bd207164c353ae4d59182c2cb", - "reference": "35c2914a9f50519bd207164c353ae4d59182c2cb", + "url": "https://api.github.com/repos/symfony/process/zipball/5b9d2bcffe4678911a4c941c00b7c161252cf09a", + "reference": "5b9d2bcffe4678911a4c941c00b7c161252cf09a", "shasum": "" }, "require": { @@ -5336,20 +5498,20 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2018-10-14T17:33:21+00:00" + "time": "2020-01-01T11:03:25+00:00" }, { "name": "symfony/yaml", - "version": "v3.4.28", + "version": "v3.4.37", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "212a27b731e5bfb735679d1ffaac82bd6a1dc996" + "reference": "aa46bc2233097d5212332c907f9911533acfbf80" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/212a27b731e5bfb735679d1ffaac82bd6a1dc996", - "reference": "212a27b731e5bfb735679d1ffaac82bd6a1dc996", + "url": "https://api.github.com/repos/symfony/yaml/zipball/aa46bc2233097d5212332c907f9911533acfbf80", + "reference": "aa46bc2233097d5212332c907f9911533acfbf80", "shasum": "" }, "require": { @@ -5395,20 +5557,20 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2019-03-25T07:48:46+00:00" + "time": "2020-01-13T08:00:59+00:00" }, { "name": "theseer/tokenizer", - "version": "1.1.0", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b" + "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b", - "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9", + "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9", "shasum": "" }, "require": { @@ -5435,24 +5597,25 @@ } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "time": "2017-04-07T12:08:54+00:00" + "time": "2019-06-13T22:48:21+00:00" }, { "name": "vlucas/phpdotenv", - "version": "v2.5.1", + "version": "v2.6.1", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "8abb4f9aa89ddea9d52112c65bbe8d0125e2fa8e" + "reference": "2a7dcf7e3e02dc5e701004e51a6f304b713107d5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/8abb4f9aa89ddea9d52112c65bbe8d0125e2fa8e", - "reference": "8abb4f9aa89ddea9d52112c65bbe8d0125e2fa8e", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/2a7dcf7e3e02dc5e701004e51a6f304b713107d5", + "reference": "2a7dcf7e3e02dc5e701004e51a6f304b713107d5", "shasum": "" }, "require": { - "php": ">=5.3.9" + "php": ">=5.3.9", + "symfony/polyfill-ctype": "^1.9" }, "require-dev": { "phpunit/phpunit": "^4.8.35 || ^5.0" @@ -5460,7 +5623,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.5-dev" + "dev-master": "2.6-dev" } }, "autoload": { @@ -5485,35 +5648,33 @@ "env", "environment" ], - "time": "2018-07-29T20:33:41+00:00" + "time": "2019-01-29T11:11:52+00:00" }, { "name": "webmozart/assert", - "version": "1.3.0", + "version": "1.6.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "0df1908962e7a3071564e857d86874dad1ef204a" + "reference": "573381c0a64f155a0d9a23f4b0c797194805b925" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a", - "reference": "0df1908962e7a3071564e857d86874dad1ef204a", + "url": "https://api.github.com/repos/webmozart/assert/zipball/573381c0a64f155a0d9a23f4b0c797194805b925", + "reference": "573381c0a64f155a0d9a23f4b0c797194805b925", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": "^5.3.3 || ^7.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "vimeo/psalm": "<3.6.0" }, "require-dev": { - "phpunit/phpunit": "^4.6", - "sebastian/version": "^1.0.1" + "phpunit/phpunit": "^4.8.36 || ^7.5.13" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3-dev" - } - }, "autoload": { "psr-4": { "Webmozart\\Assert\\": "src/" @@ -5535,7 +5696,7 @@ "check", "validate" ], - "time": "2018-01-29T19:49:41+00:00" + "time": "2019-11-24T13:36:37+00:00" }, { "name": "weew/helpers-array", @@ -5578,25 +5739,26 @@ "packages-dev": [ { "name": "brainmaestro/composer-git-hooks", - "version": "v2.6.1", + "version": "v2.8.3", "source": { "type": "git", "url": "https://github.com/BrainMaestro/composer-git-hooks.git", - "reference": "137dd2aec2be494918f8bdfb18f57b55ff20015e" + "reference": "97888dd34e900931117747cd34a42fdfcf271142" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/BrainMaestro/composer-git-hooks/zipball/137dd2aec2be494918f8bdfb18f57b55ff20015e", - "reference": "137dd2aec2be494918f8bdfb18f57b55ff20015e", + "url": "https://api.github.com/repos/BrainMaestro/composer-git-hooks/zipball/97888dd34e900931117747cd34a42fdfcf271142", + "reference": "97888dd34e900931117747cd34a42fdfcf271142", "shasum": "" }, "require": { "php": "^5.6 || >=7.0", - "symfony/console": "^3.2 || ^4.0" + "symfony/console": "^3.2 || ^4.0 || ^5.0" }, "require-dev": { + "ext-json": "*", "friendsofphp/php-cs-fixer": "^2.9", - "phpunit/phpunit": "^5.7|^7.0" + "phpunit/phpunit": "^5.7 || ^7.0" }, "bin": [ "cghooks" @@ -5607,10 +5769,11 @@ "pre-commit": "composer check-style", "pre-push": [ "composer test", - "appver=$(grep -o -P '\\d.\\d.\\d' cghooks)", - "tag=$(git tag --sort=-v:refname | head -n 1 | tr -d v)", - "if [ \"$tag\" != \"$appver\" ]; then", - "echo \"The most recent tag v$tag does not match the application version $appver\n\"", + "appver=$(grep -o -E '\\d.\\d.\\d' cghooks)", + "tag=$(git describe --tags --abbrev=0)", + "if [ \"$tag\" != \"v$appver\" ]; then", + "echo \"The most recent tag $tag does not match the application version $appver\\n\"", + "tag=${tag#v}", "sed -i -E \"s/$appver/$tag/\" cghooks", "exit 1", "fi" @@ -5641,28 +5804,29 @@ "composer", "git" ], - "time": "2018-12-28T14:57:06+00:00" + "time": "2019-12-09T09:49:20+00:00" }, { "name": "codacy/coverage", - "version": "1.4.2", + "version": "1.4.3", "source": { "type": "git", "url": "https://github.com/codacy/php-codacy-coverage.git", - "reference": "4988cd098db4d578681bfd3176071931ad475150" + "reference": "1852ca987c91ef466ebcfdbdd4e1788b653eaf1d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/codacy/php-codacy-coverage/zipball/4988cd098db4d578681bfd3176071931ad475150", - "reference": "4988cd098db4d578681bfd3176071931ad475150", + "url": "https://api.github.com/repos/codacy/php-codacy-coverage/zipball/1852ca987c91ef466ebcfdbdd4e1788b653eaf1d", + "reference": "1852ca987c91ef466ebcfdbdd4e1788b653eaf1d", "shasum": "" }, "require": { "gitonomy/gitlib": ">=1.0", "php": ">=5.3.3", - "symfony/console": "~2.5|~3.0|~4.0" + "symfony/console": "~2.5|~3.0|~4.0|~5.0" }, "require-dev": { + "clue/phar-composer": "^1.1", "phpunit/phpunit": "~6.5" }, "bin": [ @@ -5686,7 +5850,7 @@ ], "description": "Sends PHP test coverage information to Codacy.", "homepage": "https://github.com/codacy/php-codacy-coverage", - "time": "2018-03-22T16:43:39+00:00" + "time": "2020-01-10T10:52:12+00:00" }, { "name": "codeception/aspect-mock", @@ -5734,33 +5898,33 @@ }, { "name": "gitonomy/gitlib", - "version": "v1.0.4", + "version": "v1.2.0", "source": { "type": "git", "url": "https://github.com/gitonomy/gitlib.git", - "reference": "932a960221ae3484a3e82553b3be478e56beb68d" + "reference": "a0bea921266ad1c9626d712e7f8687dcc08ca528" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/gitonomy/gitlib/zipball/932a960221ae3484a3e82553b3be478e56beb68d", - "reference": "932a960221ae3484a3e82553b3be478e56beb68d", + "url": "https://api.github.com/repos/gitonomy/gitlib/zipball/a0bea921266ad1c9626d712e7f8687dcc08ca528", + "reference": "a0bea921266ad1c9626d712e7f8687dcc08ca528", "shasum": "" }, "require": { - "php": "^5.3 || ^7.0", - "symfony/process": "^2.3|^3.0|^4.0" + "php": "^5.6 || ^7.0", + "symfony/process": "^3.4|^4.0|^5.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35|^5.7", + "phpunit/phpunit": "^5.7|^6.5|^7.0", "psr/log": "^1.0" }, "suggest": { - "psr/log": "Add some log" + "psr/log": "Required to use loggers for reporting of execution" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.2-dev" } }, "autoload": { @@ -5774,19 +5938,25 @@ ], "authors": [ { - "name": "Alexandre Salomé", - "email": "alexandre.salome@gmail.com", - "homepage": "http://alexandre-salome.fr" + "name": "Graham Campbell", + "email": "graham@alt-three.com" }, { - "name": "Julien DIDIER", - "email": "genzo.wm@gmail.com", - "homepage": "http://www.jdidier.net" + "name": "Julien Didier", + "email": "genzo.wm@gmail.com" + }, + { + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info" + }, + { + "name": "Alexandre Salomé", + "email": "alexandre.salome@gmail.com" } ], "description": "Library for accessing git", "homepage": "http://gitonomy.com", - "time": "2018-04-22T19:55:36+00:00" + "time": "2019-12-08T12:42:25+00:00" }, { "name": "goaop/framework", @@ -6106,32 +6276,39 @@ }, { "name": "pdepend/pdepend", - "version": "2.5.2", + "version": "2.7.0", "source": { "type": "git", "url": "https://github.com/pdepend/pdepend.git", - "reference": "9daf26d0368d4a12bed1cacae1a9f3a6f0adf239" + "reference": "cba74e118ce806f97fcb108c00d61ebf2a5a936e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pdepend/pdepend/zipball/9daf26d0368d4a12bed1cacae1a9f3a6f0adf239", - "reference": "9daf26d0368d4a12bed1cacae1a9f3a6f0adf239", + "url": "https://api.github.com/repos/pdepend/pdepend/zipball/cba74e118ce806f97fcb108c00d61ebf2a5a936e", + "reference": "cba74e118ce806f97fcb108c00d61ebf2a5a936e", "shasum": "" }, "require": { "php": ">=5.3.7", - "symfony/config": "^2.3.0|^3|^4", - "symfony/dependency-injection": "^2.3.0|^3|^4", - "symfony/filesystem": "^2.3.0|^3|^4" + "symfony/config": "^2.3.0|^3|^4|^5", + "symfony/dependency-injection": "^2.3.0|^3|^4|^5", + "symfony/filesystem": "^2.3.0|^3|^4|^5" }, "require-dev": { - "phpunit/phpunit": "^4.8|^5.7", + "easy-doc/easy-doc": "0.0.0 || ^1.2.3", + "gregwar/rst": "^1.0", + "phpunit/phpunit": "^4.8.35|^5.7", "squizlabs/php_codesniffer": "^2.0.0" }, "bin": [ "src/bin/pdepend" ], "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, "autoload": { "psr-4": { "PDepend\\": "src/main/php/PDepend" @@ -6142,7 +6319,7 @@ "BSD-3-Clause" ], "description": "Official version of pdepend to be handled with Composer", - "time": "2017-12-13T13:21:38+00:00" + "time": "2020-01-24T08:09:26+00:00" }, { "name": "php-coveralls/php-coveralls", @@ -6207,31 +6384,35 @@ }, { "name": "phpmd/phpmd", - "version": "2.6.0", + "version": "2.8.1", "source": { "type": "git", "url": "https://github.com/phpmd/phpmd.git", - "reference": "4e9924b2c157a3eb64395460fcf56b31badc8374" + "reference": "5664b95d484797582f5af9536238deb9ecde58a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpmd/phpmd/zipball/4e9924b2c157a3eb64395460fcf56b31badc8374", - "reference": "4e9924b2c157a3eb64395460fcf56b31badc8374", + "url": "https://api.github.com/repos/phpmd/phpmd/zipball/5664b95d484797582f5af9536238deb9ecde58a1", + "reference": "5664b95d484797582f5af9536238deb9ecde58a1", "shasum": "" }, "require": { + "composer/xdebug-handler": "^1.0", "ext-xml": "*", - "pdepend/pdepend": "^2.5", + "pdepend/pdepend": "^2.6", "php": ">=5.3.9" }, "require-dev": { - "phpunit/phpunit": "^4.0", + "easy-doc/easy-doc": "0.0.0 || ^1.3.2", + "gregwar/rst": "^1.0", + "mikey179/vfsstream": "^1.6.4", + "phpunit/phpunit": "^4.8.36 || ^5.7.27", "squizlabs/php_codesniffer": "^2.0" }, "bin": [ "src/bin/phpmd" ], - "type": "project", + "type": "library", "autoload": { "psr-0": { "PHPMD\\": "src/main/php" @@ -6248,20 +6429,20 @@ "homepage": "https://github.com/manuelpichler", "role": "Project Founder" }, - { - "name": "Other contributors", - "homepage": "https://github.com/phpmd/phpmd/graphs/contributors", - "role": "Contributors" - }, { "name": "Marc Würth", "email": "ravage@bluewin.ch", "homepage": "https://github.com/ravage84", "role": "Project Maintainer" + }, + { + "name": "Other contributors", + "homepage": "https://github.com/phpmd/phpmd/graphs/contributors", + "role": "Contributors" } ], "description": "PHPMD is a spin-off project of PHP Depend and aims to be a PHP equivalent of the well known Java tool PMD.", - "homepage": "http://phpmd.org/", + "homepage": "https://phpmd.org/", "keywords": [ "mess detection", "mess detector", @@ -6269,7 +6450,7 @@ "phpmd", "pmd" ], - "time": "2017-01-20T14:41:10+00:00" + "time": "2019-12-27T11:09:06+00:00" }, { "name": "rregeer/phpunit-coverage-check", @@ -6404,16 +6585,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.3.2", + "version": "3.5.4", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "6ad28354c04b364c3c71a34e4a18b629cc3b231e" + "reference": "dceec07328401de6211037abbb18bda423677e26" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/6ad28354c04b364c3c71a34e4a18b629cc3b231e", - "reference": "6ad28354c04b364c3c71a34e4a18b629cc3b231e", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/dceec07328401de6211037abbb18bda423677e26", + "reference": "dceec07328401de6211037abbb18bda423677e26", "shasum": "" }, "require": { @@ -6446,25 +6627,25 @@ } ], "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "http://www.squizlabs.com/php-codesniffer", + "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", "keywords": [ "phpcs", "standards" ], - "time": "2018-09-23T23:08:17+00:00" + "time": "2020-01-30T22:20:29+00:00" }, { "name": "symfony/config", - "version": "v3.4.18", + "version": "v3.4.37", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "99b2fa8acc244e656cdf324ff419fbe6fd300a4d" + "reference": "6abc18b2a97f63508d23929bbb2ae65aaa07bace" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/99b2fa8acc244e656cdf324ff419fbe6fd300a4d", - "reference": "99b2fa8acc244e656cdf324ff419fbe6fd300a4d", + "url": "https://api.github.com/repos/symfony/config/zipball/6abc18b2a97f63508d23929bbb2ae65aaa07bace", + "reference": "6abc18b2a97f63508d23929bbb2ae65aaa07bace", "shasum": "" }, "require": { @@ -6515,20 +6696,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2018-10-31T09:06:03+00:00" + "time": "2020-01-04T12:05:51+00:00" }, { "name": "symfony/dependency-injection", - "version": "v3.4.18", + "version": "v3.4.37", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "9c98452ac7fff4b538956775630bc9701f5384ba" + "reference": "22000f10c9e1cfef051e8b4de46815b41a0223fc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/9c98452ac7fff4b538956775630bc9701f5384ba", - "reference": "9c98452ac7fff4b538956775630bc9701f5384ba", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/22000f10c9e1cfef051e8b4de46815b41a0223fc", + "reference": "22000f10c9e1cfef051e8b4de46815b41a0223fc", "shasum": "" }, "require": { @@ -6586,20 +6767,20 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2018-10-31T10:49:51+00:00" + "time": "2020-01-08T11:20:51+00:00" }, { "name": "symfony/stopwatch", - "version": "v3.4.18", + "version": "v3.4.37", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "05e52a39de52ba690aebaed462b2bc8a9649f0a4" + "reference": "e2d954156d4817c9a5c79f519a71516693a4a9c8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/05e52a39de52ba690aebaed462b2bc8a9649f0a4", - "reference": "05e52a39de52ba690aebaed462b2bc8a9649f0a4", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/e2d954156d4817c9a5c79f519a71516693a4a9c8", + "reference": "e2d954156d4817c9a5c79f519a71516693a4a9c8", "shasum": "" }, "require": { @@ -6635,7 +6816,7 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", - "time": "2018-10-02T12:28:39+00:00" + "time": "2020-01-01T11:03:25+00:00" }, { "name": "theseer/fdomdocument", diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Util/OperationElementExtractor.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Util/OperationElementExtractor.php index c86e27972..ed23307c9 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Util/OperationElementExtractor.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Util/OperationElementExtractor.php @@ -113,9 +113,9 @@ private function extractOperationArray(&$operationArrayData, $operationArrayArra { foreach ($operationArrayArray as $operationFieldType) { $operationElementValue = []; - if (isset($operationFieldType[OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY_VALUE])) { - foreach ($operationFieldType[OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY_VALUE] as - $operationFieldValue) { + $entityValueKey = OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY_VALUE; + if (isset($operationFieldType[$entityValueKey])) { + foreach ($operationFieldType[$entityValueKey] as $operationFieldValue) { $operationElementValue[] = $operationFieldValue[OperationElementExtractor::OPERATION_OBJECT_ARRAY_VALUE] ?? null; } From 3609f4fa57c6e9a2ee7c3d3b7c0f02e9becd8262 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Wed, 5 Feb 2020 09:53:02 -0600 Subject: [PATCH 199/888] MQE-1969: Updated CHANGELOG.md and bumped MFTF package version --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fe6bd9822..98db600cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ Magento Functional Testing Framework Changelog 2.6.0 ----- +* Usability + * `magentoCron` action added by community maintainer @lbajsarowicz * Traceability * MFTF generated cest files are fully compatible for Codeception `dry-run`. * Modularity @@ -23,6 +25,7 @@ Magento Functional Testing Framework Changelog * Customizability * AWS Secrets Manager has been added as an additional credential storage. * See DevDocs for details +* Bumped dependencies to latest possible versions ### Fixes * Fixed missing before, after, failed steps in cest file when generating tests with `--allow-skipped` option. From c67ffdd9f238706a17ee0f4bd3ed7f0688b2cf47 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 6 Feb 2020 16:11:29 -0600 Subject: [PATCH 200/888] MQE-1986: Mark `executeInSelenium` and `performOn` as deprecated in MFTF --- docs/test/actions.md | 4 ++ .../Console/BaseGenerateCommand.php | 41 +++++++++++++++++++ .../Console/GenerateSuiteCommand.php | 3 ++ .../Console/GenerateTestsCommand.php | 3 ++ .../Console/RunTestCommand.php | 3 ++ .../Console/RunTestFailedCommand.php | 3 ++ .../Console/RunTestGroupCommand.php | 3 ++ .../Util/TestGenerator.php | 14 +++++++ 8 files changed, 74 insertions(+) diff --git a/docs/test/actions.md b/docs/test/actions.md index 59fd12aa2..b3aec7204 100644 --- a/docs/test/actions.md +++ b/docs/test/actions.md @@ -973,6 +973,8 @@ Attribute|Type|Use|Description ### executeInSelenium +#### NOTE: `executeInSelenium` action is DEPRECATED and will be removed in MFTF 3.0.0. + See [executeInSelenium docs on codeception.com](http://codeception.com/docs/modules/WebDriver#executeInSelenium). Attribute|Type|Use|Description @@ -1460,6 +1462,8 @@ Attribute|Type|Use|Description ### performOn +#### NOTE: `performOn` action is DEPRECATED and will be removed in MFTF 3.0.0. + See [performOn docs on codeception.com](http://codeception.com/docs/modules/WebDriver#performOn). Attribute|Type|Use|Description diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index a0d94b16e..c33b956fb 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -12,15 +12,27 @@ use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Magento\FunctionalTestingFramework\Util\Filesystem\DirSetupUtil; use Magento\FunctionalTestingFramework\Util\TestGenerator; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\Suite\Handlers\SuiteObjectHandler; +use Symfony\Component\Console\Style\SymfonyStyle; class BaseGenerateCommand extends Command { + const MFTF_3_O_0_DEPRECATION_MESSAGE = "MFTF NOTICES:\n" + . "\"executeInSelenium\" and \"performOn\" actions are DEPRECATED and will be removed in MFTF 3.0.0\n"; + + /** + * Console output style + * + * @var SymfonyStyle + */ + private $ioStyle = null; + /** * Configures the base command. * @@ -178,4 +190,33 @@ protected function getGroupAndSuiteConfiguration(array $groupOrSuiteNames) $json = json_encode($result); return $json; } + + /** + * Set Symfony Style for output + * + * @param InputInterface $input + * @param OutputInterface $output + */ + protected function setOutputStyle(InputInterface $input, OutputInterface $output) + { + // For output style + if (null === $this->ioStyle) { + $this->ioStyle = new SymfonyStyle($input, $output); + } + } + + /** + * Show predefined global notice messages + * + * @param OutputInterface $output + * @return void + */ + protected function showMftfNotices(OutputInterface $output) + { + if (null !== $this->ioStyle) { + $this->ioStyle->note(self::MFTF_3_O_0_DEPRECATION_MESSAGE); + } else { + $output->writeln(self::MFTF_3_O_0_DEPRECATION_MESSAGE); + } + } } diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php index 8da3493aa..2c91aa7f7 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php @@ -58,6 +58,9 @@ protected function execute(InputInterface $input, OutputInterface $output) $allowSkipped ); + $this->setOutputStyle($input, $output); + $this->showMftfNotices($output); + // Remove previous GENERATED_DIR if --remove option is used if ($remove) { $this->removeGeneratedDirectory($output, $output->isVerbose()); diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php index 621f29d03..b9378edc1 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php @@ -82,6 +82,9 @@ protected function execute(InputInterface $input, OutputInterface $output) $allowSkipped ); + $this->setOutputStyle($input, $output); + $this->showMftfNotices($output); + if (!empty($tests)) { $json = $this->getTestAndSuiteConfiguration($tests); } diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php index 373256cfc..08b84d6a1 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php @@ -84,6 +84,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int $allowSkipped ); + $this->setOutputStyle($input, $output); + $this->showMftfNotices($output); + $testConfiguration = $this->getTestAndSuiteConfiguration($tests); if (!$skipGeneration) { diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php index 5f0596a7f..1909c7e0b 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php @@ -96,6 +96,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int $allowSkipped ); + $this->setOutputStyle($input, $output); + $this->showMftfNotices($output); + $testConfiguration = $this->getFailedTestList(); if ($testConfiguration === null) { diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php index 6ea37785d..be6236c73 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php @@ -79,6 +79,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int $allowSkipped ); + $this->setOutputStyle($input, $output); + $this->showMftfNotices($output); + if (!$skipGeneration) { $testConfiguration = $this->getGroupAndSuiteConfiguration($groups); $command = $this->getApplication()->find('generate:tests'); diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index e40f60dcf..527ed7323 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -59,6 +59,8 @@ class TestGenerator const ARRAY_WRAP_OPEN = '['; const ARRAY_WRAP_CLOSE = ']'; + const MFTF_3_O_0_DEPRECATION_MESSAGE = ' is DEPRECATED and will be removed in MFTF 3.0.0.'; + /** * Actor name for AcceptanceTest * @@ -1041,6 +1043,8 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato ); break; case "executeInSelenium": + $this->deprecationMessages[] = "DEPRECATED ACTION in Test: at step {$stepKey} \"executeInSelenium\"" + . self::MFTF_3_O_0_DEPRECATION_MESSAGE; $testSteps .= $this->wrapFunctionCall($actor, $actionObject, $function); break; case "executeJS": @@ -1052,6 +1056,16 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato ); break; case "performOn": + $this->deprecationMessages[] = "DEPRECATED ACTION in Test: at step {$stepKey} \"performOn\"" + . self::MFTF_3_O_0_DEPRECATION_MESSAGE; + $testSteps .= $this->wrapFunctionCall( + $actor, + $actionObject, + $selector, + $function, + $time + ); + break; case "waitForElementChange": $testSteps .= $this->wrapFunctionCall( $actor, From 165ed37bb4e02f4e8b5f993db99056926afdc017 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 6 Feb 2020 16:29:01 -0600 Subject: [PATCH 201/888] MQE-1989: added deprecation notices for upcoming MFTF 3.0.0 changes. --- .../Console/BaseGenerateCommand.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index c33b956fb..889f631cc 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -24,7 +24,10 @@ class BaseGenerateCommand extends Command { const MFTF_3_O_0_DEPRECATION_MESSAGE = "MFTF NOTICES:\n" - . "\"executeInSelenium\" and \"performOn\" actions are DEPRECATED and will be removed in MFTF 3.0.0\n"; + . "DEPRECATED ACTIONS: \"executeInSelenium\" and \"performOn\" actions will be removed in MFTF 3.0.0\n" + . "DEPRECATED TEST PATH: \"dev/tests/acceptance/tests/functional/Magento/FunctionalTest will not be read" + . " in MFTF 3.0.0 and after\n" + . "Single entity per xml file for all entities except data and metadata in MFTF 3.0.0 and after\n"; /** * Console output style From efe681606adae0b93be8051f57f78bc55f58bd92 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 6 Feb 2020 16:36:32 -0600 Subject: [PATCH 202/888] MQE-1992: Add new environment variable ELASTICSEARCH_VERSION and set default value to 7 --- etc/config/.env.example | 2 ++ 1 file changed, 2 insertions(+) diff --git a/etc/config/.env.example b/etc/config/.env.example index f5b6ef40e..349d7da9c 100644 --- a/etc/config/.env.example +++ b/etc/config/.env.example @@ -63,4 +63,6 @@ MODULE_WHITELIST=Magento_Framework,ConfigurableProductWishlist,ConfigurableProdu #ENABLE_BROWSER_LOG=true #BROWSER_LOG_BLACKLIST=other +#*** Elastic Search version used for test ***# +ELASTICSEARCH_VERSION=7 #*** End of .env ***# From db705788997330a43e5eb3f4b5c008f53029ec05 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 6 Feb 2020 17:09:51 -0600 Subject: [PATCH 203/888] MQE-1986: Mark `executeInSelenium` and `performOn` as deprecated in MFTF --- dev/tests/verification/Resources/BasicFunctionalTest.txt | 2 +- dev/tests/verification/Resources/ExecuteInSeleniumTest.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/tests/verification/Resources/BasicFunctionalTest.txt b/dev/tests/verification/Resources/BasicFunctionalTest.txt index ac42f395e..e76e409d0 100644 --- a/dev/tests/verification/Resources/BasicFunctionalTest.txt +++ b/dev/tests/verification/Resources/BasicFunctionalTest.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: A Functional Cest") * @group functional - * @Description("<h3>Test files</h3>verification/TestModule/Test/BasicFunctionalTest.xml<br>") + * @Description("<h3 class='y-label y-label_status_broken'>Deprecated Notice(s):</h3><ul><li>DEPRECATED ACTION in Test: at step performOnKey1 "performOn" is DEPRECATED and will be removed in MFTF 3.0.0.</li></ul><h3>Test files</h3>verification/TestModule/Test/BasicFunctionalTest.xml<br>") */ class BasicFunctionalTestCest { diff --git a/dev/tests/verification/Resources/ExecuteInSeleniumTest.txt b/dev/tests/verification/Resources/ExecuteInSeleniumTest.txt index bbed61691..48b818200 100644 --- a/dev/tests/verification/Resources/ExecuteInSeleniumTest.txt +++ b/dev/tests/verification/Resources/ExecuteInSeleniumTest.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<h3>Test files</h3>verification/TestModule/Test/ExecuteInSeleniumTest.xml<br>") + * @Description("<h3 class='y-label y-label_status_broken'>Deprecated Notice(s):</h3><ul><li>DEPRECATED ACTION in Test: at step executeInSeleniumStep "executeInSelenium" is DEPRECATED and will be removed in MFTF 3.0.0.</li></ul><h3>Test files</h3>verification/TestModule/Test/ExecuteInSeleniumTest.xml<br>") */ class ExecuteInSeleniumTestCest { From 93654b8f69f3964b3f8fdd1dc14a5624a071f4d0 Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Fri, 7 Feb 2020 11:51:23 -0600 Subject: [PATCH 204/888] Updated example code --- docs/test/actions.md | 45 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/docs/test/actions.md b/docs/test/actions.md index 59fd12aa2..6ec519b0f 100644 --- a/docs/test/actions.md +++ b/docs/test/actions.md @@ -22,13 +22,13 @@ This step can be referenced within the test using `conditionalClickStep1`. The value format should met the following principles: -* Must be unique within [`<test>`](../test.md#test-tag). -* Naming should be as descriptive as possible: - * Describe the action performed. - * Briefly describe the purpose. - * Describe which data is in use. -* Should be in camelCase with lowercase first letter. -* Should be the last attribute of an element. +* Must be unique within [`<test>`](../test.md#test-tag). +* Naming should be as descriptive as possible: + * Describe the action performed. + * Briefly describe the purpose. + * Describe which data is in use. +* Should be in camelCase with lowercase first letter. +* Should be the last attribute of an element. ### `before` and `after` @@ -142,14 +142,14 @@ Here, [`<click>`](#click) performs a click on a button that can be found by the The following test actions return a variable: -* [grabAttributeFrom](#grabattributefrom) -* [grabCookie](#grabcookie) -* [grabFromCurrentUrl](#grabfromcurrenturl) -* [grabMultiple](#grabmultiple) -* [grabPageSource](#grabpagesource) -* [grabTextFrom](#grabtextfrom) -* [grabValueFrom](#grabvaluefrom) -* [executeJS](#executejs) +* [grabAttributeFrom](#grabattributefrom) +* [grabCookie](#grabcookie) +* [grabFromCurrentUrl](#grabfromcurrenturl) +* [grabMultiple](#grabmultiple) +* [grabPageSource](#grabpagesource) +* [grabTextFrom](#grabtextfrom) +* [grabValueFrom](#grabvaluefrom) +* [executeJS](#executejs) Learn more in [Using data returned by test actions](../data.md#use-data-returned-by-test-actions). @@ -157,10 +157,10 @@ Learn more in [Using data returned by test actions](../data.md#use-data-returned The following test actions handle data entities using [metadata](../metadata.md): -* [createData](#createdata) -* [deleteData](#deletedata) -* [updateData](#updatedata) -* [getData](#getdata) +* [createData](#createdata) +* [deleteData](#deletedata) +* [updateData](#updatedata) +* [getData](#getdata) Learn more in [Handling a REST API response](../metadata.md#rest-response). @@ -1287,7 +1287,6 @@ Attribute|Type|Use|Description `before`|string|optional| `stepKey` of action that must be executed next. `after`|string|optional| `stepKey` of preceding action. - #### Example ```xml <magentoCron stepKey="runStagingCronJobs" groups="staging"/> @@ -1974,13 +1973,13 @@ Attribute|Type|Use|Description #### Examples ```xml -<!-- Verify there are 10 `<div id="product" ... >...</div>` elements on the page. --> +<!-- Verify there are 10 `<div class="product" ... >...</div>` elements on the page. --> <seeNumberOfElements userInput="10" selector="div.product" stepKey="seeTenProducts"/> ``` ```xml -<!-- Verify there are between 5 and 10 `<div id="product" ... >...</div>` elements on the page. --> -<seeNumberOfElements userInput="[5, 10]" selector=".product" stepKey="seeFiveToTenProducts"/> +<!-- Verify there are between 5 and 10 `<div class="product" ... >...</div>` elements on the page. --> +<seeNumberOfElements parameterArray="[5, 10]" selector="div.product" stepKey="seeFiveToTenProducts"/> ``` ### seeOptionIsSelected From 4f6812dc453b520d2ace615e339cfb0b2a06b38c Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Thu, 6 Feb 2020 13:11:17 -0600 Subject: [PATCH 205/888] MQE-1961: Remove deprecated actions executeInSelenium performOn + fixed verification tests --- .../Resources/BasicFunctionalTest.txt | 1 - .../Resources/ExecuteInSeleniumTest.txt | 31 ------------------ .../ActionGroup/XmlDuplicateActionGroup.xml | 4 --- .../TestModule/Test/BasicFunctionalTest.xml | 1 - .../TestModule/Test/ExecuteInSeleniumTest.xml | 14 -------- .../TestModule/Test/XmlDuplicateTest.xml | 12 ------- .../Tests/ExecuteInSeleniumTest.php | 22 ------------- docs/test/actions.md | 32 +------------------ etc/di.xml | 2 +- .../Test/Objects/ActionObject.php | 2 +- .../Test/etc/actionTypeTags.xsd | 31 ------------------ .../Util/TestGenerator.php | 9 +----- 12 files changed, 4 insertions(+), 157 deletions(-) delete mode 100644 dev/tests/verification/Resources/ExecuteInSeleniumTest.txt delete mode 100644 dev/tests/verification/TestModule/Test/ExecuteInSeleniumTest.xml delete mode 100644 dev/tests/verification/Tests/ExecuteInSeleniumTest.php diff --git a/dev/tests/verification/Resources/BasicFunctionalTest.txt b/dev/tests/verification/Resources/BasicFunctionalTest.txt index ac42f395e..42fd5ff56 100644 --- a/dev/tests/verification/Resources/BasicFunctionalTest.txt +++ b/dev/tests/verification/Resources/BasicFunctionalTest.txt @@ -139,7 +139,6 @@ class BasicFunctionalTestCest $I->moveMouseOver(".functionalTestSelector"); // stepKey: moveMouseOverKey1 $I->openNewTab(); // stepKey: openNewTabKey1 $I->pauseExecution(); // stepKey: pauseExecutionKey1 - $I->performOn("#selector", function(\WebDriverElement $el) {return $el->isDisplayed();}, 10); // stepKey: performOnKey1 $I->pressKey("#page", "a"); // stepKey: pressKey1 $I->pressKey("#page", ['ctrl', 'a'],'new'); // stepKey: pressKey2 $I->pressKey("#page", ['shift', '111'],'1','x'); // stepKey: pressKey3 diff --git a/dev/tests/verification/Resources/ExecuteInSeleniumTest.txt b/dev/tests/verification/Resources/ExecuteInSeleniumTest.txt deleted file mode 100644 index bbed61691..000000000 --- a/dev/tests/verification/Resources/ExecuteInSeleniumTest.txt +++ /dev/null @@ -1,31 +0,0 @@ -<?php -namespace Magento\AcceptanceTest\_default\Backend; - -use Magento\FunctionalTestingFramework\AcceptanceTester; -use \Codeception\Util\Locator; -use Yandex\Allure\Adapter\Annotation\Features; -use Yandex\Allure\Adapter\Annotation\Stories; -use Yandex\Allure\Adapter\Annotation\Title; -use Yandex\Allure\Adapter\Annotation\Description; -use Yandex\Allure\Adapter\Annotation\Parameter; -use Yandex\Allure\Adapter\Annotation\Severity; -use Yandex\Allure\Adapter\Model\SeverityLevel; -use Yandex\Allure\Adapter\Annotation\TestCaseId; - -/** - * @Description("<h3>Test files</h3>verification/TestModule/Test/ExecuteInSeleniumTest.xml<br>") - */ -class ExecuteInSeleniumTestCest -{ - /** - * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") - * @param AcceptanceTester $I - * @return void - * @throws \Exception - */ - public function ExecuteInSeleniumTest(AcceptanceTester $I) - { - $I->executeInSelenium(function ($webdriver) { return "Hello, World!"}); // stepKey: executeInSeleniumStep - } -} diff --git a/dev/tests/verification/TestModule/ActionGroup/XmlDuplicateActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/XmlDuplicateActionGroup.xml index fcc22acca..af35b0134 100644 --- a/dev/tests/verification/TestModule/ActionGroup/XmlDuplicateActionGroup.xml +++ b/dev/tests/verification/TestModule/ActionGroup/XmlDuplicateActionGroup.xml @@ -78,8 +78,6 @@ <doubleClick selector="1" stepKey="dblclick2"/> <dragAndDrop selector1="1" selector2="2" stepKey="dragndrop1"/> <dragAndDrop selector1="1" selector2="2" stepKey="dragndrop2"/> - <executeInSelenium function="1" stepKey="executeSelenium1"/> - <executeInSelenium function="1" stepKey="executeSelenium2"/> <executeJS function="1" stepKey="execJS1"/> <executeJS function="1" stepKey="execJS2"/> <fillField stepKey="fill1"/> @@ -126,8 +124,6 @@ <parseFloat stepKey="parsefloat12"/> <pauseExecution stepKey="pause1"/> <pauseExecution stepKey="pause12"/> - <performOn selector="1" function="1" stepKey="performon1"/> - <performOn selector="1" function="1" stepKey="performon12"/> <pressKey selector="1" stepKey="press1"/> <pressKey selector="1" stepKey="press12"/> <reloadPage stepKey="reload1"/> diff --git a/dev/tests/verification/TestModule/Test/BasicFunctionalTest.xml b/dev/tests/verification/TestModule/Test/BasicFunctionalTest.xml index 1ef25b43d..fdc415501 100644 --- a/dev/tests/verification/TestModule/Test/BasicFunctionalTest.xml +++ b/dev/tests/verification/TestModule/Test/BasicFunctionalTest.xml @@ -89,7 +89,6 @@ <moveMouseOver selector=".functionalTestSelector" stepKey="moveMouseOverKey1"/> <openNewTab stepKey="openNewTabKey1"/> <pauseExecution stepKey="pauseExecutionKey1"/> - <performOn selector="#selector" function="function(\WebDriverElement $el) {return $el->isDisplayed();}" stepKey="performOnKey1"/> <pressKey selector="#page" userInput="a" stepKey="pressKey1"/> <pressKey selector="#page" parameterArray="[['ctrl','a'],'new']" stepKey="pressKey2"/> <pressKey selector="#page" parameterArray="[['shift','111'],'1','x']" stepKey="pressKey3"/> diff --git a/dev/tests/verification/TestModule/Test/ExecuteInSeleniumTest.xml b/dev/tests/verification/TestModule/Test/ExecuteInSeleniumTest.xml deleted file mode 100644 index c25164220..000000000 --- a/dev/tests/verification/TestModule/Test/ExecuteInSeleniumTest.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - <test name="ExecuteInSeleniumTest"> - <executeInSelenium function="function ($webdriver) { return "Hello, World!"}" stepKey="executeInSeleniumStep"/> - </test> -</tests> diff --git a/dev/tests/verification/TestModule/Test/XmlDuplicateTest.xml b/dev/tests/verification/TestModule/Test/XmlDuplicateTest.xml index 937c6edba..d8c2fca66 100644 --- a/dev/tests/verification/TestModule/Test/XmlDuplicateTest.xml +++ b/dev/tests/verification/TestModule/Test/XmlDuplicateTest.xml @@ -82,8 +82,6 @@ <doubleClick selector="1" stepKey="dblclick2"/> <dragAndDrop selector1="1" selector2="2" stepKey="dragndrop1"/> <dragAndDrop selector1="1" selector2="2" stepKey="dragndrop2"/> - <executeInSelenium function="1" stepKey="executeSelenium1"/> - <executeInSelenium function="1" stepKey="executeSelenium2"/> <executeJS function="1" stepKey="execJS1"/> <executeJS function="1" stepKey="execJS2"/> <fillField stepKey="fill1"/> @@ -130,8 +128,6 @@ <parseFloat stepKey="parsefloat12"/> <pauseExecution stepKey="pause1"/> <pauseExecution stepKey="pause12"/> - <performOn selector="1" function="1" stepKey="performon1"/> - <performOn selector="1" function="1" stepKey="performon12"/> <pressKey selector="1" stepKey="press1"/> <pressKey selector="1" stepKey="press12"/> <reloadPage stepKey="reload1"/> @@ -298,8 +294,6 @@ <doubleClick selector="1" stepKey="dblclick2"/> <dragAndDrop selector1="1" selector2="2" stepKey="dragndrop1"/> <dragAndDrop selector1="1" selector2="2" stepKey="dragndrop2"/> - <executeInSelenium function="1" stepKey="executeSelenium1"/> - <executeInSelenium function="1" stepKey="executeSelenium2"/> <executeJS function="1" stepKey="execJS1"/> <executeJS function="1" stepKey="execJS2"/> <fillField stepKey="fill1"/> @@ -346,8 +340,6 @@ <parseFloat stepKey="parsefloat12"/> <pauseExecution stepKey="pause1"/> <pauseExecution stepKey="pause12"/> - <performOn selector="1" function="1" stepKey="performon1"/> - <performOn selector="1" function="1" stepKey="performon12"/> <pressKey selector="1" stepKey="press1"/> <pressKey selector="1" stepKey="press12"/> <reloadPage stepKey="reload1"/> @@ -513,8 +505,6 @@ <doubleClick selector="1" stepKey="dblclick2"/> <dragAndDrop selector1="1" selector2="2" stepKey="dragndrop1"/> <dragAndDrop selector1="1" selector2="2" stepKey="dragndrop2"/> - <executeInSelenium function="1" stepKey="executeSelenium1"/> - <executeInSelenium function="1" stepKey="executeSelenium2"/> <executeJS function="1" stepKey="execJS1"/> <executeJS function="1" stepKey="execJS2"/> <fillField stepKey="fill1"/> @@ -561,8 +551,6 @@ <parseFloat stepKey="parsefloat12"/> <pauseExecution stepKey="pause1"/> <pauseExecution stepKey="pause12"/> - <performOn selector="1" function="1" stepKey="performon1"/> - <performOn selector="1" function="1" stepKey="performon12"/> <pressKey selector="1" stepKey="press1"/> <pressKey selector="1" stepKey="press12"/> <reloadPage stepKey="reload1"/> diff --git a/dev/tests/verification/Tests/ExecuteInSeleniumTest.php b/dev/tests/verification/Tests/ExecuteInSeleniumTest.php deleted file mode 100644 index 36532b362..000000000 --- a/dev/tests/verification/Tests/ExecuteInSeleniumTest.php +++ /dev/null @@ -1,22 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace tests\verification\Tests; - -use tests\util\MftfTestCase; - -class ExecuteInSeleniumTest extends MftfTestCase -{ - /** - * Tests generation of executeInSelenium action. - * - * @throws \Exception - * @throws \Magento\FunctionalTestingFramework\Exceptions\TestReferenceException - */ - public function testExecuteInSeleniumTest() - { - $this->generateAndCompareTest('ExecuteInSeleniumTest'); - } -} diff --git a/docs/test/actions.md b/docs/test/actions.md index 59fd12aa2..eefd84bb5 100644 --- a/docs/test/actions.md +++ b/docs/test/actions.md @@ -971,24 +971,6 @@ Attribute|Type|Use|Description <dragAndDrop selector1="#block1" selector2="#block2" x="50" y="50" stepKey="dragAndDrop"/> ``` -### executeInSelenium - -See [executeInSelenium docs on codeception.com](http://codeception.com/docs/modules/WebDriver#executeInSelenium). - -Attribute|Type|Use|Description ----|---|---|--- -`function`|string|optional| Name of Selenium function to run. -`stepKey`|string|required| A unique identifier of the action. -`before`|string|optional| `stepKey` of action that must be executed next. -`after`|string|optional| `stepKey` of preceding action. - -#### Example - -```xml -<!-- Execute the Selenium function `function(\Facebook\WebDriver\Remote\RemoteWebDriver $webdriver) {$webdriver->get('http://google.com');}`. --> -<executeInSelenium function="function(\Facebook\WebDriver\Remote\RemoteWebDriver $webdriver) {$webdriver->get('http://google.com');}" stepKey="executeInSelenium"/> -``` - ### executeJS See [executeJS docs on codeception.com](http://codeception.com/docs/modules/WebDriver#executeJS). @@ -1458,18 +1440,6 @@ Attribute|Type|Use|Description <pauseExecution stepKey="pause"/> ``` -### performOn - -See [performOn docs on codeception.com](http://codeception.com/docs/modules/WebDriver#performOn). - -Attribute|Type|Use|Description ----|---|---|--- -`selector`|string|optional| The selector identifying the corresponding HTML element. -`function`|string|optional| Function or actions to be taken on the selected element. -`stepKey`|string|required| A unique identifier of the action. -`before`|string|optional| `stepKey` of action that must be executed next. -`after`|string|optional| `stepKey` of preceding action. - ### pressKey See [pressKey docs on codeception.com](http://codeception.com/docs/modules/WebDriver#pressKey). @@ -1484,7 +1454,7 @@ Attribute|Type|Use|Description `after`|string|optional| `stepKey` of preceding action. #### Examples - +F ```xml <!-- Press the `a` key within the selected area. --> <pressKey userInput="a" selector="#targetElement" stepKey="pressA"/> diff --git a/etc/di.xml b/etc/di.xml index e5e31cf87..aec5e872c 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -8,7 +8,7 @@ <!-- Entity value gets replaced in Dom.php before reading $xml --> <!DOCTYPE config [ - <!ENTITY commonTestActions "acceptPopup|actionGroup|amOnPage|amOnUrl|amOnSubdomain|appendField|assertArrayIsSorted|assertArraySubset|assertElementContainsAttribute|attachFile|cancelPopup|checkOption|clearField|click|clickWithLeftButton|clickWithRightButton|closeAdminNotification|closeTab|comment|conditionalClick|createData|deleteData|updateData|getData|dontSee|dontSeeJsError|dontSeeCheckboxIsChecked|dontSeeCookie|dontSeeCurrentUrlEquals|dontSeeCurrentUrlMatches|dontSeeElement|dontSeeElementInDOM|dontSeeInCurrentUrl|dontSeeInField|dontSeeInFormFields|dontSeeInPageSource|dontSeeInSource|dontSeeInTitle|dontSeeLink|dontSeeOptionIsSelected|doubleClick|dragAndDrop|entity|executeJS|executeInSelenium|fillField|formatMoney|generateDate|grabAttributeFrom|grabCookie|grabFromCurrentUrl|grabMultiple|grabPageSource|grabTextFrom|grabValueFrom|loadSessionSnapshot|loginAsAdmin|magentoCLI|magentoCron|makeScreenshot|maximizeWindow|moveBack|moveForward|moveMouseOver|mSetLocale|mResetLocale|openNewTab|pauseExecution|parseFloat|performOn|pressKey|reloadPage|resetCookie|submitForm|resizeWindow|saveSessionSnapshot|scrollTo|scrollToTopOfPage|searchAndMultiSelectOption|see|seeCheckboxIsChecked|seeCookie|seeCurrentUrlEquals|seeCurrentUrlMatches|seeElement|seeElementInDOM|seeInCurrentUrl|seeInField|seeInFormFields|seeInPageSource|seeInPopup|seeInSource|seeInTitle|seeLink|seeNumberOfElements|seeOptionIsSelected|selectOption|setCookie|submitForm|switchToIFrame|switchToNextTab|switchToPreviousTab|switchToWindow|typeInPopup|uncheckOption|unselectOption|wait|waitForAjaxLoad|waitForElement|waitForElementChange|waitForElementNotVisible|waitForElementVisible|waitForPwaElementNotVisible|waitForPwaElementVisible|waitForJS|waitForLoadingMaskToDisappear|waitForPageLoad|waitForText|assertArrayHasKey|assertArrayNotHasKey|assertArraySubset|assertContains|assertCount|assertEmpty|assertEquals|assertFalse|assertFileExists|assertFileNotExists|assertGreaterOrEquals|assertGreaterThan|assertGreaterThanOrEqual|assertInstanceOf|assertInternalType|assertIsEmpty|assertLessOrEquals|assertLessThan|assertLessThanOrEqual|assertNotContains|assertNotEmpty|assertNotEquals|assertNotInstanceOf|assertNotNull|assertNotRegExp|assertNotSame|assertNull|assertRegExp|assertSame|assertStringStartsNotWith|assertStringStartsWith|assertTrue|expectException|fail|dontSeeFullUrlEquals|dontSee|dontSeeFullUrlMatches|dontSeeInFullUrl|seeFullUrlEquals|seeFullUrlMatches|seeInFullUrl|grabFromFullUrl"> + <!ENTITY commonTestActions "acceptPopup|actionGroup|amOnPage|amOnUrl|amOnSubdomain|appendField|assertArrayIsSorted|assertArraySubset|assertElementContainsAttribute|attachFile|cancelPopup|checkOption|clearField|click|clickWithLeftButton|clickWithRightButton|closeAdminNotification|closeTab|comment|conditionalClick|createData|deleteData|updateData|getData|dontSee|dontSeeJsError|dontSeeCheckboxIsChecked|dontSeeCookie|dontSeeCurrentUrlEquals|dontSeeCurrentUrlMatches|dontSeeElement|dontSeeElementInDOM|dontSeeInCurrentUrl|dontSeeInField|dontSeeInFormFields|dontSeeInPageSource|dontSeeInSource|dontSeeInTitle|dontSeeLink|dontSeeOptionIsSelected|doubleClick|dragAndDrop|entity|executeJS|fillField|formatMoney|generateDate|grabAttributeFrom|grabCookie|grabFromCurrentUrl|grabMultiple|grabPageSource|grabTextFrom|grabValueFrom|loadSessionSnapshot|loginAsAdmin|magentoCLI|magentoCron|makeScreenshot|maximizeWindow|moveBack|moveForward|moveMouseOver|mSetLocale|mResetLocale|openNewTab|pauseExecution|parseFloat|pressKey|reloadPage|resetCookie|submitForm|resizeWindow|saveSessionSnapshot|scrollTo|scrollToTopOfPage|searchAndMultiSelectOption|see|seeCheckboxIsChecked|seeCookie|seeCurrentUrlEquals|seeCurrentUrlMatches|seeElement|seeElementInDOM|seeInCurrentUrl|seeInField|seeInFormFields|seeInPageSource|seeInPopup|seeInSource|seeInTitle|seeLink|seeNumberOfElements|seeOptionIsSelected|selectOption|setCookie|submitForm|switchToIFrame|switchToNextTab|switchToPreviousTab|switchToWindow|typeInPopup|uncheckOption|unselectOption|wait|waitForAjaxLoad|waitForElement|waitForElementChange|waitForElementNotVisible|waitForElementVisible|waitForPwaElementNotVisible|waitForPwaElementVisible|waitForJS|waitForLoadingMaskToDisappear|waitForPageLoad|waitForText|assertArrayHasKey|assertArrayNotHasKey|assertArraySubset|assertContains|assertCount|assertEmpty|assertEquals|assertFalse|assertFileExists|assertFileNotExists|assertGreaterOrEquals|assertGreaterThan|assertGreaterThanOrEqual|assertInstanceOf|assertInternalType|assertIsEmpty|assertLessOrEquals|assertLessThan|assertLessThanOrEqual|assertNotContains|assertNotEmpty|assertNotEquals|assertNotInstanceOf|assertNotNull|assertNotRegExp|assertNotSame|assertNull|assertRegExp|assertSame|assertStringStartsNotWith|assertStringStartsWith|assertTrue|expectException|fail|dontSeeFullUrlEquals|dontSee|dontSeeFullUrlMatches|dontSeeInFullUrl|seeFullUrlEquals|seeFullUrlMatches|seeInFullUrl|grabFromFullUrl"> ]> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../src/Magento/FunctionalTestingFramework/ObjectManager/etc/config.xsd"> diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php index 45b5db69d..f377e2fac 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php @@ -62,7 +62,7 @@ class ActionObject const ASSERTION_VALUE_ATTRIBUTE = "value"; const DELETE_DATA_MUTUAL_EXCLUSIVE_ATTRIBUTES = ["url", "createDataKey"]; const EXTERNAL_URL_AREA_INVALID_ACTIONS = ['amOnPage']; - const FUNCTION_CLOSURE_ACTIONS = ['waitForElementChange', 'performOn', 'executeInSelenium']; + const FUNCTION_CLOSURE_ACTIONS = ['waitForElementChange']; const COMMAND_ACTION_ATTRIBUTES = ['magentoCLI', 'magentoCLISecret']; const MERGE_ACTION_ORDER_AFTER = 'after'; const MERGE_ACTION_ORDER_BEFORE = 'before'; diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/actionTypeTags.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/actionTypeTags.xsd index 9aa772858..7bcdbdf50 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/actionTypeTags.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/actionTypeTags.xsd @@ -34,7 +34,6 @@ <xs:element type="closeTabType" name="closeTab" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="commentType" name="comment" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="dragAndDropType" name="dragAndDrop" minOccurs="0" maxOccurs="unbounded"/> - <xs:element type="executeInSeleniumType" name="executeInSelenium" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="executeJSType" name="executeJS" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="fillFieldType" name="fillField" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="loadSessionSnapshotType" name="loadSessionSnapshot" minOccurs="0" maxOccurs="unbounded"/> @@ -45,7 +44,6 @@ <xs:element type="moveMouseOverType" name="moveMouseOver" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="openNewTabType" name="openNewTab" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="pauseExecutionType" name="pauseExecution" minOccurs="0" maxOccurs="unbounded"/> - <xs:element type="performOnType" name="performOn" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="pressKeyType" name="pressKey" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="reloadPageType" name="reloadPage" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="resetCookieType" name="resetCookie" minOccurs="0" maxOccurs="unbounded"/> @@ -290,20 +288,6 @@ </xs:simpleContent> </xs:complexType> - <xs:complexType name="executeInSeleniumType"> - <xs:annotation> - <xs:documentation> - Allows you to use Selenium WebDriver methods directly; last resort method, do not use regularly. - </xs:documentation> - </xs:annotation> - <xs:simpleContent> - <xs:extension base="xs:string"> - <xs:attribute ref="function" use="required"/> - <xs:attributeGroup ref="commonActionAttributes"/> - </xs:extension> - </xs:simpleContent> - </xs:complexType> - <xs:complexType name="executeJSType"> <xs:annotation> <xs:documentation> @@ -444,21 +428,6 @@ </xs:simpleContent> </xs:complexType> - <xs:complexType name="performOnType"> - <xs:annotation> - <xs:documentation> - Performs given function on element. - </xs:documentation> - </xs:annotation> - <xs:simpleContent> - <xs:extension base="xs:string"> - <xs:attribute ref="selector" use="required"/> - <xs:attribute ref="function" use="required"/> - <xs:attributeGroup ref="commonActionAttributes"/> - </xs:extension> - </xs:simpleContent> - </xs:complexType> - <xs:complexType name="pressKeyType"> <xs:annotation> <xs:documentation> diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index e40f60dcf..24bf90a19 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -711,10 +711,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato } if (isset($customActionAttributes['function'])) { - $function = $this->addUniquenessFunctionCall( - $customActionAttributes['function'], - $actionObject->getType() !== "executeInSelenium" - ); + $function = $this->addUniquenessFunctionCall($customActionAttributes['function']); if (in_array($actionObject->getType(), ActionObject::FUNCTION_CLOSURE_ACTIONS)) { // Argument must be a closure function, not a string. $function = trim($function, '"'); @@ -1040,9 +1037,6 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $parameterArray ); break; - case "executeInSelenium": - $testSteps .= $this->wrapFunctionCall($actor, $actionObject, $function); - break; case "executeJS": $testSteps .= $this->wrapFunctionCallWithReturnValue( $stepKey, @@ -1051,7 +1045,6 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $function ); break; - case "performOn": case "waitForElementChange": $testSteps .= $this->wrapFunctionCall( $actor, From 5c3ef3648a68f297d23d9e156a94fa4ca9da00aa Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Fri, 7 Feb 2020 12:10:21 -0600 Subject: [PATCH 206/888] MQE-1961: Remove deprecated actions fixed typo --- docs/test/actions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/test/actions.md b/docs/test/actions.md index eefd84bb5..3c7c89ab3 100644 --- a/docs/test/actions.md +++ b/docs/test/actions.md @@ -1454,7 +1454,7 @@ Attribute|Type|Use|Description `after`|string|optional| `stepKey` of preceding action. #### Examples -F + ```xml <!-- Press the `a` key within the selected area. --> <pressKey userInput="a" selector="#targetElement" stepKey="pressA"/> From a6a50c8a1669705f42af84f3345cb6a72d2081aa Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 10 Feb 2020 14:33:22 -0600 Subject: [PATCH 207/888] MQE-1962: Remove support of deprecated locations for tests --- docs/mftf-tests-packaging.md | 58 +++++++++++++++++++ docs/mftf-tests.md | 3 +- .../Util/ModuleResolver.php | 25 +------- 3 files changed, 60 insertions(+), 26 deletions(-) create mode 100644 docs/mftf-tests-packaging.md diff --git a/docs/mftf-tests-packaging.md b/docs/mftf-tests-packaging.md new file mode 100644 index 000000000..07e13718b --- /dev/null +++ b/docs/mftf-tests-packaging.md @@ -0,0 +1,58 @@ +<style> +.mftf-dl { + margin-bottom: 2.5em; +} +dl dt{ + font-weight:400; +} +</style> + +# MFTF functional test modules and packaging + +## MFTF predefined test module paths +The Magento Functional Testing Framework can run tests from predefined paths and custom paths. The predefined paths are: +``` +app/code/<Vendor>/<Module>/Test/Mftf +dev/tests/acceptance/tests/functional/<Vendor>/<TestModule> +vendor/<Vendor>/<Module>/Test/Mftf +vendor/<Vendor>/<TestModule> +``` + +To support future service isolation, Test module in `dev/tests/acceptance/tests/functional/<Vendor>/<TestModule>` and +`vendor/<Vendor>/<TestModule>` must define the module type as `magento2-functional-test-module` in a `composer.json` file. +No `composer.json` file is required for tests in `app/code/<Vendor>/<Module>/Test/Mftf` and `vendor/<Vendor>/<Module>/Test/Mftf` +as they are part of the Magento modules. + +Test module for a specific Magento module can only be in one of the path. + +## Test module composer.json format + +Test module `composer.json` file should use type `magento2-functional-test-module`. + +Test module `composer.json` file should define Magento module dependencies in suggests block. +MFTF will recognize the dependency if the suggest message of a module specifies `type` using `magento2-module` and `name` +using module name registered with Magento. + +Here is an example `composer.json` file for the test module `dev/tests/acceptance/tests/functional/Magento/ConfigurableProductCatalogSearch`: + +```json +{ + "name": "magento/module-configurable-product-catalog-search-functional-test", + "description": "MFTF test module for Magento_ConfigurableProduct and Magento_CatalogSearch", + "type": "magento2-functional-test-module", + "config": { + "sort-packages": true + }, + "require": { + "magento/magento2-functional-testing-framework": ">=2.5" + }, + "suggest": { + "magento/module-configurable-product": "type: magento2-module, name: Magento_ConfigurableProduct, version: *", + "magento/module-catalog-search": "type: magento2-module, name: Magento_CatalogSearch, version: *" + }, + "license": [ + "OSL-3.0", + "AFL-3.0" + ] +} +``` \ No newline at end of file diff --git a/docs/mftf-tests.md b/docs/mftf-tests.md index cb1941053..8554396bf 100644 --- a/docs/mftf-tests.md +++ b/docs/mftf-tests.md @@ -9,8 +9,7 @@ dl dt{ # MFTF functional test reference -The Magento Functional Testing Framework runs tests on every Module within Magento. These files are stored within each Module folder in the Magento repo. -This page lists all those tests so that developers can have a good sense of what is covered. +This page lists all existing tests so that developers can have a good sense of what is covered. {% include mftf/functional_data.md %} diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index aa9a08ddb..d5e90841d 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -54,12 +54,6 @@ class ModuleResolver . 'tests' . DIRECTORY_SEPARATOR . 'functional'; - const DEPRECATED_DEV_TESTS = DIRECTORY_SEPARATOR - . self:: DEV_TESTS - . DIRECTORY_SEPARATOR - . "Magento" - . DIRECTORY_SEPARATOR - . "FunctionalTest"; /** * Enabled modules. @@ -327,8 +321,7 @@ private function aggregateTestModulePaths() $codePathsToPattern = [ $modulePath => '', $magentoBaseCodePath . $vendorCodePath => self::TEST_MFTF_PATTERN, - $magentoBaseCodePath . $appCodePath => self::TEST_MFTF_PATTERN, - $magentoBaseCodePath . self::DEPRECATED_DEV_TESTS => '' + $magentoBaseCodePath . $appCodePath => self::TEST_MFTF_PATTERN ]; foreach ($codePathsToPattern as $codePath => $pattern) { @@ -374,22 +367,6 @@ private function globRelevantPaths($testPath, $pattern) } } - /* TODO uncomment this to show deprecation warning when we ready to fully deliver test packaging feature - if (strpos($testPath, self::DEPRECATED_DEV_TESTS) !== false && !empty($modulePaths)) { - $deprecatedPath = ltrim(self::DEPRECATED_DEV_TESTS, DIRECTORY_SEPARATOR); - $suggestedPath = self::DEV_TESTS . DIRECTORY_SEPARATOR . 'Magento'; - $message = "DEPRECATION: Found MFTF test modules in the deprecated path: $deprecatedPath." - . " Move these test modules to $suggestedPath."; - - if (MftfApplicationConfig::getConfig()->verboseEnabled()) { - LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->warning($message); - } - // Suppress print during unit testing - if (MftfApplicationConfig::getConfig()->getPhase() !== MftfApplicationConfig::UNIT_TEST_PHASE) { - print ("\n$message\n\n"); - } - } - */ return $modulePaths; } From 196498dd499d4ec260fc4aeca66decca1f55eed2 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 10 Feb 2020 14:55:23 -0600 Subject: [PATCH 208/888] MQE-1962: Remove support of deprecated locations for tests --- .../Util/ModuleResolverTest.php | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php index 07e1ee7fa..ad0b1769d 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php @@ -146,20 +146,6 @@ function ($arg) { 'Test' . DIRECTORY_SEPARATOR .'Mftf' ] ); - $mockResolver->verifyInvoked( - 'globRelevantPaths', - [ - $magentoBaseCodePath - . DIRECTORY_SEPARATOR . "dev" - . DIRECTORY_SEPARATOR . "tests" - . DIRECTORY_SEPARATOR . "acceptance" - . DIRECTORY_SEPARATOR . "tests" - . DIRECTORY_SEPARATOR . "functional" - . DIRECTORY_SEPARATOR . "Magento" - . DIRECTORY_SEPARATOR . "FunctionalTest" - , '' - ] - ); } /** From ae0450392ece3e5b7e6f7cd64904ff508b5efa3a Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 11 Feb 2020 10:00:21 -0600 Subject: [PATCH 209/888] MQE-1989: added deprecation notices for upcoming MFTF 3.0.0 changes. --- .../Console/BaseGenerateCommand.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index 889f631cc..3433f23a8 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -25,9 +25,10 @@ class BaseGenerateCommand extends Command { const MFTF_3_O_0_DEPRECATION_MESSAGE = "MFTF NOTICES:\n" . "DEPRECATED ACTIONS: \"executeInSelenium\" and \"performOn\" actions will be removed in MFTF 3.0.0\n" - . "DEPRECATED TEST PATH: \"dev/tests/acceptance/tests/functional/Magento/FunctionalTest will not be read" - . " in MFTF 3.0.0 and after\n" - . "Single entity per xml file for all entities except data and metadata in MFTF 3.0.0 and after\n"; + . "DEPRECATED TEST PATH: support for \"dev/tests/acceptance/tests/functional/Magento/FunctionalTest will be " + . "removed in MFTF 3.0.0\n" + . "XSD schema change to only allow single entity per xml file for all entities except data and metadata in " + . "MFTF 3.0.0\n"; /** * Console output style From f5739a7253c7d91ddd70b697aa787dfc8b62f9d0 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Mon, 10 Feb 2020 12:21:50 -0600 Subject: [PATCH 210/888] MQE-1988: MFTF failures after PHP upgrade (libzip5 v1.60+) moved facebook/webdriver to replace added php-webdriver/webdriver --- composer.json | 6 ++- composer.lock | 133 ++++++++++++++++++++++++++------------------------ 2 files changed, 74 insertions(+), 65 deletions(-) diff --git a/composer.json b/composer.json index e6d081114..3c2fefd7a 100755 --- a/composer.json +++ b/composer.json @@ -25,7 +25,8 @@ "monolog/monolog": "^1.0", "mustache/mustache": "~2.5", "symfony/process": "^2.8 || ^3.1 || ^4.0", - "vlucas/phpdotenv": "^2.4" + "vlucas/phpdotenv": "^2.4", + "php-webdriver/webdriver": "1.8.x-dev" }, "require-dev": { "squizlabs/php_codesniffer": "~3.2", @@ -44,6 +45,9 @@ "suggest": { "epfremme/swagger-php": "^2.0" }, + "replace": { + "facebook/webdriver": "1.7.1" + }, "autoload": { "files": ["src/Magento/FunctionalTestingFramework/_bootstrap.php"], "psr-4": { diff --git a/composer.lock b/composer.lock index ac510665e..db629bea4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "859ddf6506836faaabb056ae7b377c63", + "content-hash": "480a0e5b9ab3d1248398361c90a5e246", "packages": [ { "name": "allure-framework/allure-codeception", @@ -366,7 +366,6 @@ "codeception/stub": "^2.0", "ext-json": "*", "ext-mbstring": "*", - "facebook/webdriver": ">=1.1.3 <2.0", "guzzlehttp/guzzle": ">=4.1.4 <7.0", "guzzlehttp/psr7": "~1.0", "php": ">=5.6.0 <8.0", @@ -1837,67 +1836,6 @@ ], "time": "2019-06-08T11:03:04+00:00" }, - { - "name": "facebook/webdriver", - "version": "1.7.1", - "source": { - "type": "git", - "url": "https://github.com/facebook/php-webdriver.git", - "reference": "e43de70f3c7166169d0f14a374505392734160e5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/e43de70f3c7166169d0f14a374505392734160e5", - "reference": "e43de70f3c7166169d0f14a374505392734160e5", - "shasum": "" - }, - "require": { - "ext-curl": "*", - "ext-json": "*", - "ext-mbstring": "*", - "ext-zip": "*", - "php": "^5.6 || ~7.0", - "symfony/process": "^2.8 || ^3.1 || ^4.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^2.0", - "jakub-onderka/php-parallel-lint": "^0.9.2", - "php-coveralls/php-coveralls": "^2.0", - "php-mock/php-mock-phpunit": "^1.1", - "phpunit/phpunit": "^5.7", - "sebastian/environment": "^1.3.4 || ^2.0 || ^3.0", - "squizlabs/php_codesniffer": "^2.6", - "symfony/var-dumper": "^3.3 || ^4.0" - }, - "suggest": { - "ext-SimpleXML": "For Firefox profile creation" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-community": "1.5-dev" - } - }, - "autoload": { - "psr-4": { - "Facebook\\WebDriver\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "description": "A PHP client for Selenium WebDriver", - "homepage": "https://github.com/facebook/php-webdriver", - "keywords": [ - "facebook", - "php", - "selenium", - "webdriver" - ], - "abandoned": "php-webdriver/webdriver", - "time": "2019-06-13T08:02:18+00:00" - }, { "name": "flow/jsonpath", "version": "0.5.0", @@ -3035,6 +2973,71 @@ "description": "Library for handling version information and constraints", "time": "2017-03-05T17:38:23+00:00" }, + { + "name": "php-webdriver/webdriver", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/php-webdriver/php-webdriver.git", + "reference": "3e33ee3b8a688d719c55acdd7c6788e3006e1d3e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/3e33ee3b8a688d719c55acdd7c6788e3006e1d3e", + "reference": "3e33ee3b8a688d719c55acdd7c6788e3006e1d3e", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "ext-zip": "*", + "php": "^5.6 || ~7.0", + "symfony/polyfill-mbstring": "^1.12", + "symfony/process": "^2.8 || ^3.1 || ^4.0 || ^5.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.0", + "jakub-onderka/php-parallel-lint": "^1.0", + "php-coveralls/php-coveralls": "^2.0", + "php-mock/php-mock-phpunit": "^1.1", + "phpunit/phpunit": "^5.7", + "sebastian/environment": "^1.3.4 || ^2.0 || ^3.0", + "sminnee/phpunit-mock-objects": "^3.4", + "squizlabs/php_codesniffer": "^3.5", + "symfony/var-dumper": "^3.3 || ^4.0 || ^5.0" + }, + "suggest": { + "ext-SimpleXML": "For Firefox profile creation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8.x-dev" + } + }, + "autoload": { + "files": [ + "lib/Exception/TimeoutException.php" + ], + "psr-4": { + "Facebook\\WebDriver\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A PHP client for Selenium WebDriver. Previously facebook/webdriver.", + "homepage": "https://github.com/php-webdriver/php-webdriver", + "keywords": [ + "Chromedriver", + "geckodriver", + "php", + "selenium", + "webdriver" + ], + "time": "2020-02-10T15:04:25+00:00" + }, { "name": "phpcollection/phpcollection", "version": "0.5.0", @@ -6861,7 +6864,9 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "php-webdriver/webdriver": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { From 3497e7dd643d329c5fbe0a9dfef4b4392d67e4fe Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Mon, 10 Feb 2020 15:45:02 -0600 Subject: [PATCH 211/888] MQE-1988: MFTF failures after PHP upgrade (libzip5 v1.60+) moved facebook/webdriver to replace added php-webdriver/webdriver --- composer.json | 2 +- composer.lock | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/composer.json b/composer.json index 3c2fefd7a..2e2b89877 100755 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ "mustache/mustache": "~2.5", "symfony/process": "^2.8 || ^3.1 || ^4.0", "vlucas/phpdotenv": "^2.4", - "php-webdriver/webdriver": "1.8.x-dev" + "php-webdriver/webdriver": "1.8.0" }, "require-dev": { "squizlabs/php_codesniffer": "~3.2", diff --git a/composer.lock b/composer.lock index db629bea4..975d034eb 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "480a0e5b9ab3d1248398361c90a5e246", + "content-hash": "b96147186af064985bb758d6f51bd01d", "packages": [ { "name": "allure-framework/allure-codeception", @@ -2975,7 +2975,7 @@ }, { "name": "php-webdriver/webdriver", - "version": "dev-master", + "version": "1.8.0", "source": { "type": "git", "url": "https://github.com/php-webdriver/php-webdriver.git", @@ -6864,9 +6864,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "php-webdriver/webdriver": 20 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { From e69feab8c97716c87cb6d7f923b34323d8f962df Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Tue, 11 Feb 2020 09:53:44 -0600 Subject: [PATCH 212/888] MQE-1988: MFTF failures after PHP upgrade (libzip5 v1.60+) Added Caret Version Range --- composer.json | 4 ++-- composer.lock | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 2e2b89877..a63184c18 100755 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ "mustache/mustache": "~2.5", "symfony/process": "^2.8 || ^3.1 || ^4.0", "vlucas/phpdotenv": "^2.4", - "php-webdriver/webdriver": "1.8.0" + "php-webdriver/webdriver": "^1.8.0" }, "require-dev": { "squizlabs/php_codesniffer": "~3.2", @@ -46,7 +46,7 @@ "epfremme/swagger-php": "^2.0" }, "replace": { - "facebook/webdriver": "1.7.1" + "facebook/webdriver": "^1.7.1" }, "autoload": { "files": ["src/Magento/FunctionalTestingFramework/_bootstrap.php"], diff --git a/composer.lock b/composer.lock index 975d034eb..fc8de5fce 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b96147186af064985bb758d6f51bd01d", + "content-hash": "02905fa699b13ced15ff44439441c96c", "packages": [ { "name": "allure-framework/allure-codeception", @@ -366,6 +366,7 @@ "codeception/stub": "^2.0", "ext-json": "*", "ext-mbstring": "*", + "facebook/webdriver": ">=1.1.3 <2.0", "guzzlehttp/guzzle": ">=4.1.4 <7.0", "guzzlehttp/psr7": "~1.0", "php": ">=5.6.0 <8.0", From 81f826abfd82b5c4aa13c9d76cf68ffa45c6661d Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Tue, 11 Feb 2020 12:10:49 -0600 Subject: [PATCH 213/888] MQE-1988: MFTF failures after PHP upgrade (libzip5 v1.60+) Version bump + changelog for 2.6.1 --- CHANGELOG.md | 9 +++++++++ composer.json | 2 +- composer.lock | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98db600cc..339e82ed8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,15 @@ Magento Functional Testing Framework Changelog ================================================ +2.6.1 +----- + +* Usability + * Introduced new `.env` configuration `ELASTICSEARCH_VERSION` to support multiple elasticsearch versions +* Maintainability + * Added deprecation notices for upcoming MFTF 3.0.0 +* Replaced facebook webdriver with php-webdriver to support PHP version updates + 2.6.0 ----- diff --git a/composer.json b/composer.json index a63184c18..9a806e35c 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "2.6.0", + "version": "2.6.1", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index fc8de5fce..c493c4d77 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "02905fa699b13ced15ff44439441c96c", + "content-hash": "c79110e707cbbf2553f19b50052949e6", "packages": [ { "name": "allure-framework/allure-codeception", From 29711af1512cc07a1e5f22cddb19f2e20c08675c Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 11 Feb 2020 16:00:00 -0600 Subject: [PATCH 214/888] MQE-1989: added deprecation notices for upcoming MFTF 3.0.0 changes. --- dev/tests/verification/Resources/BasicFunctionalTest.txt | 2 +- dev/tests/verification/Resources/ExecuteInSeleniumTest.txt | 2 +- src/Magento/FunctionalTestingFramework/Util/TestGenerator.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dev/tests/verification/Resources/BasicFunctionalTest.txt b/dev/tests/verification/Resources/BasicFunctionalTest.txt index e76e409d0..d9ef5cac6 100644 --- a/dev/tests/verification/Resources/BasicFunctionalTest.txt +++ b/dev/tests/verification/Resources/BasicFunctionalTest.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: A Functional Cest") * @group functional - * @Description("<h3 class='y-label y-label_status_broken'>Deprecated Notice(s):</h3><ul><li>DEPRECATED ACTION in Test: at step performOnKey1 "performOn" is DEPRECATED and will be removed in MFTF 3.0.0.</li></ul><h3>Test files</h3>verification/TestModule/Test/BasicFunctionalTest.xml<br>") + * @Description("<h3 class='y-label y-label_status_broken'>Deprecated Notice(s):</h3><ul><li>DEPRECATED ACTION in Test: at step performOnKey1 performOn is DEPRECATED and will be removed in MFTF 3.0.0.</li></ul><h3>Test files</h3>verification/TestModule/Test/BasicFunctionalTest.xml<br>") */ class BasicFunctionalTestCest { diff --git a/dev/tests/verification/Resources/ExecuteInSeleniumTest.txt b/dev/tests/verification/Resources/ExecuteInSeleniumTest.txt index 48b818200..9728059c2 100644 --- a/dev/tests/verification/Resources/ExecuteInSeleniumTest.txt +++ b/dev/tests/verification/Resources/ExecuteInSeleniumTest.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<h3 class='y-label y-label_status_broken'>Deprecated Notice(s):</h3><ul><li>DEPRECATED ACTION in Test: at step executeInSeleniumStep "executeInSelenium" is DEPRECATED and will be removed in MFTF 3.0.0.</li></ul><h3>Test files</h3>verification/TestModule/Test/ExecuteInSeleniumTest.xml<br>") + * @Description("<h3 class='y-label y-label_status_broken'>Deprecated Notice(s):</h3><ul><li>DEPRECATED ACTION in Test: at step executeInSeleniumStep executeInSelenium is DEPRECATED and will be removed in MFTF 3.0.0.</li></ul><h3>Test files</h3>verification/TestModule/Test/ExecuteInSeleniumTest.xml<br>") */ class ExecuteInSeleniumTestCest { diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 527ed7323..97add6c67 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1043,7 +1043,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato ); break; case "executeInSelenium": - $this->deprecationMessages[] = "DEPRECATED ACTION in Test: at step {$stepKey} \"executeInSelenium\"" + $this->deprecationMessages[] = "DEPRECATED ACTION in Test: at step {$stepKey} executeInSelenium" . self::MFTF_3_O_0_DEPRECATION_MESSAGE; $testSteps .= $this->wrapFunctionCall($actor, $actionObject, $function); break; @@ -1056,7 +1056,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato ); break; case "performOn": - $this->deprecationMessages[] = "DEPRECATED ACTION in Test: at step {$stepKey} \"performOn\"" + $this->deprecationMessages[] = "DEPRECATED ACTION in Test: at step {$stepKey} performOn" . self::MFTF_3_O_0_DEPRECATION_MESSAGE; $testSteps .= $this->wrapFunctionCall( $actor, From b48fbe5d226102d6fcea73db70f6ce21298801d8 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Tue, 11 Feb 2020 16:14:52 -0600 Subject: [PATCH 215/888] Update deprecation message --- src/Magento/FunctionalTestingFramework/Util/TestGenerator.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 97add6c67..dda1dbd9f 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1043,7 +1043,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato ); break; case "executeInSelenium": - $this->deprecationMessages[] = "DEPRECATED ACTION in Test: at step {$stepKey} executeInSelenium" + $this->deprecationMessages[] = "DEPRECATED ACTION in Test: at step {$stepKey} 'executeInSelenium'" . self::MFTF_3_O_0_DEPRECATION_MESSAGE; $testSteps .= $this->wrapFunctionCall($actor, $actionObject, $function); break; @@ -1056,7 +1056,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato ); break; case "performOn": - $this->deprecationMessages[] = "DEPRECATED ACTION in Test: at step {$stepKey} performOn" + $this->deprecationMessages[] = "DEPRECATED ACTION in Test: at step {$stepKey} 'performOn'" . self::MFTF_3_O_0_DEPRECATION_MESSAGE; $testSteps .= $this->wrapFunctionCall( $actor, From 5895be1cfb31fdbe55b26ea33e57472916d52cfd Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Tue, 11 Feb 2020 16:15:45 -0600 Subject: [PATCH 216/888] Update verification test --- dev/tests/verification/Resources/BasicFunctionalTest.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/verification/Resources/BasicFunctionalTest.txt b/dev/tests/verification/Resources/BasicFunctionalTest.txt index d9ef5cac6..072b58261 100644 --- a/dev/tests/verification/Resources/BasicFunctionalTest.txt +++ b/dev/tests/verification/Resources/BasicFunctionalTest.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: A Functional Cest") * @group functional - * @Description("<h3 class='y-label y-label_status_broken'>Deprecated Notice(s):</h3><ul><li>DEPRECATED ACTION in Test: at step performOnKey1 performOn is DEPRECATED and will be removed in MFTF 3.0.0.</li></ul><h3>Test files</h3>verification/TestModule/Test/BasicFunctionalTest.xml<br>") + * @Description("<h3 class='y-label y-label_status_broken'>Deprecated Notice(s):</h3><ul><li>DEPRECATED ACTION in Test: at step performOnKey1 'performOn' is DEPRECATED and will be removed in MFTF 3.0.0.</li></ul><h3>Test files</h3>verification/TestModule/Test/BasicFunctionalTest.xml<br>") */ class BasicFunctionalTestCest { From 748449dbece5b19788bef2d4442a5a68abae01e2 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Tue, 11 Feb 2020 16:16:10 -0600 Subject: [PATCH 217/888] Update verification test --- dev/tests/verification/Resources/ExecuteInSeleniumTest.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/verification/Resources/ExecuteInSeleniumTest.txt b/dev/tests/verification/Resources/ExecuteInSeleniumTest.txt index 9728059c2..5afd1a6ea 100644 --- a/dev/tests/verification/Resources/ExecuteInSeleniumTest.txt +++ b/dev/tests/verification/Resources/ExecuteInSeleniumTest.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<h3 class='y-label y-label_status_broken'>Deprecated Notice(s):</h3><ul><li>DEPRECATED ACTION in Test: at step executeInSeleniumStep executeInSelenium is DEPRECATED and will be removed in MFTF 3.0.0.</li></ul><h3>Test files</h3>verification/TestModule/Test/ExecuteInSeleniumTest.xml<br>") + * @Description("<h3 class='y-label y-label_status_broken'>Deprecated Notice(s):</h3><ul><li>DEPRECATED ACTION in Test: at step executeInSeleniumStep 'executeInSelenium' is DEPRECATED and will be removed in MFTF 3.0.0.</li></ul><h3>Test files</h3>verification/TestModule/Test/ExecuteInSeleniumTest.xml<br>") */ class ExecuteInSeleniumTestCest { From b13a8b700dfcd3b31fe46f083028ead675891bae Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 12 Feb 2020 16:07:25 -0600 Subject: [PATCH 218/888] MQE-1962: Remove support of deprecated locations for tests --- src/Magento/FunctionalTestingFramework/_bootstrap.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/_bootstrap.php b/src/Magento/FunctionalTestingFramework/_bootstrap.php index a5ce1f931..214f6a34b 100644 --- a/src/Magento/FunctionalTestingFramework/_bootstrap.php +++ b/src/Magento/FunctionalTestingFramework/_bootstrap.php @@ -66,7 +66,7 @@ // define TEST_PATH and TEST_MODULE_PATH defined('TESTS_BP') || define('TESTS_BP', realpath(MAGENTO_BP . DIRECTORY_SEPARATOR . 'dev/tests/acceptance')); -$RELATIVE_TESTS_MODULE_PATH = '/tests/functional/Magento/FunctionalTest'; +$RELATIVE_TESTS_MODULE_PATH = '/tests/functional/Magento'; defined('TESTS_MODULE_PATH') || define( 'TESTS_MODULE_PATH', realpath(TESTS_BP . $RELATIVE_TESTS_MODULE_PATH) From fb69c1a94d66e69129a9b357e3ef6873024f94a4 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 13 Feb 2020 08:53:56 -0600 Subject: [PATCH 219/888] MQE-1997: type float is wrongly treated as integer in assert actions --- dev/tests/verification/Resources/AssertTest.txt | 1 + dev/tests/verification/TestModule/Test/AssertTest.xml | 4 ++++ src/Magento/FunctionalTestingFramework/Util/TestGenerator.php | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/dev/tests/verification/Resources/AssertTest.txt b/dev/tests/verification/Resources/AssertTest.txt index bb29759d5..c0cf932ae 100644 --- a/dev/tests/verification/Resources/AssertTest.txt +++ b/dev/tests/verification/Resources/AssertTest.txt @@ -49,6 +49,7 @@ class AssertTestCest $I->assertEmpty([], "pass"); // stepKey: assertEmpty $I->assertEquals($text, "Copyright © 2013-2017 Magento, Inc. All rights reserved.", "pass"); // stepKey: assertEquals1 $I->assertEquals("Copyright © 2013-2017 Magento, Inc. All rights reserved.", $text, "pass"); // stepKey: assertEquals2 + $I->assertEquals(1.5, $text, "pass"); // stepKey: assertFloatTypeIsCorrect $I->assertFalse(false, "pass"); // stepKey: assertFalse1 $I->assertFileNotExists("/out.txt", "pass"); // stepKey: assertFileNotExists1 $I->assertFileNotExists($text, "pass"); // stepKey: assertFileNotExists2 diff --git a/dev/tests/verification/TestModule/Test/AssertTest.xml b/dev/tests/verification/TestModule/Test/AssertTest.xml index 82f69b9b0..8cdc724cc 100644 --- a/dev/tests/verification/TestModule/Test/AssertTest.xml +++ b/dev/tests/verification/TestModule/Test/AssertTest.xml @@ -54,6 +54,10 @@ <expectedResult type="string">Copyright © 2013-2017 Magento, Inc. All rights reserved.</expectedResult> <actualResult type="variable">text</actualResult> </assertEquals> + <assertEquals stepKey="assertFloatTypeIsCorrect" message="pass"> + <expectedResult type="float">1.5</expectedResult> + <actualResult type="variable">text</actualResult> + </assertEquals> <assertFalse stepKey="assertFalse1" message="pass"> <actualResult type="bool">0</actualResult> </assertFalse> diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index dda1dbd9f..2ec565c44 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -2194,6 +2194,6 @@ private function wrapParameterArray(string $value): string */ private function hasDecimalPoint(string $outStr) { - return strpos($outStr, localeconv()['decimal_point']) === false; + return strpos($outStr, localeconv()['decimal_point']) !== false; } } From 724ca691b51db6d6aff70195b977dab48345cc54 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Thu, 13 Feb 2020 14:47:35 -0600 Subject: [PATCH 220/888] MQE-2000: CHANGELOG.MD and Composer version bump 2.6.2 --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 339e82ed8..4792fa8ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ Magento Functional Testing Framework Changelog ================================================ +2.6.2 +----- + +### Fixes +* Fixed float conversion error in test generation + 2.6.1 ----- From ba72b5a5428996305162cab5c99509a1f3abb3c4 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Thu, 13 Feb 2020 14:49:57 -0600 Subject: [PATCH 221/888] MQE-2000: CHANGELOG.MD and Composer version bump 2.6.2 --- composer.json | 2 +- composer.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 9a806e35c..ed4656a37 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "2.6.1", + "version": "2.6.2", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index c493c4d77..caa95e992 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c79110e707cbbf2553f19b50052949e6", + "content-hash": "d9ea4056a8f4501c3f2766e09edce40d", "packages": [ { "name": "allure-framework/allure-codeception", From 8026f6fceb945c1df0269a8758f522a1ac5d4b86 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Fri, 14 Feb 2020 12:53:38 -0600 Subject: [PATCH 222/888] MQE-1961: Remove deprecated actions fixing verification tests --- dev/tests/verification/Resources/BasicFunctionalTest.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/verification/Resources/BasicFunctionalTest.txt b/dev/tests/verification/Resources/BasicFunctionalTest.txt index 19837fccd..42fd5ff56 100644 --- a/dev/tests/verification/Resources/BasicFunctionalTest.txt +++ b/dev/tests/verification/Resources/BasicFunctionalTest.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: A Functional Cest") * @group functional - * @Description("<h3 class='y-label y-label_status_broken'>Deprecated Notice(s):</h3><ul><li>DEPRECATED ACTION in Test: at step performOnKey1 'performOn' is DEPRECATED and will be removed in MFTF 3.0.0.</li></ul><h3>Test files</h3>verification/TestModule/Test/BasicFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/BasicFunctionalTest.xml<br>") */ class BasicFunctionalTestCest { From 7c3609adcd4268473cd6d0fc2bd03ab0b8b80d4d Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Tue, 18 Feb 2020 11:43:42 -0600 Subject: [PATCH 223/888] MQE-1961: Remove deprecated actions removed deprecation notices, and changes from 2.6.1 --- .../Console/BaseGenerateCommand.php | 11 +++-------- .../Console/GenerateSuiteCommand.php | 3 --- .../Console/GenerateTestsCommand.php | 3 --- .../Console/RunTestCommand.php | 3 --- .../Console/RunTestFailedCommand.php | 3 --- .../Console/RunTestGroupCommand.php | 3 --- .../Util/TestGenerator.php | 18 ------------------ 7 files changed, 3 insertions(+), 41 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index 3433f23a8..c331ee93f 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -23,12 +23,7 @@ class BaseGenerateCommand extends Command { - const MFTF_3_O_0_DEPRECATION_MESSAGE = "MFTF NOTICES:\n" - . "DEPRECATED ACTIONS: \"executeInSelenium\" and \"performOn\" actions will be removed in MFTF 3.0.0\n" - . "DEPRECATED TEST PATH: support for \"dev/tests/acceptance/tests/functional/Magento/FunctionalTest will be " - . "removed in MFTF 3.0.0\n" - . "XSD schema change to only allow single entity per xml file for all entities except data and metadata in " - . "MFTF 3.0.0\n"; + const MFTF_NOTICES = "Placeholder text for MFTF notices\n"; /** * Console output style @@ -218,9 +213,9 @@ protected function setOutputStyle(InputInterface $input, OutputInterface $output protected function showMftfNotices(OutputInterface $output) { if (null !== $this->ioStyle) { - $this->ioStyle->note(self::MFTF_3_O_0_DEPRECATION_MESSAGE); + $this->ioStyle->note(self::MFTF_NOTICES); } else { - $output->writeln(self::MFTF_3_O_0_DEPRECATION_MESSAGE); + $output->writeln(self::MFTF_NOTICES); } } } diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php index 2c91aa7f7..8da3493aa 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php @@ -58,9 +58,6 @@ protected function execute(InputInterface $input, OutputInterface $output) $allowSkipped ); - $this->setOutputStyle($input, $output); - $this->showMftfNotices($output); - // Remove previous GENERATED_DIR if --remove option is used if ($remove) { $this->removeGeneratedDirectory($output, $output->isVerbose()); diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php index b9378edc1..621f29d03 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php @@ -82,9 +82,6 @@ protected function execute(InputInterface $input, OutputInterface $output) $allowSkipped ); - $this->setOutputStyle($input, $output); - $this->showMftfNotices($output); - if (!empty($tests)) { $json = $this->getTestAndSuiteConfiguration($tests); } diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php index 08b84d6a1..373256cfc 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php @@ -84,9 +84,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int $allowSkipped ); - $this->setOutputStyle($input, $output); - $this->showMftfNotices($output); - $testConfiguration = $this->getTestAndSuiteConfiguration($tests); if (!$skipGeneration) { diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php index 1909c7e0b..5f0596a7f 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php @@ -96,9 +96,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int $allowSkipped ); - $this->setOutputStyle($input, $output); - $this->showMftfNotices($output); - $testConfiguration = $this->getFailedTestList(); if ($testConfiguration === null) { diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php index be6236c73..6ea37785d 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php @@ -79,9 +79,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int $allowSkipped ); - $this->setOutputStyle($input, $output); - $this->showMftfNotices($output); - if (!$skipGeneration) { $testConfiguration = $this->getGroupAndSuiteConfiguration($groups); $command = $this->getApplication()->find('generate:tests'); diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 749d80c2c..ab47bce7e 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -59,8 +59,6 @@ class TestGenerator const ARRAY_WRAP_OPEN = '['; const ARRAY_WRAP_CLOSE = ']'; - const MFTF_3_O_0_DEPRECATION_MESSAGE = ' is DEPRECATED and will be removed in MFTF 3.0.0.'; - /** * Actor name for AcceptanceTest * @@ -1039,11 +1037,6 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $parameterArray ); break; - case "executeInSelenium": - $this->deprecationMessages[] = "DEPRECATED ACTION in Test: at step {$stepKey} 'executeInSelenium'" - . self::MFTF_3_O_0_DEPRECATION_MESSAGE; - $testSteps .= $this->wrapFunctionCall($actor, $actionObject, $function); - break; case "executeJS": $testSteps .= $this->wrapFunctionCallWithReturnValue( $stepKey, @@ -1052,17 +1045,6 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $function ); break; - case "performOn": - $this->deprecationMessages[] = "DEPRECATED ACTION in Test: at step {$stepKey} 'performOn'" - . self::MFTF_3_O_0_DEPRECATION_MESSAGE; - $testSteps .= $this->wrapFunctionCall( - $actor, - $actionObject, - $selector, - $function, - $time - ); - break; case "waitForElementChange": $testSteps .= $this->wrapFunctionCall( $actor, From 0f305ebbafbedeee491383cbc4d531beaa3ccafd Mon Sep 17 00:00:00 2001 From: Ajith <ajithkumar.maragathavel@ziffity.com> Date: Wed, 19 Feb 2020 01:18:30 +0530 Subject: [PATCH 224/888] Changed sentence formation --- docs/data.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data.md b/docs/data.md index df3e89479..a9db68561 100644 --- a/docs/data.md +++ b/docs/data.md @@ -85,7 +85,7 @@ The following example shows the usage of `grabValueFrom` in testing, where the r <fillField selector=".functionalTestSelector" userInput="{$grabStepKey}" stepKey="fillFieldKey1"/> ``` -Below is an example used in Magento/Catalog/Test/Mftf/ActionGroup/AssertDiscountsPercentageOfProductsActionGroup.xml test. +The following is an example of the `Magento/Catalog/Test/Mftf/ActionGroup/AssertDiscountsPercentageOfProductsActionGroup.xml` test: ```xml <grabValueFrom selector="{{AdminProductFormAdvancedPricingSection.productTierPricePercentageValuePriceInput('0')}}" stepKey="grabProductTierPriceInput"/> From 39ecbd0e1c1fcf27b158375a04723b51deb0072d Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Fri, 21 Feb 2020 11:14:57 -0600 Subject: [PATCH 225/888] MQE-1962: Remove support of deprecated locations for tests --- docs/mftf-tests-packaging.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/mftf-tests-packaging.md b/docs/mftf-tests-packaging.md index 07e13718b..8a37b8013 100644 --- a/docs/mftf-tests-packaging.md +++ b/docs/mftf-tests-packaging.md @@ -19,11 +19,11 @@ vendor/<Vendor>/<TestModule> ``` To support future service isolation, Test module in `dev/tests/acceptance/tests/functional/<Vendor>/<TestModule>` and -`vendor/<Vendor>/<TestModule>` must define the module type as `magento2-functional-test-module` in a `composer.json` file. +`vendor/<Vendor>/<TestModule>` must define the module type as `magento2-functional-test-module` in its `composer.json` file. No `composer.json` file is required for tests in `app/code/<Vendor>/<Module>/Test/Mftf` and `vendor/<Vendor>/<Module>/Test/Mftf` as they are part of the Magento modules. -Test module for a specific Magento module can only be in one of the path. +Test module for a specific Magento module can only be in one of the paths. ## Test module composer.json format From e32eac1476789f195a6a9d560c879fa6d87a550e Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 19 Feb 2020 17:53:19 -0600 Subject: [PATCH 226/888] MQE-1963: Update XSD Schema to verify that file has only single entity --- docs/best-practices.md | 5 +- docs/page.md | 3 +- docs/section.md | 3 +- docs/suite.md | 1 + docs/test.md | 4 +- docs/test/action-groups.md | 2 +- etc/di.xml | 18 +- .../Console/BuildProjectCommand.php | 2 +- .../Console/UpgradeTestsCommand.php | 12 +- .../Page/etc/PageObject.xsd | 101 +------- .../Page/etc/SectionObject.xsd | 134 +---------- .../Page/etc/mergedPageObject.xsd | 116 ++++++++++ .../Page/etc/mergedSectionObject.xsd | 149 ++++++++++++ .../StaticCheck/ActionGroupArgumentsCheck.php | 15 +- .../StaticCheck/TestDependencyCheck.php | 20 +- .../Suite/etc/mergedSuiteSchema.xsd | 77 +++++++ .../Suite/etc/suiteSchema.xsd | 74 +----- .../Test/etc/actionGroupSchema.xsd | 57 +---- .../Test/etc/mergedActionGroupSchema.xsd | 60 +++++ .../Test/etc/testSchema.xsd | 2 +- .../Upgrade/SplitMultipleEntitiesFiles.php | 216 ++++++++++++++++++ .../Upgrade/UpdateTestSchemaPaths.php | 35 +-- .../Upgrade/UpgradeInterface.php | 6 +- .../Upgrade/UpgradeScriptList.php | 1 + .../Script/ScriptUtil.php} | 31 ++- 25 files changed, 734 insertions(+), 410 deletions(-) create mode 100644 src/Magento/FunctionalTestingFramework/Page/etc/mergedPageObject.xsd create mode 100644 src/Magento/FunctionalTestingFramework/Page/etc/mergedSectionObject.xsd create mode 100644 src/Magento/FunctionalTestingFramework/Suite/etc/mergedSuiteSchema.xsd create mode 100644 src/Magento/FunctionalTestingFramework/Test/etc/mergedActionGroupSchema.xsd create mode 100644 src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php rename src/Magento/FunctionalTestingFramework/{StaticCheck/StaticCheckHelper.php => Util/Script/ScriptUtil.php} (62%) diff --git a/docs/best-practices.md b/docs/best-practices.md index 0b95b1c41..2f18bc205 100644 --- a/docs/best-practices.md +++ b/docs/best-practices.md @@ -7,6 +7,7 @@ Check out our best practices below to ensure you are getting the absolute most o 1. [Action group] names should be sufficiently descriptive to inform a test writer of what the action group does and when it should be used. Add additional explanation in annotations if needed. 2. Provide default values for the arguments that apply to your most common case scenarios. +3. One `<actionGroup>` tag is allowed per action group XML file. ## `actionGroups` vs `extends` @@ -111,7 +112,8 @@ Use a lower case first letter for: ## Page object -Use [parameterized selectors] for constructing a selector when test specific or runtime generated information is needed. +1. One `<page>` tag is allowed per page XML file. +2. Use [parameterized selectors] for constructing a selector when test specific or runtime generated information is needed. Do not use them for static elements. <span class="color:red"> @@ -149,6 +151,7 @@ Define these three elements and reference them by name in the tests. It helps to inform the reader of what you are testing and to yield a more descriptive Allure report. - Explain in comments unclear or tricky test steps. 1. Refer to [sections] instead of writing selectors. +1. One `<test>` tag is allowed per test XML file. ## Test step merging order diff --git a/docs/page.md b/docs/page.md index cf8448dd8..41afd274f 100644 --- a/docs/page.md +++ b/docs/page.md @@ -45,7 +45,8 @@ The following conventions apply to MFTF pages: - `<page>` name must be alphanumeric. - `*Page.xml` is stored in the _Page_ directory of a module. - The name format is `{Admin|Storefront}{PageDescription}Page.xml`. - +- One `<page>` tag is allowed per page XML file. + The `.url` attribute is required when using the page for [actions] that require the URL argument. ## Page examples diff --git a/docs/section.md b/docs/section.md index aa3555dc4..f5c15c70c 100644 --- a/docs/section.md +++ b/docs/section.md @@ -48,7 +48,8 @@ The following conventions apply to MFTF sections: - `*Section.xml` is stored in the _Section_ directory of a module. - The name format is `{Admin|Storefront}{SectionDescription}Section.xml`. - Camel case is used for `<section>` elements. - They describe the function of the element rather than attempting to describe the selector used. +They describe the function of the element rather than attempting to describe the selector used. +- One `<section>` tag is allowed per section XML file. ## Example diff --git a/docs/suite.md b/docs/suite.md index 38e54926f..65bcedce0 100644 --- a/docs/suite.md +++ b/docs/suite.md @@ -52,6 +52,7 @@ The format of a suite: - A suite must contain at least one `<include>`, or one `<exclude>`, or both. - Using `<before>` in a suite, you must add the corresponding `<after>` to restore the initial state of your testing instance. +- One `<suite>` tag is allowed per suite XML file. ## Conditions diff --git a/docs/test.md b/docs/test.md index 363732fd7..444f6cf6a 100644 --- a/docs/test.md +++ b/docs/test.md @@ -49,9 +49,7 @@ The following conventions apply to MFTF tests: * Each action and action group has its own identifier `<stepKey>` for reference purposes. * A test may have any number of [assertions][assertion] at any point within the `<test>`. * If `<test>` is included in `<suite>`, it **cannot be generated in isolation** to the rest of the contents of the suite (see [suites] for details). - -Multiple `<test>` tags per XML file can make it hard to find and organize tags. -To simplify, we generate one `test.php` file per `<test>` tag provided, though we support both single and multiple `<test>` tags per XML file. +* One `<test>` tag is allowed per test XML file. ## Elements reference diff --git a/docs/test/action-groups.md b/docs/test/action-groups.md index 162ac0541..70af0621a 100644 --- a/docs/test/action-groups.md +++ b/docs/test/action-groups.md @@ -15,7 +15,7 @@ The following conventions apply to MFTF action groups: - All action groups are declared in XML files and stored in the `<module>/Test/Mftf/ActionGroup/` directory. - Every file name ends with `ActionGroup` suffix. For exampe `LoginAsAdminActionGroup.xml`. - Action group name should be the same as file name without extension. -- Single file should contain only one `<actionGroup>` node +- One `<actionGroup>` tag is allowed per action group XML file. The XML format for the `actionGroups` declaration is: diff --git a/etc/di.xml b/etc/di.xml index e5e31cf87..bb01098cc 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -70,12 +70,12 @@ <virtualType name="Magento\FunctionalTestingFramework\Config\SchemaLocator\Page" type="Magento\FunctionalTestingFramework\Config\SchemaLocator"> <arguments> - <argument name="schemaPath" xsi:type="string">Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd</argument> + <argument name="schemaPath" xsi:type="string">Magento/FunctionalTestingFramework/Page/etc/mergedPageObject.xsd</argument> </arguments> </virtualType> <virtualType name="Magento\FunctionalTestingFramework\Config\SchemaLocator\Section" type="Magento\FunctionalTestingFramework\Config\SchemaLocator"> <arguments> - <argument name="schemaPath" xsi:type="string">Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd</argument> + <argument name="schemaPath" xsi:type="string">Magento/FunctionalTestingFramework/Page/etc/mergedSectionObject.xsd</argument> </arguments> </virtualType> <virtualType name="Magento\FunctionalTestingFramework\Config\Reader\Page" type="Magento\FunctionalTestingFramework\Config\Reader\MftfFilesystem"> @@ -94,7 +94,7 @@ </virtualType> <virtualType name="Magento\FunctionalTestingFramework\Config\Reader\Section" type="Magento\FunctionalTestingFramework\Config\Reader\MftfFilesystem"> <arguments> - <argument name="fileResolver" xsi:type="object">Magento\FunctionalTestingFramework\Config\FileResolver\Module</argument> + <argument name="fileResolver" xsi:type="object">Magento\FunctionalTestingFramework\Config\FileResolver\Mask</argument> <argument name="converter" xsi:type="object">Magento\FunctionalTestingFramework\Config\Converter</argument> <argument name="schemaLocator" xsi:type="object">Magento\FunctionalTestingFramework\Config\SchemaLocator\Section</argument> <argument name="domDocumentClass" xsi:type="string">Magento\FunctionalTestingFramework\Page\Config\SectionDom</argument> @@ -150,7 +150,7 @@ </virtualType> <virtualType name="Magento\FunctionalTestingFramework\Config\Reader\DataProfile" type="Magento\FunctionalTestingFramework\Config\Reader\MftfFilesystem"> <arguments> - <argument name="fileResolver" xsi:type="object">Magento\FunctionalTestingFramework\Config\FileResolver\Module</argument> + <argument name="fileResolver" xsi:type="object">Magento\FunctionalTestingFramework\Config\FileResolver\Mask</argument> <argument name="converter" xsi:type="object">Magento\FunctionalTestingFramework\Config\Converter</argument> <argument name="domDocumentClass" xsi:type="string">Magento\FunctionalTestingFramework\DataGenerator\Config\Dom</argument> <argument name="schemaLocator" xsi:type="object">Magento\FunctionalTestingFramework\Config\SchemaLocator\DataProfile</argument> @@ -187,7 +187,7 @@ </virtualType> <virtualType name="Magento\FunctionalTestingFramework\Config\Reader\Metadata" type="Magento\FunctionalTestingFramework\Config\Reader\MftfFilesystem"> <arguments> - <argument name="fileResolver" xsi:type="object">Magento\FunctionalTestingFramework\Config\FileResolver\Module</argument> + <argument name="fileResolver" xsi:type="object">Magento\FunctionalTestingFramework\Config\FileResolver\Mask</argument> <argument name="converter" xsi:type="object">Magento\FunctionalTestingFramework\Config\Converter</argument> <argument name="domDocumentClass" xsi:type="string">Magento\FunctionalTestingFramework\DataGenerator\Config\OperationDom</argument> <argument name="schemaLocator" xsi:type="object">Magento\FunctionalTestingFramework\Config\SchemaLocator\Metadata</argument> @@ -212,7 +212,7 @@ </virtualType> <virtualType name="Magento\FunctionalTestingFramework\Config\Reader\TestData" type="Magento\FunctionalTestingFramework\Config\Reader\MftfFilesystem"> <arguments> - <argument name="fileResolver" xsi:type="object">Magento\FunctionalTestingFramework\Config\FileResolver\Module</argument> + <argument name="fileResolver" xsi:type="object">Magento\FunctionalTestingFramework\Config\FileResolver\Mask</argument> <argument name="converter" xsi:type="object">Magento\FunctionalTestingFramework\Config\TestDataConverter</argument> <argument name="schemaLocator" xsi:type="object">Magento\FunctionalTestingFramework\Config\SchemaLocator\TestData</argument> <argument name="domDocumentClass" xsi:type="string">Magento\FunctionalTestingFramework\Test\Config\Dom</argument> @@ -286,13 +286,13 @@ <virtualType name="Magento\FunctionalTestingFramework\Config\SchemaLocator\ActionGroup" type="Magento\FunctionalTestingFramework\Config\SchemaLocator"> <arguments> - <argument name="schemaPath" xsi:type="string">Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd</argument> + <argument name="schemaPath" xsi:type="string">Magento/FunctionalTestingFramework/Test/etc/mergedActionGroupSchema.xsd</argument> </arguments> </virtualType> <virtualType name="Magento\FunctionalTestingFramework\Config\Reader\ActionGroupData" type="Magento\FunctionalTestingFramework\Config\Reader\MftfFilesystem"> <arguments> - <argument name="fileResolver" xsi:type="object">Magento\FunctionalTestingFramework\Config\FileResolver\Module</argument> + <argument name="fileResolver" xsi:type="object">Magento\FunctionalTestingFramework\Config\FileResolver\Mask</argument> <argument name="converter" xsi:type="object">Magento\FunctionalTestingFramework\Config\ActionGroupDataConverter</argument> <argument name="schemaLocator" xsi:type="object">Magento\FunctionalTestingFramework\Config\SchemaLocator\ActionGroup</argument> <argument name="domDocumentClass" xsi:type="string">Magento\FunctionalTestingFramework\Test\Config\ActionGroupDom</argument> @@ -353,7 +353,7 @@ </virtualType> <virtualType name="Magento\FunctionalTestingFramework\Config\SchemaLocator\SuiteData" type="Magento\FunctionalTestingFramework\Config\SchemaLocator"> <arguments> - <argument name="schemaPath" xsi:type="string">Magento/FunctionalTestingFramework/Suite/etc/suiteSchema.xsd</argument> + <argument name="schemaPath" xsi:type="string">Magento/FunctionalTestingFramework/Suite/etc/mergedSuiteSchema.xsd</argument> </arguments> </virtualType> <virtualType name="Magento\FunctionalTestingFramework\Config\Reader\SuiteData" type="Magento\FunctionalTestingFramework\Config\Reader\Filesystem"> diff --git a/src/Magento/FunctionalTestingFramework/Console/BuildProjectCommand.php b/src/Magento/FunctionalTestingFramework/Console/BuildProjectCommand.php index 02dfcda82..23736925f 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BuildProjectCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BuildProjectCommand.php @@ -109,7 +109,7 @@ function ($type, $buffer) use ($output) { if ($input->getOption('upgrade')) { $upgradeCommand = new UpgradeTestsCommand(); - $upgradeOptions = new ArrayInput(['path' => FilePathFormatter::format(TESTS_MODULE_PATH)]); + $upgradeOptions = new ArrayInput([]); $upgradeCommand->run($upgradeOptions, $output); } } diff --git a/src/Magento/FunctionalTestingFramework/Console/UpgradeTestsCommand.php b/src/Magento/FunctionalTestingFramework/Console/UpgradeTestsCommand.php index 8e24290b5..c302fdd37 100644 --- a/src/Magento/FunctionalTestingFramework/Console/UpgradeTestsCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/UpgradeTestsCommand.php @@ -32,8 +32,9 @@ class UpgradeTestsCommand extends Command protected function configure() { $this->setName('upgrade:tests') - ->setDescription('This command will upgrade all tests in the provided path according to new MFTF Major version requirements.') - ->addArgument('path', InputArgument::REQUIRED, 'path to MFTF tests to upgrade'); + ->setDescription( + 'This command will upgrade all installed mftf tests according to new MFTF Major version requirements.' + ); $this->upgradeScriptsList = new UpgradeScriptList(); } @@ -49,10 +50,11 @@ protected function execute(InputInterface $input, OutputInterface $output) { /** @var \Magento\FunctionalTestingFramework\Upgrade\UpgradeInterface[] $upgradeScriptObjects */ $upgradeScriptObjects = $this->upgradeScriptsList->getUpgradeScripts(); - foreach ($upgradeScriptObjects as $upgradeScriptObject) { - $upgradeOutput = $upgradeScriptObject->execute($input); + foreach ($upgradeScriptObjects as $scriptName => $upgradeScriptObject) { + $output->writeln('Running upgrade script: ' . $scriptName . PHP_EOL); + $upgradeOutput = $upgradeScriptObject->execute($input, $output); LoggingUtil::getInstance()->getLogger(get_class($upgradeScriptObject))->info($upgradeOutput); - $output->writeln($upgradeOutput); + $output->writeln($upgradeOutput . PHP_EOL); } } } diff --git a/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd b/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd index 65ac8290d..7b857a235 100644 --- a/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd +++ b/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd @@ -7,19 +7,10 @@ --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> - <xs:annotation> - <xs:documentation>The definition of a page object.</xs:documentation> - </xs:annotation> - - <xs:element name="pages"> - <xs:annotation> - <xs:documentation> - The root element for configuration data. - </xs:documentation> - </xs:annotation> - <xs:complexType> + <xs:redefine schemaLocation="mergedPageObject.xsd"> + <xs:complexType name="PageType"> <xs:sequence> - <xs:element ref="page" maxOccurs="unbounded" minOccurs="1"> + <xs:element ref="page" maxOccurs="1" minOccurs="1"> <xs:annotation> <xs:documentation> Contains sequence of ui sections in a page. @@ -28,89 +19,5 @@ </xs:element> </xs:sequence> </xs:complexType> - </xs:element> - - <xs:element name="page"> - <xs:complexType> - <xs:sequence> - <xs:element ref="section" maxOccurs="unbounded" minOccurs="0"> - <xs:annotation> - <xs:documentation> - Contains sequence of ui elements. - </xs:documentation> - </xs:annotation> - </xs:element> - </xs:sequence> - <xs:attribute type="notEmptyType" name="name" use="required"> - <xs:annotation> - <xs:documentation> - Unique page name identifier. - </xs:documentation> - </xs:annotation> - </xs:attribute> - <xs:attribute type="xs:string" name="deprecated"> - <xs:annotation> - <xs:documentation> - Message and flag which shows that entity is deprecated. - </xs:documentation> - </xs:annotation> - </xs:attribute> - - <xs:attribute type="notEmptyType" name="url" use="required"> - <xs:annotation> - <xs:documentation> - URL for the page. Do not include the hostname. For example: "/admin/customer/index/" - </xs:documentation> - </xs:annotation> - </xs:attribute> - <xs:attribute type="notEmptyType" name="module" use="required"> - <xs:annotation> - <xs:documentation> - The name of the module to which the page belongs. For example: "Magento_Catalog". - </xs:documentation> - </xs:annotation> - </xs:attribute> - <xs:attribute type="xs:boolean" name="parameterized" use="optional"/> - <xs:attribute type="pageArea" name="area" use="required"/> - <xs:attributeGroup ref="removeAttribute"/> - <xs:attribute type="xs:string" name="filename"/> - </xs:complexType> - </xs:element> - - <xs:element name="section"> - <xs:complexType> - <xs:attribute type="notEmptyType" name="name" use="required"> - <xs:annotation> - <xs:documentation> - Unique section name identifier. - </xs:documentation> - </xs:annotation> - </xs:attribute> - <xs:attributeGroup ref="removeAttribute"/> - </xs:complexType> - </xs:element> - - <xs:simpleType name="notEmptyType"> - <xs:restriction base="xs:string"> - <xs:minLength value="1" /> - </xs:restriction> - </xs:simpleType> - - <xs:attributeGroup name="removeAttribute"> - <xs:attribute type="xs:boolean" name="remove" use="optional" default="false"> - <xs:annotation> - <xs:documentation> - Set to true to remove this element during parsing. - </xs:documentation> - </xs:annotation> - </xs:attribute> - </xs:attributeGroup> - - <xs:simpleType name="pageArea" final="restriction" > - <xs:restriction base="xs:string"> - <xs:enumeration value="admin" /> - <xs:enumeration value="storefront" /> - <xs:enumeration value="external" /> - </xs:restriction> - </xs:simpleType> + </xs:redefine> </xs:schema> diff --git a/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd b/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd index 1b5b44ddd..2267ed09b 100644 --- a/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd +++ b/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd @@ -7,15 +7,10 @@ --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> - <xs:element name="sections"> - <xs:annotation> - <xs:documentation> - The root element for configuration data. - </xs:documentation> - </xs:annotation> - <xs:complexType> + <xs:redefine schemaLocation="mergedSectionObject.xsd"> + <xs:complexType name="SectionType"> <xs:sequence> - <xs:element ref="section" maxOccurs="unbounded" minOccurs="1"> + <xs:element ref="section" maxOccurs="1" minOccurs="1"> <xs:annotation> <xs:documentation> Contains sequence of ui elements in a section of a page. @@ -24,126 +19,5 @@ </xs:element> </xs:sequence> </xs:complexType> - </xs:element> - - <xs:element name="section"> - <xs:complexType> - <xs:sequence> - <xs:element ref="element" maxOccurs="unbounded" minOccurs="1"> - <xs:annotation> - <xs:documentation> - Contains information of an ui element. - </xs:documentation> - </xs:annotation> - </xs:element> - </xs:sequence> - <xs:attribute type="notEmptyType" name="name" use="required"> - <xs:annotation> - <xs:documentation> - Unique section name identifier. - </xs:documentation> - </xs:annotation> - </xs:attribute> - <xs:attribute type="xs:string" name="deprecated"> - <xs:annotation> - <xs:documentation> - Message and flag which shows that entity is deprecated. - </xs:documentation> - </xs:annotation> - </xs:attribute> - <xs:attributeGroup ref="removeAttribute"/> - <xs:attribute type="xs:string" name="filename"/> - </xs:complexType> - </xs:element> - - <xs:element name="element"> - <xs:complexType> - <xs:attribute type="notEmptyType" name="name" use="required"> - <xs:annotation> - <xs:documentation> - Element name. - </xs:documentation> - </xs:annotation> - </xs:attribute> - <xs:attribute type="xs:string" name="deprecated"> - <xs:annotation> - <xs:documentation> - Message and flag which shows that entity is deprecated. - </xs:documentation> - </xs:annotation> - </xs:attribute> - <xs:attribute type="uiElementType" name="type" use="required"> - <xs:annotation> - <xs:documentation> - The type of the element, e.g. select, radio, etc. - </xs:documentation> - </xs:annotation> - </xs:attribute> - <xs:attribute type="notEmptyType" name="selector" use="optional"> - <xs:annotation> - <xs:documentation> - Selector of the element. Optional due to being able to use either this or locatorFunction. - </xs:documentation> - </xs:annotation> - </xs:attribute> - <xs:attribute type="notEmptyType" name="locatorFunction" use="optional"> - <xs:annotation> - <xs:documentation> - LocatorFunction of an element, substitute for a selector. - </xs:documentation> - </xs:annotation> - </xs:attribute> - <xs:attribute type="timeoutType" name="timeout" use="optional"> - <xs:annotation> - <xs:documentation> - Optional timeout value in second to wait for the operation on the element. use "-" for default value. - </xs:documentation> - </xs:annotation> - </xs:attribute> - <xs:attribute type="xs:boolean" name="parameterized" use="optional"/> - <xs:attributeGroup ref="removeAttribute"/> - </xs:complexType> - </xs:element> - - <xs:simpleType name="uiElementType"> - <xs:restriction base="xs:string"> - <xs:enumeration value="text"/> - <xs:enumeration value="textarea"/> - <xs:enumeration value="input"/> - <xs:enumeration value="button"/> - <xs:enumeration value="checkbox"/> - <xs:enumeration value="radio"/> - <xs:enumeration value="checkboxset"/> - <xs:enumeration value="radioset"/> - <xs:enumeration value="date"/> - <xs:enumeration value="file"/> - <xs:enumeration value="select"/> - <xs:enumeration value="multiselect"/> - <xs:enumeration value="wysiwyg"/> - <xs:enumeration value="iframe"/> - <xs:enumeration value="block"/> - </xs:restriction> - </xs:simpleType> - - <xs:simpleType name="notEmptyType"> - <xs:restriction base="xs:string"> - <xs:minLength value="1" /> - </xs:restriction> - </xs:simpleType> - - <xs:simpleType name="timeoutType"> - <xs:restriction base="xs:string"> - <xs:pattern value="([0-9])+|-"/> - </xs:restriction> - </xs:simpleType> - - <xs:attributeGroup name="removeAttribute"> - <xs:attribute type="xs:boolean" name="remove" use="optional" default="false"> - <xs:annotation> - <xs:documentation> - Set to true to remove this element during parsing. - </xs:documentation> - </xs:annotation> - </xs:attribute> - </xs:attributeGroup> + </xs:redefine> </xs:schema> diff --git a/src/Magento/FunctionalTestingFramework/Page/etc/mergedPageObject.xsd b/src/Magento/FunctionalTestingFramework/Page/etc/mergedPageObject.xsd new file mode 100644 index 000000000..65ac8290d --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Page/etc/mergedPageObject.xsd @@ -0,0 +1,116 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <xs:annotation> + <xs:documentation>The definition of a page object.</xs:documentation> + </xs:annotation> + + <xs:element name="pages"> + <xs:annotation> + <xs:documentation> + The root element for configuration data. + </xs:documentation> + </xs:annotation> + <xs:complexType> + <xs:sequence> + <xs:element ref="page" maxOccurs="unbounded" minOccurs="1"> + <xs:annotation> + <xs:documentation> + Contains sequence of ui sections in a page. + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + </xs:element> + + <xs:element name="page"> + <xs:complexType> + <xs:sequence> + <xs:element ref="section" maxOccurs="unbounded" minOccurs="0"> + <xs:annotation> + <xs:documentation> + Contains sequence of ui elements. + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + <xs:attribute type="notEmptyType" name="name" use="required"> + <xs:annotation> + <xs:documentation> + Unique page name identifier. + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute type="xs:string" name="deprecated"> + <xs:annotation> + <xs:documentation> + Message and flag which shows that entity is deprecated. + </xs:documentation> + </xs:annotation> + </xs:attribute> + + <xs:attribute type="notEmptyType" name="url" use="required"> + <xs:annotation> + <xs:documentation> + URL for the page. Do not include the hostname. For example: "/admin/customer/index/" + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute type="notEmptyType" name="module" use="required"> + <xs:annotation> + <xs:documentation> + The name of the module to which the page belongs. For example: "Magento_Catalog". + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute type="xs:boolean" name="parameterized" use="optional"/> + <xs:attribute type="pageArea" name="area" use="required"/> + <xs:attributeGroup ref="removeAttribute"/> + <xs:attribute type="xs:string" name="filename"/> + </xs:complexType> + </xs:element> + + <xs:element name="section"> + <xs:complexType> + <xs:attribute type="notEmptyType" name="name" use="required"> + <xs:annotation> + <xs:documentation> + Unique section name identifier. + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attributeGroup ref="removeAttribute"/> + </xs:complexType> + </xs:element> + + <xs:simpleType name="notEmptyType"> + <xs:restriction base="xs:string"> + <xs:minLength value="1" /> + </xs:restriction> + </xs:simpleType> + + <xs:attributeGroup name="removeAttribute"> + <xs:attribute type="xs:boolean" name="remove" use="optional" default="false"> + <xs:annotation> + <xs:documentation> + Set to true to remove this element during parsing. + </xs:documentation> + </xs:annotation> + </xs:attribute> + </xs:attributeGroup> + + <xs:simpleType name="pageArea" final="restriction" > + <xs:restriction base="xs:string"> + <xs:enumeration value="admin" /> + <xs:enumeration value="storefront" /> + <xs:enumeration value="external" /> + </xs:restriction> + </xs:simpleType> +</xs:schema> diff --git a/src/Magento/FunctionalTestingFramework/Page/etc/mergedSectionObject.xsd b/src/Magento/FunctionalTestingFramework/Page/etc/mergedSectionObject.xsd new file mode 100644 index 000000000..1b5b44ddd --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Page/etc/mergedSectionObject.xsd @@ -0,0 +1,149 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <xs:element name="sections"> + <xs:annotation> + <xs:documentation> + The root element for configuration data. + </xs:documentation> + </xs:annotation> + <xs:complexType> + <xs:sequence> + <xs:element ref="section" maxOccurs="unbounded" minOccurs="1"> + <xs:annotation> + <xs:documentation> + Contains sequence of ui elements in a section of a page. + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + </xs:complexType> + </xs:element> + + <xs:element name="section"> + <xs:complexType> + <xs:sequence> + <xs:element ref="element" maxOccurs="unbounded" minOccurs="1"> + <xs:annotation> + <xs:documentation> + Contains information of an ui element. + </xs:documentation> + </xs:annotation> + </xs:element> + </xs:sequence> + <xs:attribute type="notEmptyType" name="name" use="required"> + <xs:annotation> + <xs:documentation> + Unique section name identifier. + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute type="xs:string" name="deprecated"> + <xs:annotation> + <xs:documentation> + Message and flag which shows that entity is deprecated. + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attributeGroup ref="removeAttribute"/> + <xs:attribute type="xs:string" name="filename"/> + </xs:complexType> + </xs:element> + + <xs:element name="element"> + <xs:complexType> + <xs:attribute type="notEmptyType" name="name" use="required"> + <xs:annotation> + <xs:documentation> + Element name. + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute type="xs:string" name="deprecated"> + <xs:annotation> + <xs:documentation> + Message and flag which shows that entity is deprecated. + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute type="uiElementType" name="type" use="required"> + <xs:annotation> + <xs:documentation> + The type of the element, e.g. select, radio, etc. + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute type="notEmptyType" name="selector" use="optional"> + <xs:annotation> + <xs:documentation> + Selector of the element. Optional due to being able to use either this or locatorFunction. + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute type="notEmptyType" name="locatorFunction" use="optional"> + <xs:annotation> + <xs:documentation> + LocatorFunction of an element, substitute for a selector. + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute type="timeoutType" name="timeout" use="optional"> + <xs:annotation> + <xs:documentation> + Optional timeout value in second to wait for the operation on the element. use "-" for default value. + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute type="xs:boolean" name="parameterized" use="optional"/> + <xs:attributeGroup ref="removeAttribute"/> + </xs:complexType> + </xs:element> + + <xs:simpleType name="uiElementType"> + <xs:restriction base="xs:string"> + <xs:enumeration value="text"/> + <xs:enumeration value="textarea"/> + <xs:enumeration value="input"/> + <xs:enumeration value="button"/> + <xs:enumeration value="checkbox"/> + <xs:enumeration value="radio"/> + <xs:enumeration value="checkboxset"/> + <xs:enumeration value="radioset"/> + <xs:enumeration value="date"/> + <xs:enumeration value="file"/> + <xs:enumeration value="select"/> + <xs:enumeration value="multiselect"/> + <xs:enumeration value="wysiwyg"/> + <xs:enumeration value="iframe"/> + <xs:enumeration value="block"/> + </xs:restriction> + </xs:simpleType> + + <xs:simpleType name="notEmptyType"> + <xs:restriction base="xs:string"> + <xs:minLength value="1" /> + </xs:restriction> + </xs:simpleType> + + <xs:simpleType name="timeoutType"> + <xs:restriction base="xs:string"> + <xs:pattern value="([0-9])+|-"/> + </xs:restriction> + </xs:simpleType> + + <xs:attributeGroup name="removeAttribute"> + <xs:attribute type="xs:boolean" name="remove" use="optional" default="false"> + <xs:annotation> + <xs:documentation> + Set to true to remove this element during parsing. + </xs:documentation> + </xs:annotation> + </xs:attribute> + </xs:attributeGroup> +</xs:schema> diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php index 32c7661fe..246e9427e 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php @@ -14,6 +14,7 @@ use Magento\FunctionalTestingFramework\Util\ModuleResolver; use Symfony\Component\Finder\Finder; use Exception; +use Magento\FunctionalTestingFramework\Util\Script\ScriptUtil; /** * Class ActionGroupArgumentsCheck @@ -50,24 +51,16 @@ class ActionGroupArgumentsCheck implements StaticCheckInterface */ public function execute(InputInterface $input) { - MftfApplicationConfig::create( - true, - MftfApplicationConfig::UNIT_TEST_PHASE, - false, - MftfApplicationConfig::LEVEL_NONE, - true - ); - - $allModules = ModuleResolver::getInstance()->getModulesPath(); + $allModules = ScriptUtil::getAllModulePaths(); - $actionGroupXmlFiles = StaticCheckHelper::buildFileList( + $actionGroupXmlFiles = ScriptUtil::buildFileList( $allModules, DIRECTORY_SEPARATOR . 'ActionGroup' . DIRECTORY_SEPARATOR ); $this->errors = $this->findErrorsInFileSet($actionGroupXmlFiles); - $this->output = StaticCheckHelper::printErrorsToFile( + $this->output = ScriptUtil::printErrorsToFile( $this->errors, self::ERROR_LOG_FILENAME, self::ERROR_LOG_MESSAGE diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php index 3c3ed6a37..55179c634 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php @@ -15,11 +15,11 @@ use Magento\FunctionalTestingFramework\Test\Handlers\ActionGroupObjectHandler; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; -use Magento\FunctionalTestingFramework\Util\ModuleResolver; use Magento\FunctionalTestingFramework\Util\TestGenerator; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Finder\Finder; use Exception; +use Magento\FunctionalTestingFramework\Util\Script\ScriptUtil; /** * Class TestDependencyCheck @@ -92,15 +92,8 @@ class TestDependencyCheck implements StaticCheckInterface */ public function execute(InputInterface $input) { - MftfApplicationConfig::create( - true, - MftfApplicationConfig::UNIT_TEST_PHASE, - false, - MftfApplicationConfig::LEVEL_NONE, - true - ); + $allModules = ScriptUtil::getAllModulePaths(); - ModuleResolver::getInstance()->getModulesPath(); if (!class_exists('\Magento\Framework\Component\ComponentRegistrar')) { return "TEST DEPENDENCY CHECK ABORTED: MFTF must be attached or pointing to Magento codebase."; } @@ -109,16 +102,15 @@ public function execute(InputInterface $input) $this->moduleNameToComposerName = $this->buildModuleNameToComposerName($this->moduleNameToPath); $this->flattenedDependencies = $this->buildComposerDependencyList(); - $allModules = ModuleResolver::getInstance()->getModulesPath(); $filePaths = [ DIRECTORY_SEPARATOR . 'Test' . DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR . 'ActionGroup' . DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR . 'Data' . DIRECTORY_SEPARATOR, ]; // These files can contain references to other modules. - $testXmlFiles = StaticCheckHelper::buildFileList($allModules, $filePaths[0]); - $actionGroupXmlFiles = StaticCheckHelper::buildFileList($allModules, $filePaths[1]); - $dataXmlFiles= StaticCheckHelper::buildFileList($allModules, $filePaths[2]); + $testXmlFiles = ScriptUtil::buildFileList($allModules, $filePaths[0]); + $actionGroupXmlFiles = ScriptUtil::buildFileList($allModules, $filePaths[1]); + $dataXmlFiles= ScriptUtil::buildFileList($allModules, $filePaths[2]); $this->errors = []; $this->errors += $this->findErrorsInFileSet($testXmlFiles); @@ -126,7 +118,7 @@ public function execute(InputInterface $input) $this->errors += $this->findErrorsInFileSet($dataXmlFiles); // hold on to the output and print any errors to a file - $this->output = StaticCheckHelper::printErrorsToFile( + $this->output = ScriptUtil::printErrorsToFile( $this->errors, self::ERROR_LOG_FILENAME, self::ERROR_LOG_MESSAGE diff --git a/src/Magento/FunctionalTestingFramework/Suite/etc/mergedSuiteSchema.xsd b/src/Magento/FunctionalTestingFramework/Suite/etc/mergedSuiteSchema.xsd new file mode 100644 index 000000000..b36e35517 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Suite/etc/mergedSuiteSchema.xsd @@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <xs:include schemaLocation="../../Test/etc/testSchema.xsd"/> + <xs:element name="suites" type="suiteConfigType"/> + <xs:complexType name="groupSuiteOptionType"> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute type="xs:string" name="name" use="required"/> + <xs:attribute type="xs:boolean" name="remove" use="optional"/> + </xs:extension> + </xs:simpleContent> + </xs:complexType> + <xs:complexType name="testSuiteOptionType"> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute type="xs:string" name="name" use="required"/> + <xs:attribute type="xs:boolean" name="remove" use="optional"/> + </xs:extension> + </xs:simpleContent> + </xs:complexType> + <xs:complexType name="moduleSuiteOptionType"> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute type="xs:string" name="name" use="optional"/> + <xs:attribute type="xs:string" name="file" use="optional"/> + <xs:attribute type="xs:boolean" name="remove" use="optional"/> + </xs:extension> + </xs:simpleContent> + </xs:complexType> + <xs:complexType name="includeType"> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element type="groupSuiteOptionType" name="group" minOccurs="0"/> + <xs:element type="testSuiteOptionType" name="test" minOccurs="0"/> + <xs:element type="moduleSuiteOptionType" name="module" minOccurs="0"/> + </xs:choice> + </xs:complexType> + <xs:complexType name="excludeType"> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element type="groupSuiteOptionType" name="group" minOccurs="0"/> + <xs:element type="testSuiteOptionType" name="test" minOccurs="0"/> + <xs:element type="moduleSuiteOptionType" name="module" minOccurs="0"/> + </xs:choice> + </xs:complexType> + <!--<xs:complexType name="suiteHookType">--> + <!--<xs:choice minOccurs="0" maxOccurs="unbounded">--> + <!--<xs:group ref="dataOperationTags" maxOccurs="unbounded" minOccurs="0"/>--> + <!--</xs:choice>--> + <!--</xs:complexType>--> + <xs:complexType name="suiteType"> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element type="includeType" name="include" maxOccurs="1"/> + <xs:element type="excludeType" name="exclude" maxOccurs="1"/> + <xs:element type="hookType" name="before" maxOccurs="1"/> + <xs:element type="hookType" name="after" maxOccurs="1"/> + </xs:choice> + <xs:attribute type="xs:string" name="name"/> + <xs:attribute type="xs:string" name="deprecated"> + <xs:annotation> + <xs:documentation> + Message and flag which shows that entity is deprecated. + </xs:documentation> + </xs:annotation> + </xs:attribute> + </xs:complexType> + <xs:complexType name="suiteConfigType"> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element type="suiteType" name="suite"/> + </xs:choice> + </xs:complexType> +</xs:schema> diff --git a/src/Magento/FunctionalTestingFramework/Suite/etc/suiteSchema.xsd b/src/Magento/FunctionalTestingFramework/Suite/etc/suiteSchema.xsd index b36e35517..8dc9d573d 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/etc/suiteSchema.xsd +++ b/src/Magento/FunctionalTestingFramework/Suite/etc/suiteSchema.xsd @@ -7,71 +7,11 @@ --> <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"> - <xs:include schemaLocation="../../Test/etc/testSchema.xsd"/> - <xs:element name="suites" type="suiteConfigType"/> - <xs:complexType name="groupSuiteOptionType"> - <xs:simpleContent> - <xs:extension base="xs:string"> - <xs:attribute type="xs:string" name="name" use="required"/> - <xs:attribute type="xs:boolean" name="remove" use="optional"/> - </xs:extension> - </xs:simpleContent> - </xs:complexType> - <xs:complexType name="testSuiteOptionType"> - <xs:simpleContent> - <xs:extension base="xs:string"> - <xs:attribute type="xs:string" name="name" use="required"/> - <xs:attribute type="xs:boolean" name="remove" use="optional"/> - </xs:extension> - </xs:simpleContent> - </xs:complexType> - <xs:complexType name="moduleSuiteOptionType"> - <xs:simpleContent> - <xs:extension base="xs:string"> - <xs:attribute type="xs:string" name="name" use="optional"/> - <xs:attribute type="xs:string" name="file" use="optional"/> - <xs:attribute type="xs:boolean" name="remove" use="optional"/> - </xs:extension> - </xs:simpleContent> - </xs:complexType> - <xs:complexType name="includeType"> - <xs:choice minOccurs="0" maxOccurs="unbounded"> - <xs:element type="groupSuiteOptionType" name="group" minOccurs="0"/> - <xs:element type="testSuiteOptionType" name="test" minOccurs="0"/> - <xs:element type="moduleSuiteOptionType" name="module" minOccurs="0"/> - </xs:choice> - </xs:complexType> - <xs:complexType name="excludeType"> - <xs:choice minOccurs="0" maxOccurs="unbounded"> - <xs:element type="groupSuiteOptionType" name="group" minOccurs="0"/> - <xs:element type="testSuiteOptionType" name="test" minOccurs="0"/> - <xs:element type="moduleSuiteOptionType" name="module" minOccurs="0"/> - </xs:choice> - </xs:complexType> - <!--<xs:complexType name="suiteHookType">--> - <!--<xs:choice minOccurs="0" maxOccurs="unbounded">--> - <!--<xs:group ref="dataOperationTags" maxOccurs="unbounded" minOccurs="0"/>--> - <!--</xs:choice>--> - <!--</xs:complexType>--> - <xs:complexType name="suiteType"> - <xs:choice minOccurs="0" maxOccurs="unbounded"> - <xs:element type="includeType" name="include" maxOccurs="1"/> - <xs:element type="excludeType" name="exclude" maxOccurs="1"/> - <xs:element type="hookType" name="before" maxOccurs="1"/> - <xs:element type="hookType" name="after" maxOccurs="1"/> - </xs:choice> - <xs:attribute type="xs:string" name="name"/> - <xs:attribute type="xs:string" name="deprecated"> - <xs:annotation> - <xs:documentation> - Message and flag which shows that entity is deprecated. - </xs:documentation> - </xs:annotation> - </xs:attribute> - </xs:complexType> - <xs:complexType name="suiteConfigType"> - <xs:choice minOccurs="0" maxOccurs="unbounded"> - <xs:element type="suiteType" name="suite"/> - </xs:choice> - </xs:complexType> + <xs:redefine schemaLocation="mergedSuiteSchema.xsd"> + <xs:complexType name="suiteConfigType"> + <xs:choice minOccurs="0" maxOccurs="1"> + <xs:element type="suiteType" name="suite"/> + </xs:choice> + </xs:complexType> + </xs:redefine> </xs:schema> diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd index bd32ba879..2638722d8 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd @@ -7,54 +7,11 @@ --> <xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"> - <xs:include schemaLocation="../../Test/etc/actionTypeTags.xsd"/> - <xs:element name="actionGroups" type="actionGroupType"/> - <xs:complexType name="actionGroupType"> - <xs:choice minOccurs="0" maxOccurs="unbounded"> - <xs:element type="actionsRefType" name="actionGroup" maxOccurs="unbounded"/> - </xs:choice> - </xs:complexType> - <xs:complexType name="actionsRefType"> - <xs:choice minOccurs="0" maxOccurs="unbounded"> - <xs:group ref="actionTypeTags"/> - <xs:element name="arguments"> - <xs:complexType> - <xs:sequence> - <xs:element name="argument" maxOccurs="unbounded" minOccurs="0"> - <xs:complexType> - <xs:attribute type="xs:string" name="name" use="required"/> - <xs:attribute type="xs:string" name="defaultValue"/> - <xs:attribute type="dataTypeEnum" name="type" default="entity"/> - </xs:complexType> - </xs:element> - </xs:sequence> - </xs:complexType> - </xs:element> - <xs:element name="annotations"> - <xs:complexType> - <xs:sequence> - <xs:element name="description"/> - </xs:sequence> - </xs:complexType> - </xs:element> - </xs:choice> - <xs:attribute type="xs:string" name="name" use="required"/> - <xs:attribute type="xs:string" name="filename"/> - <xs:attribute type="xs:string" name="insertBefore"/> - <xs:attribute type="xs:string" name="insertAfter"/> - <xs:attribute type="xs:string" name="extends"/> - <xs:attribute type="xs:string" name="deprecated"> - <xs:annotation> - <xs:documentation> - Message and flag which shows that entity is deprecated. - </xs:documentation> - </xs:annotation> - </xs:attribute> - </xs:complexType> - <xs:simpleType name="dataTypeEnum" final="restriction"> - <xs:restriction base="xs:string"> - <xs:enumeration value="string"/> - <xs:enumeration value="entity"/> - </xs:restriction> - </xs:simpleType> + <xs:redefine schemaLocation="mergedActionGroupSchema.xsd"> + <xs:complexType name="actionGroupType"> + <xs:choice minOccurs="0" maxOccurs="1"> + <xs:element type="actionsRefType" name="actionGroup" maxOccurs="1"/> + </xs:choice> + </xs:complexType> + </xs:redefine> </xs:schema> diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/mergedActionGroupSchema.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/mergedActionGroupSchema.xsd new file mode 100644 index 000000000..bd32ba879 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Test/etc/mergedActionGroupSchema.xsd @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <xs:include schemaLocation="../../Test/etc/actionTypeTags.xsd"/> + <xs:element name="actionGroups" type="actionGroupType"/> + <xs:complexType name="actionGroupType"> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element type="actionsRefType" name="actionGroup" maxOccurs="unbounded"/> + </xs:choice> + </xs:complexType> + <xs:complexType name="actionsRefType"> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:group ref="actionTypeTags"/> + <xs:element name="arguments"> + <xs:complexType> + <xs:sequence> + <xs:element name="argument" maxOccurs="unbounded" minOccurs="0"> + <xs:complexType> + <xs:attribute type="xs:string" name="name" use="required"/> + <xs:attribute type="xs:string" name="defaultValue"/> + <xs:attribute type="dataTypeEnum" name="type" default="entity"/> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + </xs:element> + <xs:element name="annotations"> + <xs:complexType> + <xs:sequence> + <xs:element name="description"/> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:choice> + <xs:attribute type="xs:string" name="name" use="required"/> + <xs:attribute type="xs:string" name="filename"/> + <xs:attribute type="xs:string" name="insertBefore"/> + <xs:attribute type="xs:string" name="insertAfter"/> + <xs:attribute type="xs:string" name="extends"/> + <xs:attribute type="xs:string" name="deprecated"> + <xs:annotation> + <xs:documentation> + Message and flag which shows that entity is deprecated. + </xs:documentation> + </xs:annotation> + </xs:attribute> + </xs:complexType> + <xs:simpleType name="dataTypeEnum" final="restriction"> + <xs:restriction base="xs:string"> + <xs:enumeration value="string"/> + <xs:enumeration value="entity"/> + </xs:restriction> + </xs:simpleType> +</xs:schema> diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd index f9b09a86f..8fce6e63e 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd @@ -12,7 +12,7 @@ <xs:complexContent> <xs:restriction base="configType"> <xs:choice> - <xs:element type="testType" name="test" maxOccurs="unbounded"> + <xs:element type="testType" name="test" maxOccurs="1"> <xs:unique name="uniqueStepKeyInTestBlock"> <xs:annotation> <xs:documentation> diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php b/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php new file mode 100644 index 000000000..7da20524b --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php @@ -0,0 +1,216 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\FunctionalTestingFramework\Upgrade; + +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\Script\ScriptUtil; +use PHP_CodeSniffer\Exceptions\DeepExitException; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Class SplitMultipleEntitiesFiles + * @package Magento\FunctionalTestingFramework\Upgrade + */ +class SplitMultipleEntitiesFiles implements UpgradeInterface +{ + const XML_VERSION = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL; + const XML_COPYRIGHT = '<!--' . PHP_EOL + . ' /**' . PHP_EOL + . ' * Copyright © Magento, Inc. All rights reserved.' . PHP_EOL + . ' * See COPYING.txt for license details.' . PHP_EOL + . ' */' . PHP_EOL + . '-->' . PHP_EOL; + const XML_NAMESPACE = 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' . PHP_EOL; + const XML_SCHEMA_LOCATION = "\t" . 'xsi:noNamespaceSchemaLocation="urn:magento:mftf:'; + + const FILENAME_BASE = 'base'; + const FILENAME_SUFFIX = 'type'; + + /** + * Entity categories for the upgrade script + * + * @var array + */ + private $entityCategories = [ + 'Suite' => 'Suite/etc/suiteSchema.xsd', + 'Test' => 'Test/etc/testSchema.xsd', + 'ActionGroup' => 'Test/etc/actionGroupSchema.xsd', + 'Page' => 'Page/etc/PageObject.xsd', + 'Section' => 'Page/etc/SectionObject.xsd', + ]; + + /** + * Scan all test xml files and split xml files that contains more than one entities + * for Test, Action Group, Page, Section, Suite types. + * + * @param InputInterface $input + * @param OutputInterface $output + * @return string + * @throws TestFrameworkException + */ + public function execute(InputInterface $input, OutputInterface $output) + { + $testsUpdated = 0; + $allModulePaths = ScriptUtil::getAllModulePaths(); + foreach ($this->entityCategories as $type => $urn) { + $xmlFiles = ScriptUtil::buildFileList( + $allModulePaths, + DIRECTORY_SEPARATOR . $type . DIRECTORY_SEPARATOR + ); + + foreach ($xmlFiles as $file) { + $contents = $file->getContents(); + $entityContents = $this->getEntityContents($contents, $type); + if (count($entityContents) > 1) { + $filename = $file->getRealPath(); + $output->writeln('Processing file:' . $filename); + foreach ($entityContents as $entityName => $entityContent) { + $dir = dirname($file); + $dir .= DIRECTORY_SEPARATOR . ucfirst(basename($file, '.xml')); + $splitFileName = $this->formatName($entityName, $type); + $this->filePutContents( + $dir . DIRECTORY_SEPARATOR . $splitFileName . '.xml', + $type, + $urn, + $entityContent + ); + $output->writeln( + 'Created file:' . $dir . DIRECTORY_SEPARATOR . $splitFileName . '.xml' + ); + $testsUpdated++; + } + unlink($file); + $output->writeln('Unlinked file:' . $filename . PHP_EOL); + } + } + } + return ("Split multiple entities in {$testsUpdated} file(s)."); + } + + /** + * Parse contents and return array of single entity content according to entity type + * + * @param string $contents + * @param string $type + * @return array + */ + private function getEntityContents($contents, $type) + { + $pattern = '/[\S\s]+\n(?<entity>[\s]+<' . lcfirst($type) + . '[ \t]+name="(?<name>[^\W]+)"[\S\s]+<\/'. lcfirst($type) . '>)+[\S\s]+/'; + preg_match($pattern, $contents, $matches); + if (isset($matches['entity']) && isset($matches['name'])) { + $contents = str_replace($matches['entity'], '', $contents); + $entityContents[$matches['name']] = $matches['entity']; + if (!empty($this->getEntityContents($contents, $type))) { + $entityContents = array_merge($entityContents, $this->getEntityContents($contents, $type)); + } + return $entityContents; + } else { + return []; + } + } + + /** + * Create file with contents and create dir if needed + * + * @param string $fullPath + * @param string $type + * @param string $urn + * @param string $contents + * @return void + */ + private function filePutContents($fullPath, $type, $urn, $contents) + { + $dir = dirname($fullPath); + + if (!is_dir($dir)) { + mkdir($dir, 0777, true); + } + + $fullPath = $this->getNonExistingFileFullPath($fullPath, $type); + + $fullContents = self::XML_VERSION + . self::XML_COPYRIGHT + . '<' . lcfirst($type) . 's ' + . self::XML_NAMESPACE + . self::XML_SCHEMA_LOCATION . $urn . '">' . PHP_EOL + . $contents . PHP_EOL + . '</' . lcfirst($type) . 's>' . PHP_EOL; + + file_put_contents($fullPath, $fullContents); + } + + /** + * Format name to include type if it's Page, Section or Action Group + * + * @param string $name + * @param string $type + * @return string + */ + private function formatName($name, $type) + { + $name = ucfirst($name); + $type = ucfirst($type); + + if ($type !== 'Section' && $type !== 'Page' && $type !== 'ActionGroup') { + return $name; + } + + $parts = $this->getFileNameParts($name, $type); + if (empty($parts[self::FILENAME_SUFFIX])) { + $name .= $type; + } + return $name; + } + + /** + * Vary the input to return a non-existing file name + * + * @param string $fullPath + * @param string $type + * @return string + */ + private function getNonExistingFileFullPath($fullPath, $type) + { + $type = ucfirst($type); + $dir = dirname($fullPath); + $filename = basename($fullPath, '.xml'); + $i = 1; + $parts = []; + while (file_exists($fullPath)) { + if (empty($parts)) { + $parts = $this->getFileNameParts($filename, $type); + } + $basename = $parts[self::FILENAME_BASE] . strval(++$i); + $fullPath = $dir . DIRECTORY_SEPARATOR . $basename . $parts[self::FILENAME_SUFFIX] . '.xml'; + } + return $fullPath; + } + + /** + * Split filename into two parts and return it in an associate array with keys FILENAME_BASE and FILENAME_SUFFIX + * + * @param string $filename + * @param string $type + * @return array + */ + private function getFileNameParts($filename, $type) + { + $type = ucfirst($type); + $fileNameParts = []; + if (substr($filename, -strlen($type)) === $type) { + $fileNameParts[self::FILENAME_BASE] = substr($filename, 0, strlen($filename) - strlen($type)); + $fileNameParts[self::FILENAME_SUFFIX] = $type; + } else { + $fileNameParts[self::FILENAME_BASE] = $filename; + $fileNameParts[self::FILENAME_SUFFIX] = ''; + } + return $fileNameParts; + } +} diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateTestSchemaPaths.php b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateTestSchemaPaths.php index 8b79b6019..901212f0e 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateTestSchemaPaths.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateTestSchemaPaths.php @@ -6,9 +6,12 @@ namespace Magento\FunctionalTestingFramework\Upgrade; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\Script\ScriptUtil; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Finder\Finder; +use Symfony\Component\Console\Output\OutputInterface; /** * Class UpdateTestSchemaPaths @@ -19,10 +22,12 @@ class UpdateTestSchemaPaths implements UpgradeInterface /** * Upgrades all test xml files, replacing relative schema paths to URN. * - * @param InputInterface $input + * @param InputInterface $input + * @param OutputInterface $output * @return string + * @throws TestFrameworkException */ - public function execute(InputInterface $input) + public function execute(InputInterface $input, OutputInterface $output) { // @codingStandardsIgnoreStart $relativeToUrn = [ @@ -52,19 +57,21 @@ public function execute(InputInterface $input) $urns[] = $urn; } - $testsPath = $input->getArgument('path'); - $finder = new Finder(); - $finder->files()->in($testsPath)->name("*.xml"); - - $fileSystem = new Filesystem(); $testsUpdated = 0; - foreach ($finder->files() as $file) { - $count = 0; - $contents = $file->getContents(); - $contents = preg_replace($relativePatterns, $urns, $contents, -1, $count); - $fileSystem->dumpFile($file->getRealPath(), $contents); - if ($count > 0) { - $testsUpdated++; + $allModulePaths = ScriptUtil::getAllModulePaths(); + foreach ($allModulePaths as $testsPath) { + $finder = new Finder(); + $finder->files()->in($testsPath)->name("*.xml"); + + $fileSystem = new Filesystem(); + foreach ($finder->files() as $file) { + $count = 0; + $contents = $file->getContents(); + $contents = preg_replace($relativePatterns, $urns, $contents, -1, $count); + $fileSystem->dumpFile($file->getRealPath(), $contents); + if ($count > 0) { + $testsUpdated++; + } } } diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/UpgradeInterface.php b/src/Magento/FunctionalTestingFramework/Upgrade/UpgradeInterface.php index b6905845c..150737bc2 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/UpgradeInterface.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/UpgradeInterface.php @@ -7,6 +7,7 @@ namespace Magento\FunctionalTestingFramework\Upgrade; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; /** * Upgrade script interface @@ -15,8 +16,9 @@ interface UpgradeInterface { /** * Executes upgrade script, returns output. - * @param InputInterface $input + * @param InputInterface $input + * @param OutputInterface $output * @return string */ - public function execute(InputInterface $input); + public function execute(InputInterface $input, OutputInterface $output); } diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/UpgradeScriptList.php b/src/Magento/FunctionalTestingFramework/Upgrade/UpgradeScriptList.php index 245f95d82..3a75402bb 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/UpgradeScriptList.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/UpgradeScriptList.php @@ -29,6 +29,7 @@ public function __construct(array $scripts = []) { $this->scripts = [ 'upgradeTestSchema' => new UpdateTestSchemaPaths(), + 'splitMultipleEntitiesFiles' => new SplitMultipleEntitiesFiles() ] + $scripts; } diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticCheckHelper.php b/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php similarity index 62% rename from src/Magento/FunctionalTestingFramework/StaticCheck/StaticCheckHelper.php rename to src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php index f534544fc..60f8cfa28 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticCheckHelper.php +++ b/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php @@ -3,12 +3,39 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\FunctionalTestingFramework\StaticCheck; +namespace Magento\FunctionalTestingFramework\Util\Script; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Symfony\Component\Finder\Finder; +use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Util\ModuleResolver; -class StaticCheckHelper +/** + * ScriptUtil class that contains helper functions for static and upgrade scripts + * + * @package Magento\FunctionalTestingFramework\Util\Script + */ +class ScriptUtil { + /** + * Return all installed Magento module paths + * + * @return array + * @throws TestFrameworkException + */ + public static function getAllModulePaths() + { + MftfApplicationConfig::create( + true, + MftfApplicationConfig::UNIT_TEST_PHASE, + false, + MftfApplicationConfig::LEVEL_NONE, + true + ); + + return ModuleResolver::getInstance()->getModulesPath(); + } + /** * Prints out given errors to file, and returns summary result string * @param array $errors From b081cf2836e84ea2afac754a22e974a839b8d9b6 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Fri, 21 Feb 2020 16:05:18 -0600 Subject: [PATCH 227/888] MQE-1963: Update XSD Schema to verify that file has only single entity --- etc/di.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/etc/di.xml b/etc/di.xml index 88535706e..8d1e15f23 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -88,7 +88,7 @@ <item name="/pages/page" xsi:type="string">name</item> <item name="/pages/page/section" xsi:type="string">name</item> </argument> - <argument name="fileName" xsi:type="string">*Page.xml</argument> + <argument name="fileName" xsi:type="string">/[\p{L}\p{N}_\-]+Page.xml$/</argument> <argument name="defaultScope" xsi:type="string">Page</argument> </arguments> </virtualType> @@ -102,7 +102,7 @@ <item name="/sections/section" xsi:type="string">name</item> <item name="/sections/section/element" xsi:type="string">name</item> </argument> - <argument name="fileName" xsi:type="string">*Section.xml</argument> + <argument name="fileName" xsi:type="string">/[\p{L}\p{N}_\-]+Section.xml$/</argument> <argument name="defaultScope" xsi:type="string">Section</argument> </arguments> </virtualType> @@ -163,7 +163,7 @@ <item name="/entities/entity/requiredEntity" xsi:type="string"/> <item name="/entities/entity/array" xsi:type="string"/> </argument> - <argument name="fileName" xsi:type="string">*Data.xml</argument> + <argument name="fileName" xsi:type="string">/[\p{L}\p{N}_\-]+Data.xml$/</argument> <argument name="defaultScope" xsi:type="string">Data</argument> </arguments> </virtualType> @@ -198,7 +198,7 @@ <argument name="mergeablePaths" xsi:type="array"> <item name="/operations/operation/object" xsi:type="string"/> </argument> - <argument name="fileName" xsi:type="string">*-meta.xml</argument> + <argument name="fileName" xsi:type="string">/[\p{L}\p{N}_\-]+-meta.xml$/</argument> <argument name="defaultScope" xsi:type="string">Metadata</argument> </arguments> </virtualType> @@ -229,7 +229,7 @@ <item name="/tests/test/(before|after)/(createData|updateData|getData)/field" xsi:type="string">key</item> <item name="/tests/test/annotations(/group)+" xsi:type="string">value</item> </argument> - <argument name="fileName" xsi:type="string">*.xml</argument> + <argument name="fileName" xsi:type="string">/[\p{L}\p{N}_\-]+.xml$/</argument> <argument name="defaultScope" xsi:type="string">Test</argument> </arguments> </virtualType> @@ -304,7 +304,7 @@ <item name="/actionGroups/actionGroup/(createData|updateData|getData)/field" xsi:type="string">key</item> <item name="/actionGroups/actionGroup/remove" xsi:type="string">keyForRemoval</item> </argument> - <argument name="fileName" xsi:type="string">*ActionGroup.xml</argument> + <argument name="fileName" xsi:type="string">/[\p{L}\p{N}_\-]+ActionGroup.xml$/</argument> <argument name="defaultScope" xsi:type="string">ActionGroup</argument> </arguments> </virtualType> @@ -371,7 +371,7 @@ <item name="/suites/suite/include/(group|test|module)" xsi:type="string">name</item> <item name="/suites/suite/exclude/(group|test|module)" xsi:type="string">name</item> </argument> - <argument name="fileName" xsi:type="string">*.xml</argument> + <argument name="fileName" xsi:type="string">/[\p{L}\p{N}_\-]+.xml$/</argument> <argument name="defaultScope" xsi:type="string">Suite</argument> </arguments> </virtualType> From 27f1c6f2820e2d92e53ec18543948c33d7ec0c90 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 24 Feb 2020 16:06:32 -0600 Subject: [PATCH 228/888] MQE-1963: Update XSD Schema to verify that file has only single entity --- docs/commands/mftf.md | 15 ++++++--- etc/di.xml | 2 +- .../Config/FileResolver/Root.php | 31 +++++++++++++------ .../Console/UpgradeTestsCommand.php | 7 +++-- .../Upgrade/SplitMultipleEntitiesFiles.php | 8 +++-- .../Upgrade/UpdateTestSchemaPaths.php | 8 +++-- .../Util/ModulePathExtractor.php | 2 +- .../Util/Script/ScriptUtil.php | 12 +++++-- 8 files changed, 62 insertions(+), 23 deletions(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index b2c36dae4..2eef575ac 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -28,7 +28,7 @@ vendor/bin/mftf build:project vendor/bin/mftf build:project --upgrade ``` -Upgrades the existing MFTF tests after the MFTF major upgrade. +Upgrades the all installed MFTF tests after the MFTF major upgrade. ### Generate all tests @@ -115,7 +115,7 @@ vendor/bin/mftf build:project [--upgrade] [config_param_options] | Option | Description | | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `-u`, `--upgrade` | Upgrades existing MFTF tests according to requirements of the last major release. Specifying this flag upgrades only those tests in the default location. Example: `build:project --upgrade`. | +| `-u`, `--upgrade` | Upgrades all installed MFTF tests according to requirements of the last major release. Specifying this flag upgrades only those tests in the default location. Example: `build:project --upgrade`. | You can include options to set configuration parameter values for your environment since the project build process also [sets up the environment][setup]. @@ -505,12 +505,13 @@ vendor/bin/mftf static-checks testDependencies actionGroupArguments ### `upgrade:tests` -Applies all the MFTF major version upgrade scripts to test components in the given path (`test.xml`, `data.xml`, etc). +When path argument is specified, this command will apply all the MFTF major version upgrade scripts to test components in the given path (`test.xml`, `data.xml`, etc); +otherwise it will apply all the MFTF major version upgrade scripts to all installed test components. #### Usage ```bash -vendor/bin/mftf upgrade:tests <path> +vendor/bin/mftf upgrade:tests [<path>] ``` `<path>` is the path that contains MFTF test components that need to be upgraded. @@ -518,6 +519,12 @@ The command searches recursively for any `*.xml` files to upgrade. #### Examples +To upgrade all installed MFTF tests + +```bash +vendor/bin/mftf upgrade:tests +``` + To upgrade all test components inside modules in the `dev/tests/acceptance/tests/` directory: ```bash diff --git a/etc/di.xml b/etc/di.xml index 8d1e15f23..08a96f32e 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -80,7 +80,7 @@ </virtualType> <virtualType name="Magento\FunctionalTestingFramework\Config\Reader\Page" type="Magento\FunctionalTestingFramework\Config\Reader\MftfFilesystem"> <arguments> - <argument name="fileResolver" xsi:type="object">Magento\FunctionalTestingFramework\Config\FileResolver\Module</argument> + <argument name="fileResolver" xsi:type="object">Magento\FunctionalTestingFramework\Config\FileResolver\Mask</argument> <argument name="converter" xsi:type="object">Magento\FunctionalTestingFramework\Config\Converter</argument> <argument name="schemaLocator" xsi:type="object">Magento\FunctionalTestingFramework\Config\SchemaLocator\Page</argument> <argument name="domDocumentClass" xsi:type="string">Magento\FunctionalTestingFramework\Page\Config\Dom</argument> diff --git a/src/Magento/FunctionalTestingFramework/Config/FileResolver/Root.php b/src/Magento/FunctionalTestingFramework/Config/FileResolver/Root.php index 4ebb11942..eaabed4db 100644 --- a/src/Magento/FunctionalTestingFramework/Config/FileResolver/Root.php +++ b/src/Magento/FunctionalTestingFramework/Config/FileResolver/Root.php @@ -11,7 +11,7 @@ use Magento\FunctionalTestingFramework\Util\Iterator\File; use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; -class Root extends Module +class Root extends Mask { const ROOT_SUITE_DIR = "tests/_suite"; @@ -26,16 +26,29 @@ class Root extends Module */ public function get($filename, $scope) { - // first pick up the root level test suite dir - $paths = glob( - FilePathFormatter::format(TESTS_BP) . self::ROOT_SUITE_DIR - . DIRECTORY_SEPARATOR . $filename - ); + // First pick up the root level test suite dir + $paths = []; + $dir = FilePathFormatter::format(TESTS_BP) . self::ROOT_SUITE_DIR; + if (is_readable($dir)) { + $directoryIterator = new \RecursiveIteratorIterator( + new \RecursiveDirectoryIterator( + $dir, + \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS + ) + ); + $regexpIterator = new \RegexIterator($directoryIterator, $filename); + /** @var \SplFileInfo $file */ + foreach ($regexpIterator as $file) { + if ($file->isFile() && $file->isReadable()) { + $paths[] = $file->getRealPath(); + } + } + } - // then merge this path into the module based paths - // Since we are sharing this code with Module based resolution we will unncessarily glob against modules in the + // Then merge this path into the module based paths + // Since we are sharing this code with Module based resolution we will unnecessarily glob against modules in the // dev/tests dir tree, however as we plan to migrate to app/code this will be a temporary unneeded check. - $paths = array_merge($paths, $this->getPaths($filename, $scope)); + $paths = array_merge($paths, $this->getFileCollection($filename, $scope)); // create and return the iterator for these file paths $iterator = new File($paths); diff --git a/src/Magento/FunctionalTestingFramework/Console/UpgradeTestsCommand.php b/src/Magento/FunctionalTestingFramework/Console/UpgradeTestsCommand.php index c302fdd37..526ab4903 100644 --- a/src/Magento/FunctionalTestingFramework/Console/UpgradeTestsCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/UpgradeTestsCommand.php @@ -33,8 +33,11 @@ protected function configure() { $this->setName('upgrade:tests') ->setDescription( - 'This command will upgrade all installed mftf tests according to new MFTF Major version requirements.' - ); + 'This command will upgrade MFTF tests according to new MFTF Major version requirements. ' + . 'It will upgrade MFTF tests in specific path when "path" argument is specified, otherwise it will ' + . 'upgrade all MFTF tests installed.' + ) + ->addArgument('path', InputArgument::OPTIONAL, 'path to MFTF tests to upgrade'); $this->upgradeScriptsList = new UpgradeScriptList(); } diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php b/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php index 7da20524b..7f1124717 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php @@ -56,10 +56,14 @@ class SplitMultipleEntitiesFiles implements UpgradeInterface public function execute(InputInterface $input, OutputInterface $output) { $testsUpdated = 0; - $allModulePaths = ScriptUtil::getAllModulePaths(); + $testPaths[] = $input->getArgument('path'); + if (empty($testPaths[0])) { + $testPaths = ScriptUtil::getAllModulePaths(); + } + foreach ($this->entityCategories as $type => $urn) { $xmlFiles = ScriptUtil::buildFileList( - $allModulePaths, + $testPaths, DIRECTORY_SEPARATOR . $type . DIRECTORY_SEPARATOR ); diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateTestSchemaPaths.php b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateTestSchemaPaths.php index 901212f0e..7a08b39df 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateTestSchemaPaths.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateTestSchemaPaths.php @@ -58,8 +58,12 @@ public function execute(InputInterface $input, OutputInterface $output) } $testsUpdated = 0; - $allModulePaths = ScriptUtil::getAllModulePaths(); - foreach ($allModulePaths as $testsPath) { + $testPaths[] = $input->getArgument('path'); + if (empty($testPaths[0])) { + $testPaths = ScriptUtil::getAllModulePaths(); + } + + foreach ($testPaths as $testsPath) { $finder = new Finder(); $finder->files()->in($testsPath)->name("*.xml"); diff --git a/src/Magento/FunctionalTestingFramework/Util/ModulePathExtractor.php b/src/Magento/FunctionalTestingFramework/Util/ModulePathExtractor.php index 80b556f9a..b7386a586 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModulePathExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModulePathExtractor.php @@ -90,7 +90,7 @@ private function extractKeyByPath($path) } foreach ($this->testModulePaths as $key => $value) { - if ($value == $shortenedPath) { + if (substr($path, 0, strlen($value)) == $value) { return $key; } } diff --git a/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php b/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php index 60f8cfa28..f53578c39 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php @@ -65,19 +65,27 @@ public static function printErrorsToFile($errors, $filename, $message) /** * Builds list of all XML files in given modulePaths + path given + * Return empty array if Finder is not run + * * @param array $modulePaths * @param string $path - * @return Finder + * @return Finder|array */ public static function buildFileList($modulePaths, $path) { + $finderRun = false; $finder = new Finder(); foreach ($modulePaths as $modulePath) { if (!realpath($modulePath . $path)) { continue; } $finder->files()->in($modulePath . $path)->name("*.xml"); + $finderRun = true; + } + if ($finderRun) { + return $finder->files(); + } else { + return []; } - return $finder->files(); } } From fd1d845f38e963fdb42d3322540e203155c9ba77 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Tue, 25 Feb 2020 16:23:21 -0600 Subject: [PATCH 229/888] MQE-2008: Filter test generation and execution by severity --- .../DevDocs/Test/DeprecatedDevDocsTest.xml | 2 +- .../Suite/Handlers/SuiteObjectHandlerTest.php | 2 +- .../Suite/SuiteGeneratorTest.php | 8 +- .../Test/Handlers/TestObjectHandlerTest.php | 10 +-- .../Test/Util/ObjectExtensionUtilTest.php | 8 +- .../Config/MftfApplicationConfig.php | 36 ++++++++- .../Console/GenerateTestsCommand.php | 74 ++++++++++++++----- .../Filter/FilterInterface.php | 27 +++++++ .../Filter/FilterList.php | 57 ++++++++++++++ .../Filter/Test/Severity.php | 69 +++++++++++++++++ .../Suite/Objects/SuiteObject.php | 10 ++- .../Test/Handlers/TestObjectHandler.php | 4 +- .../Test/Parsers/TestDataParser.php | 33 ++++++++- .../Util/Logger/MftfLogger.php | 19 +++++ 14 files changed, 315 insertions(+), 44 deletions(-) create mode 100644 src/Magento/FunctionalTestingFramework/Filter/FilterInterface.php create mode 100644 src/Magento/FunctionalTestingFramework/Filter/FilterList.php create mode 100644 src/Magento/FunctionalTestingFramework/Filter/Test/Severity.php diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Test/DeprecatedDevDocsTest.xml b/dev/tests/functional/tests/MFTF/DevDocs/Test/DeprecatedDevDocsTest.xml index bf0078df4..c93dc8011 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Test/DeprecatedDevDocsTest.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/Test/DeprecatedDevDocsTest.xml @@ -15,7 +15,7 @@ <stories value="[Deprecated] MFTF DevDocs available"/> <title value="[Deprecated] Magento Functional Testing Framework Documentation is available."/> <description value="[Deprecated] Magento Functional Testing Framework Documentation is available."/> - <severity value="CRITICAL"/> + <severity value="MINOR"/> <group value="mftf"/> </annotations> diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/Handlers/SuiteObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/Handlers/SuiteObjectHandlerTest.php index 5bf29507c..e45127f4c 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/Handlers/SuiteObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/Handlers/SuiteObjectHandlerTest.php @@ -65,7 +65,7 @@ public function testGetSuiteObject() ->withTestActions() ->build(); - $mockTestData = ['tests' => array_merge($mockSimpleTest, $mockGroup1Test1, $mockGroup1Test2, $mockGroup2Test1)]; + $mockTestData = array_merge($mockSimpleTest, $mockGroup1Test1, $mockGroup1Test2, $mockGroup2Test1); $this->setMockTestAndSuiteParserOutput($mockTestData, $mockData); // parse and retrieve suite object with mocked data diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php index e3f820ede..842be4f88 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php @@ -69,7 +69,7 @@ public function testGenerateSuite() ->withTestActions() ->build(); - $mockTestData = ['tests' => array_merge($mockSimpleTest)]; + $mockTestData = array_merge($mockSimpleTest); $this->setMockTestAndSuiteParserOutput($mockTestData, $mockData); // parse and generate suite object with mocked data @@ -105,7 +105,7 @@ public function testGenerateAllSuites() ->withTestActions() ->build(); - $mockTestData = ['tests' => array_merge($mockSimpleTest)]; + $mockTestData = array_merge($mockSimpleTest); $this->setMockTestAndSuiteParserOutput($mockTestData, $mockData); // parse and retrieve suite object with mocked data @@ -172,7 +172,7 @@ public function testInvalidSuiteTestPair() ->withAnnotations(['group' => [['value' => 'group2']]]) ->withTestActions() ->build(); - $mockTestData = ['tests' => array_merge($mockSimpleTest, $mockSimpleTest2)]; + $mockTestData = array_merge($mockSimpleTest, $mockSimpleTest2); $this->setMockTestAndSuiteParserOutput($mockTestData, $mockSuiteData); // Make invalid manifest @@ -196,7 +196,7 @@ public function testNonExistentSuiteTestPair() ->withAnnotations(['group' => [['value' => 'group1']]]) ->withTestActions() ->build(); - $mockTestData = ['tests' => array_merge($mockSimpleTest)]; + $mockTestData = array_merge($mockSimpleTest); $this->setMockTestAndSuiteParserOutput($mockTestData, []); // Make invalid manifest diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php index 67f6f2b43..a4504ab07 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php @@ -41,7 +41,7 @@ public function testGetTestObject() $resolverMock = new MockModuleResolverBuilder(); $resolverMock->setup(); - $this->setMockParserOutput(['tests' => $mockData]); + $this->setMockParserOutput($mockData); // run object handler method $toh = TestObjectHandler::getInstance(); @@ -135,7 +135,7 @@ public function testGetTestsByGroup() $resolverMock = new MockModuleResolverBuilder(); $resolverMock->setup(); - $this->setMockParserOutput(['tests' => array_merge($includeTest, $excludeTest)]); + $this->setMockParserOutput(array_merge($includeTest, $excludeTest)); // execute test method $toh = TestObjectHandler::getInstance(); @@ -184,7 +184,7 @@ public function testGetTestWithModuleName() $resolverMock = new MockModuleResolverBuilder(); $resolverMock->setup(['Vendor_' . $moduleExpected => $filepath]); - $this->setMockParserOutput(['tests' => $mockData]); + $this->setMockParserOutput($mockData); // Execute Test Method $toh = TestObjectHandler::getInstance(); $actualTestObject = $toh->getObject($testDataArrayBuilder->testName); @@ -212,7 +212,7 @@ public function testGetTestObjectWithInvalidExtends() ->build(); $resolverMock = new MockModuleResolverBuilder(); $resolverMock->setup(); - $this->setMockParserOutput(['tests' => $testOne]); + $this->setMockParserOutput($testOne); $toh = TestObjectHandler::getInstance(); @@ -250,7 +250,7 @@ public function testGetAllTestObjectsWithInvalidExtends() $resolverMock = new MockModuleResolverBuilder(); $resolverMock->setup(); - $this->setMockParserOutput(['tests' => array_merge($testOne, $testTwo)]); + $this->setMockParserOutput(array_merge($testOne, $testTwo)); $toh = TestObjectHandler::getInstance(); diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ObjectExtensionUtilTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ObjectExtensionUtilTest.php index d86185b83..9982b8040 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ObjectExtensionUtilTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ObjectExtensionUtilTest.php @@ -67,7 +67,7 @@ public function testGenerateExtendedTest() ->withTestReference("simpleTest") ->build(); - $mockTestData = ['tests' => array_merge($mockSimpleTest, $mockExtendedTest)]; + $mockTestData = array_merge($mockSimpleTest, $mockExtendedTest); $this->setMockTestOutput($mockTestData); // parse and generate test object with mocked data @@ -112,7 +112,7 @@ public function testGenerateExtendedWithHooks() ->withTestReference("simpleTest") ->build(); - $mockTestData = ['tests' => array_merge($mockSimpleTest, $mockExtendedTest)]; + $mockTestData = array_merge($mockSimpleTest, $mockExtendedTest); $this->setMockTestOutput($mockTestData); // parse and generate test object with mocked data @@ -143,7 +143,7 @@ public function testExtendedTestNoParent() ->withTestReference("simpleTest") ->build(); - $mockTestData = ['tests' => array_merge($mockExtendedTest)]; + $mockTestData = array_merge($mockExtendedTest); $this->setMockTestOutput($mockTestData); // parse and generate test object with mocked data @@ -182,7 +182,7 @@ public function testExtendingExtendedTest() ->withTestReference("simpleTest") ->build(); - $mockTestData = ['tests' => array_merge($mockParentTest, $mockSimpleTest, $mockExtendedTest)]; + $mockTestData = array_merge($mockParentTest, $mockSimpleTest, $mockExtendedTest); $this->setMockTestOutput($mockTestData); $this->expectExceptionMessage("Cannot extend a test that already extends another test. Test: simpleTest"); diff --git a/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php b/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php index 80db27de0..4b215cb4f 100644 --- a/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php +++ b/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php @@ -6,6 +6,7 @@ namespace Magento\FunctionalTestingFramework\Config; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Filter\FilterList; class MftfApplicationConfig { @@ -25,6 +26,13 @@ class MftfApplicationConfig const LEVEL_NONE = "none"; const MFTF_DEBUG_LEVEL = [self::LEVEL_DEFAULT, self::LEVEL_DEVELOPER, self::LEVEL_NONE]; + /** + * Contains object with test filters. + * + * @var FilterList + */ + private $filterList; + /** * Determines whether the user has specified a force option for generation * @@ -74,6 +82,7 @@ class MftfApplicationConfig * @param boolean $verboseEnabled * @param string $debugLevel * @param boolean $allowSkipped + * @param array $filters * @throws TestFrameworkException */ private function __construct( @@ -81,7 +90,8 @@ private function __construct( $phase = self::EXECUTION_PHASE, $verboseEnabled = null, $debugLevel = self::LEVEL_NONE, - $allowSkipped = false + $allowSkipped = false, + $filters = [] ) { $this->forceGenerate = $forceGenerate; @@ -101,6 +111,7 @@ private function __construct( $this->debugLevel = self::LEVEL_DEVELOPER; } $this->allowSkipped = $allowSkipped; + $this->filterList = new FilterList($filters); } /** @@ -112,6 +123,7 @@ private function __construct( * @param boolean $verboseEnabled * @param string $debugLevel * @param boolean $allowSkipped + * @param array $filters * @return void * @throws TestFrameworkException */ @@ -120,11 +132,19 @@ public static function create( $phase = self::EXECUTION_PHASE, $verboseEnabled = null, $debugLevel = self::LEVEL_NONE, - $allowSkipped = false + $allowSkipped = false, + $filters = [] ) { if (self::$MFTF_APPLICATION_CONTEXT == null) { self::$MFTF_APPLICATION_CONTEXT = - new MftfApplicationConfig($forceGenerate, $phase, $verboseEnabled, $debugLevel, $allowSkipped); + new MftfApplicationConfig( + $forceGenerate, + $phase, + $verboseEnabled, + $debugLevel, + $allowSkipped, + $filters + ); } } @@ -196,4 +216,14 @@ public function getPhase() { return $this->phase; } + + /** + * Returns a class with registered filter list. + * + * @return FilterList + */ + public function getFilterList() + { + return $this->filterList; + } } diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php index b9378edc1..f43488c0b 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php @@ -18,7 +18,11 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +/** + * @SuppressWarnings(PHPMD) + */ class GenerateTestsCommand extends BaseGenerateCommand { /** @@ -30,6 +34,7 @@ protected function configure() { $this->setName('generate:tests') ->setDescription('Run validation and generate all test files and suites based on xml declarations') + ->addUsage('AdminLoginTest') ->addArgument( 'name', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, @@ -46,6 +51,15 @@ protected function configure() 't', InputOption::VALUE_REQUIRED, 'A parameter accepting a JSON string used to determine the test configuration' + )->addOption( + 'filter', + null, + InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, + 'Option to filter tests to be generated.' . PHP_EOL + . '<info>Template:</info> <filterName>:<filterValue>' . PHP_EOL + . '<info>Existing filter types:</info> severity.' . PHP_EOL + . '<info>Existing severity values:</info> BLOCKER, CRITICAL, MAJOR, AVERAGE, MINOR.' . PHP_EOL + . '<info>Example:</info> --filter=severity:CRITICAL' . PHP_EOL ); parent::configure(); @@ -56,13 +70,14 @@ protected function configure() * * @param InputInterface $input * @param OutputInterface $output - * @return void + * @return void|integer * @throws TestFrameworkException * @throws \Magento\FunctionalTestingFramework\Exceptions\TestReferenceException * @throws \Magento\FunctionalTestingFramework\Exceptions\XmlException */ protected function execute(InputInterface $input, OutputInterface $output) { + $ioStyle = new SymfonyStyle($input, $output); $tests = $input->getArgument('name'); $config = $input->getOption('config'); $json = $input->getOption('tests'); // for backward compatibility @@ -72,15 +87,25 @@ protected function execute(InputInterface $input, OutputInterface $output) $remove = $input->getOption('remove'); $verbose = $output->isVerbose(); $allowSkipped = $input->getOption('allow-skipped'); - + $filters = $input->getOption('filter'); + foreach ($filters as $filter) { + list($filterType, $filterValue) = explode(':', $filter); + $filterList[$filterType][] = $filterValue; + } // Set application configuration so we can references the user options in our framework - MftfApplicationConfig::create( - $force, - MftfApplicationConfig::GENERATION_PHASE, - $verbose, - $debug, - $allowSkipped - ); + try { + MftfApplicationConfig::create( + $force, + MftfApplicationConfig::GENERATION_PHASE, + $verbose, + $debug, + $allowSkipped, + $filterList ?? [] + ); + } catch (\Exception $exception) { + $ioStyle->error("Test generation failed." . PHP_EOL . $exception->getMessage()); + return 1; + } $this->setOutputStyle($input, $output); $this->showMftfNotices($output); @@ -105,20 +130,31 @@ protected function execute(InputInterface $input, OutputInterface $output) ($debug !== MftfApplicationConfig::LEVEL_NONE)); } - $testConfiguration = $this->createTestConfiguration($json, $tests); + try { + $testConfiguration = $this->createTestConfiguration($json, $tests); - // create our manifest file here - $testManifest = TestManifestFactory::makeManifest($config, $testConfiguration['suites']); - TestGenerator::getInstance(null, $testConfiguration['tests'])->createAllTestFiles($testManifest); + // create our manifest file here + $testManifest = TestManifestFactory::makeManifest($config, $testConfiguration['suites']); - if ($config == 'parallel') { - /** @var ParallelTestManifest $testManifest */ - $testManifest->createTestGroups($time); - } + TestGenerator::getInstance(null, $testConfiguration['tests'])->createAllTestFiles($testManifest); + + if ($config == 'parallel') { + /** @var ParallelTestManifest $testManifest */ + $testManifest->createTestGroups($time); + } + + SuiteGenerator::getInstance()->generateAllSuites($testManifest); - SuiteGenerator::getInstance()->generateAllSuites($testManifest); + $testManifest->generate(); + } catch (\Exception $e) { + $message = $e->getMessage() . PHP_EOL; + $message .= !empty($filters) ? 'Filter(s): ' . implode(', ', $filters) . PHP_EOL : ''; + $message .= !empty($tests) ? 'Test name(s): ' . implode(', ', $tests) . PHP_EOL : ''; + $message .= !empty($json) && empty($tests) ? 'Test configuration: ' . $json . PHP_EOL : ''; + $ioStyle->note($message); - $testManifest->generate(); + return 1; + } $output->writeln("Generate Tests Command Run"); } diff --git a/src/Magento/FunctionalTestingFramework/Filter/FilterInterface.php b/src/Magento/FunctionalTestingFramework/Filter/FilterInterface.php new file mode 100644 index 000000000..bb89ab3c2 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Filter/FilterInterface.php @@ -0,0 +1,27 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\FunctionalTestingFramework\Filter; + +/** + * Interface for future test filters + * @api + */ +interface FilterInterface +{ + /** + * @param array $filterValues + */ + public function __construct(array $filterValues = []); + + /** + * @param array $tests + * @return void + */ + public function filter(array &$tests); +} diff --git a/src/Magento/FunctionalTestingFramework/Filter/FilterList.php b/src/Magento/FunctionalTestingFramework/Filter/FilterList.php new file mode 100644 index 000000000..35ff32edd --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Filter/FilterList.php @@ -0,0 +1,57 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\FunctionalTestingFramework\Filter; + +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; + +/** + * Class FilterList has a list of filters. + */ +class FilterList +{ + /** + * List of filters + * @var \Magento\FunctionalTestingFramework\Filter\FilterInterface[] + */ + private $filters = []; + + /** + * Constructor for Filter list. + * + * @param array $filters + * @throws \Exception + */ + public function __construct(array $filters = []) + { + foreach ($filters as $filterType => $filterValue) { + $className = "Magento\FunctionalTestingFramework\Filter\Test\\" . ucfirst($filterType); + if (!class_exists($className)) { + throw new TestFrameworkException("Filter type '" . $filterType . "' do not exist."); + } + $this->filters[$filterType] = new $className($filterValue); + } + } + + /** + * @return array + */ + public function getFilters(): array + { + return $this->filters; + } + + /** + * @param string $filterType + * @return \Magento\FunctionalTestingFramework\Filter\FilterInterface + */ + public function getFilter(string $filterType): FilterInterface + { + return $this->filters[$filterType]; + } +} diff --git a/src/Magento/FunctionalTestingFramework/Filter/Test/Severity.php b/src/Magento/FunctionalTestingFramework/Filter/Test/Severity.php new file mode 100644 index 000000000..cfcb82de1 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Filter/Test/Severity.php @@ -0,0 +1,69 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\FunctionalTestingFramework\Filter\Test; + +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Filter\FilterInterface; + +/** + * Class Severity + */ +class Severity implements FilterInterface +{ + const ANNOTATION_TAG = 'severity'; + const SEVERITY_VALUES = [ + "BLOCKER", + "CRITICAL", + "MAJOR", + "AVERAGE", + "MINOR", + ]; + + /** + * @var array + */ + private $filterValues = []; + + /** + * Severity constructor. + * + * @param array $filterValues + * @throws TestFrameworkException + */ + public function __construct(array $filterValues = []) + { + if (array_diff($filterValues, self::SEVERITY_VALUES) ==! []) { + throw new TestFrameworkException( + 'Not existing severity specified.' . PHP_EOL + . 'Possible values: '. implode(', ', self::SEVERITY_VALUES) . '.' . PHP_EOL + . 'Provided values: ' . implode(', ', $filterValues) . '.' . PHP_EOL + ); + } + $this->filterValues = $filterValues; + } + + /** + * Filter tests by severity. + * + * @param array $tests + * @return void + */ + public function filter(array &$tests) + { + foreach ($tests as $testName => $test) { + if (is_array($test) && !empty($test['annotations'][self::ANNOTATION_TAG])) { + foreach ($test['annotations'][self::ANNOTATION_TAG] as $severity) { + if (!in_array($severity['value'], $this->filterValues, true)) { + unset($tests[$testName]); + } + } + } + } + } +} diff --git a/src/Magento/FunctionalTestingFramework/Suite/Objects/SuiteObject.php b/src/Magento/FunctionalTestingFramework/Suite/Objects/SuiteObject.php index d7f6bd18a..e10c58681 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Objects/SuiteObject.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Objects/SuiteObject.php @@ -7,6 +7,7 @@ use Magento\FunctionalTestingFramework\Test\Objects\TestHookObject; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; +use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; /** * Class SuiteObject @@ -84,6 +85,7 @@ public function getTests() * @param TestObject[] $includeTests * @param TestObject[] $excludeTests * @return TestObject[] + * @throws \Exception */ private function resolveTests($includeTests, $excludeTests) { @@ -96,10 +98,10 @@ private function resolveTests($includeTests, $excludeTests) } if (empty($finalTestList)) { - trigger_error( - "Current suite configuration for " . - $this->name . " contains no tests.", - E_USER_WARNING + LoggingUtil::getInstance()->getLogger(self::class)->notification( + "Current suite configuration for " . $this->name . " contains no tests." . PHP_EOL, + [], + true ); } diff --git a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php index a0d490df5..d5ed43806 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php @@ -16,6 +16,8 @@ use Magento\FunctionalTestingFramework\Test\Util\ObjectExtensionUtil; use Magento\FunctionalTestingFramework\Test\Util\TestObjectExtractor; use Magento\FunctionalTestingFramework\Test\Util\AnnotationExtractor; +use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; +use PHP_CodeSniffer\Tokenizers\PHP; /** * Class TestObjectHandler @@ -140,7 +142,7 @@ private function initTestData() } $exceptionCollector = new ExceptionCollector(); - foreach ($parsedTestArray[TestObjectHandler::XML_ROOT] as $testName => $testData) { + foreach ($parsedTestArray as $testName => $testData) { if (!is_array($testData)) { continue; } diff --git a/src/Magento/FunctionalTestingFramework/Test/Parsers/TestDataParser.php b/src/Magento/FunctionalTestingFramework/Test/Parsers/TestDataParser.php index 18044c1af..04baca734 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Parsers/TestDataParser.php +++ b/src/Magento/FunctionalTestingFramework/Test/Parsers/TestDataParser.php @@ -7,29 +7,58 @@ namespace Magento\FunctionalTestingFramework\Test\Parsers; use Magento\FunctionalTestingFramework\Config\DataInterface; +use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Filter\FilterInterface; +use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; /** * Class TestDataParser */ class TestDataParser { + /** + * @var DataInterface + */ + private $testData; + + /** + * @var \Magento\FunctionalTestingFramework\Filter\FilterList + */ + private $filterList; + /** * TestDataParser constructor. * * @param DataInterface $testData + * @throws \Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException */ public function __construct(DataInterface $testData) { - $this->testData = $testData; + $this->testData = array_filter($testData->get('tests'), function ($value) { + return is_array($value); + }); + + $this->filterList = MftfApplicationConfig::getConfig()->getFilterList(); } /** * Returns an array of data based on *Test.xml files * * @return array + * @throws TestFrameworkException */ public function readTestData() { - return $this->testData->get(); + /** @var FilterInterface $filter */ + foreach ($this->filterList->getFilters() as $filter) { + $filter->filter($this->testData); + } + + if (empty($this->testData)) { + throw new TestFrameworkException("No tests found."); + } + + return $this->testData; } } diff --git a/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php b/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php index 3983a755a..0e8c1e17f 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php +++ b/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php @@ -49,4 +49,23 @@ public function criticalFailure($message, array $context = [], $verbose = false) } parent::critical($message, $context); } + + /** + * Adds a log record at the NOTICE level. + * + * @param string $message + * @param array $context + * @param boolean $verbose + * @return void + * @throws \Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException + */ + public function notification($message, array $context = [], $verbose = false) + { + $message = "NOTICE: " . $message; + // Suppress print during unit testing + if (MftfApplicationConfig::getConfig()->getPhase() !== MftfApplicationConfig::UNIT_TEST_PHASE && $verbose) { + print ($message . implode("\n", $context) . "\n"); + } + parent::notice($message, $context); + } } From 269a4e506be9a821d37b7f3c893ccdff33c68150 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Wed, 26 Feb 2020 10:19:31 -0600 Subject: [PATCH 230/888] MQE-2008: Filter test generation and execution by severity --- docs/commands/mftf.md | 1 + .../Test/Handlers/TestObjectHandler.php | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index b2c36dae4..e0394dc12 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -159,6 +159,7 @@ vendor/bin/mftf generate:tests [option] [<test name>] [<test name>] [--remove] | Option | Description| | ---| --- | | `--config=[<default> or <singleRun> or <parallel>]` | Creates a single manifest file with a list of all tests. The default location is `tests/functional/Magento/FunctionalTest/_generated/testManifest.txt`.<br/> You can split the list into multiple groups using `--config=parallel`; the groups will be generated in `_generated/groups/` like `_generated/groups/group1.txt, group2.txt, ...`.<br/> Available values: `default` (default), `singleRun`(same as `default`), and `parallel`.<br/> Example: `generate:tests --config=parallel`. | +| `--filter` | Option to filter tests to be generated.<br/>Template: '<filterName>:<filterValue>'.<br/>Existing filter types: severity.<br/>Existing severity values: BLOCKER, CRITICAL, MAJOR, AVERAGE, MINOR.<br/>Example: --filter=severity:CRITICAL| | `--force` | Forces test generation, regardless of the module merge order defined in the Magento instance. Example: `generate:tests --force`. | | `-i,--time` | Set time in minutes to determine the group size when `--config=parallel` is used. The __default value__ is `10`. Example: `generate:tests --config=parallel --time=15`| | `--tests` | Defines the test configuration as a JSON string.| diff --git a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php index d5ed43806..18d3cd184 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php @@ -24,8 +24,6 @@ */ class TestObjectHandler implements ObjectHandlerInterface { - const XML_ROOT = 'tests'; - /** * Test Object Handler * From 7758075324312085720017f98fe61af467ff544b Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Wed, 26 Feb 2020 16:50:49 -0600 Subject: [PATCH 231/888] MQE-2008: Filter test generation and execution by severity --- .../Filter/Test/Severity.php | 13 +++++++------ .../Suite/Objects/SuiteObject.php | 12 ++++++------ .../Suite/SuiteGenerator.php | 6 ++++++ .../Test/Handlers/TestObjectHandler.php | 2 ++ .../Test/Parsers/TestDataParser.php | 16 ---------------- .../Util/Manifest/DefaultTestManifest.php | 3 +++ .../Util/Manifest/ParallelTestManifest.php | 2 +- .../Util/TestGenerator.php | 10 ++++++++++ 8 files changed, 35 insertions(+), 29 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Filter/Test/Severity.php b/src/Magento/FunctionalTestingFramework/Filter/Test/Severity.php index cfcb82de1..9c3aa0e7a 100644 --- a/src/Magento/FunctionalTestingFramework/Filter/Test/Severity.php +++ b/src/Magento/FunctionalTestingFramework/Filter/Test/Severity.php @@ -10,6 +10,7 @@ use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Filter\FilterInterface; +use Magento\FunctionalTestingFramework\Test\Objects\TestObject; /** * Class Severity @@ -51,17 +52,17 @@ public function __construct(array $filterValues = []) /** * Filter tests by severity. * - * @param array $tests + * @param TestObject[] $tests * @return void */ public function filter(array &$tests) { + /** @var TestObject $test */ foreach ($tests as $testName => $test) { - if (is_array($test) && !empty($test['annotations'][self::ANNOTATION_TAG])) { - foreach ($test['annotations'][self::ANNOTATION_TAG] as $severity) { - if (!in_array($severity['value'], $this->filterValues, true)) { - unset($tests[$testName]); - } + $severities = $test->getAnnotationByName(self::ANNOTATION_TAG); + foreach ($severities as $severity) { + if (!in_array($severity, $this->filterValues, true)) { + unset($tests[$testName]); } } } diff --git a/src/Magento/FunctionalTestingFramework/Suite/Objects/SuiteObject.php b/src/Magento/FunctionalTestingFramework/Suite/Objects/SuiteObject.php index e10c58681..7168d9556 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Objects/SuiteObject.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Objects/SuiteObject.php @@ -5,6 +5,8 @@ */ namespace Magento\FunctionalTestingFramework\Suite\Objects; +use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Filter\FilterInterface; use Magento\FunctionalTestingFramework\Test\Objects\TestHookObject; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; @@ -97,12 +99,10 @@ private function resolveTests($includeTests, $excludeTests) unset($finalTestList[$testName]); } - if (empty($finalTestList)) { - LoggingUtil::getInstance()->getLogger(self::class)->notification( - "Current suite configuration for " . $this->name . " contains no tests." . PHP_EOL, - [], - true - ); + $filters = MftfApplicationConfig::getConfig()->getFilterList()->getFilters(); + /** @var FilterInterface $filter */ + foreach ($filters as $filter) { + $filter->filter($finalTestList); } return $finalTestList; diff --git a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php index e3da10497..7aec4f21f 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php @@ -95,6 +95,12 @@ public function generateAllSuites($testManifest) $suites = $testManifest->getSuiteConfig(); foreach ($suites as $suiteName => $suiteContent) { + if (empty($suiteContent)) { + LoggingUtil::getInstance()->getLogger(self::class)->notification( + "Suite '" . $suiteName . "' contains no tests and won't be generated." . PHP_EOL, [], true + ); + continue; + } $firstElement = array_values($suiteContent)[0]; // if the first element is a string we know that we simply have an array of tests diff --git a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php index 18d3cd184..d5ed43806 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php @@ -24,6 +24,8 @@ */ class TestObjectHandler implements ObjectHandlerInterface { + const XML_ROOT = 'tests'; + /** * Test Object Handler * diff --git a/src/Magento/FunctionalTestingFramework/Test/Parsers/TestDataParser.php b/src/Magento/FunctionalTestingFramework/Test/Parsers/TestDataParser.php index 04baca734..dc3489de1 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Parsers/TestDataParser.php +++ b/src/Magento/FunctionalTestingFramework/Test/Parsers/TestDataParser.php @@ -22,11 +22,6 @@ class TestDataParser */ private $testData; - /** - * @var \Magento\FunctionalTestingFramework\Filter\FilterList - */ - private $filterList; - /** * TestDataParser constructor. * @@ -38,8 +33,6 @@ public function __construct(DataInterface $testData) $this->testData = array_filter($testData->get('tests'), function ($value) { return is_array($value); }); - - $this->filterList = MftfApplicationConfig::getConfig()->getFilterList(); } /** @@ -50,15 +43,6 @@ public function __construct(DataInterface $testData) */ public function readTestData() { - /** @var FilterInterface $filter */ - foreach ($this->filterList->getFilters() as $filter) { - $filter->filter($this->testData); - } - - if (empty($this->testData)) { - throw new TestFrameworkException("No tests found."); - } - return $this->testData; } } diff --git a/src/Magento/FunctionalTestingFramework/Util/Manifest/DefaultTestManifest.php b/src/Magento/FunctionalTestingFramework/Util/Manifest/DefaultTestManifest.php index eb4f79db2..4cbef3168 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Manifest/DefaultTestManifest.php +++ b/src/Magento/FunctionalTestingFramework/Util/Manifest/DefaultTestManifest.php @@ -86,6 +86,9 @@ public function generate() protected function generateSuiteEntries($fileResource) { foreach ($this->getSuiteConfig() as $suiteName => $tests) { + if (count($tests) === 0) { + continue; + } $line = "-g {$suiteName}"; fwrite($fileResource, $line . PHP_EOL); } diff --git a/src/Magento/FunctionalTestingFramework/Util/Manifest/ParallelTestManifest.php b/src/Magento/FunctionalTestingFramework/Util/Manifest/ParallelTestManifest.php index 9b12cfd00..201e002a2 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Manifest/ParallelTestManifest.php +++ b/src/Magento/FunctionalTestingFramework/Util/Manifest/ParallelTestManifest.php @@ -132,7 +132,7 @@ private function generateGroupFile($testGroup, $nodeNumber, $suites) $fileResource = fopen($this->dirPath . DIRECTORY_SEPARATOR . "group{$nodeNumber}.txt", 'a'); $line = null; - if (array_key_exists($entryName, $suites)) { + if (!empty($suites[$entryName])) { $line = "-g {$entryName}"; } else { $line = $this->relativeDirPath . DIRECTORY_SEPARATOR . $entryName . '.php'; diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 2ec565c44..d68010e7d 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -11,6 +11,7 @@ use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; +use Magento\FunctionalTestingFramework\Filter\FilterInterface; use Magento\FunctionalTestingFramework\Suite\Handlers\SuiteObjectHandler; use Magento\FunctionalTestingFramework\Test\Handlers\ActionGroupObjectHandler; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; @@ -171,6 +172,9 @@ private function loadAllTestObjects($testsToIgnore) { if ($this->tests === null || empty($this->tests)) { $testObjects = TestObjectHandler::getInstance()->getAllObjects(); + + + return array_diff_key($testObjects, $testsToIgnore); } @@ -288,6 +292,12 @@ private function assembleAllTestPhp($testManifest, array $testsToIgnore) /** @var TestObject[] $testObjects */ $testObjects = $this->loadAllTestObjects($testsToIgnore); $cestPhpArray = []; + $filters = MftfApplicationConfig::getConfig()->getFilterList()->getFilters(); + /** @var FilterInterface $filter */ + foreach ($filters as $filter) { + $filter->filter($testObjects); + } + foreach ($testObjects as $test) { // Do not generate test if it is an extended test and parent does not exist From a9f5bba4197a442b137f94cb77b8b4da4951afae Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Wed, 26 Feb 2020 21:53:15 -0600 Subject: [PATCH 232/888] MQE-2008: Filter test generation and execution by severity --- .../Filter/Test/Severity.php | 26 +++++++++---------- .../Suite/SuiteGenerator.php | 4 ++- .../Util/TestGenerator.php | 4 --- 3 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Filter/Test/Severity.php b/src/Magento/FunctionalTestingFramework/Filter/Test/Severity.php index 9c3aa0e7a..e88c4af7b 100644 --- a/src/Magento/FunctionalTestingFramework/Filter/Test/Severity.php +++ b/src/Magento/FunctionalTestingFramework/Filter/Test/Severity.php @@ -11,6 +11,7 @@ use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Filter\FilterInterface; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; +use Magento\FunctionalTestingFramework\Test\Util\AnnotationExtractor; /** * Class Severity @@ -18,13 +19,6 @@ class Severity implements FilterInterface { const ANNOTATION_TAG = 'severity'; - const SEVERITY_VALUES = [ - "BLOCKER", - "CRITICAL", - "MAJOR", - "AVERAGE", - "MINOR", - ]; /** * @var array @@ -39,14 +33,18 @@ class Severity implements FilterInterface */ public function __construct(array $filterValues = []) { - if (array_diff($filterValues, self::SEVERITY_VALUES) ==! []) { - throw new TestFrameworkException( - 'Not existing severity specified.' . PHP_EOL - . 'Possible values: '. implode(', ', self::SEVERITY_VALUES) . '.' . PHP_EOL - . 'Provided values: ' . implode(', ', $filterValues) . '.' . PHP_EOL - ); + $severityValues = AnnotationExtractor::MAGENTO_TO_ALLURE_SEVERITY_MAP; + + foreach ($filterValues as $filterValue) { + if (!isset($severityValues[$filterValue])) { + throw new TestFrameworkException( + 'Not existing severity specified.' . PHP_EOL + . 'Possible values: '. implode(', ', array_keys($severityValues)) . '.' . PHP_EOL + . 'Provided values: ' . implode(', ', $filterValues) . '.' . PHP_EOL + ); + } + $this->filterValues[] = $severityValues[$filterValue]; } - $this->filterValues = $filterValues; } /** diff --git a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php index 7aec4f21f..b40b48ae7 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php @@ -97,7 +97,9 @@ public function generateAllSuites($testManifest) foreach ($suites as $suiteName => $suiteContent) { if (empty($suiteContent)) { LoggingUtil::getInstance()->getLogger(self::class)->notification( - "Suite '" . $suiteName . "' contains no tests and won't be generated." . PHP_EOL, [], true + "Suite '" . $suiteName . "' contains no tests and won't be generated." . PHP_EOL, + [], + true ); continue; } diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index d68010e7d..2e7d265fa 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -172,9 +172,6 @@ private function loadAllTestObjects($testsToIgnore) { if ($this->tests === null || empty($this->tests)) { $testObjects = TestObjectHandler::getInstance()->getAllObjects(); - - - return array_diff_key($testObjects, $testsToIgnore); } @@ -298,7 +295,6 @@ private function assembleAllTestPhp($testManifest, array $testsToIgnore) $filter->filter($testObjects); } - foreach ($testObjects as $test) { // Do not generate test if it is an extended test and parent does not exist if ($test->isSkipped() && !empty($test->getParentName())) { From 61027d915f18b1ae235cf21a5214f038758a8760 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Thu, 27 Feb 2020 08:59:46 -0600 Subject: [PATCH 233/888] MQE-683: [Deprecation] Only use more nested assertion syntax - Deprecated one-line syntax - added upgrade script --- .../Test/Objects/ActionObject.php | 47 ------ .../Test/etc/Actions/assertActions.xsd | 136 ------------------ .../Upgrade/UpdateAssertionSchema.php | 126 ++++++++++++++++ .../Upgrade/UpgradeScriptList.php | 1 + 4 files changed, 127 insertions(+), 183 deletions(-) create mode 100644 src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php index f377e2fac..a3bbd3cf3 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php @@ -56,7 +56,6 @@ class ActionObject "command", "html" ]; - const OLD_ASSERTION_ATTRIBUTES = ["expected", "expectedType", "actual", "actualType"]; const ASSERTION_ATTRIBUTES = ["expectedResult" => "expected", "actualResult" => "actual"]; const ASSERTION_TYPE_ATTRIBUTE = "type"; const ASSERTION_VALUE_ATTRIBUTE = "value"; @@ -303,24 +302,6 @@ public function resolveReferences() public function trimAssertionAttributes() { $actionAttributeKeys = array_keys($this->actionAttributes); - - /** MQE-683 DEPRECATE OLD METHOD HERE - * Checks if action has any of the old, single line attributes - * Throws a warning and returns, assuming old syntax is used. - */ - $oldAttributes = array_intersect($actionAttributeKeys, ActionObject::OLD_ASSERTION_ATTRIBUTES); - if (!empty($oldAttributes)) { - $appConfig = MftfApplicationConfig::getConfig(); - if ($appConfig->getPhase() == MftfApplicationConfig::GENERATION_PHASE && $appConfig->verboseEnabled()) { - LoggingUtil::getInstance()->getLogger(ActionObject::class)->deprecation( - "use of one line Assertion actions will be deprecated in MFTF 3.0.0, please use nested syntax", - ["action" => $this->type, "stepKey" => $this->stepKey], - true - ); - } - return; - } - $relevantKeys = array_keys(ActionObject::ASSERTION_ATTRIBUTES); $relevantAssertionAttributes = array_intersect($actionAttributeKeys, $relevantKeys); @@ -328,8 +309,6 @@ public function trimAssertionAttributes() return; } - $this->validateAssertionSchema($relevantAssertionAttributes); - // Flatten nested Elements's type and value into key=>value entries foreach ($this->actionAttributes as $key => $subAttributes) { if (in_array($key, $relevantKeys)) { @@ -343,32 +322,6 @@ public function trimAssertionAttributes() } } - /** - * Validates that the given assertion attributes have valid schema according to nested assertion syntax. - * @param array $attributes - * @return void - * @throws TestReferenceException - */ - private function validateAssertionSchema($attributes) - { - /** MQE-683 DEPRECATE OLD METHOD HERE - * Unnecessary validation, only needed for backwards compatibility - */ - $singleChildTypes = ['assertEmpty', 'assertFalse', 'assertFileExists', 'assertFileNotExists', - 'assertIsEmpty', 'assertNotEmpty', 'assertNotNull', 'assertNull', 'assertTrue', - 'assertElementContainsAttribute']; - - if (!in_array($this->type, $singleChildTypes)) { - if (!in_array('expectedResult', $attributes) - || !in_array('actualResult', $attributes)) { - throw new TestReferenceException( - "{$this->type} must have both an expectedResult & actualResult defined (stepKey: {$this->stepKey})", - ["action" => $this->type, "stepKey" => $this->stepKey] - ); - } - } - } - /** * Look up the selector for SomeSectionName.ElementName and set it as the selector attribute in the * resolved custom attributes. Also set the timeout value. diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/assertActions.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/assertActions.xsd index 4fdde9990..b06e156e6 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/assertActions.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/assertActions.xsd @@ -98,10 +98,6 @@ <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attribute ref="delta"/> <xs:attribute ref="strict"/> @@ -145,10 +141,6 @@ <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -163,10 +155,6 @@ <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -181,10 +169,6 @@ <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attribute ref="strict"/> <xs:attributeGroup ref="commonActionAttributes"/> @@ -200,10 +184,6 @@ <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -218,10 +198,6 @@ <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -235,10 +211,6 @@ <xs:choice maxOccurs="unbounded"> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -253,10 +225,6 @@ <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="delta"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> @@ -271,10 +239,6 @@ <xs:choice maxOccurs="unbounded"> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -288,10 +252,6 @@ <xs:choice maxOccurs="unbounded"> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -305,10 +265,6 @@ <xs:choice maxOccurs="unbounded"> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -323,10 +279,6 @@ <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -341,10 +293,6 @@ <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -359,10 +307,6 @@ <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -377,10 +321,6 @@ <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -395,10 +335,6 @@ <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -412,10 +348,6 @@ <xs:choice maxOccurs="unbounded"> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -430,10 +362,6 @@ <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -448,10 +376,6 @@ <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -466,10 +390,6 @@ <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -484,10 +404,6 @@ <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -501,10 +417,6 @@ <xs:choice maxOccurs="unbounded"> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -519,10 +431,6 @@ <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attribute ref="delta"/> <xs:attributeGroup ref="commonActionAttributes"/> @@ -538,10 +446,6 @@ <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -555,10 +459,6 @@ <xs:choice maxOccurs="unbounded"> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -573,10 +473,6 @@ <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -591,10 +487,6 @@ <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -608,10 +500,6 @@ <xs:choice maxOccurs="unbounded"> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -626,10 +514,6 @@ <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -644,10 +528,6 @@ <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -662,10 +542,6 @@ <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -680,10 +556,6 @@ <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -697,10 +569,6 @@ <xs:choice maxOccurs="unbounded"> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -715,10 +583,6 @@ <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> - <xs:attribute ref="expected"/> - <xs:attribute type="assertEnum" name="expectedType" default="const"/> - <xs:attribute ref="actual"/> - <xs:attribute type="assertEnum" name="actualType" default="const"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php new file mode 100644 index 000000000..6eca6a11e --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php @@ -0,0 +1,126 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\FunctionalTestingFramework\Upgrade; + +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Filesystem\Filesystem; +use Symfony\Component\Finder\Finder; + +/** + * Class UpdateAssertionSchema + * @package Magento\FunctionalTestingFramework\Upgrade + */ +class UpdateAssertionSchema implements UpgradeInterface +{ + const OLD_ASSERTION_ATTRIBUTES = ["expected", "expectedType", "actual", "actualType"]; + + private $currentFile; + private $errors = []; + /** + * Upgrades all test xml files, changing <assert> actions to be nested + * + * @param InputInterface $input + * @return string + */ + public function execute(InputInterface $input) + { + $testsPath = $input->getArgument('path'); + $finder = new Finder(); + $finder->files()->in($testsPath)->name("*.xml"); + + $fileSystem = new Filesystem(); + $testsUpdated = 0; + foreach ($finder->files() as $file) { + if (!$this->detectOldAttributes($file)) { + continue; + } + $this->currentFile = $file->getFilename(); + $contents = $file->getContents(); + // Isolate <assert ... /> but not <assert ... > + preg_match_all('/<assert[^>]*\/>/', $contents, $potentialAssertions); + $newAssertions = []; + $index = 0; + foreach ($potentialAssertions[0] as $potentialAssertion) { + $newAssertions[$index] = $this->convertOldAssertionToNew($potentialAssertion); + $index++; + } + foreach ($newAssertions as $currentIndex => $replacements) { + $contents = str_replace($potentialAssertions[0][$currentIndex], $replacements, $contents); + } + $fileSystem->dumpFile($file->getRealPath(), $contents); + $testsUpdated++; + } + + return ("Assertion Syntax updated in {$testsUpdated} file(s).\n" . implode("\n\t", $this->errors)); + } + + private function detectOldAttributes($file) + { + foreach (self::OLD_ASSERTION_ATTRIBUTES as $OLD_ASSERTION_ATTRIBUTE) { + if (strpos($file->getContents(), $OLD_ASSERTION_ATTRIBUTE) !== false) { + return true; + } + } + return false; + } + + private function convertOldAssertionToNew($assertion) + { + // <assertSomething => assertSomething + $assertType = ltrim(explode(' ', $assertion)[0], '<'); + $stepKey = ""; + + // regex to grab values + $grabValueRegex = '/(stepKey|actual|actualType|expected|expectedType|delta|message)="([^"]*)"/'; + + // Make 3 arrays in $grabbedParts: + // 0 contains stepKey="value" + // 1 contains stepKey + // 2 contains value + $sortedParts = []; + preg_match_all($grabValueRegex, $assertion, $grabbedParts); + for ($i = 0; $i < count($grabbedParts[0]); $i++) { + $sortedParts[$grabbedParts[1][$i]] = $grabbedParts[2][$i]; + } + + // Build new String + $newString = "<$assertType "; + $subElements = ["actual" => [], "expected" => []]; + foreach ($sortedParts as $type => $value) { + if (in_array($type, ["stepKey", "delta", "message"])) { + if ($type == "stepKey") { + $stepKey = $value; + } + $newString .= "$type=\"$value\""; + continue; + } + if ($type == "actual") { + $subElements["actual"]["value"] = $value; + } elseif ($type == "actualType") { + $subElements["actual"]["type"] = $value; + } elseif ($type == "expected") { + $subElements["expected"]["value"] = $value; + } elseif ($type == "expectedType") { + $subElements["expected"]["type"] = $value; + } + } + $newString .= ">\n"; + foreach ($subElements as $type => $subElement) { + if (!isset($subElement['value']) || !isset($subElement['type'])) { + //don't have all the info we need to rebuild + $this->errors[] = "UNABLE TO FULLY REBUILD ASSERTION, PLEASE MANUALLY CHECK FORMAT ($assertType \"$stepKey\" in $this->currentFile)"; + continue; + } + $value = $subElement['value']; + $typeValue = $subElement['type']; + $newString .= "<{$type}Result type=\"$typeValue\">$value</{$type}Result>\n"; + } + $newString .= "</$assertType>"; + return $newString; + } + +} diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/UpgradeScriptList.php b/src/Magento/FunctionalTestingFramework/Upgrade/UpgradeScriptList.php index 245f95d82..949b2bb0a 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/UpgradeScriptList.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/UpgradeScriptList.php @@ -29,6 +29,7 @@ public function __construct(array $scripts = []) { $this->scripts = [ 'upgradeTestSchema' => new UpdateTestSchemaPaths(), + 'upgradeAssertionSchema' => new UpdateAssertionSchema(), ] + $scripts; } From fe3c8f59362ac432e52b761fd4dc863be467d5a6 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 25 Feb 2020 15:01:37 -0600 Subject: [PATCH 234/888] MQE-1963: Update XSD Schema to verify that file has only single entity --- dev/tests/_bootstrap.php | 4 +- .../ActionGroupContainsStepKeyInArgText.txt | 2 +- .../ActionGroupMergedViaInsertAfter.txt | 2 +- .../ActionGroupMergedViaInsertBefore.txt | 2 +- .../Resources/ActionGroupSkipReadiness.txt | 2 +- .../Resources/ActionGroupToExtend.txt | 2 +- .../Resources/ActionGroupUsingCreateData.txt | 2 +- .../ActionGroupUsingNestedArgument.txt | 2 +- .../ActionGroupWithDataOverrideTest.txt | 2 +- .../Resources/ActionGroupWithDataTest.txt | 2 +- ...hDefaultArgumentAndStringSelectorParam.txt | 2 +- ...eParameterSelectorsFromDefaultArgument.txt | 2 +- .../Resources/ActionGroupWithNoArguments.txt | 2 +- .../ActionGroupWithNoDefaultTest.txt | 2 +- ...roupWithParameterizedElementWithHyphen.txt | 2 +- ...meterizedElementsWithStepKeyReferences.txt | 2 +- ...thPassedArgumentAndStringSelectorParam.txt | 2 +- .../ActionGroupWithPersistedData.txt | 2 +- ...tionGroupWithSectionAndDataAsArguments.txt | 2 +- ...WithSimpleDataUsageFromDefaultArgument.txt | 2 +- ...pWithSimpleDataUsageFromPassedArgument.txt | 2 +- ...leParameterSelectorFromDefaultArgument.txt | 2 +- ...gleParameterSelectorFromPassedArgument.txt | 2 +- .../ActionGroupWithStepKeyReferences.txt | 2 +- .../ActionGroupWithTopLevelPersistedData.txt | 2 +- .../ArgumentWithSameNameAsElement.txt | 2 +- .../Resources/BasicActionGroupTest.txt | 2 +- .../Resources/BasicFunctionalTest.txt | 2 +- .../verification/Resources/BasicMergeTest.txt | 2 +- .../Resources/ChildExtendedTestAddHooks.txt | 2 +- .../Resources/ChildExtendedTestMerging.txt | 2 +- .../Resources/ChildExtendedTestNoParent.txt | 2 +- .../ChildExtendedTestRemoveAction.txt | 2 +- .../ChildExtendedTestRemoveHookAction.txt | 2 +- .../Resources/ChildExtendedTestReplace.txt | 2 +- .../ChildExtendedTestReplaceHook.txt | 2 +- .../Resources/ExtendedActionGroup.txt | 2 +- .../ExtendedChildTestInSuiteCest.txt | 2 +- .../Resources/ExtendedChildTestNotInSuite.txt | 2 +- .../Resources/ExtendedRemoveActionGroup.txt | 2 +- .../Resources/ExtendingSkippedTest.txt | 2 +- .../Resources/MergeMassViaInsertAfter.txt | 2 +- .../Resources/MergeMassViaInsertBefore.txt | 2 +- .../verification/Resources/MergeSkip.txt | 2 +- .../Resources/MergedActionGroupTest.txt | 2 +- .../Resources/MergedReferencesTest.txt | 2 +- .../Resources/MultipleActionGroupsTest.txt | 2 +- .../Resources/ParentExtendedTest.txt | 2 +- .../PersistedAndXmlEntityArguments.txt | 2 +- .../verification/Resources/SkippedTest.txt | 2 +- .../Resources/SkippedTestNoIssues.txt | 2 +- .../Resources/SkippedTestTwoIssues.txt | 2 +- .../Resources/SkippedTestWithHooks.txt | 2 +- .../ActionGroup/BasicActionGroup.xml | 125 ----------- ...upContainsStepKeyInArgValueActionGroup.xml | 16 ++ .../ActionGroupToExtendActionGroup.xml | 20 ++ .../ActionGroupWithCreateDataActionGroup.xml | 16 ++ ...umentAndStringSelectorParamActionGroup.xml | 17 ++ .../ActionGroupWithEntityUsageActionGroup.xml | 16 ++ ...ameterSelectorsFromArgumentActionGroup.xml | 17 ++ ...tionGroupWithNestedArgumentActionGroup.xml | 20 ++ ...tionGroupWithSectionAndDataActionGroup.xml | 17 ++ ...rameterSelectorFromArgumentActionGroup.xml | 17 ++ .../ActionGroupWithStringUsageActionGroup.xml | 16 ++ ...ActionGroupWithTwoArgumentsActionGroup.xml | 18 ++ ...ActionGroupWithoutArgumentsActionGroup.xml | 13 ++ .../ExtendBasicActionGroup.xml | 13 ++ .../ExtendRemoveTestActionGroup.xml | 13 ++ .../ExtendTestActionGroup.xml | 22 ++ .../ActionGroup/FunctionalActionGroup.xml | 106 --------- ...upWithParametrizedSelectorsActionGroup.xml | 22 ++ ...nGroupWithStepKeyReferencesActionGroup.xml | 33 +++ .../FunctionalActionGroup.xml | 14 ++ ...ctionGroupForMassMergeAfterActionGroup.xml | 15 ++ ...tionGroupForMassMergeBeforeActionGroup.xml | 15 ++ ...nctionalActionGroupForMergeActionGroup.xml | 18 ++ ...ctionalActionGroupNoDefaultActionGroup.xml | 18 ++ ...nctionalActionGroupWithDataActionGroup.xml | 20 ++ ...tionGroupWithTrickyArgumentActionGroup.xml | 17 ++ ...roupWithXmlAndPersistedDataActionGroup.xml | 17 ++ ...ntWithParameterizedSelectorActionGroup.xml | 16 ++ .../MergeFunctionalActionGroup.xml | 28 --- ...ctionGroupForMassMergeAfterActionGroup.xml | 15 ++ ...tionGroupForMassMergeBeforeActionGroup.xml | 15 ++ ...nctionalActionGroupForMergeActionGroup.xml | 15 ++ .../ActionGroup/PersistenceActionGroup.xml | 41 ---- .../DataPersistenceAppendingActionGroup.xml | 17 ++ ...ataPersistenceSelfReferenceActionGroup.xml | 18 ++ .../PersistenceActionGroup.xml | 26 +++ .../TestModule/Page/SamplePage.xml | 32 --- .../Page/SamplePage/AdminOneParamPage.xml | 13 ++ .../TestModule/Page/SamplePage/AdminPage.xml | 13 ++ .../Page/SamplePage/ExternalPage.xml | 13 ++ .../Page/SamplePage/NoParamPage.xml | 13 ++ .../Page/SamplePage/OneParamPage.xml | 13 ++ .../TestModule/Page/SamplePage/SamplePage.xml | 13 ++ .../Page/SamplePage/TwoParamPage.xml | 13 ++ .../Test/ActionGroupFunctionalTest.xml | 187 ---------------- .../ActionGroupMergedViaInsertAfter.xml | 13 ++ .../ActionGroupMergedViaInsertBefore.xml | 13 ++ .../ActionGroupWithDataOverrideTest.xml | 30 +++ .../ActionGroupWithDataTest.xml | 28 +++ .../ActionGroupWithNoDefaultTest.xml | 30 +++ .../ActionGroupWithPersistedData.xml | 29 +++ .../ActionGroupWithTopLevelPersistedData.xml | 28 +++ .../ArgumentWithSameNameAsElement.xml | 26 +++ .../BasicActionGroupTest.xml | 25 +++ .../MergedActionGroupTest.xml | 28 +++ .../MultipleActionGroupsTest.xml | 31 +++ .../PersistedAndXmlEntityArguments.xml | 15 ++ .../TestModule/Test/ActionGroupTest.xml | 181 ---------------- .../ActionGroupContainsStepKeyInArgText.xml | 20 ++ .../ActionGroupSkipReadiness.xml | 13 ++ .../ActionGroupTest/ActionGroupToExtend.xml | 15 ++ .../ActionGroupUsingCreateData.xml | 15 ++ .../ActionGroupUsingNestedArgument.xml | 15 ++ ...hDefaultArgumentAndStringSelectorParam.xml | 18 ++ ...eParameterSelectorsFromDefaultArgument.xml | 18 ++ .../ActionGroupWithNoArguments.xml | 17 ++ ...roupWithParameterizedElementWithHyphen.xml | 15 ++ ...meterizedElementsWithStepKeyReferences.xml | 16 ++ ...thPassedArgumentAndStringSelectorParam.xml | 20 ++ ...tionGroupWithSectionAndDataAsArguments.xml | 16 ++ ...WithSimpleDataUsageFromDefaultArgument.xml | 17 ++ ...pWithSimpleDataUsageFromPassedArgument.xml | 48 +++++ ...leParameterSelectorFromDefaultArgument.xml | 18 ++ ...gleParameterSelectorFromPassedArgument.xml | 20 ++ .../ActionGroupWithStepKeyReferences.xml | 13 ++ .../ActionGroupTest/ExtendedActionGroup.xml | 16 ++ .../ExtendedRemoveActionGroup.xml | 13 ++ .../BasicFunctionalTest.xml | 13 +- .../MergeMassViaInsertAfter.xml | 15 ++ .../MergeMassViaInsertBefore.xml | 15 ++ .../Test/ExtendedFunctionalTest.xml | 201 ------------------ .../ChildExtendedTestAddHooks.xml | 25 +++ .../ChildExtendedTestMerging.xml | 26 +++ .../ChildExtendedTestNoParent.xml | 22 ++ .../ChildExtendedTestRemoveAction.xml | 20 ++ .../ChildExtendedTestRemoveHookAction.xml | 22 ++ .../ChildExtendedTestReplace.xml | 20 ++ .../ChildExtendedTestReplaceHook.xml | 22 ++ .../ExtendedChildTestInSuite.xml | 21 ++ .../ExtendedChildTestNotInSuite.xml | 20 ++ .../ExtendedTestRelatedToSuiteParentTest.xml | 27 +++ .../ExtendingSkippedTest.xml | 20 ++ .../ParentExtendedTest.xml | 26 +++ .../ParentExtendedTestNoHooks.xml | 20 ++ .../ExtendedFunctionalTest/SkippedParent.xml | 30 +++ .../TestModule/Test/MergeFunctionalTest.xml | 61 ------ .../MergeFunctionalTest/BasicMergeTest.xml | 30 +++ .../MergeMassViaInsertAfter.xml | 15 ++ .../MergeMassViaInsertBefore.xml | 15 ++ .../Test/MergeFunctionalTest/MergeSkip.xml | 13 ++ .../MergedReferencesTest.xml | 27 +++ .../AdditionalExcludeTest2.xml} | 9 +- .../AdditionalIncludeTest2.xml | 16 ++ .../TestModule/Test/SampleSuiteTest.xml | 50 ----- .../Test/SampleSuiteTest/AdditionalTest.xml | 19 ++ .../Test/SampleSuiteTest/ExcludeTest.xml | 16 ++ .../Test/SampleSuiteTest/ExcludeTest2.xml | 19 ++ .../Test/SampleSuiteTest/IncludeTest.xml | 16 ++ .../Test/SampleSuiteTest/IncludeTest2.xml | 19 ++ .../TestModule/Test/SkippedTest.xml | 60 ------ .../Test/SkippedTest/SkippedTest.xml | 21 ++ .../Test/SkippedTest/SkippedTestNoIssues.xml | 19 ++ .../Test/SkippedTest/SkippedTestTwoIssues.xml | 22 ++ .../Test/SkippedTest/SkippedTestWithHooks.xml | 27 +++ .../XmlDuplicateTest/BasicDupedActionTest.xml | 31 +++ .../XmlDuplicateTest.xml | 27 +-- .../BasicMergeTest.xml} | 10 +- .../Test/MergeFunctionalTest/MergeSkip.xml | 17 ++ .../Tests/BasicCestGenerationTest.php | 25 +++ .../functionalSuite/functionalSuite1.xml | 22 ++ .../functionalSuite/functionalSuite2.xml | 22 ++ .../functionalSuiteWithComments.xml} | 22 -- .../Console/BaseGenerateCommand.php | 3 +- .../Suite/Util/SuiteObjectExtractor.php | 47 ++-- .../Suite/etc/mergedSuiteSchema.xsd | 1 - .../Upgrade/RemoveModuleFileInSuiteFiles.php | 126 +++++++++++ .../Upgrade/SplitMultipleEntitiesFiles.php | 35 ++- .../Upgrade/UpgradeScriptList.php | 3 +- .../Util/Filesystem/RecursiveGlobUtil.php | 72 +++++++ 182 files changed, 2354 insertions(+), 1248 deletions(-) delete mode 100644 dev/tests/verification/TestModule/ActionGroup/BasicActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupContainsStepKeyInArgValueActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupToExtendActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithCreateDataActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithDefaultArgumentAndStringSelectorParamActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithEntityUsageActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithMultipleParameterSelectorsFromArgumentActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithNestedArgumentActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithSectionAndDataActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithSingleParameterSelectorFromArgumentActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithStringUsageActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithTwoArgumentsActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithoutArgumentsActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ExtendBasicActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ExtendRemoveTestActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ExtendTestActionGroup.xml delete mode 100644 dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/ActionGroupWithParametrizedSelectorsActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionActionGroupWithStepKeyReferencesActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupForMassMergeAfterActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupForMassMergeBeforeActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupForMergeActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupNoDefaultActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupWithDataActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupWithTrickyArgumentActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupWithXmlAndPersistedDataActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/SectionArgumentWithParameterizedSelectorActionGroup.xml delete mode 100644 dev/tests/verification/TestModule/ActionGroup/MergeFunctionalActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/MergeFunctionalActionGroup/FunctionalActionGroupForMassMergeAfterActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/MergeFunctionalActionGroup/FunctionalActionGroupForMassMergeBeforeActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/MergeFunctionalActionGroup/FunctionalActionGroupForMergeActionGroup.xml delete mode 100644 dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup/DataPersistenceAppendingActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup/DataPersistenceSelfReferenceActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup/PersistenceActionGroup.xml delete mode 100644 dev/tests/verification/TestModule/Page/SamplePage.xml create mode 100644 dev/tests/verification/TestModule/Page/SamplePage/AdminOneParamPage.xml create mode 100644 dev/tests/verification/TestModule/Page/SamplePage/AdminPage.xml create mode 100644 dev/tests/verification/TestModule/Page/SamplePage/ExternalPage.xml create mode 100644 dev/tests/verification/TestModule/Page/SamplePage/NoParamPage.xml create mode 100644 dev/tests/verification/TestModule/Page/SamplePage/OneParamPage.xml create mode 100644 dev/tests/verification/TestModule/Page/SamplePage/SamplePage.xml create mode 100644 dev/tests/verification/TestModule/Page/SamplePage/TwoParamPage.xml delete mode 100644 dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupMergedViaInsertAfter.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupMergedViaInsertBefore.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupWithDataOverrideTest.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupWithDataTest.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupWithNoDefaultTest.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupWithPersistedData.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupWithTopLevelPersistedData.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ArgumentWithSameNameAsElement.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/BasicActionGroupTest.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/MergedActionGroupTest.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/MultipleActionGroupsTest.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/PersistedAndXmlEntityArguments.xml delete mode 100644 dev/tests/verification/TestModule/Test/ActionGroupTest.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupContainsStepKeyInArgText.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupSkipReadiness.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupToExtend.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupUsingCreateData.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupUsingNestedArgument.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithDefaultArgumentAndStringSelectorParam.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithNoArguments.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithParameterizedElementWithHyphen.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithParameterizedElementsWithStepKeyReferences.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithPassedArgumentAndStringSelectorParam.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithSectionAndDataAsArguments.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithSimpleDataUsageFromDefaultArgument.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithSimpleDataUsageFromPassedArgument.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithSingleParameterSelectorFromDefaultArgument.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithSingleParameterSelectorFromPassedArgument.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithStepKeyReferences.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupTest/ExtendedActionGroup.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupTest/ExtendedRemoveActionGroup.xml rename dev/tests/verification/TestModule/Test/{ => BasicFunctionalTest}/BasicFunctionalTest.xml (94%) create mode 100644 dev/tests/verification/TestModule/Test/BasicFunctionalTest/MergeMassViaInsertAfter.xml create mode 100644 dev/tests/verification/TestModule/Test/BasicFunctionalTest/MergeMassViaInsertBefore.xml delete mode 100644 dev/tests/verification/TestModule/Test/ExtendedFunctionalTest.xml create mode 100644 dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestAddHooks.xml create mode 100644 dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestMerging.xml create mode 100644 dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestNoParent.xml create mode 100644 dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestRemoveAction.xml create mode 100644 dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestRemoveHookAction.xml create mode 100644 dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestReplace.xml create mode 100644 dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestReplaceHook.xml create mode 100644 dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ExtendedChildTestInSuite.xml create mode 100644 dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ExtendedChildTestNotInSuite.xml create mode 100644 dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ExtendedTestRelatedToSuiteParentTest.xml create mode 100644 dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ExtendingSkippedTest.xml create mode 100644 dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ParentExtendedTest.xml create mode 100644 dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ParentExtendedTestNoHooks.xml create mode 100644 dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/SkippedParent.xml delete mode 100644 dev/tests/verification/TestModule/Test/MergeFunctionalTest.xml create mode 100644 dev/tests/verification/TestModule/Test/MergeFunctionalTest/BasicMergeTest.xml create mode 100644 dev/tests/verification/TestModule/Test/MergeFunctionalTest/MergeMassViaInsertAfter.xml create mode 100644 dev/tests/verification/TestModule/Test/MergeFunctionalTest/MergeMassViaInsertBefore.xml create mode 100644 dev/tests/verification/TestModule/Test/MergeFunctionalTest/MergeSkip.xml create mode 100644 dev/tests/verification/TestModule/Test/MergeFunctionalTest/MergedReferencesTest.xml rename dev/tests/verification/TestModule/Test/{SampleSuite2Test.xml => SampleSuite2Test/AdditionalExcludeTest2.xml} (59%) create mode 100644 dev/tests/verification/TestModule/Test/SampleSuite2Test/AdditionalIncludeTest2.xml delete mode 100644 dev/tests/verification/TestModule/Test/SampleSuiteTest.xml create mode 100644 dev/tests/verification/TestModule/Test/SampleSuiteTest/AdditionalTest.xml create mode 100644 dev/tests/verification/TestModule/Test/SampleSuiteTest/ExcludeTest.xml create mode 100644 dev/tests/verification/TestModule/Test/SampleSuiteTest/ExcludeTest2.xml create mode 100644 dev/tests/verification/TestModule/Test/SampleSuiteTest/IncludeTest.xml create mode 100644 dev/tests/verification/TestModule/Test/SampleSuiteTest/IncludeTest2.xml delete mode 100644 dev/tests/verification/TestModule/Test/SkippedTest.xml create mode 100644 dev/tests/verification/TestModule/Test/SkippedTest/SkippedTest.xml create mode 100644 dev/tests/verification/TestModule/Test/SkippedTest/SkippedTestNoIssues.xml create mode 100644 dev/tests/verification/TestModule/Test/SkippedTest/SkippedTestTwoIssues.xml create mode 100644 dev/tests/verification/TestModule/Test/SkippedTest/SkippedTestWithHooks.xml create mode 100644 dev/tests/verification/TestModule/Test/XmlDuplicateTest/BasicDupedActionTest.xml rename dev/tests/verification/TestModule/Test/{ => XmlDuplicateTest}/XmlDuplicateTest.xml (97%) rename dev/tests/verification/TestModuleMerged/Test/{MergeFunctionalTest.xml => MergeFunctionalTest/BasicMergeTest.xml} (79%) create mode 100644 dev/tests/verification/TestModuleMerged/Test/MergeFunctionalTest/MergeSkip.xml create mode 100644 dev/tests/verification/_suite/functionalSuite/functionalSuite1.xml create mode 100644 dev/tests/verification/_suite/functionalSuite/functionalSuite2.xml rename dev/tests/verification/_suite/{functionalSuite.xml => functionalSuite/functionalSuiteWithComments.xml} (66%) create mode 100644 src/Magento/FunctionalTestingFramework/Upgrade/RemoveModuleFileInSuiteFiles.php create mode 100644 src/Magento/FunctionalTestingFramework/Util/Filesystem/RecursiveGlobUtil.php diff --git a/dev/tests/_bootstrap.php b/dev/tests/_bootstrap.php index 3f57ad139..f8a1c8479 100644 --- a/dev/tests/_bootstrap.php +++ b/dev/tests/_bootstrap.php @@ -108,7 +108,9 @@ $suiteDirectory = TESTS_BP . DIRECTORY_SEPARATOR . "verification" . DIRECTORY_SEPARATOR . "_suite"; $paths = [ - $suiteDirectory . DIRECTORY_SEPARATOR . 'functionalSuite.xml', + $suiteDirectory . DIRECTORY_SEPARATOR . 'functionalSuite' . DIRECTORY_SEPARATOR . 'functionalSuite1.xml', + $suiteDirectory . DIRECTORY_SEPARATOR . 'functionalSuite' . DIRECTORY_SEPARATOR . 'functionalSuite2.xml', + $suiteDirectory . DIRECTORY_SEPARATOR . 'functionalSuite' . DIRECTORY_SEPARATOR . 'functionalSuiteWithComments.xml', $suiteDirectory . DIRECTORY_SEPARATOR . 'functionalSuiteHooks.xml', $suiteDirectory . DIRECTORY_SEPARATOR . 'functionalSuiteExtends.xml' ]; diff --git a/dev/tests/verification/Resources/ActionGroupContainsStepKeyInArgText.txt b/dev/tests/verification/Resources/ActionGroupContainsStepKeyInArgText.txt index 23e0f0b69..d6640846f 100644 --- a/dev/tests/verification/Resources/ActionGroupContainsStepKeyInArgText.txt +++ b/dev/tests/verification/Resources/ActionGroupContainsStepKeyInArgText.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest/ActionGroupContainsStepKeyInArgText.xml<br>") */ class ActionGroupContainsStepKeyInArgTextCest { diff --git a/dev/tests/verification/Resources/ActionGroupMergedViaInsertAfter.txt b/dev/tests/verification/Resources/ActionGroupMergedViaInsertAfter.txt index da3d84daf..352af3a2b 100644 --- a/dev/tests/verification/Resources/ActionGroupMergedViaInsertAfter.txt +++ b/dev/tests/verification/Resources/ActionGroupMergedViaInsertAfter.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupMergedViaInsertAfter.xml<br>") */ class ActionGroupMergedViaInsertAfterCest { diff --git a/dev/tests/verification/Resources/ActionGroupMergedViaInsertBefore.txt b/dev/tests/verification/Resources/ActionGroupMergedViaInsertBefore.txt index 22e8148d9..009109146 100644 --- a/dev/tests/verification/Resources/ActionGroupMergedViaInsertBefore.txt +++ b/dev/tests/verification/Resources/ActionGroupMergedViaInsertBefore.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupMergedViaInsertBefore.xml<br>") */ class ActionGroupMergedViaInsertBeforeCest { diff --git a/dev/tests/verification/Resources/ActionGroupSkipReadiness.txt b/dev/tests/verification/Resources/ActionGroupSkipReadiness.txt index efd5a8cb5..891054638 100644 --- a/dev/tests/verification/Resources/ActionGroupSkipReadiness.txt +++ b/dev/tests/verification/Resources/ActionGroupSkipReadiness.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest/ActionGroupSkipReadiness.xml<br>") */ class ActionGroupSkipReadinessCest { diff --git a/dev/tests/verification/Resources/ActionGroupToExtend.txt b/dev/tests/verification/Resources/ActionGroupToExtend.txt index 29d08c0b6..bbb9efa0f 100644 --- a/dev/tests/verification/Resources/ActionGroupToExtend.txt +++ b/dev/tests/verification/Resources/ActionGroupToExtend.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest/ActionGroupToExtend.xml<br>") */ class ActionGroupToExtendCest { diff --git a/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt b/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt index b64822cf6..cbddc5f4d 100644 --- a/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt +++ b/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest/ActionGroupUsingCreateData.xml<br>") */ class ActionGroupUsingCreateDataCest { diff --git a/dev/tests/verification/Resources/ActionGroupUsingNestedArgument.txt b/dev/tests/verification/Resources/ActionGroupUsingNestedArgument.txt index 5eb67f577..0cfd7f84d 100644 --- a/dev/tests/verification/Resources/ActionGroupUsingNestedArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupUsingNestedArgument.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest/ActionGroupUsingNestedArgument.xml<br>") */ class ActionGroupUsingNestedArgumentCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt b/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt index bb6404315..b60a4da5f 100644 --- a/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt +++ b/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @group functional - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupWithDataOverrideTest.xml<br>") */ class ActionGroupWithDataOverrideTestCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithDataTest.txt b/dev/tests/verification/Resources/ActionGroupWithDataTest.txt index 6b22f83e0..5f19cdc37 100644 --- a/dev/tests/verification/Resources/ActionGroupWithDataTest.txt +++ b/dev/tests/verification/Resources/ActionGroupWithDataTest.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @group functional - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupWithDataTest.xml<br>") */ class ActionGroupWithDataTestCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithDefaultArgumentAndStringSelectorParam.txt b/dev/tests/verification/Resources/ActionGroupWithDefaultArgumentAndStringSelectorParam.txt index ca5f72cc0..65339e970 100644 --- a/dev/tests/verification/Resources/ActionGroupWithDefaultArgumentAndStringSelectorParam.txt +++ b/dev/tests/verification/Resources/ActionGroupWithDefaultArgumentAndStringSelectorParam.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: Action Group With Default Argument Value and Hardcoded Value in Param") - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest/ActionGroupWithDefaultArgumentAndStringSelectorParam.xml<br>") */ class ActionGroupWithDefaultArgumentAndStringSelectorParamCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.txt b/dev/tests/verification/Resources/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.txt index f3ad492b0..e8cedee97 100644 --- a/dev/tests/verification/Resources/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: Action Group With Passed Argument Value and Multiple Argument Values in Param") - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.xml<br>") */ class ActionGroupWithMultipleParameterSelectorsFromDefaultArgumentCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithNoArguments.txt b/dev/tests/verification/Resources/ActionGroupWithNoArguments.txt index 0f69c40e8..e5b9717c2 100644 --- a/dev/tests/verification/Resources/ActionGroupWithNoArguments.txt +++ b/dev/tests/verification/Resources/ActionGroupWithNoArguments.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: Action Group With No Argument") - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest/ActionGroupWithNoArguments.xml<br>") */ class ActionGroupWithNoArgumentsCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt b/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt index 533e14b9d..c0bde006d 100644 --- a/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt +++ b/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @group functional - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupWithNoDefaultTest.xml<br>") */ class ActionGroupWithNoDefaultTestCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithParameterizedElementWithHyphen.txt b/dev/tests/verification/Resources/ActionGroupWithParameterizedElementWithHyphen.txt index acc6aa58a..812285111 100644 --- a/dev/tests/verification/Resources/ActionGroupWithParameterizedElementWithHyphen.txt +++ b/dev/tests/verification/Resources/ActionGroupWithParameterizedElementWithHyphen.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest/ActionGroupWithParameterizedElementWithHyphen.xml<br>") */ class ActionGroupWithParameterizedElementWithHyphenCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithParameterizedElementsWithStepKeyReferences.txt b/dev/tests/verification/Resources/ActionGroupWithParameterizedElementsWithStepKeyReferences.txt index ac20299a8..6c0c3fd0f 100644 --- a/dev/tests/verification/Resources/ActionGroupWithParameterizedElementsWithStepKeyReferences.txt +++ b/dev/tests/verification/Resources/ActionGroupWithParameterizedElementsWithStepKeyReferences.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest/ActionGroupWithParameterizedElementsWithStepKeyReferences.xml<br>") */ class ActionGroupWithParameterizedElementsWithStepKeyReferencesCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithPassedArgumentAndStringSelectorParam.txt b/dev/tests/verification/Resources/ActionGroupWithPassedArgumentAndStringSelectorParam.txt index e816da90b..6614a320d 100644 --- a/dev/tests/verification/Resources/ActionGroupWithPassedArgumentAndStringSelectorParam.txt +++ b/dev/tests/verification/Resources/ActionGroupWithPassedArgumentAndStringSelectorParam.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: Action Group With Passed Argument Value and Hardcoded Value in Param") - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest/ActionGroupWithPassedArgumentAndStringSelectorParam.xml<br>") */ class ActionGroupWithPassedArgumentAndStringSelectorParamCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt b/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt index 7d0bb58e9..c1905ff39 100644 --- a/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt +++ b/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @group functional - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupWithPersistedData.xml<br>") */ class ActionGroupWithPersistedDataCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithSectionAndDataAsArguments.txt b/dev/tests/verification/Resources/ActionGroupWithSectionAndDataAsArguments.txt index f629f32f1..b3dcc585f 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSectionAndDataAsArguments.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSectionAndDataAsArguments.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest/ActionGroupWithSectionAndDataAsArguments.xml<br>") */ class ActionGroupWithSectionAndDataAsArgumentsCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromDefaultArgument.txt b/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromDefaultArgument.txt index 10206867a..6d540cb95 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromDefaultArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromDefaultArgument.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: Action Group With Simple Data Usage From Default Argument") - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest/ActionGroupWithSimpleDataUsageFromDefaultArgument.xml<br>") */ class ActionGroupWithSimpleDataUsageFromDefaultArgumentCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromPassedArgument.txt b/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromPassedArgument.txt index 54aec35a7..826671a63 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromPassedArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromPassedArgument.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: Action Group With Simple Data Usage From Passed Argument") - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest/ActionGroupWithSimpleDataUsageFromPassedArgument.xml<br>") */ class ActionGroupWithSimpleDataUsageFromPassedArgumentCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromDefaultArgument.txt b/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromDefaultArgument.txt index c23b99cab..5e64aded3 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromDefaultArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromDefaultArgument.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: Action Group With Default Argument Value and Argument Value in Param") - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest/ActionGroupWithSingleParameterSelectorFromDefaultArgument.xml<br>") */ class ActionGroupWithSingleParameterSelectorFromDefaultArgumentCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromPassedArgument.txt b/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromPassedArgument.txt index 4a0932b99..e71a8a716 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromPassedArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromPassedArgument.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: Action Group With Passed Argument Value and Argument Value in Param") - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest/ActionGroupWithSingleParameterSelectorFromPassedArgument.xml<br>") */ class ActionGroupWithSingleParameterSelectorFromPassedArgumentCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt b/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt index 8098142fd..d623839d3 100644 --- a/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt +++ b/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest/ActionGroupWithStepKeyReferences.xml<br>") */ class ActionGroupWithStepKeyReferencesCest { diff --git a/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt b/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt index a8f80eae6..18a205544 100644 --- a/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt +++ b/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @group functional - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupWithTopLevelPersistedData.xml<br>") */ class ActionGroupWithTopLevelPersistedDataCest { diff --git a/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt b/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt index e45207249..4bf9332b7 100644 --- a/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt +++ b/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @group functional - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest/ArgumentWithSameNameAsElement.xml<br>") */ class ArgumentWithSameNameAsElementCest { diff --git a/dev/tests/verification/Resources/BasicActionGroupTest.txt b/dev/tests/verification/Resources/BasicActionGroupTest.txt index 7d8c40f0b..95c31b813 100644 --- a/dev/tests/verification/Resources/BasicActionGroupTest.txt +++ b/dev/tests/verification/Resources/BasicActionGroupTest.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @group functional - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest/BasicActionGroupTest.xml<br>") */ class BasicActionGroupTestCest { diff --git a/dev/tests/verification/Resources/BasicFunctionalTest.txt b/dev/tests/verification/Resources/BasicFunctionalTest.txt index 42fd5ff56..7f7e25c60 100644 --- a/dev/tests/verification/Resources/BasicFunctionalTest.txt +++ b/dev/tests/verification/Resources/BasicFunctionalTest.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: A Functional Cest") * @group functional - * @Description("<h3>Test files</h3>verification/TestModule/Test/BasicFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/BasicFunctionalTest/BasicFunctionalTest.xml<br>") */ class BasicFunctionalTestCest { diff --git a/dev/tests/verification/Resources/BasicMergeTest.txt b/dev/tests/verification/Resources/BasicMergeTest.txt index 8171cd892..8842d3d99 100644 --- a/dev/tests/verification/Resources/BasicMergeTest.txt +++ b/dev/tests/verification/Resources/BasicMergeTest.txt @@ -16,7 +16,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; * @Title("[NO TESTCASEID]: BasicMergeTest") * @group functional * @group mergeTest - * @Description("<h3>Test files</h3>verification/TestModule/Test/MergeFunctionalTest.xml<br>verification/TestModuleMerged/Test/MergeFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/MergeFunctionalTest/BasicMergeTest.xml<br>verification/TestModuleMerged/Test/MergeFunctionalTest/BasicMergeTest.xml<br>") */ class BasicMergeTestCest { diff --git a/dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt b/dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt index 86d81f848..72e924954 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: ChildExtendedTestAddHooks") * @group Parent - * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestAddHooks.xml<br>") */ class ChildExtendedTestAddHooksCest { diff --git a/dev/tests/verification/Resources/ChildExtendedTestMerging.txt b/dev/tests/verification/Resources/ChildExtendedTestMerging.txt index 08345bd86..7900ca9a0 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestMerging.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestMerging.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: ChildExtendedTestMerging") * @group Child - * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestMerging.xml<br>") */ class ChildExtendedTestMergingCest { diff --git a/dev/tests/verification/Resources/ChildExtendedTestNoParent.txt b/dev/tests/verification/Resources/ChildExtendedTestNoParent.txt index 4cca6ec06..be775aba9 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestNoParent.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestNoParent.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: ChildExtendedTestNoParent") * @group Child - * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestNoParent.xml<br>") * @group skip */ class ChildExtendedTestNoParentCest diff --git a/dev/tests/verification/Resources/ChildExtendedTestRemoveAction.txt b/dev/tests/verification/Resources/ChildExtendedTestRemoveAction.txt index 370ffe404..d3017e010 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestRemoveAction.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestRemoveAction.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: ChildExtendedTestRemoveAction") * @group Child - * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestRemoveAction.xml<br>") */ class ChildExtendedTestRemoveActionCest { diff --git a/dev/tests/verification/Resources/ChildExtendedTestRemoveHookAction.txt b/dev/tests/verification/Resources/ChildExtendedTestRemoveHookAction.txt index 50b6e030d..0988e5d71 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestRemoveHookAction.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestRemoveHookAction.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: ChildExtendedTestRemoveHookAction") * @group Child - * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestRemoveHookAction.xml<br>") */ class ChildExtendedTestRemoveHookActionCest { diff --git a/dev/tests/verification/Resources/ChildExtendedTestReplace.txt b/dev/tests/verification/Resources/ChildExtendedTestReplace.txt index ce32f6af1..9d0a65a3b 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestReplace.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestReplace.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: ChildExtendedTestReplace") * @group Child - * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestReplace.xml<br>") */ class ChildExtendedTestReplaceCest { diff --git a/dev/tests/verification/Resources/ChildExtendedTestReplaceHook.txt b/dev/tests/verification/Resources/ChildExtendedTestReplaceHook.txt index bbb6c5ef9..c40b46fa0 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestReplaceHook.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestReplaceHook.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: ChildExtendedTestReplaceHook") * @group Child - * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestReplaceHook.xml<br>") */ class ChildExtendedTestReplaceHookCest { diff --git a/dev/tests/verification/Resources/ExtendedActionGroup.txt b/dev/tests/verification/Resources/ExtendedActionGroup.txt index 8996526ba..9ed588df4 100644 --- a/dev/tests/verification/Resources/ExtendedActionGroup.txt +++ b/dev/tests/verification/Resources/ExtendedActionGroup.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest/ExtendedActionGroup.xml<br>") */ class ExtendedActionGroupCest { diff --git a/dev/tests/verification/Resources/ExtendedChildTestInSuiteCest.txt b/dev/tests/verification/Resources/ExtendedChildTestInSuiteCest.txt index e4a006c8f..d1f74abe1 100644 --- a/dev/tests/verification/Resources/ExtendedChildTestInSuiteCest.txt +++ b/dev/tests/verification/Resources/ExtendedChildTestInSuiteCest.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: ExtendedChildTestInSuite") * @group ExtendedTestInSuite - * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest/ExtendedChildTestInSuite.xml<br>") */ class ExtendedChildTestInSuiteCest { diff --git a/dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt b/dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt index 1d5af7d3e..d9f8a72e6 100644 --- a/dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt +++ b/dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: ExtendedChildTestNotInSuite") - * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest/ExtendedChildTestNotInSuite.xml<br>") */ class ExtendedChildTestNotInSuiteCest { diff --git a/dev/tests/verification/Resources/ExtendedRemoveActionGroup.txt b/dev/tests/verification/Resources/ExtendedRemoveActionGroup.txt index fde8842e7..b593a9231 100644 --- a/dev/tests/verification/Resources/ExtendedRemoveActionGroup.txt +++ b/dev/tests/verification/Resources/ExtendedRemoveActionGroup.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest/ExtendedRemoveActionGroup.xml<br>") */ class ExtendedRemoveActionGroupCest { diff --git a/dev/tests/verification/Resources/ExtendingSkippedTest.txt b/dev/tests/verification/Resources/ExtendingSkippedTest.txt index 93e9b6a60..553131988 100644 --- a/dev/tests/verification/Resources/ExtendingSkippedTest.txt +++ b/dev/tests/verification/Resources/ExtendingSkippedTest.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: ChildExtendedTestSkippedParent") * @group Child - * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest/ExtendingSkippedTest.xml<br>") */ class ExtendingSkippedTestCest { diff --git a/dev/tests/verification/Resources/MergeMassViaInsertAfter.txt b/dev/tests/verification/Resources/MergeMassViaInsertAfter.txt index a57ca4471..1a94b90a6 100644 --- a/dev/tests/verification/Resources/MergeMassViaInsertAfter.txt +++ b/dev/tests/verification/Resources/MergeMassViaInsertAfter.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<h3>Test files</h3>verification/TestModule/Test/BasicFunctionalTest.xml<br>verification/TestModule/Test/MergeFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/BasicFunctionalTest/MergeMassViaInsertAfter.xml<br>verification/TestModule/Test/MergeFunctionalTest/MergeMassViaInsertAfter.xml<br>") */ class MergeMassViaInsertAfterCest { diff --git a/dev/tests/verification/Resources/MergeMassViaInsertBefore.txt b/dev/tests/verification/Resources/MergeMassViaInsertBefore.txt index 7c6fdc906..12b073bfb 100644 --- a/dev/tests/verification/Resources/MergeMassViaInsertBefore.txt +++ b/dev/tests/verification/Resources/MergeMassViaInsertBefore.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<h3>Test files</h3>verification/TestModule/Test/BasicFunctionalTest.xml<br>verification/TestModule/Test/MergeFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/BasicFunctionalTest/MergeMassViaInsertBefore.xml<br>verification/TestModule/Test/MergeFunctionalTest/MergeMassViaInsertBefore.xml<br>") */ class MergeMassViaInsertBeforeCest { diff --git a/dev/tests/verification/Resources/MergeSkip.txt b/dev/tests/verification/Resources/MergeSkip.txt index b2a1b8918..d08f52b56 100644 --- a/dev/tests/verification/Resources/MergeSkip.txt +++ b/dev/tests/verification/Resources/MergeSkip.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<h3>Test files</h3>verification/TestModule/Test/MergeFunctionalTest.xml<br>verification/TestModuleMerged/Test/MergeFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/MergeFunctionalTest/MergeSkip.xml<br>verification/TestModuleMerged/Test/MergeFunctionalTest/MergeSkip.xml<br>") */ class MergeSkipCest { diff --git a/dev/tests/verification/Resources/MergedActionGroupTest.txt b/dev/tests/verification/Resources/MergedActionGroupTest.txt index a9c740127..c8401874d 100644 --- a/dev/tests/verification/Resources/MergedActionGroupTest.txt +++ b/dev/tests/verification/Resources/MergedActionGroupTest.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @group functional - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest/MergedActionGroupTest.xml<br>") */ class MergedActionGroupTestCest { diff --git a/dev/tests/verification/Resources/MergedReferencesTest.txt b/dev/tests/verification/Resources/MergedReferencesTest.txt index b3fc29966..74f780aac 100644 --- a/dev/tests/verification/Resources/MergedReferencesTest.txt +++ b/dev/tests/verification/Resources/MergedReferencesTest.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: MergedReferencesTest") * @group functional - * @Description("<h3>Test files</h3>verification/TestModule/Test/MergeFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/MergeFunctionalTest/MergedReferencesTest.xml<br>") */ class MergedReferencesTestCest { diff --git a/dev/tests/verification/Resources/MultipleActionGroupsTest.txt b/dev/tests/verification/Resources/MultipleActionGroupsTest.txt index 5f1db5081..46673f473 100644 --- a/dev/tests/verification/Resources/MultipleActionGroupsTest.txt +++ b/dev/tests/verification/Resources/MultipleActionGroupsTest.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @group functional - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest/MultipleActionGroupsTest.xml<br>") */ class MultipleActionGroupsTestCest { diff --git a/dev/tests/verification/Resources/ParentExtendedTest.txt b/dev/tests/verification/Resources/ParentExtendedTest.txt index 8c756f010..5606b2ac3 100644 --- a/dev/tests/verification/Resources/ParentExtendedTest.txt +++ b/dev/tests/verification/Resources/ParentExtendedTest.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: ParentExtendedTest") * @group Parent - * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ExtendedFunctionalTest/ParentExtendedTest.xml<br>") */ class ParentExtendedTestCest { diff --git a/dev/tests/verification/Resources/PersistedAndXmlEntityArguments.txt b/dev/tests/verification/Resources/PersistedAndXmlEntityArguments.txt index f6956f5d9..d49b99306 100644 --- a/dev/tests/verification/Resources/PersistedAndXmlEntityArguments.txt +++ b/dev/tests/verification/Resources/PersistedAndXmlEntityArguments.txt @@ -13,7 +13,7 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest/PersistedAndXmlEntityArguments.xml<br>") */ class PersistedAndXmlEntityArgumentsCest { diff --git a/dev/tests/verification/Resources/SkippedTest.txt b/dev/tests/verification/Resources/SkippedTest.txt index 95783ca66..7dd9ba280 100644 --- a/dev/tests/verification/Resources/SkippedTest.txt +++ b/dev/tests/verification/Resources/SkippedTest.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: skippedTest") - * @Description("<h3>Test files</h3>verification/TestModule/Test/SkippedTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/SkippedTest/SkippedTest.xml<br>") */ class SkippedTestCest { diff --git a/dev/tests/verification/Resources/SkippedTestNoIssues.txt b/dev/tests/verification/Resources/SkippedTestNoIssues.txt index e8f4726d9..387ada571 100644 --- a/dev/tests/verification/Resources/SkippedTestNoIssues.txt +++ b/dev/tests/verification/Resources/SkippedTestNoIssues.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: skippedNoIssuesTest") - * @Description("<h3>Test files</h3>verification/TestModule/Test/SkippedTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/SkippedTest/SkippedTestNoIssues.xml<br>") * @group skip */ class SkippedTestNoIssuesCest diff --git a/dev/tests/verification/Resources/SkippedTestTwoIssues.txt b/dev/tests/verification/Resources/SkippedTestTwoIssues.txt index 4a801856e..0087ba92d 100644 --- a/dev/tests/verification/Resources/SkippedTestTwoIssues.txt +++ b/dev/tests/verification/Resources/SkippedTestTwoIssues.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: skippedMultipleIssuesTest") - * @Description("<h3>Test files</h3>verification/TestModule/Test/SkippedTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/SkippedTest/SkippedTestTwoIssues.xml<br>") */ class SkippedTestTwoIssuesCest { diff --git a/dev/tests/verification/Resources/SkippedTestWithHooks.txt b/dev/tests/verification/Resources/SkippedTestWithHooks.txt index ad59d48c3..6b2682c49 100644 --- a/dev/tests/verification/Resources/SkippedTestWithHooks.txt +++ b/dev/tests/verification/Resources/SkippedTestWithHooks.txt @@ -14,7 +14,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Title("[NO TESTCASEID]: skippedTestWithHooks") - * @Description("<h3>Test files</h3>verification/TestModule/Test/SkippedTest.xml<br>") + * @Description("<h3>Test files</h3>verification/TestModule/Test/SkippedTest/SkippedTestWithHooks.xml<br>") */ class SkippedTestWithHooksCest { diff --git a/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup.xml deleted file mode 100644 index 45ccdbd24..000000000 --- a/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup.xml +++ /dev/null @@ -1,125 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> - <actionGroup name="actionGroupWithoutArguments"> - <wait time="1" stepKey="waitForNothing" /> - </actionGroup> - - <actionGroup name="actionGroupWithDefaultArgumentAndStringSelectorParam"> - <arguments> - <argument name="someArgument" defaultValue="ReplacementPerson" /> - </arguments> - - <see selector="{{SampleSection.oneParamElement('test1')}}" userInput="{{someArgument.firstname}}" stepKey="seeFirstName" /> - </actionGroup> - - <actionGroup name="actionGroupWithTwoArguments"> - <arguments> - <argument name="somePerson"/> - <argument name="anotherPerson"/> - </arguments> - - <see selector="{{anotherPerson.firstname}}" userInput="{{somePerson.firstname}}" stepKey="seeFirstName" /> - </actionGroup> - - <actionGroup name="actionGroupWithSingleParameterSelectorFromArgument"> - <arguments> - <argument name="someArgument" defaultValue="ReplacementPerson" /> - </arguments> - - <see selector="{{SampleSection.oneParamElement(someArgument.firstname)}}" userInput="{{someArgument.lastname}}" stepKey="seeLastName" /> - </actionGroup> - - <actionGroup name="actionGroupWithMultipleParameterSelectorsFromArgument"> - <arguments> - <argument name="someArgument" defaultValue="ReplacementPerson" /> - </arguments> - - <see selector="{{SampleSection.threeParamElement(someArgument.firstname, someArgument.lastname, 'test')}}" userInput="{{someArgument.lastname}}" stepKey="seeLastName" /> - </actionGroup> - - <actionGroup name="actionGroupWithStringUsage"> - <arguments> - <argument name="someArgument" type="string" defaultValue="stringLiteral"/> - </arguments> - <see selector="{{SampleSection.oneParamElement(someArgument)}}" userInput="{{someArgument}}" stepKey="see1" /> - </actionGroup> - - <actionGroup name="actionGroupWithEntityUsage"> - <arguments> - <argument name="someArgument" type="entity" defaultValue="stringLiteral"/> - </arguments> - <see selector="{{SampleSection.oneParamElement(someArgument)}}" userInput="{{someArgument}}" stepKey="see1" /> - </actionGroup> - - <actionGroup name="actionGroupWithNestedArgument"> - <arguments> - <argument name="count" defaultValue="10" type="string"/> - </arguments> - <grabMultiple selector="selector" stepKey="grabProducts"/> - <assertCount stepKey="assertCount"> - <expectedResult type="int">{{count}}</expectedResult> - <actualResult type="variable">grabProducts</actualResult> - </assertCount> - </actionGroup> - - <actionGroup name="ActionGroupToExtend"> - <arguments> - <argument name="count" type="string"/> - </arguments> - <grabMultiple selector="selector" stepKey="grabProducts"/> - <assertCount stepKey="assertCount"> - <expectedResult type="int">{{count}}</expectedResult> - <actualResult type="variable">grabProducts</actualResult> - </assertCount> - </actionGroup> - - <actionGroup name="extendTestActionGroup" extends="ActionGroupToExtend"> - <arguments> - <argument name="otherCount" type="string"/> - </arguments> - <grabMultiple selector="notASelector" stepKey="grabProducts"/> - <comment userInput="New Input After" stepKey="afterGrabProducts" after="grabProducts"/> - <comment userInput="New Input Before" stepKey="beforeGrabProducts" before="grabProducts"/> - <assertCount stepKey="assertSecondCount"> - <expectedResult type="int">{{otherCount}}</expectedResult> - <actualResult type="variable">grabProducts</actualResult> - </assertCount> - </actionGroup> - - <actionGroup name="extendBasicActionGroup"> - <comment stepKey="removeMe" userInput="This Should Be Removed"/> - </actionGroup> - - <actionGroup name="extendRemoveTestActionGroup" extends="extendBasicActionGroup"> - <remove keyForRemoval="removeMe"/> - </actionGroup> - - <actionGroup name="actionGroupWithCreateData"> - <createData entity="ApiCategory" stepKey="createCategory"/> - <createData entity="ApiConfigurableProduct" stepKey="createConfigProduct"> - <requiredEntity createDataKey="createCategory"/> - </createData> - </actionGroup> - - <actionGroup name="actionGroupContainsStepKeyInArgValue"> - <arguments> - <argument name="sameStepKeyAsArg" type="string" defaultValue="stringLiteral"/> - </arguments> - <see selector=".selector" userInput="{{sameStepKeyAsArg}}" stepKey="arg1" /> - </actionGroup> - - <actionGroup name="actionGroupWithSectionAndData"> - <arguments> - <argument name="content" type="string"/> - <argument name="section"/> - </arguments> - <waitForElementVisible selector="{{section.oneParamElement(content)}}" stepKey="arg1"/> - </actionGroup> -</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupContainsStepKeyInArgValueActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupContainsStepKeyInArgValueActionGroup.xml new file mode 100644 index 000000000..afc7f0e04 --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupContainsStepKeyInArgValueActionGroup.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="actionGroupContainsStepKeyInArgValue"> + <arguments> + <argument name="sameStepKeyAsArg" type="string" defaultValue="stringLiteral"/> + </arguments> + <see selector=".selector" userInput="{{sameStepKeyAsArg}}" stepKey="arg1" /> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupToExtendActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupToExtendActionGroup.xml new file mode 100644 index 000000000..8e87f46c5 --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupToExtendActionGroup.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="ActionGroupToExtend"> + <arguments> + <argument name="count" type="string"/> + </arguments> + <grabMultiple selector="selector" stepKey="grabProducts"/> + <assertCount stepKey="assertCount"> + <expectedResult type="int">{{count}}</expectedResult> + <actualResult type="variable">grabProducts</actualResult> + </assertCount> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithCreateDataActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithCreateDataActionGroup.xml new file mode 100644 index 000000000..9f3a11a4f --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithCreateDataActionGroup.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="actionGroupWithCreateData"> + <createData entity="ApiCategory" stepKey="createCategory"/> + <createData entity="ApiConfigurableProduct" stepKey="createConfigProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithDefaultArgumentAndStringSelectorParamActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithDefaultArgumentAndStringSelectorParamActionGroup.xml new file mode 100644 index 000000000..6a397120c --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithDefaultArgumentAndStringSelectorParamActionGroup.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="actionGroupWithDefaultArgumentAndStringSelectorParam"> + <arguments> + <argument name="someArgument" defaultValue="ReplacementPerson" /> + </arguments> + + <see selector="{{SampleSection.oneParamElement('test1')}}" userInput="{{someArgument.firstname}}" stepKey="seeFirstName" /> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithEntityUsageActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithEntityUsageActionGroup.xml new file mode 100644 index 000000000..d85c5f661 --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithEntityUsageActionGroup.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="actionGroupWithEntityUsage"> + <arguments> + <argument name="someArgument" type="entity" defaultValue="stringLiteral"/> + </arguments> + <see selector="{{SampleSection.oneParamElement(someArgument)}}" userInput="{{someArgument}}" stepKey="see1" /> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithMultipleParameterSelectorsFromArgumentActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithMultipleParameterSelectorsFromArgumentActionGroup.xml new file mode 100644 index 000000000..44561f91d --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithMultipleParameterSelectorsFromArgumentActionGroup.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="actionGroupWithMultipleParameterSelectorsFromArgument"> + <arguments> + <argument name="someArgument" defaultValue="ReplacementPerson" /> + </arguments> + + <see selector="{{SampleSection.threeParamElement(someArgument.firstname, someArgument.lastname, 'test')}}" userInput="{{someArgument.lastname}}" stepKey="seeLastName" /> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithNestedArgumentActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithNestedArgumentActionGroup.xml new file mode 100644 index 000000000..2e767481d --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithNestedArgumentActionGroup.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="actionGroupWithNestedArgument"> + <arguments> + <argument name="count" defaultValue="10" type="string"/> + </arguments> + <grabMultiple selector="selector" stepKey="grabProducts"/> + <assertCount stepKey="assertCount"> + <expectedResult type="int">{{count}}</expectedResult> + <actualResult type="variable">grabProducts</actualResult> + </assertCount> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithSectionAndDataActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithSectionAndDataActionGroup.xml new file mode 100644 index 000000000..4917a4545 --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithSectionAndDataActionGroup.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="actionGroupWithSectionAndData"> + <arguments> + <argument name="content" type="string"/> + <argument name="section"/> + </arguments> + <waitForElementVisible selector="{{section.oneParamElement(content)}}" stepKey="arg1"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithSingleParameterSelectorFromArgumentActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithSingleParameterSelectorFromArgumentActionGroup.xml new file mode 100644 index 000000000..1e6c2de78 --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithSingleParameterSelectorFromArgumentActionGroup.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="actionGroupWithSingleParameterSelectorFromArgument"> + <arguments> + <argument name="someArgument" defaultValue="ReplacementPerson" /> + </arguments> + + <see selector="{{SampleSection.oneParamElement(someArgument.firstname)}}" userInput="{{someArgument.lastname}}" stepKey="seeLastName" /> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithStringUsageActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithStringUsageActionGroup.xml new file mode 100644 index 000000000..0ee47f9f2 --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithStringUsageActionGroup.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="actionGroupWithStringUsage"> + <arguments> + <argument name="someArgument" type="string" defaultValue="stringLiteral"/> + </arguments> + <see selector="{{SampleSection.oneParamElement(someArgument)}}" userInput="{{someArgument}}" stepKey="see1" /> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithTwoArgumentsActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithTwoArgumentsActionGroup.xml new file mode 100644 index 000000000..d54143e4c --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithTwoArgumentsActionGroup.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="actionGroupWithTwoArguments"> + <arguments> + <argument name="somePerson"/> + <argument name="anotherPerson"/> + </arguments> + + <see selector="{{anotherPerson.firstname}}" userInput="{{somePerson.firstname}}" stepKey="seeFirstName" /> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithoutArgumentsActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithoutArgumentsActionGroup.xml new file mode 100644 index 000000000..428ca1a40 --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithoutArgumentsActionGroup.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="actionGroupWithoutArguments"> + <wait time="1" stepKey="waitForNothing" /> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ExtendBasicActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ExtendBasicActionGroup.xml new file mode 100644 index 000000000..bda82ebad --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ExtendBasicActionGroup.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="extendBasicActionGroup"> + <comment stepKey="removeMe" userInput="This Should Be Removed"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ExtendRemoveTestActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ExtendRemoveTestActionGroup.xml new file mode 100644 index 000000000..f4f8e5647 --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ExtendRemoveTestActionGroup.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="extendRemoveTestActionGroup" extends="extendBasicActionGroup"> + <remove keyForRemoval="removeMe"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ExtendTestActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ExtendTestActionGroup.xml new file mode 100644 index 000000000..0b9bf6041 --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ExtendTestActionGroup.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="extendTestActionGroup" extends="ActionGroupToExtend"> + <arguments> + <argument name="otherCount" type="string"/> + </arguments> + <grabMultiple selector="notASelector" stepKey="grabProducts"/> + <comment userInput="New Input After" stepKey="afterGrabProducts" after="grabProducts"/> + <comment userInput="New Input Before" stepKey="beforeGrabProducts" before="grabProducts"/> + <assertCount stepKey="assertSecondCount"> + <expectedResult type="int">{{otherCount}}</expectedResult> + <actualResult type="variable">grabProducts</actualResult> + </assertCount> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup.xml deleted file mode 100644 index 30cba3848..000000000 --- a/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup.xml +++ /dev/null @@ -1,106 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> - <actionGroup name="FunctionalActionGroup"> - <fillField selector="#foo" userInput="myData1" stepKey="fillField1"/> - <fillField selector="#bar" userInput="myData2" stepKey="fillField2"/> - </actionGroup> - <actionGroup name="FunctionalActionGroupWithData"> - <arguments> - <argument name="person" defaultValue="DefaultPerson"/> - </arguments> - <amOnPage url="{{SamplePage.url(person.firstname,person.lastname)}}" stepKey="amOnPage1"/> - <fillField selector="#foo" userInput="{{person.firstname}}" stepKey="fillField1"/> - <fillField selector="#bar" userInput="{{person.lastname}}" stepKey="fillField2"/> - <searchAndMultiSelectOption selector="#foo" parameterArray="[{{person.firstname}}, {{person.lastname}}]" stepKey="multi1"/> - <see selector="{{SampleSection.oneParamElement(person.firstname)}}" stepKey="see1"/> - </actionGroup> - <actionGroup name="FunctionalActionGroupNoDefault"> - <arguments> - <argument name="person"/> - </arguments> - <fillField selector="#foo" userInput="{{person.firstname}}" stepKey="fillField1"/> - <fillField selector="#bar" userInput="{{person.lastname}}" stepKey="fillField2"/> - <see selector="{{SampleSection.twoParamElement(person.firstname,person.lastname)}}" stepKey="see2"/> - </actionGroup> - <actionGroup name="FunctionalActionGroupForMerge"> - <arguments> - <argument name="myArg"/> - </arguments> - <fillField stepKey="deleteMe" userInput="Please delete me" selector="#delete" /> - <see selector="{{SampleSection.oneParamElement(myArg.firstname)}}" stepKey="see1"/> - <amOnPage url="{{SamplePage.url(myArg.firstname,myArg.lastname)}}" stepKey="amOnPage1"/> - </actionGroup> - <actionGroup name="FunctionalActionGroupWithTrickyArgument"> - <arguments> - <argument name="simple" defaultValue="simpleData"/> - </arguments> - <seeElement stepKey="see1" selector="{{SampleSection.simpleElement}}"/> - <seeElement stepKey="see2" selector="{{SampleSection.simpleElementOneParam(simple.firstname)}}"/> - </actionGroup> - <actionGroup name="FunctionActionGroupWithStepKeyReferences"> - <createData entity="simpleData" stepKey="createSimpleData"/> - <grabTextFrom selector=".class" stepKey="grabTextData"/> - <fillField stepKey="fill1" selector=".{$grabTextData}" userInput="$createSimpleData.field$"/> - <comment userInput="Invocation stepKey will not be appended in non stepKey instances" stepKey="comment1"/> - <click selector="{$action0}" stepKey="action0"/> - <fillField selector="{$action1}" stepKey="action1"/> - <comment userInput="Invocation stepKey will be appended in non stepKey instances" stepKey="comment2"/> - <executeJS function="{$action3}" stepKey="action3"/> - <magentoCLI command="{$action4}" arguments=""stuffHere"" stepKey="action4"/> - <generateDate date="{$action5}" format="H:i:s" stepKey="action5"/> - <formatMoney userInput="{$action6}" stepKey="action6"/> - <deleteData createDataKey="{$action7}" stepKey="action7"/> - <getData entity="{$action8}" stepKey="action8"/> - <updateData entity="{$action9}" stepKey="action9" createDataKey="1"/> - <createData entity="{$action10}" stepKey="action10"/> - <grabAttributeFrom selector="{$action11}" userInput="someInput" stepKey="action11"/> - <grabCookie userInput="{$action12}" parameterArray="['domain' => 'www.google.com']" stepKey="action12"/> - <grabFromCurrentUrl regex="{$action13}" stepKey="action13"/> - <grabMultiple selector="{$action14}" stepKey="action14"/> - <grabTextFrom selector="{$action15}" stepKey="action15"/> - <grabValueFrom selector="{$action16}" stepKey="action16"/> - </actionGroup> - <actionGroup name="FunctionalActionGroupForMassMergeBefore"> - <fillField selector="#foo" userInput="foo" stepKey="fillField1"/> - <fillField selector="#bar" userInput="bar" stepKey="fillField2"/> - <fillField selector="#baz" userInput="baz" stepKey="fillField3"/> - </actionGroup> - <actionGroup name="FunctionalActionGroupForMassMergeAfter"> - <fillField selector="#foo" userInput="foo" stepKey="fillField1"/> - <fillField selector="#bar" userInput="bar" stepKey="fillField2"/> - <fillField selector="#baz" userInput="baz" stepKey="fillField3"/> - </actionGroup> - <actionGroup name="FunctionalActionGroupWithXmlAndPersistedData"> - <arguments> - <argument name="xmlData" defaultValue="uniqueData"/> - <argument name="persistedData"/> - </arguments> - <seeInCurrentUrl url="/{{persistedData.urlKey}}.html?___store={{xmlData.firstname}}" stepKey="checkUrl"/> - </actionGroup> - <actionGroup name="SectionArgumentWithParameterizedSelector"> - <arguments> - <argument name="section" defaultValue="SampleSection"/> - </arguments> - <executeJS function="{{section.oneParamElement('full-width')}}" stepKey="keyone"/> - </actionGroup> - <actionGroup name="actionGroupWithParametrizedSelectors"> - <arguments> - <argument name="param" type="entity"/> - <argument name="param2" type="entity" defaultValue="simpleParamData"/> - </arguments> - <executeJS function="return 1" stepKey="testVariable"/> - <executeJS function="return 'test'" stepKey="testVariable2"/> - <createData entity="simpleData" stepKey="createSimpleData"/> - <click selector="{{SampleSection.twoParamElement({$testVariable2}, param.firstname)}}" stepKey="click1"/> - <click selector="{{SampleSection.threeParamElement(param.lastname, param2.uniqueNamePre, {$testVariable})}}" stepKey="click2"/> - <seeElement selector="{{SampleSection.fourParamElement(param.middlename, {$testVariable}, {$testVariable2}, $$createSimpleData.name$$)}}" stepKey="see1"/> - </actionGroup> -</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/ActionGroupWithParametrizedSelectorsActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/ActionGroupWithParametrizedSelectorsActionGroup.xml new file mode 100644 index 000000000..cfa4e1343 --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/ActionGroupWithParametrizedSelectorsActionGroup.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="actionGroupWithParametrizedSelectors"> + <arguments> + <argument name="param" type="entity"/> + <argument name="param2" type="entity" defaultValue="simpleParamData"/> + </arguments> + <executeJS function="return 1" stepKey="testVariable"/> + <executeJS function="return 'test'" stepKey="testVariable2"/> + <createData entity="simpleData" stepKey="createSimpleData"/> + <click selector="{{SampleSection.twoParamElement({$testVariable2}, param.firstname)}}" stepKey="click1"/> + <click selector="{{SampleSection.threeParamElement(param.lastname, param2.uniqueNamePre, {$testVariable})}}" stepKey="click2"/> + <seeElement selector="{{SampleSection.fourParamElement(param.middlename, {$testVariable}, {$testVariable2}, $$createSimpleData.name$$)}}" stepKey="see1"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionActionGroupWithStepKeyReferencesActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionActionGroupWithStepKeyReferencesActionGroup.xml new file mode 100644 index 000000000..8d36773e8 --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionActionGroupWithStepKeyReferencesActionGroup.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="FunctionActionGroupWithStepKeyReferences"> + <createData entity="simpleData" stepKey="createSimpleData"/> + <grabTextFrom selector=".class" stepKey="grabTextData"/> + <fillField stepKey="fill1" selector=".{$grabTextData}" userInput="$createSimpleData.field$"/> + <comment userInput="Invocation stepKey will not be appended in non stepKey instances" stepKey="comment1"/> + <click selector="{$action0}" stepKey="action0"/> + <fillField selector="{$action1}" stepKey="action1"/> + <comment userInput="Invocation stepKey will be appended in non stepKey instances" stepKey="comment2"/> + <executeJS function="{$action3}" stepKey="action3"/> + <magentoCLI command="{$action4}" arguments=""stuffHere"" stepKey="action4"/> + <generateDate date="{$action5}" format="H:i:s" stepKey="action5"/> + <formatMoney userInput="{$action6}" stepKey="action6"/> + <deleteData createDataKey="{$action7}" stepKey="action7"/> + <getData entity="{$action8}" stepKey="action8"/> + <updateData entity="{$action9}" stepKey="action9" createDataKey="1"/> + <createData entity="{$action10}" stepKey="action10"/> + <grabAttributeFrom selector="{$action11}" userInput="someInput" stepKey="action11"/> + <grabCookie userInput="{$action12}" parameterArray="['domain' => 'www.google.com']" stepKey="action12"/> + <grabFromCurrentUrl regex="{$action13}" stepKey="action13"/> + <grabMultiple selector="{$action14}" stepKey="action14"/> + <grabTextFrom selector="{$action15}" stepKey="action15"/> + <grabValueFrom selector="{$action16}" stepKey="action16"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroup.xml new file mode 100644 index 000000000..1da276f10 --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroup.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="FunctionalActionGroup"> + <fillField selector="#foo" userInput="myData1" stepKey="fillField1"/> + <fillField selector="#bar" userInput="myData2" stepKey="fillField2"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupForMassMergeAfterActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupForMassMergeAfterActionGroup.xml new file mode 100644 index 000000000..0868a28e2 --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupForMassMergeAfterActionGroup.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="FunctionalActionGroupForMassMergeAfter"> + <fillField selector="#foo" userInput="foo" stepKey="fillField1"/> + <fillField selector="#bar" userInput="bar" stepKey="fillField2"/> + <fillField selector="#baz" userInput="baz" stepKey="fillField3"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupForMassMergeBeforeActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupForMassMergeBeforeActionGroup.xml new file mode 100644 index 000000000..e9b7f52c2 --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupForMassMergeBeforeActionGroup.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="FunctionalActionGroupForMassMergeBefore"> + <fillField selector="#foo" userInput="foo" stepKey="fillField1"/> + <fillField selector="#bar" userInput="bar" stepKey="fillField2"/> + <fillField selector="#baz" userInput="baz" stepKey="fillField3"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupForMergeActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupForMergeActionGroup.xml new file mode 100644 index 000000000..f3fabe074 --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupForMergeActionGroup.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="FunctionalActionGroupForMerge"> + <arguments> + <argument name="myArg"/> + </arguments> + <fillField stepKey="deleteMe" userInput="Please delete me" selector="#delete" /> + <see selector="{{SampleSection.oneParamElement(myArg.firstname)}}" stepKey="see1"/> + <amOnPage url="{{SamplePage.url(myArg.firstname,myArg.lastname)}}" stepKey="amOnPage1"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupNoDefaultActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupNoDefaultActionGroup.xml new file mode 100644 index 000000000..5313178f9 --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupNoDefaultActionGroup.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="FunctionalActionGroupNoDefault"> + <arguments> + <argument name="person"/> + </arguments> + <fillField selector="#foo" userInput="{{person.firstname}}" stepKey="fillField1"/> + <fillField selector="#bar" userInput="{{person.lastname}}" stepKey="fillField2"/> + <see selector="{{SampleSection.twoParamElement(person.firstname,person.lastname)}}" stepKey="see2"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupWithDataActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupWithDataActionGroup.xml new file mode 100644 index 000000000..6948f8ffd --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupWithDataActionGroup.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="FunctionalActionGroupWithData"> + <arguments> + <argument name="person" defaultValue="DefaultPerson"/> + </arguments> + <amOnPage url="{{SamplePage.url(person.firstname,person.lastname)}}" stepKey="amOnPage1"/> + <fillField selector="#foo" userInput="{{person.firstname}}" stepKey="fillField1"/> + <fillField selector="#bar" userInput="{{person.lastname}}" stepKey="fillField2"/> + <searchAndMultiSelectOption selector="#foo" parameterArray="[{{person.firstname}}, {{person.lastname}}]" stepKey="multi1"/> + <see selector="{{SampleSection.oneParamElement(person.firstname)}}" stepKey="see1"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupWithTrickyArgumentActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupWithTrickyArgumentActionGroup.xml new file mode 100644 index 000000000..cad553151 --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupWithTrickyArgumentActionGroup.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="FunctionalActionGroupWithTrickyArgument"> + <arguments> + <argument name="simple" defaultValue="simpleData"/> + </arguments> + <seeElement stepKey="see1" selector="{{SampleSection.simpleElement}}"/> + <seeElement stepKey="see2" selector="{{SampleSection.simpleElementOneParam(simple.firstname)}}"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupWithXmlAndPersistedDataActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupWithXmlAndPersistedDataActionGroup.xml new file mode 100644 index 000000000..949d5b95d --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupWithXmlAndPersistedDataActionGroup.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="FunctionalActionGroupWithXmlAndPersistedData"> + <arguments> + <argument name="xmlData" defaultValue="uniqueData"/> + <argument name="persistedData"/> + </arguments> + <seeInCurrentUrl url="/{{persistedData.urlKey}}.html?___store={{xmlData.firstname}}" stepKey="checkUrl"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/SectionArgumentWithParameterizedSelectorActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/SectionArgumentWithParameterizedSelectorActionGroup.xml new file mode 100644 index 000000000..d82b6d64a --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/SectionArgumentWithParameterizedSelectorActionGroup.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="SectionArgumentWithParameterizedSelector"> + <arguments> + <argument name="section" defaultValue="SampleSection"/> + </arguments> + <executeJS function="{{section.oneParamElement('full-width')}}" stepKey="keyone"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/MergeFunctionalActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/MergeFunctionalActionGroup.xml deleted file mode 100644 index 7d8585772..000000000 --- a/dev/tests/verification/TestModule/ActionGroup/MergeFunctionalActionGroup.xml +++ /dev/null @@ -1,28 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> - <actionGroup name="FunctionalActionGroupForMerge"> - <see stepKey="myMergedSeeElement" selector=".merge .{{myArg.firstname}}" before="see1"/> - <click stepKey="myMergedClick" selector=".merge .{{myArg.lastname}}" after="amOnPage1"/> - <remove keyForRemoval="deleteMe"/> - </actionGroup> - - <actionGroup name="FunctionalActionGroupForMassMergeBefore" insertBefore="fillField2"> - <click stepKey="mergeBeforeBar" selector="#foo2"/> - <click stepKey="mergeAfterFoo2" selector="#bar2"/> - <click stepKey="mergeAfterBar2" selector="#baz2"/> - </actionGroup> - - <actionGroup name="FunctionalActionGroupForMassMergeAfter" insertAfter="fillField2"> - <click stepKey="mergeAfterBar" selector="#foo2"/> - <click stepKey="mergeAfterFoo2" selector="#bar2"/> - <click stepKey="mergeAfterBar2" selector="#baz2"/> - </actionGroup> -</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/MergeFunctionalActionGroup/FunctionalActionGroupForMassMergeAfterActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/MergeFunctionalActionGroup/FunctionalActionGroupForMassMergeAfterActionGroup.xml new file mode 100644 index 000000000..cca3c1b24 --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/MergeFunctionalActionGroup/FunctionalActionGroupForMassMergeAfterActionGroup.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="FunctionalActionGroupForMassMergeAfter" insertAfter="fillField2"> + <click stepKey="mergeAfterBar" selector="#foo2"/> + <click stepKey="mergeAfterFoo2" selector="#bar2"/> + <click stepKey="mergeAfterBar2" selector="#baz2"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/MergeFunctionalActionGroup/FunctionalActionGroupForMassMergeBeforeActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/MergeFunctionalActionGroup/FunctionalActionGroupForMassMergeBeforeActionGroup.xml new file mode 100644 index 000000000..d9a5c3f55 --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/MergeFunctionalActionGroup/FunctionalActionGroupForMassMergeBeforeActionGroup.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="FunctionalActionGroupForMassMergeBefore" insertBefore="fillField2"> + <click stepKey="mergeBeforeBar" selector="#foo2"/> + <click stepKey="mergeAfterFoo2" selector="#bar2"/> + <click stepKey="mergeAfterBar2" selector="#baz2"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/MergeFunctionalActionGroup/FunctionalActionGroupForMergeActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/MergeFunctionalActionGroup/FunctionalActionGroupForMergeActionGroup.xml new file mode 100644 index 000000000..dd451f511 --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/MergeFunctionalActionGroup/FunctionalActionGroupForMergeActionGroup.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="FunctionalActionGroupForMerge"> + <see stepKey="myMergedSeeElement" selector=".merge .{{myArg.firstname}}" before="see1"/> + <click stepKey="myMergedClick" selector=".merge .{{myArg.lastname}}" after="amOnPage1"/> + <remove keyForRemoval="deleteMe"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup.xml deleted file mode 100644 index f98fd2406..000000000 --- a/dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup.xml +++ /dev/null @@ -1,41 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> - <actionGroup name="PersistenceActionGroup"> - <arguments> - <argument name="arg1" type="string"/> - <argument name="arg2"/> - <argument name="arg3"/> - </arguments> - <createData entity="simpleData" stepKey="createDataAG1"> - <field key="firstname">{{arg1}}</field> - </createData> - <createData entity="simpleData" stepKey="createDataAG2"> - <field key="firstname">{{arg2}}</field> - </createData> - <createData entity="simpleData" stepKey="createDataAG3"> - <field key="firstname">{{arg3}}</field> - </createData> - </actionGroup> - <actionGroup name="DataPersistenceAppendingActionGroup"> - <createData entity="entity" stepKey="createData"/> - <updateData entity="newEntity" createDataKey="createData" stepKey="updateData"/> - <deleteData createDataKey="createData" stepKey="deleteData"/> - <getData entity="someEneity" stepKey="getData"/> - <comment userInput="$createData.field$" stepKey="comment"/> - </actionGroup> - <actionGroup name="DataPersistenceSelfReferenceActionGroup"> - <createData entity="entity1" stepKey="createData1"/> - <createData entity="entity2" stepKey="createData2"/> - <createData entity="entity3" stepKey="createData3"> - <field key="key1">$createData1.field$</field> - <field key="key2">$createData2.field$</field> - </createData> - </actionGroup> -</actionGroups> \ No newline at end of file diff --git a/dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup/DataPersistenceAppendingActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup/DataPersistenceAppendingActionGroup.xml new file mode 100644 index 000000000..e5ee7ce4f --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup/DataPersistenceAppendingActionGroup.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="DataPersistenceAppendingActionGroup"> + <createData entity="entity" stepKey="createData"/> + <updateData entity="newEntity" createDataKey="createData" stepKey="updateData"/> + <deleteData createDataKey="createData" stepKey="deleteData"/> + <getData entity="someEneity" stepKey="getData"/> + <comment userInput="$createData.field$" stepKey="comment"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup/DataPersistenceSelfReferenceActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup/DataPersistenceSelfReferenceActionGroup.xml new file mode 100644 index 000000000..091a7a6e3 --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup/DataPersistenceSelfReferenceActionGroup.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="DataPersistenceSelfReferenceActionGroup"> + <createData entity="entity1" stepKey="createData1"/> + <createData entity="entity2" stepKey="createData2"/> + <createData entity="entity3" stepKey="createData3"> + <field key="key1">$createData1.field$</field> + <field key="key2">$createData2.field$</field> + </createData> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup/PersistenceActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup/PersistenceActionGroup.xml new file mode 100644 index 000000000..c164e13c8 --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup/PersistenceActionGroup.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="PersistenceActionGroup"> + <arguments> + <argument name="arg1" type="string"/> + <argument name="arg2"/> + <argument name="arg3"/> + </arguments> + <createData entity="simpleData" stepKey="createDataAG1"> + <field key="firstname">{{arg1}}</field> + </createData> + <createData entity="simpleData" stepKey="createDataAG2"> + <field key="firstname">{{arg2}}</field> + </createData> + <createData entity="simpleData" stepKey="createDataAG3"> + <field key="firstname">{{arg3}}</field> + </createData> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/Page/SamplePage.xml b/dev/tests/verification/TestModule/Page/SamplePage.xml deleted file mode 100644 index 59efded6e..000000000 --- a/dev/tests/verification/TestModule/Page/SamplePage.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> - <page name="SamplePage" url="/{{var1}}/{{var2}}.html" area="storefront" module="UnknownVendor_TestModule" parameterized="true"> - <section name="SampleSection"/> - </page> - <page name="NoParamPage" url="/page.html" area="storefront" module="UnknownVendor_TestModule"> - <section name="SampleSection"/> - </page> - <page name="OneParamPage" url="/{{var1}}/page.html" area="storefront" module="UnknownVendor_TestModule" parameterized="true"> - <section name="SampleSection"/> - </page> - <page name="TwoParamPage" url="/{{var1}}/{{var2}}.html" area="storefront" module="UnknownVendor_TestModule" parameterized="true"> - <section name="SampleSection"/> - </page> - <page name="AdminPage" url="/backend" area="admin" module="UnknownVendor_TestModule"> - <section name="SampleSection"/> - </page> - <page name="AdminOneParamPage" url="/{{var1}}/page.html" area="admin" module="UnknownVendor_TestModule" parameterized="true"> - <section name="SampleSection"/> - </page> - <page name="ExternalPage" url="http://myFullUrl.com/" area="external" module="UnknownVendor_TestModule"> - <section name="SampleSection"/> - </page> -</pages> diff --git a/dev/tests/verification/TestModule/Page/SamplePage/AdminOneParamPage.xml b/dev/tests/verification/TestModule/Page/SamplePage/AdminOneParamPage.xml new file mode 100644 index 000000000..de51a11fa --- /dev/null +++ b/dev/tests/verification/TestModule/Page/SamplePage/AdminOneParamPage.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="AdminOneParamPage" url="/{{var1}}/page.html" area="admin" module="UnknownVendor_TestModule" parameterized="true"> + <section name="SampleSection"/> + </page> +</pages> diff --git a/dev/tests/verification/TestModule/Page/SamplePage/AdminPage.xml b/dev/tests/verification/TestModule/Page/SamplePage/AdminPage.xml new file mode 100644 index 000000000..12f554da6 --- /dev/null +++ b/dev/tests/verification/TestModule/Page/SamplePage/AdminPage.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="AdminPage" url="/backend" area="admin" module="UnknownVendor_TestModule"> + <section name="SampleSection"/> + </page> +</pages> diff --git a/dev/tests/verification/TestModule/Page/SamplePage/ExternalPage.xml b/dev/tests/verification/TestModule/Page/SamplePage/ExternalPage.xml new file mode 100644 index 000000000..5c3e131e4 --- /dev/null +++ b/dev/tests/verification/TestModule/Page/SamplePage/ExternalPage.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="ExternalPage" url="http://myFullUrl.com/" area="external" module="UnknownVendor_TestModule"> + <section name="SampleSection"/> + </page> +</pages> diff --git a/dev/tests/verification/TestModule/Page/SamplePage/NoParamPage.xml b/dev/tests/verification/TestModule/Page/SamplePage/NoParamPage.xml new file mode 100644 index 000000000..2a9b0efc5 --- /dev/null +++ b/dev/tests/verification/TestModule/Page/SamplePage/NoParamPage.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="NoParamPage" url="/page.html" area="storefront" module="UnknownVendor_TestModule"> + <section name="SampleSection"/> + </page> +</pages> diff --git a/dev/tests/verification/TestModule/Page/SamplePage/OneParamPage.xml b/dev/tests/verification/TestModule/Page/SamplePage/OneParamPage.xml new file mode 100644 index 000000000..2986ebed9 --- /dev/null +++ b/dev/tests/verification/TestModule/Page/SamplePage/OneParamPage.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="OneParamPage" url="/{{var1}}/page.html" area="storefront" module="UnknownVendor_TestModule" parameterized="true"> + <section name="SampleSection"/> + </page> +</pages> diff --git a/dev/tests/verification/TestModule/Page/SamplePage/SamplePage.xml b/dev/tests/verification/TestModule/Page/SamplePage/SamplePage.xml new file mode 100644 index 000000000..7baa9858e --- /dev/null +++ b/dev/tests/verification/TestModule/Page/SamplePage/SamplePage.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="SamplePage" url="/{{var1}}/{{var2}}.html" area="storefront" module="UnknownVendor_TestModule" parameterized="true"> + <section name="SampleSection"/> + </page> +</pages> diff --git a/dev/tests/verification/TestModule/Page/SamplePage/TwoParamPage.xml b/dev/tests/verification/TestModule/Page/SamplePage/TwoParamPage.xml new file mode 100644 index 000000000..4ab1f632a --- /dev/null +++ b/dev/tests/verification/TestModule/Page/SamplePage/TwoParamPage.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="TwoParamPage" url="/{{var1}}/{{var2}}.html" area="storefront" module="UnknownVendor_TestModule" parameterized="true"> + <section name="SampleSection"/> + </page> +</pages> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest.xml b/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest.xml deleted file mode 100644 index 8c24794e1..000000000 --- a/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest.xml +++ /dev/null @@ -1,187 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - <test name="BasicActionGroupTest"> - <annotations> - <severity value="CRITICAL"/> - <group value="functional"/> - <features value="Action Group Functional Cest"/> - <stories value="MQE-433"/> - </annotations> - <before> - <createData entity="ReplacementPerson" stepKey="createPersonParam"/> - <actionGroup ref="FunctionalActionGroup" stepKey="beforeGroup"/> - </before> - <amOnPage stepKey="step1" url="/someUrl"/> - <actionGroup ref="FunctionalActionGroup" stepKey="actionGroup1"/> - <click stepKey="step6" selector="loginButton"/> - </test> - <test name="ActionGroupWithDataTest"> - <annotations> - <severity value="CRITICAL"/> - <group value="functional"/> - <features value="Action Group Functional Cest"/> - <stories value="MQE-433"/> - </annotations> - <before> - <createData entity="ReplacementPerson" stepKey="createPersonParam"/> - <actionGroup ref="FunctionalActionGroup" stepKey="beforeGroup"/> - </before> - <amOnPage stepKey="step1" url="/someUrl"/> - <actionGroup ref="FunctionalActionGroupWithData" stepKey="actionGroupWithData1"/> - <click stepKey="step6" selector="loginButton"/> - <after> - <actionGroup ref="FunctionalActionGroup" stepKey="afterGroup"/> - </after> - </test> - <test name="ActionGroupWithDataOverrideTest"> - <annotations> - <severity value="CRITICAL"/> - <group value="functional"/> - <features value="Action Group Functional Cest"/> - <stories value="MQE-433"/> - </annotations> - <before> - <createData entity="ReplacementPerson" stepKey="createPersonParam"/> - <actionGroup ref="FunctionalActionGroup" stepKey="beforeGroup"/> - </before> - <amOnPage stepKey="step1" url="/someUrl"/> - <actionGroup ref="FunctionalActionGroupWithData" stepKey="actionGroupWithDataOverride1"> - <argument name="person" value="ReplacementPerson"/> - </actionGroup> - <click stepKey="step6" selector="loginButton"/> - <after> - <actionGroup ref="FunctionalActionGroup" stepKey="afterGroup"/> - </after> - </test> - <test name="ActionGroupWithNoDefaultTest"> - <annotations> - <severity value="CRITICAL"/> - <group value="functional"/> - <features value="Action Group Functional Cest"/> - <stories value="MQE-433"/> - </annotations> - <before> - <createData entity="ReplacementPerson" stepKey="createPersonParam"/> - <actionGroup ref="FunctionalActionGroup" stepKey="beforeGroup"/> - </before> - <amOnPage stepKey="step1" url="/someUrl"/> - <actionGroup ref="FunctionalActionGroupNoDefault" stepKey="actionGroupWithDataOverride1"> - <argument name="person" value="DefaultPerson"/> - </actionGroup> - <click stepKey="step6" selector="loginButton"/> - <after> - <actionGroup ref="FunctionalActionGroup" stepKey="afterGroup"/> - </after> - </test> - <test name="ActionGroupWithPersistedData"> - <annotations> - <severity value="CRITICAL"/> - <group value="functional"/> - <features value="Action Group Functional Cest"/> - <stories value="MQE-433"/> - </annotations> - <before> - <createData entity="ReplacementPerson" stepKey="createPersonParam"/> - <actionGroup ref="FunctionalActionGroup" stepKey="beforeGroup"/> - </before> - <createData entity="DefaultPerson" stepKey="createPerson"/> - <actionGroup ref="FunctionalActionGroupWithData" stepKey="actionGroupWithPersistedData1"> - <argument name="person" value="$createPerson$"/> - </actionGroup> - <after> - <actionGroup ref="FunctionalActionGroup" stepKey="afterGroup"/> - </after> - </test> - <test name="ActionGroupWithTopLevelPersistedData"> - <annotations> - <severity value="CRITICAL"/> - <group value="functional"/> - <features value="Action Group Functional Cest"/> - <stories value="MQE-433"/> - </annotations> - <before> - <createData entity="ReplacementPerson" stepKey="createPersonParam"/> - <actionGroup ref="FunctionalActionGroup" stepKey="beforeGroup"/> - </before> - <actionGroup ref="FunctionalActionGroupWithData" stepKey="actionGroupWithPersistedData1"> - <argument name="person" value="$$createPersonParam$$"/> - </actionGroup> - <after> - <actionGroup ref="FunctionalActionGroup" stepKey="afterGroup"/> - </after> - </test> - <test name="MultipleActionGroupsTest"> - <annotations> - <severity value="CRITICAL"/> - <group value="functional"/> - <features value="Action Group Functional Cest"/> - <stories value="MQE-433"/> - </annotations> - <before> - <createData entity="ReplacementPerson" stepKey="createPersonParam"/> - <actionGroup ref="FunctionalActionGroup" stepKey="beforeGroup"/> - </before> - <amOnPage stepKey="step1" url="/someUrl"/> - <actionGroup ref="FunctionalActionGroupWithData" stepKey="actionGroup1"/> - <click stepKey="step6" selector="loginButton"/> - <actionGroup ref="FunctionalActionGroupWithData" stepKey="actionGroupWithDataOverride2"> - <argument name="person" value="ReplacementPerson"/> - </actionGroup> - <after> - <actionGroup ref="FunctionalActionGroup" stepKey="afterGroup"/> - </after> - </test> - <test name="MergedActionGroupTest"> - <annotations> - <severity value="CRITICAL"/> - <group value="functional"/> - <features value="Action Group Functional Cest"/> - <stories value="MQE-433"/> - </annotations> - <before> - <createData entity="ReplacementPerson" stepKey="createPersonParam"/> - <actionGroup ref="FunctionalActionGroup" stepKey="beforeGroup"/> - </before> - <actionGroup ref="FunctionalActionGroupForMerge" stepKey="actionGroupForMerge"> - <argument name="myArg" value="DefaultPerson"/> - </actionGroup> - <after> - <actionGroup ref="FunctionalActionGroup" stepKey="afterGroup"/> - </after> - </test> - <test name="ArgumentWithSameNameAsElement"> - <annotations> - <severity value="CRITICAL"/> - <group value="functional"/> - <features value="Action Group Functional Cest"/> - <stories value="MQE-433"/> - </annotations> - <before> - <createData entity="ReplacementPerson" stepKey="createPersonParam"/> - <actionGroup ref="FunctionalActionGroup" stepKey="beforeGroup"/> - </before> - <actionGroup ref="FunctionalActionGroupWithTrickyArgument" stepKey="actionGroup1"/> - <after> - <actionGroup ref="FunctionalActionGroup" stepKey="afterGroup"/> - </after> - </test> - <test name="ActionGroupMergedViaInsertBefore"> - <actionGroup ref="FunctionalActionGroupForMassMergeBefore" stepKey="keyone"/> - </test> - <test name="ActionGroupMergedViaInsertAfter"> - <actionGroup ref="FunctionalActionGroupForMassMergeAfter" stepKey="keyone"/> - </test> - <test name="PersistedAndXmlEntityArguments"> - <actionGroup ref="FunctionalActionGroupWithXmlAndPersistedData" stepKey="afterGroup"> - <argument name="persistedData" value="$persistedInTest$"/> - </actionGroup> - </test> -</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupMergedViaInsertAfter.xml b/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupMergedViaInsertAfter.xml new file mode 100644 index 000000000..0bca36759 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupMergedViaInsertAfter.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ActionGroupMergedViaInsertAfter"> + <actionGroup ref="FunctionalActionGroupForMassMergeAfter" stepKey="keyone"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupMergedViaInsertBefore.xml b/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupMergedViaInsertBefore.xml new file mode 100644 index 000000000..06d9c965d --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupMergedViaInsertBefore.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ActionGroupMergedViaInsertBefore"> + <actionGroup ref="FunctionalActionGroupForMassMergeBefore" stepKey="keyone"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupWithDataOverrideTest.xml b/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupWithDataOverrideTest.xml new file mode 100644 index 000000000..e1b72784d --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupWithDataOverrideTest.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ActionGroupWithDataOverrideTest"> + <annotations> + <severity value="CRITICAL"/> + <group value="functional"/> + <features value="Action Group Functional Cest"/> + <stories value="MQE-433"/> + </annotations> + <before> + <createData entity="ReplacementPerson" stepKey="createPersonParam"/> + <actionGroup ref="FunctionalActionGroup" stepKey="beforeGroup"/> + </before> + <amOnPage stepKey="step1" url="/someUrl"/> + <actionGroup ref="FunctionalActionGroupWithData" stepKey="actionGroupWithDataOverride1"> + <argument name="person" value="ReplacementPerson"/> + </actionGroup> + <click stepKey="step6" selector="loginButton"/> + <after> + <actionGroup ref="FunctionalActionGroup" stepKey="afterGroup"/> + </after> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupWithDataTest.xml b/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupWithDataTest.xml new file mode 100644 index 000000000..379d79a48 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupWithDataTest.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ActionGroupWithDataTest"> + <annotations> + <severity value="CRITICAL"/> + <group value="functional"/> + <features value="Action Group Functional Cest"/> + <stories value="MQE-433"/> + </annotations> + <before> + <createData entity="ReplacementPerson" stepKey="createPersonParam"/> + <actionGroup ref="FunctionalActionGroup" stepKey="beforeGroup"/> + </before> + <amOnPage stepKey="step1" url="/someUrl"/> + <actionGroup ref="FunctionalActionGroupWithData" stepKey="actionGroupWithData1"/> + <click stepKey="step6" selector="loginButton"/> + <after> + <actionGroup ref="FunctionalActionGroup" stepKey="afterGroup"/> + </after> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupWithNoDefaultTest.xml b/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupWithNoDefaultTest.xml new file mode 100644 index 000000000..d5e77c7e7 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupWithNoDefaultTest.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ActionGroupWithNoDefaultTest"> + <annotations> + <severity value="CRITICAL"/> + <group value="functional"/> + <features value="Action Group Functional Cest"/> + <stories value="MQE-433"/> + </annotations> + <before> + <createData entity="ReplacementPerson" stepKey="createPersonParam"/> + <actionGroup ref="FunctionalActionGroup" stepKey="beforeGroup"/> + </before> + <amOnPage stepKey="step1" url="/someUrl"/> + <actionGroup ref="FunctionalActionGroupNoDefault" stepKey="actionGroupWithDataOverride1"> + <argument name="person" value="DefaultPerson"/> + </actionGroup> + <click stepKey="step6" selector="loginButton"/> + <after> + <actionGroup ref="FunctionalActionGroup" stepKey="afterGroup"/> + </after> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupWithPersistedData.xml b/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupWithPersistedData.xml new file mode 100644 index 000000000..bfb8a7cc2 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupWithPersistedData.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ActionGroupWithPersistedData"> + <annotations> + <severity value="CRITICAL"/> + <group value="functional"/> + <features value="Action Group Functional Cest"/> + <stories value="MQE-433"/> + </annotations> + <before> + <createData entity="ReplacementPerson" stepKey="createPersonParam"/> + <actionGroup ref="FunctionalActionGroup" stepKey="beforeGroup"/> + </before> + <createData entity="DefaultPerson" stepKey="createPerson"/> + <actionGroup ref="FunctionalActionGroupWithData" stepKey="actionGroupWithPersistedData1"> + <argument name="person" value="$createPerson$"/> + </actionGroup> + <after> + <actionGroup ref="FunctionalActionGroup" stepKey="afterGroup"/> + </after> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupWithTopLevelPersistedData.xml b/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupWithTopLevelPersistedData.xml new file mode 100644 index 000000000..a7f2a558b --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupWithTopLevelPersistedData.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ActionGroupWithTopLevelPersistedData"> + <annotations> + <severity value="CRITICAL"/> + <group value="functional"/> + <features value="Action Group Functional Cest"/> + <stories value="MQE-433"/> + </annotations> + <before> + <createData entity="ReplacementPerson" stepKey="createPersonParam"/> + <actionGroup ref="FunctionalActionGroup" stepKey="beforeGroup"/> + </before> + <actionGroup ref="FunctionalActionGroupWithData" stepKey="actionGroupWithPersistedData1"> + <argument name="person" value="$$createPersonParam$$"/> + </actionGroup> + <after> + <actionGroup ref="FunctionalActionGroup" stepKey="afterGroup"/> + </after> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ArgumentWithSameNameAsElement.xml b/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ArgumentWithSameNameAsElement.xml new file mode 100644 index 000000000..e8e994d46 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ArgumentWithSameNameAsElement.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ArgumentWithSameNameAsElement"> + <annotations> + <severity value="CRITICAL"/> + <group value="functional"/> + <features value="Action Group Functional Cest"/> + <stories value="MQE-433"/> + </annotations> + <before> + <createData entity="ReplacementPerson" stepKey="createPersonParam"/> + <actionGroup ref="FunctionalActionGroup" stepKey="beforeGroup"/> + </before> + <actionGroup ref="FunctionalActionGroupWithTrickyArgument" stepKey="actionGroup1"/> + <after> + <actionGroup ref="FunctionalActionGroup" stepKey="afterGroup"/> + </after> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/BasicActionGroupTest.xml b/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/BasicActionGroupTest.xml new file mode 100644 index 000000000..0c72b0f19 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/BasicActionGroupTest.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="BasicActionGroupTest"> + <annotations> + <severity value="CRITICAL"/> + <group value="functional"/> + <features value="Action Group Functional Cest"/> + <stories value="MQE-433"/> + </annotations> + <before> + <createData entity="ReplacementPerson" stepKey="createPersonParam"/> + <actionGroup ref="FunctionalActionGroup" stepKey="beforeGroup"/> + </before> + <amOnPage stepKey="step1" url="/someUrl"/> + <actionGroup ref="FunctionalActionGroup" stepKey="actionGroup1"/> + <click stepKey="step6" selector="loginButton"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/MergedActionGroupTest.xml b/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/MergedActionGroupTest.xml new file mode 100644 index 000000000..a5a3a0685 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/MergedActionGroupTest.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="MergedActionGroupTest"> + <annotations> + <severity value="CRITICAL"/> + <group value="functional"/> + <features value="Action Group Functional Cest"/> + <stories value="MQE-433"/> + </annotations> + <before> + <createData entity="ReplacementPerson" stepKey="createPersonParam"/> + <actionGroup ref="FunctionalActionGroup" stepKey="beforeGroup"/> + </before> + <actionGroup ref="FunctionalActionGroupForMerge" stepKey="actionGroupForMerge"> + <argument name="myArg" value="DefaultPerson"/> + </actionGroup> + <after> + <actionGroup ref="FunctionalActionGroup" stepKey="afterGroup"/> + </after> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/MultipleActionGroupsTest.xml b/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/MultipleActionGroupsTest.xml new file mode 100644 index 000000000..c5473b789 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/MultipleActionGroupsTest.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="MultipleActionGroupsTest"> + <annotations> + <severity value="CRITICAL"/> + <group value="functional"/> + <features value="Action Group Functional Cest"/> + <stories value="MQE-433"/> + </annotations> + <before> + <createData entity="ReplacementPerson" stepKey="createPersonParam"/> + <actionGroup ref="FunctionalActionGroup" stepKey="beforeGroup"/> + </before> + <amOnPage stepKey="step1" url="/someUrl"/> + <actionGroup ref="FunctionalActionGroupWithData" stepKey="actionGroup1"/> + <click stepKey="step6" selector="loginButton"/> + <actionGroup ref="FunctionalActionGroupWithData" stepKey="actionGroupWithDataOverride2"> + <argument name="person" value="ReplacementPerson"/> + </actionGroup> + <after> + <actionGroup ref="FunctionalActionGroup" stepKey="afterGroup"/> + </after> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/PersistedAndXmlEntityArguments.xml b/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/PersistedAndXmlEntityArguments.xml new file mode 100644 index 000000000..defd72174 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/PersistedAndXmlEntityArguments.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="PersistedAndXmlEntityArguments"> + <actionGroup ref="FunctionalActionGroupWithXmlAndPersistedData" stepKey="afterGroup"> + <argument name="persistedData" value="$persistedInTest$"/> + </actionGroup> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupTest.xml b/dev/tests/verification/TestModule/Test/ActionGroupTest.xml deleted file mode 100644 index 5dce96934..000000000 --- a/dev/tests/verification/TestModule/Test/ActionGroupTest.xml +++ /dev/null @@ -1,181 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - <test name="ActionGroupWithNoArguments"> - <annotations> - <severity value="BLOCKER"/> - <title value="Action Group With No Argument"/> - </annotations> - <actionGroup ref="actionGroupWithoutArguments" stepKey="actionGroup"/> - </test> - - <test name="ActionGroupWithDefaultArgumentAndStringSelectorParam"> - <annotations> - <severity value="BLOCKER"/> - <title value="Action Group With Default Argument Value and Hardcoded Value in Param"/> - </annotations> - - <actionGroup ref="actionGroupWithDefaultArgumentAndStringSelectorParam" stepKey="actionGroup"/> - </test> - - <test name="ActionGroupWithPassedArgumentAndStringSelectorParam"> - <annotations> - <severity value="BLOCKER"/> - <title value="Action Group With Passed Argument Value and Hardcoded Value in Param"/> - </annotations> - - <actionGroup ref="actionGroupWithDefaultArgumentAndStringSelectorParam" stepKey="actionGroup"> - <argument name="someArgument" value="UniquePerson"/> - </actionGroup> - </test> - - <test name="ActionGroupWithSingleParameterSelectorFromDefaultArgument"> - <annotations> - <severity value="BLOCKER"/> - <title value="Action Group With Default Argument Value and Argument Value in Param"/> - </annotations> - - <actionGroup ref="actionGroupWithSingleParameterSelectorFromArgument" stepKey="actionGroup"/> - </test> - - <test name="ActionGroupWithSingleParameterSelectorFromPassedArgument"> - <annotations> - <severity value="BLOCKER"/> - <title value="Action Group With Passed Argument Value and Argument Value in Param"/> - </annotations> - - <actionGroup ref="actionGroupWithSingleParameterSelectorFromArgument" stepKey="actionGroup"> - <argument name="someArgument" value="UniquePerson"/> - </actionGroup> - </test> - - <test name="ActionGroupWithMultipleParameterSelectorsFromDefaultArgument"> - <annotations> - <severity value="BLOCKER"/> - <title value="Action Group With Passed Argument Value and Multiple Argument Values in Param"/> - </annotations> - - <actionGroup ref="actionGroupWithMultipleParameterSelectorsFromArgument" stepKey="actionGroup"/> - </test> - - <test name="ActionGroupWithSimpleDataUsageFromPassedArgument"> - <annotations> - <severity value="CRITICAL"/> - <title value="Action Group With Simple Data Usage From Passed Argument"/> - </annotations> - - <actionGroup ref="actionGroupWithStringUsage" stepKey="actionGroup1"> - <argument name="someArgument" value="overrideString"/> - </actionGroup> - <actionGroup ref="actionGroupWithStringUsage" stepKey="actionGroup11"> - <argument name="someArgument" value="1"/> - </actionGroup> - <actionGroup ref="actionGroupWithStringUsage" stepKey="actionGroup12"> - <argument name="someArgument" value="1.5"/> - </actionGroup> - <actionGroup ref="actionGroupWithStringUsage" stepKey="actionGroup13"> - <argument name="someArgument" value="true"/> - </actionGroup> - <actionGroup ref="actionGroupWithStringUsage" stepKey="actionGroup2"> - <argument name="someArgument" value="simpleData.firstname"/> - </actionGroup> - <actionGroup ref="actionGroupWithStringUsage" stepKey="actionGroup3"> - <argument name="someArgument" value="$persisted.data$"/> - </actionGroup> - - <actionGroup ref="actionGroupWithEntityUsage" stepKey="actionGroup4"> - <argument name="someArgument" value="simpleData.firstname"/> - </actionGroup> - <actionGroup ref="actionGroupWithEntityUsage" stepKey="actionGroup5"> - <argument name="someArgument" value="$simpleData.firstname$"/> - </actionGroup> - <actionGroup ref="actionGroupWithEntityUsage" stepKey="actionGroup6"> - <argument name="someArgument" value="$simpleData.firstname[0]$"/> - </actionGroup> - <actionGroup ref="actionGroupWithEntityUsage" stepKey="actionGroup7"> - <argument name="someArgument" value="$simpleData.firstname[data_index]$"/> - </actionGroup> - </test> - - <test name="ActionGroupWithSimpleDataUsageFromDefaultArgument"> - <annotations> - <severity value="CRITICAL"/> - <title value="Action Group With Simple Data Usage From Default Argument"/> - </annotations> - <actionGroup ref="actionGroupWithStringUsage" stepKey="actionGroup"/> - </test> - - <test name="ActionGroupWithStepKeyReferences"> - <actionGroup ref="FunctionActionGroupWithStepKeyReferences" stepKey="actionGroup"/> - </test> - - <test name="ActionGroupUsingNestedArgument"> - <actionGroup ref="ActionGroupToExtend" stepKey="actionGroup"> - <argument name="count" value="99"/> - </actionGroup> - </test> - - <test name="ActionGroupToExtend"> - <actionGroup ref="ActionGroupToExtend" stepKey="actionGroup"> - <argument name="count" value="99"/> - </actionGroup> - </test> - - <test name="ExtendedActionGroup"> - <actionGroup ref="extendTestActionGroup" stepKey="actionGroup"> - <argument name="count" value="99"/> - <argument name="otherCount" value="8000"/> - </actionGroup> - </test> - - <test name="ExtendedRemoveActionGroup"> - <actionGroup ref="extendRemoveTestActionGroup" stepKey="actionGroup"/> - </test> - - <test name="ActionGroupUsingCreateData"> - <before> - <actionGroup ref="actionGroupWithCreateData" stepKey="Key1"/> - </before> - </test> - - <test name="ActionGroupSkipReadiness"> - <actionGroup ref="actionGroupWithSkipReadinessActions" stepKey="skipReadinessActionGroup"/> - </test> - - <test name="ActionGroupContainsStepKeyInArgText"> - <before> - <actionGroup ref="actionGroupContainsStepKeyInArgValue" stepKey="actionGroup"> - <argument name="sameStepKeyAsArg" value="arg1"/> - </actionGroup> - </before> - <actionGroup ref="actionGroupContainsStepKeyInArgValue" stepKey="actionGroup"> - <argument name="sameStepKeyAsArg" value="arg1"/> - </actionGroup> - </test> - - <test name="ActionGroupWithSectionAndDataAsArguments"> - <actionGroup ref="actionGroupWithSectionAndData" stepKey="actionGroup"> - <argument name="content" value="{{simpleData.firstname}}"/> - <argument name="section" value="SampleSection"/> - </actionGroup> - </test> - - <test name="ActionGroupWithParameterizedElementWithHyphen"> - <actionGroup ref="SectionArgumentWithParameterizedSelector" stepKey="actionGroup"> - <argument name="section" value="SampleSection"/> - </actionGroup> - </test> - - <test name="ActionGroupWithParameterizedElementsWithStepKeyReferences"> - <actionGroup ref="actionGroupWithParametrizedSelectors" stepKey="actionGroup"> - <argument name="param" value="simpleData"/> - <argument name="param2" value="simpleParamData"/> - </actionGroup> - </test> -</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupContainsStepKeyInArgText.xml b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupContainsStepKeyInArgText.xml new file mode 100644 index 000000000..bdea3c163 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupContainsStepKeyInArgText.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ActionGroupContainsStepKeyInArgText"> + <before> + <actionGroup ref="actionGroupContainsStepKeyInArgValue" stepKey="actionGroup"> + <argument name="sameStepKeyAsArg" value="arg1"/> + </actionGroup> + </before> + <actionGroup ref="actionGroupContainsStepKeyInArgValue" stepKey="actionGroup"> + <argument name="sameStepKeyAsArg" value="arg1"/> + </actionGroup> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupSkipReadiness.xml b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupSkipReadiness.xml new file mode 100644 index 000000000..776a6f10f --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupSkipReadiness.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ActionGroupSkipReadiness"> + <actionGroup ref="actionGroupWithSkipReadinessActions" stepKey="skipReadinessActionGroup"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupToExtend.xml b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupToExtend.xml new file mode 100644 index 000000000..a08122fdb --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupToExtend.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ActionGroupToExtend"> + <actionGroup ref="ActionGroupToExtend" stepKey="actionGroup"> + <argument name="count" value="99"/> + </actionGroup> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupUsingCreateData.xml b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupUsingCreateData.xml new file mode 100644 index 000000000..92d142700 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupUsingCreateData.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ActionGroupUsingCreateData"> + <before> + <actionGroup ref="actionGroupWithCreateData" stepKey="Key1"/> + </before> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupUsingNestedArgument.xml b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupUsingNestedArgument.xml new file mode 100644 index 000000000..100c498b6 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupUsingNestedArgument.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ActionGroupUsingNestedArgument"> + <actionGroup ref="ActionGroupToExtend" stepKey="actionGroup"> + <argument name="count" value="99"/> + </actionGroup> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithDefaultArgumentAndStringSelectorParam.xml b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithDefaultArgumentAndStringSelectorParam.xml new file mode 100644 index 000000000..7d780ef11 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithDefaultArgumentAndStringSelectorParam.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ActionGroupWithDefaultArgumentAndStringSelectorParam"> + <annotations> + <severity value="BLOCKER"/> + <title value="Action Group With Default Argument Value and Hardcoded Value in Param"/> + </annotations> + + <actionGroup ref="actionGroupWithDefaultArgumentAndStringSelectorParam" stepKey="actionGroup"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.xml b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.xml new file mode 100644 index 000000000..2607a9fd0 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ActionGroupWithMultipleParameterSelectorsFromDefaultArgument"> + <annotations> + <severity value="BLOCKER"/> + <title value="Action Group With Passed Argument Value and Multiple Argument Values in Param"/> + </annotations> + + <actionGroup ref="actionGroupWithMultipleParameterSelectorsFromArgument" stepKey="actionGroup"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithNoArguments.xml b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithNoArguments.xml new file mode 100644 index 000000000..36c8b53b2 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithNoArguments.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ActionGroupWithNoArguments"> + <annotations> + <severity value="BLOCKER"/> + <title value="Action Group With No Argument"/> + </annotations> + <actionGroup ref="actionGroupWithoutArguments" stepKey="actionGroup"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithParameterizedElementWithHyphen.xml b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithParameterizedElementWithHyphen.xml new file mode 100644 index 000000000..261c493f1 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithParameterizedElementWithHyphen.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ActionGroupWithParameterizedElementWithHyphen"> + <actionGroup ref="SectionArgumentWithParameterizedSelector" stepKey="actionGroup"> + <argument name="section" value="SampleSection"/> + </actionGroup> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithParameterizedElementsWithStepKeyReferences.xml b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithParameterizedElementsWithStepKeyReferences.xml new file mode 100644 index 000000000..f99004311 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithParameterizedElementsWithStepKeyReferences.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ActionGroupWithParameterizedElementsWithStepKeyReferences"> + <actionGroup ref="actionGroupWithParametrizedSelectors" stepKey="actionGroup"> + <argument name="param" value="simpleData"/> + <argument name="param2" value="simpleParamData"/> + </actionGroup> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithPassedArgumentAndStringSelectorParam.xml b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithPassedArgumentAndStringSelectorParam.xml new file mode 100644 index 000000000..ea8e98b8a --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithPassedArgumentAndStringSelectorParam.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ActionGroupWithPassedArgumentAndStringSelectorParam"> + <annotations> + <severity value="BLOCKER"/> + <title value="Action Group With Passed Argument Value and Hardcoded Value in Param"/> + </annotations> + + <actionGroup ref="actionGroupWithDefaultArgumentAndStringSelectorParam" stepKey="actionGroup"> + <argument name="someArgument" value="UniquePerson"/> + </actionGroup> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithSectionAndDataAsArguments.xml b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithSectionAndDataAsArguments.xml new file mode 100644 index 000000000..dacb2ed18 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithSectionAndDataAsArguments.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ActionGroupWithSectionAndDataAsArguments"> + <actionGroup ref="actionGroupWithSectionAndData" stepKey="actionGroup"> + <argument name="content" value="{{simpleData.firstname}}"/> + <argument name="section" value="SampleSection"/> + </actionGroup> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithSimpleDataUsageFromDefaultArgument.xml b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithSimpleDataUsageFromDefaultArgument.xml new file mode 100644 index 000000000..a33603c07 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithSimpleDataUsageFromDefaultArgument.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ActionGroupWithSimpleDataUsageFromDefaultArgument"> + <annotations> + <severity value="CRITICAL"/> + <title value="Action Group With Simple Data Usage From Default Argument"/> + </annotations> + <actionGroup ref="actionGroupWithStringUsage" stepKey="actionGroup"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithSimpleDataUsageFromPassedArgument.xml b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithSimpleDataUsageFromPassedArgument.xml new file mode 100644 index 000000000..61aa66f9b --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithSimpleDataUsageFromPassedArgument.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ActionGroupWithSimpleDataUsageFromPassedArgument"> + <annotations> + <severity value="CRITICAL"/> + <title value="Action Group With Simple Data Usage From Passed Argument"/> + </annotations> + + <actionGroup ref="actionGroupWithStringUsage" stepKey="actionGroup1"> + <argument name="someArgument" value="overrideString"/> + </actionGroup> + <actionGroup ref="actionGroupWithStringUsage" stepKey="actionGroup11"> + <argument name="someArgument" value="1"/> + </actionGroup> + <actionGroup ref="actionGroupWithStringUsage" stepKey="actionGroup12"> + <argument name="someArgument" value="1.5"/> + </actionGroup> + <actionGroup ref="actionGroupWithStringUsage" stepKey="actionGroup13"> + <argument name="someArgument" value="true"/> + </actionGroup> + <actionGroup ref="actionGroupWithStringUsage" stepKey="actionGroup2"> + <argument name="someArgument" value="simpleData.firstname"/> + </actionGroup> + <actionGroup ref="actionGroupWithStringUsage" stepKey="actionGroup3"> + <argument name="someArgument" value="$persisted.data$"/> + </actionGroup> + + <actionGroup ref="actionGroupWithEntityUsage" stepKey="actionGroup4"> + <argument name="someArgument" value="simpleData.firstname"/> + </actionGroup> + <actionGroup ref="actionGroupWithEntityUsage" stepKey="actionGroup5"> + <argument name="someArgument" value="$simpleData.firstname$"/> + </actionGroup> + <actionGroup ref="actionGroupWithEntityUsage" stepKey="actionGroup6"> + <argument name="someArgument" value="$simpleData.firstname[0]$"/> + </actionGroup> + <actionGroup ref="actionGroupWithEntityUsage" stepKey="actionGroup7"> + <argument name="someArgument" value="$simpleData.firstname[data_index]$"/> + </actionGroup> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithSingleParameterSelectorFromDefaultArgument.xml b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithSingleParameterSelectorFromDefaultArgument.xml new file mode 100644 index 000000000..f76e45acf --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithSingleParameterSelectorFromDefaultArgument.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ActionGroupWithSingleParameterSelectorFromDefaultArgument"> + <annotations> + <severity value="BLOCKER"/> + <title value="Action Group With Default Argument Value and Argument Value in Param"/> + </annotations> + + <actionGroup ref="actionGroupWithSingleParameterSelectorFromArgument" stepKey="actionGroup"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithSingleParameterSelectorFromPassedArgument.xml b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithSingleParameterSelectorFromPassedArgument.xml new file mode 100644 index 000000000..d9bfbe656 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithSingleParameterSelectorFromPassedArgument.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ActionGroupWithSingleParameterSelectorFromPassedArgument"> + <annotations> + <severity value="BLOCKER"/> + <title value="Action Group With Passed Argument Value and Argument Value in Param"/> + </annotations> + + <actionGroup ref="actionGroupWithSingleParameterSelectorFromArgument" stepKey="actionGroup"> + <argument name="someArgument" value="UniquePerson"/> + </actionGroup> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithStepKeyReferences.xml b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithStepKeyReferences.xml new file mode 100644 index 000000000..d68190f83 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupWithStepKeyReferences.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ActionGroupWithStepKeyReferences"> + <actionGroup ref="FunctionActionGroupWithStepKeyReferences" stepKey="actionGroup"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupTest/ExtendedActionGroup.xml b/dev/tests/verification/TestModule/Test/ActionGroupTest/ExtendedActionGroup.xml new file mode 100644 index 000000000..c7bb24c4f --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupTest/ExtendedActionGroup.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ExtendedActionGroup"> + <actionGroup ref="extendTestActionGroup" stepKey="actionGroup"> + <argument name="count" value="99"/> + <argument name="otherCount" value="8000"/> + </actionGroup> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupTest/ExtendedRemoveActionGroup.xml b/dev/tests/verification/TestModule/Test/ActionGroupTest/ExtendedRemoveActionGroup.xml new file mode 100644 index 000000000..bcbed8f23 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupTest/ExtendedRemoveActionGroup.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ExtendedRemoveActionGroup"> + <actionGroup ref="extendRemoveTestActionGroup" stepKey="actionGroup"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/BasicFunctionalTest.xml b/dev/tests/verification/TestModule/Test/BasicFunctionalTest/BasicFunctionalTest.xml similarity index 94% rename from dev/tests/verification/TestModule/Test/BasicFunctionalTest.xml rename to dev/tests/verification/TestModule/Test/BasicFunctionalTest/BasicFunctionalTest.xml index fdc415501..ea2a48e9e 100644 --- a/dev/tests/verification/TestModule/Test/BasicFunctionalTest.xml +++ b/dev/tests/verification/TestModule/Test/BasicFunctionalTest/BasicFunctionalTest.xml @@ -5,9 +5,8 @@ * See COPYING.txt for license details. */ --> - <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="BasicFunctionalTest"> <annotations> <severity value="CRITICAL"/> @@ -135,14 +134,4 @@ <waitForJS function="someJsFunction" time="30" stepKey="waitForJSKey1" /> <waitForText selector=".functionalTestSelector" userInput="someInput" time="30" stepKey="waitForText1"/> </test> - <test name="MergeMassViaInsertBefore"> - <fillField selector="#foo" userInput="foo" stepKey="fillField1"/> - <fillField selector="#bar" userInput="bar" stepKey="fillField2"/> - <fillField selector="#baz" userInput="baz" stepKey="fillField3"/> - </test> - <test name="MergeMassViaInsertAfter"> - <fillField selector="#foo" userInput="foo" stepKey="fillField1"/> - <fillField selector="#bar" userInput="bar" stepKey="fillField2"/> - <fillField selector="#baz" userInput="baz" stepKey="fillField3"/> - </test> </tests> diff --git a/dev/tests/verification/TestModule/Test/BasicFunctionalTest/MergeMassViaInsertAfter.xml b/dev/tests/verification/TestModule/Test/BasicFunctionalTest/MergeMassViaInsertAfter.xml new file mode 100644 index 000000000..6efe33e49 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/BasicFunctionalTest/MergeMassViaInsertAfter.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="MergeMassViaInsertAfter"> + <fillField selector="#foo" userInput="foo" stepKey="fillField1"/> + <fillField selector="#bar" userInput="bar" stepKey="fillField2"/> + <fillField selector="#baz" userInput="baz" stepKey="fillField3"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/BasicFunctionalTest/MergeMassViaInsertBefore.xml b/dev/tests/verification/TestModule/Test/BasicFunctionalTest/MergeMassViaInsertBefore.xml new file mode 100644 index 000000000..897fb51cc --- /dev/null +++ b/dev/tests/verification/TestModule/Test/BasicFunctionalTest/MergeMassViaInsertBefore.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="MergeMassViaInsertBefore"> + <fillField selector="#foo" userInput="foo" stepKey="fillField1"/> + <fillField selector="#bar" userInput="bar" stepKey="fillField2"/> + <fillField selector="#baz" userInput="baz" stepKey="fillField3"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest.xml b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest.xml deleted file mode 100644 index 486a6036f..000000000 --- a/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest.xml +++ /dev/null @@ -1,201 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - <test name="ParentExtendedTest"> - <annotations> - <severity value="AVERAGE"/> - <title value="ParentExtendedTest"/> - <group value="Parent"/> - <features value="Parent"/> - <stories value="Parent"/> - </annotations> - <before> - <amOnPage url="/beforeUrl" stepKey="beforeAmOnPageKey"/> - </before> - <after> - <amOnPage url="/afterUrl" stepKey="afterAmOnPageKey"/> - </after> - <comment stepKey="basicCommentWithNoData" userInput="Parent Comment"/> - </test> - - <test name="ChildExtendedTestReplace" extends="ParentExtendedTest"> - <annotations> - <severity value="MINOR"/> - <title value="ChildExtendedTestReplace"/> - <group value="Child"/> - <features value="Child"/> - <stories value="Child"/> - </annotations> - <comment stepKey="basicCommentWithNoData" userInput="Different Input"/> - </test> - - <test name="ChildExtendedTestReplaceHook" extends="ParentExtendedTest"> - <annotations> - <severity value="MINOR"/> - <title value="ChildExtendedTestReplaceHook"/> - <group value="Child"/> - <features value="Child"/> - <stories value="Child"/> - </annotations> - <before> - <amOnPage url="/slightlyDifferentBeforeUrl" stepKey="beforeAmOnPageKey"/> - </before> - </test> - - <test name="ChildExtendedTestMerging" extends="ParentExtendedTest"> - <annotations> - <severity value="MINOR"/> - <title value="ChildExtendedTestMerging"/> - <group value="Child"/> - <features value="Child"/> - <stories value="Child"/> - </annotations> - <before> - <amOnPage url="/firstUrl" stepKey="firstBeforeAmOnPageKey" before="beforeAmOnPageKey"/> - <amOnPage url="/lastUrl" stepKey="lastBefore" after="beforeAmOnPageKey"/> - </before> - <comment stepKey="lastStepKey" userInput="Last Comment"/> - <comment stepKey="beforeBasicCommentWithNoData" userInput="Before Comment" before="basicCommentWithNoData"/> - <comment stepKey="afterBasicCommentWithNoData" userInput="After Comment" after="basicCommentWithNoData"/> - </test> - - <test name="ChildExtendedTestRemoveAction" extends="ParentExtendedTest"> - <annotations> - <severity value="CRITICAL"/> - <title value="ChildExtendedTestRemoveAction"/> - <group value="Child"/> - <features value="Child"/> - <stories value="Child"/> - </annotations> - <remove keyForRemoval="basicCommentWithNoData"/> - </test> - - <test name="ParentExtendedTestNoHooks"> - <annotations> - <severity value="AVERAGE"/> - <title value="ParentExtendedTestNoHooks"/> - <group value="Parent"/> - <features value="Parent"/> - <stories value="Parent"/> - </annotations> - <comment stepKey="basicCommentWithNoData" userInput="Parent Comment"/> - </test> - - <test name="ChildExtendedTestAddHooks"> - <annotations> - <severity value="AVERAGE"/> - <title value="ChildExtendedTestAddHooks"/> - <group value="Parent"/> - <features value="Parent"/> - <stories value="Parent"/> - </annotations> - <before> - <amOnPage url="/beforeUrl" stepKey="beforeAmOnPageKey"/> - </before> - <after> - <amOnPage url="/afterUrl" stepKey="afterAmOnPageKey"/> - </after> - </test> - - <test name="ChildExtendedTestRemoveHookAction" extends="ParentExtendedTest"> - <annotations> - <severity value="CRITICAL"/> - <title value="ChildExtendedTestRemoveHookAction"/> - <group value="Child"/> - <features value="Child"/> - <stories value="Child"/> - </annotations> - <before> - <remove keyForRemoval="beforeAmOnPageKey"/> - </before> - </test> - <test name="ChildExtendedTestNoParent" extends="ThisTestDoesNotExist"> - <annotations> - <severity value="CRITICAL"/> - <title value="ChildExtendedTestNoParent"/> - <group value="Child"/> - <features value="Child"/> - <stories value="Child"/> - </annotations> - <before> - <remove keyForRemoval="beforeAmOnPageKey"/> - </before> - </test> - <test name="SkippedParent"> - <annotations> - <severity value="CRITICAL"/> - <title value="PARENTSKIPPED"/> - <group value="Parent"/> - <features value="Parent"/> - <stories value="Parent"/> - <skip> - <issueId value="NONE"/> - </skip> - </annotations> - <before> - <amOnPage url="/beforeUrl" stepKey="beforeAmOnPageKey"/> - </before> - <after> - <amOnPage url="/afterUrl" stepKey="afterAmOnPageKey"/> - </after> - <comment userInput="text" stepKey="keepMe"/> - <comment userInput="text" stepKey="replaceMe"/> - </test> - <test name="ExtendingSkippedTest" extends="SkippedParent"> - <annotations> - <severity value="CRITICAL"/> - <title value="ChildExtendedTestSkippedParent"/> - <group value="Child"/> - <features value="Child"/> - <stories value="Child"/> - </annotations> - <comment userInput="child" stepKey="replaceMe"/> - </test> - - <test name="ExtendedTestRelatedToSuiteParentTest"> - <annotations> - <severity value="AVERAGE"/> - <title value="ExtendedTestRelatedToSuiteParentTest"/> - <group value="ExtendedTestRelatedToSuite"/> - <features value="ExtendedTestRelatedToSuiteParentTest"/> - <stories value="ExtendedTestRelatedToSuiteParentTest"/> - </annotations> - <before> - <amOnPage url="/beforeUrl" stepKey="beforeAmOnPageKey"/> - </before> - <after> - <amOnPage url="/afterUrl" stepKey="afterAmOnPageKey"/> - </after> - <comment stepKey="basicCommentWithNoData" userInput="Parent Comment"/> - <amOnPage url="/url/in/parent" stepKey="amOnPageInParent"/> - </test> - - <test name="ExtendedChildTestInSuite" extends="ExtendedTestRelatedToSuiteParentTest"> - <annotations> - <severity value="MINOR"/> - <title value="ExtendedChildTestInSuite"/> - <group value="ExtendedTestInSuite"/> - <features value="ExtendedChildTestInSuite"/> - <stories value="ExtendedChildTestInSuite"/> - </annotations> - <comment stepKey="basicCommentWithNoData" userInput="Different Input"/> - <remove keyForRemoval="amOnPageInParent"/> - </test> - <test name="ExtendedChildTestNotInSuite" extends="ExtendedTestRelatedToSuiteParentTest"> - <annotations> - <severity value="MINOR"/> - <title value="ExtendedChildTestNotInSuite"/> - <features value="ExtendedChildTestNotInSuite"/> - <stories value="ExtendedChildTestNotInSuite"/> - </annotations> - <comment stepKey="basicCommentWithNoData" userInput="Different Input"/> - <remove keyForRemoval="amOnPageInParent"/> - </test> -</tests> \ No newline at end of file diff --git a/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestAddHooks.xml b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestAddHooks.xml new file mode 100644 index 000000000..70cb3c285 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestAddHooks.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ChildExtendedTestAddHooks"> + <annotations> + <severity value="AVERAGE"/> + <title value="ChildExtendedTestAddHooks"/> + <group value="Parent"/> + <features value="Parent"/> + <stories value="Parent"/> + </annotations> + <before> + <amOnPage url="/beforeUrl" stepKey="beforeAmOnPageKey"/> + </before> + <after> + <amOnPage url="/afterUrl" stepKey="afterAmOnPageKey"/> + </after> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestMerging.xml b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestMerging.xml new file mode 100644 index 000000000..dfef954e1 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestMerging.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ChildExtendedTestMerging" extends="ParentExtendedTest"> + <annotations> + <severity value="MINOR"/> + <title value="ChildExtendedTestMerging"/> + <group value="Child"/> + <features value="Child"/> + <stories value="Child"/> + </annotations> + <before> + <amOnPage url="/firstUrl" stepKey="firstBeforeAmOnPageKey" before="beforeAmOnPageKey"/> + <amOnPage url="/lastUrl" stepKey="lastBefore" after="beforeAmOnPageKey"/> + </before> + <comment stepKey="lastStepKey" userInput="Last Comment"/> + <comment stepKey="beforeBasicCommentWithNoData" userInput="Before Comment" before="basicCommentWithNoData"/> + <comment stepKey="afterBasicCommentWithNoData" userInput="After Comment" after="basicCommentWithNoData"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestNoParent.xml b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestNoParent.xml new file mode 100644 index 000000000..81add5d0e --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestNoParent.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ChildExtendedTestNoParent" extends="ThisTestDoesNotExist"> + <annotations> + <severity value="CRITICAL"/> + <title value="ChildExtendedTestNoParent"/> + <group value="Child"/> + <features value="Child"/> + <stories value="Child"/> + </annotations> + <before> + <remove keyForRemoval="beforeAmOnPageKey"/> + </before> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestRemoveAction.xml b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestRemoveAction.xml new file mode 100644 index 000000000..aa82ced68 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestRemoveAction.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ChildExtendedTestRemoveAction" extends="ParentExtendedTest"> + <annotations> + <severity value="CRITICAL"/> + <title value="ChildExtendedTestRemoveAction"/> + <group value="Child"/> + <features value="Child"/> + <stories value="Child"/> + </annotations> + <remove keyForRemoval="basicCommentWithNoData"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestRemoveHookAction.xml b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestRemoveHookAction.xml new file mode 100644 index 000000000..7388a293e --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestRemoveHookAction.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ChildExtendedTestRemoveHookAction" extends="ParentExtendedTest"> + <annotations> + <severity value="CRITICAL"/> + <title value="ChildExtendedTestRemoveHookAction"/> + <group value="Child"/> + <features value="Child"/> + <stories value="Child"/> + </annotations> + <before> + <remove keyForRemoval="beforeAmOnPageKey"/> + </before> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestReplace.xml b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestReplace.xml new file mode 100644 index 000000000..1872fc645 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestReplace.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ChildExtendedTestReplace" extends="ParentExtendedTest"> + <annotations> + <severity value="MINOR"/> + <title value="ChildExtendedTestReplace"/> + <group value="Child"/> + <features value="Child"/> + <stories value="Child"/> + </annotations> + <comment stepKey="basicCommentWithNoData" userInput="Different Input"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestReplaceHook.xml b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestReplaceHook.xml new file mode 100644 index 000000000..d12bb6d09 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ChildExtendedTestReplaceHook.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ChildExtendedTestReplaceHook" extends="ParentExtendedTest"> + <annotations> + <severity value="MINOR"/> + <title value="ChildExtendedTestReplaceHook"/> + <group value="Child"/> + <features value="Child"/> + <stories value="Child"/> + </annotations> + <before> + <amOnPage url="/slightlyDifferentBeforeUrl" stepKey="beforeAmOnPageKey"/> + </before> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ExtendedChildTestInSuite.xml b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ExtendedChildTestInSuite.xml new file mode 100644 index 000000000..76e1e10e3 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ExtendedChildTestInSuite.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ExtendedChildTestInSuite" extends="ExtendedTestRelatedToSuiteParentTest"> + <annotations> + <severity value="MINOR"/> + <title value="ExtendedChildTestInSuite"/> + <group value="ExtendedTestInSuite"/> + <features value="ExtendedChildTestInSuite"/> + <stories value="ExtendedChildTestInSuite"/> + </annotations> + <comment stepKey="basicCommentWithNoData" userInput="Different Input"/> + <remove keyForRemoval="amOnPageInParent"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ExtendedChildTestNotInSuite.xml b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ExtendedChildTestNotInSuite.xml new file mode 100644 index 000000000..54d0f5cbf --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ExtendedChildTestNotInSuite.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ExtendedChildTestNotInSuite" extends="ExtendedTestRelatedToSuiteParentTest"> + <annotations> + <severity value="MINOR"/> + <title value="ExtendedChildTestNotInSuite"/> + <features value="ExtendedChildTestNotInSuite"/> + <stories value="ExtendedChildTestNotInSuite"/> + </annotations> + <comment stepKey="basicCommentWithNoData" userInput="Different Input"/> + <remove keyForRemoval="amOnPageInParent"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ExtendedTestRelatedToSuiteParentTest.xml b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ExtendedTestRelatedToSuiteParentTest.xml new file mode 100644 index 000000000..1bc656149 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ExtendedTestRelatedToSuiteParentTest.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ExtendedTestRelatedToSuiteParentTest"> + <annotations> + <severity value="AVERAGE"/> + <title value="ExtendedTestRelatedToSuiteParentTest"/> + <group value="ExtendedTestRelatedToSuite"/> + <features value="ExtendedTestRelatedToSuiteParentTest"/> + <stories value="ExtendedTestRelatedToSuiteParentTest"/> + </annotations> + <before> + <amOnPage url="/beforeUrl" stepKey="beforeAmOnPageKey"/> + </before> + <after> + <amOnPage url="/afterUrl" stepKey="afterAmOnPageKey"/> + </after> + <comment stepKey="basicCommentWithNoData" userInput="Parent Comment"/> + <amOnPage url="/url/in/parent" stepKey="amOnPageInParent"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ExtendingSkippedTest.xml b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ExtendingSkippedTest.xml new file mode 100644 index 000000000..f451c143a --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ExtendingSkippedTest.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ExtendingSkippedTest" extends="SkippedParent"> + <annotations> + <severity value="CRITICAL"/> + <title value="ChildExtendedTestSkippedParent"/> + <group value="Child"/> + <features value="Child"/> + <stories value="Child"/> + </annotations> + <comment userInput="child" stepKey="replaceMe"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ParentExtendedTest.xml b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ParentExtendedTest.xml new file mode 100644 index 000000000..ed5aa6c16 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ParentExtendedTest.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ParentExtendedTest"> + <annotations> + <severity value="AVERAGE"/> + <title value="ParentExtendedTest"/> + <group value="Parent"/> + <features value="Parent"/> + <stories value="Parent"/> + </annotations> + <before> + <amOnPage url="/beforeUrl" stepKey="beforeAmOnPageKey"/> + </before> + <after> + <amOnPage url="/afterUrl" stepKey="afterAmOnPageKey"/> + </after> + <comment stepKey="basicCommentWithNoData" userInput="Parent Comment"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ParentExtendedTestNoHooks.xml b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ParentExtendedTestNoHooks.xml new file mode 100644 index 000000000..c7d17857e --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/ParentExtendedTestNoHooks.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ParentExtendedTestNoHooks"> + <annotations> + <severity value="AVERAGE"/> + <title value="ParentExtendedTestNoHooks"/> + <group value="Parent"/> + <features value="Parent"/> + <stories value="Parent"/> + </annotations> + <comment stepKey="basicCommentWithNoData" userInput="Parent Comment"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/SkippedParent.xml b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/SkippedParent.xml new file mode 100644 index 000000000..ff36905e7 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ExtendedFunctionalTest/SkippedParent.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="SkippedParent"> + <annotations> + <severity value="CRITICAL"/> + <title value="PARENTSKIPPED"/> + <group value="Parent"/> + <features value="Parent"/> + <stories value="Parent"/> + <skip> + <issueId value="NONE"/> + </skip> + </annotations> + <before> + <amOnPage url="/beforeUrl" stepKey="beforeAmOnPageKey"/> + </before> + <after> + <amOnPage url="/afterUrl" stepKey="afterAmOnPageKey"/> + </after> + <comment userInput="text" stepKey="keepMe"/> + <comment userInput="text" stepKey="replaceMe"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/MergeFunctionalTest.xml b/dev/tests/verification/TestModule/Test/MergeFunctionalTest.xml deleted file mode 100644 index 5189b8cf4..000000000 --- a/dev/tests/verification/TestModule/Test/MergeFunctionalTest.xml +++ /dev/null @@ -1,61 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - <test name="BasicMergeTest"> - <annotations> - <severity value="CRITICAL"/> - <title value="BasicMergeTest"/> - <group value="functional"/> - <features value="Merge Functional Cest"/> - <stories value="MQE-433"/> - </annotations> - <before> - <amOnPage url="/beforeUrl" stepKey="before1"/> - </before> - <after> - <amOnPage url="/afterUrl" stepKey="after1"/> - </after> - <amOnPage stepKey="step1" url="/step1"/> - <fillField stepKey="step3" selector="#username" userInput="step3"/> - <fillField stepKey="step5" selector="#password" userInput="step5"/> - <click stepKey="step6" selector=".step6"/> - <click stepKey="step10" selector="#step10ShouldNotInResult"/> - </test> - <test name="MergedReferencesTest"> - <annotations> - <severity value="CRITICAL"/> - <title value="MergedReferencesTest"/> - <group value="functional"/> - <features value="Merge Functional Cest"/> - <stories value="MQE-433"/> - </annotations> - <before> - <amOnPage url="/beforeUrl" stepKey="before1"/> - </before> - <after> - <amOnPage url="/afterUrl" stepKey="after1"/> - </after> - <fillField stepKey="fillField1" selector="{{SampleSection.mergeElement}}" userInput="{{DefaultPerson.mergedField}}"/> - <fillField stepKey="fillField2" selector="{{SampleSection.newElement}}" userInput="{{DefaultPerson.newField}}" /> - </test> - <test name="MergeMassViaInsertBefore" insertBefore="fillField2"> - <click stepKey="clickOne" selector="#mergeOne"/> - <click stepKey="clickTwo" selector="#mergeTwo"/> - <click stepKey="clickThree" selector="#mergeThree"/> - </test> - <test name="MergeMassViaInsertAfter" insertAfter="fillField2"> - <click stepKey="clickOne" selector="#mergeOne"/> - <click stepKey="clickTwo" selector="#mergeTwo"/> - <click stepKey="clickThree" selector="#mergeThree"/> - </test> - <test name="MergeSkip"> - <comment userInput="ThisTestShouldBeSkipped" stepKey="skipComment"/> - </test> -</tests> diff --git a/dev/tests/verification/TestModule/Test/MergeFunctionalTest/BasicMergeTest.xml b/dev/tests/verification/TestModule/Test/MergeFunctionalTest/BasicMergeTest.xml new file mode 100644 index 000000000..3237ba7bb --- /dev/null +++ b/dev/tests/verification/TestModule/Test/MergeFunctionalTest/BasicMergeTest.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="BasicMergeTest"> + <annotations> + <severity value="CRITICAL"/> + <title value="BasicMergeTest"/> + <group value="functional"/> + <features value="Merge Functional Cest"/> + <stories value="MQE-433"/> + </annotations> + <before> + <amOnPage url="/beforeUrl" stepKey="before1"/> + </before> + <after> + <amOnPage url="/afterUrl" stepKey="after1"/> + </after> + <amOnPage stepKey="step1" url="/step1"/> + <fillField stepKey="step3" selector="#username" userInput="step3"/> + <fillField stepKey="step5" selector="#password" userInput="step5"/> + <click stepKey="step6" selector=".step6"/> + <click stepKey="step10" selector="#step10ShouldNotInResult"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/MergeFunctionalTest/MergeMassViaInsertAfter.xml b/dev/tests/verification/TestModule/Test/MergeFunctionalTest/MergeMassViaInsertAfter.xml new file mode 100644 index 000000000..2f35be2cb --- /dev/null +++ b/dev/tests/verification/TestModule/Test/MergeFunctionalTest/MergeMassViaInsertAfter.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="MergeMassViaInsertAfter" insertAfter="fillField2"> + <click stepKey="clickOne" selector="#mergeOne"/> + <click stepKey="clickTwo" selector="#mergeTwo"/> + <click stepKey="clickThree" selector="#mergeThree"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/MergeFunctionalTest/MergeMassViaInsertBefore.xml b/dev/tests/verification/TestModule/Test/MergeFunctionalTest/MergeMassViaInsertBefore.xml new file mode 100644 index 000000000..913644f51 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/MergeFunctionalTest/MergeMassViaInsertBefore.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="MergeMassViaInsertBefore" insertBefore="fillField2"> + <click stepKey="clickOne" selector="#mergeOne"/> + <click stepKey="clickTwo" selector="#mergeTwo"/> + <click stepKey="clickThree" selector="#mergeThree"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/MergeFunctionalTest/MergeSkip.xml b/dev/tests/verification/TestModule/Test/MergeFunctionalTest/MergeSkip.xml new file mode 100644 index 000000000..1d8b82200 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/MergeFunctionalTest/MergeSkip.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="MergeSkip"> + <comment userInput="ThisTestShouldBeSkipped" stepKey="skipComment"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/MergeFunctionalTest/MergedReferencesTest.xml b/dev/tests/verification/TestModule/Test/MergeFunctionalTest/MergedReferencesTest.xml new file mode 100644 index 000000000..d48de5d3a --- /dev/null +++ b/dev/tests/verification/TestModule/Test/MergeFunctionalTest/MergedReferencesTest.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="MergedReferencesTest"> + <annotations> + <severity value="CRITICAL"/> + <title value="MergedReferencesTest"/> + <group value="functional"/> + <features value="Merge Functional Cest"/> + <stories value="MQE-433"/> + </annotations> + <before> + <amOnPage url="/beforeUrl" stepKey="before1"/> + </before> + <after> + <amOnPage url="/afterUrl" stepKey="after1"/> + </after> + <fillField stepKey="fillField1" selector="{{SampleSection.mergeElement}}" userInput="{{DefaultPerson.mergedField}}"/> + <fillField stepKey="fillField2" selector="{{SampleSection.newElement}}" userInput="{{DefaultPerson.newField}}" /> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/SampleSuite2Test.xml b/dev/tests/verification/TestModule/Test/SampleSuite2Test/AdditionalExcludeTest2.xml similarity index 59% rename from dev/tests/verification/TestModule/Test/SampleSuite2Test.xml rename to dev/tests/verification/TestModule/Test/SampleSuite2Test/AdditionalExcludeTest2.xml index 92f10ddd0..c38915bf4 100644 --- a/dev/tests/verification/TestModule/Test/SampleSuite2Test.xml +++ b/dev/tests/verification/TestModule/Test/SampleSuite2Test/AdditionalExcludeTest2.xml @@ -5,9 +5,8 @@ * See COPYING.txt for license details. */ --> - <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="additionalExcludeTest2"> <annotations> <group value="exclude"/> @@ -17,10 +16,4 @@ <click stepKey="clickOnSomething" selector=".clickable"/> <fillField stepKey="fillAField" selector=".fillable"/> </test> - <test name="additionalIncludeTest2"> - <amOnPage stepKey="testOnPage" url="/someUrl"/> - <see stepKey="seeThePage" selector=".someSelector"/> - <click stepKey="clickOnSomething" selector=".clickable"/> - <fillField stepKey="fillAField" selector=".fillable"/> - </test> </tests> diff --git a/dev/tests/verification/TestModule/Test/SampleSuite2Test/AdditionalIncludeTest2.xml b/dev/tests/verification/TestModule/Test/SampleSuite2Test/AdditionalIncludeTest2.xml new file mode 100644 index 000000000..81f6d7c1c --- /dev/null +++ b/dev/tests/verification/TestModule/Test/SampleSuite2Test/AdditionalIncludeTest2.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="additionalIncludeTest2"> + <amOnPage stepKey="testOnPage" url="/someUrl"/> + <see stepKey="seeThePage" selector=".someSelector"/> + <click stepKey="clickOnSomething" selector=".clickable"/> + <fillField stepKey="fillAField" selector=".fillable"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/SampleSuiteTest.xml b/dev/tests/verification/TestModule/Test/SampleSuiteTest.xml deleted file mode 100644 index 921071cfc..000000000 --- a/dev/tests/verification/TestModule/Test/SampleSuiteTest.xml +++ /dev/null @@ -1,50 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - <test name="IncludeTest"> - <amOnPage stepKey="testOnPage" url="/someUrl"/> - <see stepKey="seeThePage" selector=".someSelector"/> - <click stepKey="clickOnSomething" selector=".clickable"/> - <fillField stepKey="fillAField" selector=".fillable"/> - </test> - <test name="ExcludeTest"> - <amOnPage stepKey="testOnPage" url="/someUrl"/> - <see stepKey="seeThePage" selector=".someSelector"/> - <click stepKey="clickOnSomething" selector=".clickable"/> - <fillField stepKey="fillAField" selector=".fillable"/> - </test> - <test name="IncludeTest2"> - <annotations> - <group value="include"/> - </annotations> - <amOnPage stepKey="testOnPage" url="/someUrl"/> - <see stepKey="seeThePage" selector=".someSelector"/> - <click stepKey="clickOnSomething" selector=".clickable"/> - <fillField stepKey="fillAField" selector=".fillable"/> - </test> - <test name="additionalTest"> - <annotations> - <group value="include"/> - </annotations> - <amOnPage stepKey="testOnPage" url="/someUrl"/> - <see stepKey="seeThePage" selector=".someSelector"/> - <click stepKey="clickOnSomething" selector=".clickable"/> - <fillField stepKey="fillAField" selector=".fillable"/> - </test> - <test name="ExcludeTest2"> - <annotations> - <group value="include"/> - </annotations> - <amOnPage stepKey="testOnPage" url="/someUrl"/> - <see stepKey="seeThePage" selector=".someSelector"/> - <click stepKey="clickOnSomething" selector=".clickable"/> - <fillField stepKey="fillAField" selector=".fillable"/> - </test> -</tests> diff --git a/dev/tests/verification/TestModule/Test/SampleSuiteTest/AdditionalTest.xml b/dev/tests/verification/TestModule/Test/SampleSuiteTest/AdditionalTest.xml new file mode 100644 index 000000000..848d45612 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/SampleSuiteTest/AdditionalTest.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="additionalTest"> + <annotations> + <group value="include"/> + </annotations> + <amOnPage stepKey="testOnPage" url="/someUrl"/> + <see stepKey="seeThePage" selector=".someSelector"/> + <click stepKey="clickOnSomething" selector=".clickable"/> + <fillField stepKey="fillAField" selector=".fillable"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/SampleSuiteTest/ExcludeTest.xml b/dev/tests/verification/TestModule/Test/SampleSuiteTest/ExcludeTest.xml new file mode 100644 index 000000000..0996e4a59 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/SampleSuiteTest/ExcludeTest.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ExcludeTest"> + <amOnPage stepKey="testOnPage" url="/someUrl"/> + <see stepKey="seeThePage" selector=".someSelector"/> + <click stepKey="clickOnSomething" selector=".clickable"/> + <fillField stepKey="fillAField" selector=".fillable"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/SampleSuiteTest/ExcludeTest2.xml b/dev/tests/verification/TestModule/Test/SampleSuiteTest/ExcludeTest2.xml new file mode 100644 index 000000000..d03b847da --- /dev/null +++ b/dev/tests/verification/TestModule/Test/SampleSuiteTest/ExcludeTest2.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ExcludeTest2"> + <annotations> + <group value="include"/> + </annotations> + <amOnPage stepKey="testOnPage" url="/someUrl"/> + <see stepKey="seeThePage" selector=".someSelector"/> + <click stepKey="clickOnSomething" selector=".clickable"/> + <fillField stepKey="fillAField" selector=".fillable"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/SampleSuiteTest/IncludeTest.xml b/dev/tests/verification/TestModule/Test/SampleSuiteTest/IncludeTest.xml new file mode 100644 index 000000000..b293742c7 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/SampleSuiteTest/IncludeTest.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="IncludeTest"> + <amOnPage stepKey="testOnPage" url="/someUrl"/> + <see stepKey="seeThePage" selector=".someSelector"/> + <click stepKey="clickOnSomething" selector=".clickable"/> + <fillField stepKey="fillAField" selector=".fillable"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/SampleSuiteTest/IncludeTest2.xml b/dev/tests/verification/TestModule/Test/SampleSuiteTest/IncludeTest2.xml new file mode 100644 index 000000000..d6c40fe2d --- /dev/null +++ b/dev/tests/verification/TestModule/Test/SampleSuiteTest/IncludeTest2.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="IncludeTest2"> + <annotations> + <group value="include"/> + </annotations> + <amOnPage stepKey="testOnPage" url="/someUrl"/> + <see stepKey="seeThePage" selector=".someSelector"/> + <click stepKey="clickOnSomething" selector=".clickable"/> + <fillField stepKey="fillAField" selector=".fillable"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/SkippedTest.xml b/dev/tests/verification/TestModule/Test/SkippedTest.xml deleted file mode 100644 index 7641e270e..000000000 --- a/dev/tests/verification/TestModule/Test/SkippedTest.xml +++ /dev/null @@ -1,60 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - <test name="SkippedTest"> - <annotations> - <stories value="skipped"/> - <title value="skippedTest"/> - <description value=""/> - <severity value="AVERAGE"/> - <skip> - <issueId value="SkippedValue"/> - </skip> - </annotations> - </test> - <test name="SkippedTestWithHooks"> - <annotations> - <stories value="skippedWithHooks"/> - <title value="skippedTestWithHooks"/> - <description value=""/> - <severity value="AVERAGE"/> - <skip> - <issueId value="SkippedValue"/> - </skip> - </annotations> - <before> - <comment userInput="skippedComment" stepKey="beforeComment"/> - </before> - <after> - <comment userInput="skippedComment" stepKey="afterComment"/> - </after> - </test> - <test name="SkippedTestTwoIssues"> - <annotations> - <stories value="skippedMultiple"/> - <title value="skippedMultipleIssuesTest"/> - <description value=""/> - <severity value="AVERAGE"/> - <skip> - <issueId value="SkippedValue"/> - <issueId value="SecondSkippedValue"/> - </skip> - </annotations> - </test> - <test name="SkippedTestNoIssues"> - <annotations> - <stories value="skippedNo"/> - <title value="skippedNoIssuesTest"/> - <description value=""/> - <severity value="AVERAGE"/> - <group value="skip"/> - </annotations> - </test> -</tests> diff --git a/dev/tests/verification/TestModule/Test/SkippedTest/SkippedTest.xml b/dev/tests/verification/TestModule/Test/SkippedTest/SkippedTest.xml new file mode 100644 index 000000000..f0162a562 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/SkippedTest/SkippedTest.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="SkippedTest"> + <annotations> + <stories value="skipped"/> + <title value="skippedTest"/> + <description value=""/> + <severity value="AVERAGE"/> + <skip> + <issueId value="SkippedValue"/> + </skip> + </annotations> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/SkippedTest/SkippedTestNoIssues.xml b/dev/tests/verification/TestModule/Test/SkippedTest/SkippedTestNoIssues.xml new file mode 100644 index 000000000..02f800536 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/SkippedTest/SkippedTestNoIssues.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="SkippedTestNoIssues"> + <annotations> + <stories value="skippedNo"/> + <title value="skippedNoIssuesTest"/> + <description value=""/> + <severity value="AVERAGE"/> + <group value="skip"/> + </annotations> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/SkippedTest/SkippedTestTwoIssues.xml b/dev/tests/verification/TestModule/Test/SkippedTest/SkippedTestTwoIssues.xml new file mode 100644 index 000000000..66ad090b4 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/SkippedTest/SkippedTestTwoIssues.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="SkippedTestTwoIssues"> + <annotations> + <stories value="skippedMultiple"/> + <title value="skippedMultipleIssuesTest"/> + <description value=""/> + <severity value="AVERAGE"/> + <skip> + <issueId value="SkippedValue"/> + <issueId value="SecondSkippedValue"/> + </skip> + </annotations> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/SkippedTest/SkippedTestWithHooks.xml b/dev/tests/verification/TestModule/Test/SkippedTest/SkippedTestWithHooks.xml new file mode 100644 index 000000000..790a44a40 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/SkippedTest/SkippedTestWithHooks.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="SkippedTestWithHooks"> + <annotations> + <stories value="skippedWithHooks"/> + <title value="skippedTestWithHooks"/> + <description value=""/> + <severity value="AVERAGE"/> + <skip> + <issueId value="SkippedValue"/> + </skip> + </annotations> + <before> + <comment userInput="skippedComment" stepKey="beforeComment"/> + </before> + <after> + <comment userInput="skippedComment" stepKey="afterComment"/> + </after> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/XmlDuplicateTest/BasicDupedActionTest.xml b/dev/tests/verification/TestModule/Test/XmlDuplicateTest/BasicDupedActionTest.xml new file mode 100644 index 000000000..19104dbee --- /dev/null +++ b/dev/tests/verification/TestModule/Test/XmlDuplicateTest/BasicDupedActionTest.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="BasicDupedActionTest"> + <before> + <createData entity="simpleData" stepKey="cb1"> + <requiredEntity createDataKey="simpleData2"/> + </createData> + <amOnPage stepKey="aopb1" url="1"/> + <amOnPage stepKey="aopb2" url="2"/> + </before> + <after> + <createData entity="simpleData" stepKey="ca1"> + <requiredEntity createDataKey="simpleData2"/> + </createData> + <amOnPage stepKey="aopf1" url="1"/> + <amOnPage stepKey="aopf2" url="2"/> + </after> + <createData entity="simpleData" stepKey="c1"> + <requiredEntity createDataKey="simpleData2"/> + </createData> + <amOnPage stepKey="aop1" url="1"/> + <amOnPage stepKey="aop2" url="2"/> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/XmlDuplicateTest.xml b/dev/tests/verification/TestModule/Test/XmlDuplicateTest/XmlDuplicateTest.xml similarity index 97% rename from dev/tests/verification/TestModule/Test/XmlDuplicateTest.xml rename to dev/tests/verification/TestModule/Test/XmlDuplicateTest/XmlDuplicateTest.xml index d8c2fca66..6df962ffa 100644 --- a/dev/tests/verification/TestModule/Test/XmlDuplicateTest.xml +++ b/dev/tests/verification/TestModule/Test/XmlDuplicateTest/XmlDuplicateTest.xml @@ -5,9 +5,8 @@ * See COPYING.txt for license details. */ --> - <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="XmlDuplicateTest"> <before> <acceptPopup stepKey="ap1"/> @@ -644,26 +643,4 @@ <waitForText stepKey="waittext1"/> <waitForText stepKey="waittext12"/> </test> - - <test name="BasicDupedActionTest"> - <before> - <createData entity="simpleData" stepKey="cb1"> - <requiredEntity createDataKey="simpleData2"/> - </createData> - <amOnPage stepKey="aopb1" url="1"/> - <amOnPage stepKey="aopb2" url="2"/> - </before> - <after> - <createData entity="simpleData" stepKey="ca1"> - <requiredEntity createDataKey="simpleData2"/> - </createData> - <amOnPage stepKey="aopf1" url="1"/> - <amOnPage stepKey="aopf2" url="2"/> - </after> - <createData entity="simpleData" stepKey="c1"> - <requiredEntity createDataKey="simpleData2"/> - </createData> - <amOnPage stepKey="aop1" url="1"/> - <amOnPage stepKey="aop2" url="2"/> - </test> -</tests> \ No newline at end of file +</tests> diff --git a/dev/tests/verification/TestModuleMerged/Test/MergeFunctionalTest.xml b/dev/tests/verification/TestModuleMerged/Test/MergeFunctionalTest/BasicMergeTest.xml similarity index 79% rename from dev/tests/verification/TestModuleMerged/Test/MergeFunctionalTest.xml rename to dev/tests/verification/TestModuleMerged/Test/MergeFunctionalTest/BasicMergeTest.xml index 912854cc4..807258b0f 100644 --- a/dev/tests/verification/TestModuleMerged/Test/MergeFunctionalTest.xml +++ b/dev/tests/verification/TestModuleMerged/Test/MergeFunctionalTest/BasicMergeTest.xml @@ -5,9 +5,8 @@ * See COPYING.txt for license details. */ --> - <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="BasicMergeTest"> <annotations> <group value="mergeTest"/> @@ -26,11 +25,4 @@ <click stepKey="step10" selector="#step10MergedInResult"/> <actionGroup ref="FunctionalActionGroupWithData" stepKey="step8Merge" after="step7Merge"/> </test> - <test name="MergeSkip"> - <annotations> - <skip> - <issueId value="Issue5"/> - </skip> - </annotations> - </test> </tests> diff --git a/dev/tests/verification/TestModuleMerged/Test/MergeFunctionalTest/MergeSkip.xml b/dev/tests/verification/TestModuleMerged/Test/MergeFunctionalTest/MergeSkip.xml new file mode 100644 index 000000000..5c9e189c3 --- /dev/null +++ b/dev/tests/verification/TestModuleMerged/Test/MergeFunctionalTest/MergeSkip.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="MergeSkip"> + <annotations> + <skip> + <issueId value="Issue5"/> + </skip> + </annotations> + </test> +</tests> diff --git a/dev/tests/verification/Tests/BasicCestGenerationTest.php b/dev/tests/verification/Tests/BasicCestGenerationTest.php index 793b2a502..39802c50d 100644 --- a/dev/tests/verification/Tests/BasicCestGenerationTest.php +++ b/dev/tests/verification/Tests/BasicCestGenerationTest.php @@ -10,6 +10,7 @@ class BasicCestGenerationTest extends MftfTestCase { /** + * BasicFunctionalTest: * Tests flat generation of a hardcoded test file with no external references. * * @throws \Exception @@ -20,6 +21,30 @@ public function testBasicGeneration() $this->generateAndCompareTest('BasicFunctionalTest'); } + /** + * MergeMassViaInsertAfter: + * Tests flat generation of a hardcoded test file with no external references. + * + * @throws \Exception + * @throws \Magento\FunctionalTestingFramework\Exceptions\TestReferenceException + */ + public function testMergeMassViaInsertAfter() + { + $this->generateAndCompareTest('MergeMassViaInsertAfter'); + } + + /** + * MergeMassViaInsertBefore: + * Tests flat generation of a hardcoded test file with no external references. + * + * @throws \Exception + * @throws \Magento\FunctionalTestingFramework\Exceptions\TestReferenceException + */ + public function testMergeMassViaInsertBefore() + { + $this->generateAndCompareTest('MergeMassViaInsertBefore'); + } + /** * Tests flat generation of a hardcoded test file with no external references and with XML comments in: * - root `tests` element diff --git a/dev/tests/verification/_suite/functionalSuite/functionalSuite1.xml b/dev/tests/verification/_suite/functionalSuite/functionalSuite1.xml new file mode 100644 index 000000000..8f5f4145e --- /dev/null +++ b/dev/tests/verification/_suite/functionalSuite/functionalSuite1.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<suites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Suite/etc/suiteSchema.xsd"> + <suite name="functionalSuite1"> + <include> + <group name = "include" /> + <test name="IncludeTest"/> + <test name="additionalExcludeTest2"/> + <test name="additionalIncludeTest2"/> + </include> + <exclude> + <group name="exclude"/> + <test name="ExcludeTest2"/> + </exclude> + </suite> +</suites> diff --git a/dev/tests/verification/_suite/functionalSuite/functionalSuite2.xml b/dev/tests/verification/_suite/functionalSuite/functionalSuite2.xml new file mode 100644 index 000000000..5f926fbc3 --- /dev/null +++ b/dev/tests/verification/_suite/functionalSuite/functionalSuite2.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<suites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Suite/etc/suiteSchema.xsd"> + <suite name="functionalSuite2"> + <include> + <group name="include"/> + <test name="IncludeTest"/> + <test name="additionalExcludeTest2"/> + <test name="additionalIncludeTest2"/> + </include> + <exclude> + <group name="exclude"/> + <test name="ExcludeTest2"/> + </exclude> + </suite> +</suites> diff --git a/dev/tests/verification/_suite/functionalSuite.xml b/dev/tests/verification/_suite/functionalSuite/functionalSuiteWithComments.xml similarity index 66% rename from dev/tests/verification/_suite/functionalSuite.xml rename to dev/tests/verification/_suite/functionalSuite/functionalSuiteWithComments.xml index cfdaa3557..471f2312d 100644 --- a/dev/tests/verification/_suite/functionalSuite.xml +++ b/dev/tests/verification/_suite/functionalSuite/functionalSuiteWithComments.xml @@ -7,28 +7,6 @@ --> <suites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../src/Magento/FunctionalTestingFramework/Suite/etc/suiteSchema.xsd"> - <suite name="functionalSuite1"> - <include> - <group name="include"/> - <test name="IncludeTest"/> - <module name="TestModule" file="SampleSuite2Test.xml"/> - </include> - <exclude> - <group name="exclude"/> - <test name="ExcludeTest2"/> - </exclude> - </suite> - <suite name="functionalSuite2"> - <include> - <group name="include"/> - <test name="IncludeTest"/> - <module name="TestModule" file="SampleSuite2Test.xml"/> - </include> - <exclude> - <group name="exclude"/> - <test name="ExcludeTest2"/> - </exclude> - </suite> <suite name="functionalSuiteWithComments"> <include> <!-- Comment Block--> diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index c331ee93f..b1718f131 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -193,8 +193,9 @@ protected function getGroupAndSuiteConfiguration(array $groupOrSuiteNames) /** * Set Symfony Style for output * - * @param InputInterface $input + * @param InputInterface $input * @param OutputInterface $output + * @return void */ protected function setOutputStyle(InputInterface $input, OutputInterface $output) { diff --git a/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php index 2e4d7f9dd..abeb86da4 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php @@ -15,6 +15,7 @@ use Magento\FunctionalTestingFramework\Test\Util\TestObjectExtractor; use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Magento\FunctionalTestingFramework\Util\Validation\NameValidationUtil; +use Magento\FunctionalTestingFramework\Util\Filesystem\RecursiveGlobUtil; class SuiteObjectExtractor extends BaseObjectExtractor { @@ -23,7 +24,6 @@ class SuiteObjectExtractor extends BaseObjectExtractor const INCLUDE_TAG_NAME = 'include'; const EXCLUDE_TAG_NAME = 'exclude'; const MODULE_TAG_NAME = 'module'; - const MODULE_TAG_FILE_ATTRIBUTE = 'file'; const TEST_TAG_NAME = 'test'; const GROUP_TAG_NAME = 'group'; @@ -181,7 +181,6 @@ private function parseObjectHooks($parsedSuite) */ private function isSuiteEmpty($suiteHooks, $includeTests, $excludeTests) { - $noHooks = count($suiteHooks) == 0 || ( empty($suiteHooks['before']->getActions()) && @@ -220,10 +219,10 @@ private function extractTestObjectsFromSuiteRef($suiteReferences) TestObjectHandler::getInstance()->getTestsByGroup($suiteRefData[self::NAME]); break; case self::MODULE_TAG_NAME: - $testObjectList = array_merge($testObjectList, $this->extractModuleAndFiles( - $suiteRefData[self::NAME], - $suiteRefData[self::MODULE_TAG_FILE_ATTRIBUTE] ?? null - )); + $testObjectList = array_merge( + $testObjectList, + $this->resolveModulePathTestNames($suiteRefData[self::NAME]) + ); break; } } @@ -231,23 +230,6 @@ private function extractTestObjectsFromSuiteRef($suiteReferences) return $testObjectList; } - /** - * Takes an array of modules/files and resolves to an array of test objects. - * - * @param string $moduleName - * @param string $moduleFilePath - * @return array - * @throws \Exception - */ - private function extractModuleAndFiles($moduleName, $moduleFilePath) - { - if (empty($moduleFilePath)) { - return $this->resolveModulePathTestNames($moduleName); - } - - return $this->resolveFilePathTestNames($moduleFilePath, $moduleName); - } - /** * Takes a filepath (and optionally a module name) and resolves to a test object. * @@ -259,17 +241,14 @@ private function extractModuleAndFiles($moduleName, $moduleFilePath) private function resolveFilePathTestNames($filename, $moduleName = null) { $filepath = $filename; - if (!strstr($filepath, DIRECTORY_SEPARATOR)) { - $filepath = FilePathFormatter::format(TESTS_MODULE_PATH) . - $moduleName . - DIRECTORY_SEPARATOR . - 'Test' . - DIRECTORY_SEPARATOR . - $filename; - } - - if (!file_exists($filepath)) { - throw new Exception("Could not find file ${filename}"); + if (!file_exists($filename) && null !== $moduleName) { + $dir = FilePathFormatter::format(TESTS_MODULE_PATH) . $moduleName . DIRECTORY_SEPARATOR . 'Test'; + $filepaths = RecursiveGlobUtil::glob($filename, $dir); + if (isset($filepaths[0]) && file_exists($filepaths[0])) { + $filepath = $filepaths[0]; + } else { + throw new Exception("Could not find file ${filename}"); + } } $testObjects = []; diff --git a/src/Magento/FunctionalTestingFramework/Suite/etc/mergedSuiteSchema.xsd b/src/Magento/FunctionalTestingFramework/Suite/etc/mergedSuiteSchema.xsd index b36e35517..912a7a585 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/etc/mergedSuiteSchema.xsd +++ b/src/Magento/FunctionalTestingFramework/Suite/etc/mergedSuiteSchema.xsd @@ -29,7 +29,6 @@ <xs:simpleContent> <xs:extension base="xs:string"> <xs:attribute type="xs:string" name="name" use="optional"/> - <xs:attribute type="xs:string" name="file" use="optional"/> <xs:attribute type="xs:boolean" name="remove" use="optional"/> </xs:extension> </xs:simpleContent> diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/RemoveModuleFileInSuiteFiles.php b/src/Magento/FunctionalTestingFramework/Upgrade/RemoveModuleFileInSuiteFiles.php new file mode 100644 index 000000000..ffbae59aa --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Upgrade/RemoveModuleFileInSuiteFiles.php @@ -0,0 +1,126 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\FunctionalTestingFramework\Upgrade; + +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\Script\ScriptUtil; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; + +/** + * Class RemoveModuleFileInSuiteFiles + * @package Magento\FunctionalTestingFramework\Upgrade + */ +class RemoveModuleFileInSuiteFiles implements UpgradeInterface +{ + /** + * OutputInterface + * + * @var OutputInterface + */ + private $output; + + /** + * Console output style + * + * @var SymfonyStyle + */ + private $ioStyle = null; + + /** + * Indicate if notice is print + * + * @var boolean + */ + private $printNotice = false; + + /** + * Number of test being updated + * + * @var integer + */ + private $testsUpdated = 0; + + /** + * Scan all suite xml files, remove <module file="".../> node, and print update message + * + * @param InputInterface $input + * @param OutputInterface $output + * @return string + * @throws TestFrameworkException + */ + public function execute(InputInterface $input, OutputInterface $output) + { + $this->setOutputStyle($input, $output); + $this->output = $output; + $testPaths[] = $input->getArgument('path'); + if (empty($testPaths[0])) { + $testPaths = ScriptUtil::getAllModulePaths(); + } + + $xmlFiles = ScriptUtil::buildFileList( + $testPaths, + DIRECTORY_SEPARATOR . 'Suite' . DIRECTORY_SEPARATOR + ); + + foreach ($xmlFiles as $file) { + $contents = $file->getContents(); + $filePath = $file->getRealPath(); + file_put_contents($filePath, $this->removeModuleFileAttributeInSuite($contents, $filePath)); + } + return ("Removed module file reference in {$this->testsUpdated} suite file(s)."); + } + + /** + * Remove module file attribute in Suite xml file + * + * @param string $contents + * @param string $file + * @return string|string[]|null + */ + private function removeModuleFileAttributeInSuite($contents, $file) + { + $pattern = '/<module[^\<\>]+file[\s]*=[\s]*"(?<file>[^"\<\>]*)"[^\>\<]*>/'; + $contents = preg_replace_callback( + $pattern, + function ($matches) use ($file) { + if (!$this->printNotice) { + $this->ioStyle->note( + '`file` attribute is removed from <module> in Suite XML schema.' . PHP_EOL + . 'The references in the following xml files are removed. Consider using <test> instead.' + ); + $this->printNotice = true; + } + $this->output->writeln( + PHP_EOL + . '"' . trim($matches[0]) . '"' . PHP_EOL + . 'is removed from file: ' . $file . PHP_EOL + ); + return ''; + }, + $contents + ); + $this->testsUpdated += 1; + return $contents; + } + + /** + * Set Symfony Style for output + * + * @param InputInterface $input + * @param OutputInterface $output + * @return void + */ + private function setOutputStyle(InputInterface $input, OutputInterface $output) + { + // For output style + if (null === $this->ioStyle) { + $this->ioStyle = new SymfonyStyle($input, $output); + } + } +} diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php b/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php index 7f1124717..39962fc9a 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php @@ -8,7 +8,6 @@ use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Util\Script\ScriptUtil; -use PHP_CodeSniffer\Exceptions\DeepExitException; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -31,6 +30,13 @@ class SplitMultipleEntitiesFiles implements UpgradeInterface const FILENAME_BASE = 'base'; const FILENAME_SUFFIX = 'type'; + /** + * OutputInterface + * + * @var OutputInterface + */ + private $output; + /** * Entity categories for the upgrade script * @@ -45,7 +51,7 @@ class SplitMultipleEntitiesFiles implements UpgradeInterface ]; /** - * Scan all test xml files and split xml files that contains more than one entities + * Scan all xml files and split xml files that contains more than one entities * for Test, Action Group, Page, Section, Suite types. * * @param InputInterface $input @@ -55,6 +61,7 @@ class SplitMultipleEntitiesFiles implements UpgradeInterface */ public function execute(InputInterface $input, OutputInterface $output) { + $this->output = $output; $testsUpdated = 0; $testPaths[] = $input->getArgument('path'); if (empty($testPaths[0])) { @@ -72,7 +79,9 @@ public function execute(InputInterface $input, OutputInterface $output) $entityContents = $this->getEntityContents($contents, $type); if (count($entityContents) > 1) { $filename = $file->getRealPath(); - $output->writeln('Processing file:' . $filename); + if ($this->output->isVerbose()) { + $this->output->writeln('Processing file:' . $filename); + } foreach ($entityContents as $entityName => $entityContent) { $dir = dirname($file); $dir .= DIRECTORY_SEPARATOR . ucfirst(basename($file, '.xml')); @@ -83,13 +92,17 @@ public function execute(InputInterface $input, OutputInterface $output) $urn, $entityContent ); - $output->writeln( - 'Created file:' . $dir . DIRECTORY_SEPARATOR . $splitFileName . '.xml' - ); + if ($this->output->isVerbose()) { + $this->output->writeln( + 'Created file:' . $dir . DIRECTORY_SEPARATOR . $splitFileName . '.xml' + ); + } $testsUpdated++; } unlink($file); - $output->writeln('Unlinked file:' . $filename . PHP_EOL); + if ($this->output->isVerbose()) { + $this->output->writeln('Unlinked file:' . $filename . PHP_EOL); + } } } } @@ -105,12 +118,13 @@ public function execute(InputInterface $input, OutputInterface $output) */ private function getEntityContents($contents, $type) { - $pattern = '/[\S\s]+\n(?<entity>[\s]+<' . lcfirst($type) - . '[ \t]+name="(?<name>[^\W]+)"[\S\s]+<\/'. lcfirst($type) . '>)+[\S\s]+/'; + $pattern = '/[\S\s]+\n(?<entity>[\s]*<' . lcfirst($type) + . '[^\<\>]+name[\s]*=[\s]*"(?<name>[^\"\'\<\>\&]+)"[^\<\>]*>[\S\s]+<\/' + . lcfirst($type) . '[\s]*>)+[\S\s]+/'; preg_match($pattern, $contents, $matches); if (isset($matches['entity']) && isset($matches['name'])) { $contents = str_replace($matches['entity'], '', $contents); - $entityContents[$matches['name']] = $matches['entity']; + $entityContents[trim($matches['name'])] = $matches['entity']; if (!empty($this->getEntityContents($contents, $type))) { $entityContents = array_merge($entityContents, $this->getEntityContents($contents, $type)); } @@ -137,6 +151,7 @@ private function filePutContents($fullPath, $type, $urn, $contents) mkdir($dir, 0777, true); } + // Make sure not overwriting an existing file $fullPath = $this->getNonExistingFileFullPath($fullPath, $type); $fullContents = self::XML_VERSION diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/UpgradeScriptList.php b/src/Magento/FunctionalTestingFramework/Upgrade/UpgradeScriptList.php index 3a75402bb..bbc240e7e 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/UpgradeScriptList.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/UpgradeScriptList.php @@ -29,7 +29,8 @@ public function __construct(array $scripts = []) { $this->scripts = [ 'upgradeTestSchema' => new UpdateTestSchemaPaths(), - 'splitMultipleEntitiesFiles' => new SplitMultipleEntitiesFiles() + 'splitMultipleEntitiesFiles' => new SplitMultipleEntitiesFiles(), + 'removeModuleFileInSuiteFiles' => new RemoveModuleFileInSuiteFiles(), ] + $scripts; } diff --git a/src/Magento/FunctionalTestingFramework/Util/Filesystem/RecursiveGlobUtil.php b/src/Magento/FunctionalTestingFramework/Util/Filesystem/RecursiveGlobUtil.php new file mode 100644 index 000000000..bf012d4e8 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/Filesystem/RecursiveGlobUtil.php @@ -0,0 +1,72 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\FunctionalTestingFramework\Util\Filesystem; + +class RecursiveGlobUtil +{ + /** + * Recursively glob full pathnames matching a pattern in a given directory + * + * @param string $pattern + * @param string $directory + * @return array + */ + public static function glob($pattern, $directory) + { + $directory = realpath($directory); + if ($directory === false) { + return []; + } + $pattern = DIRECTORY_SEPARATOR . ltrim($pattern, DIRECTORY_SEPARATOR); + $subDirectoryPattern = DIRECTORY_SEPARATOR . "*"; + + $fileList = []; + foreach (glob($directory . $subDirectoryPattern, GLOB_ONLYDIR) as $dir) { + $fileList = array_merge_recursive($fileList, self::glob($pattern, $dir)); + } + + $curFiles = glob($directory . $pattern); + if ($curFiles !== false && !empty($curFiles)) { + $fileList = array_merge_recursive($fileList, $curFiles); + } + return $fileList; + } + + /** + * Recursive glob full pathnames matching a pattern in a given directory at certain depths + * + * @param string $pattern + * @param string $directory + * @param integer $depth + * @return array + */ + public static function globAtDepth($pattern, $directory, $depth) + { + $directory = realpath($directory); + if ($directory === false) { + return []; + } + $pattern = DIRECTORY_SEPARATOR . ltrim($pattern, DIRECTORY_SEPARATOR); + $subDirectoryPattern = DIRECTORY_SEPARATOR . "*"; + + $fileList = []; + if ($depth > 0) { + foreach (glob($directory . $subDirectoryPattern, GLOB_ONLYDIR) as $dir) { + $fileList = array_merge_recursive( + $fileList, + self::globAtDepth($pattern, $dir, $depth-1) + ); + } + } elseif ($depth == 0) { + $fileList = glob($directory . $pattern); + if ($fileList === false) { + $fileList = []; + } + } + return $fileList; + } +} From 1c7b03b63e249e6990c5b28a7675b94b757f9c4f Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Thu, 27 Feb 2020 10:17:01 -0600 Subject: [PATCH 235/888] MQE-2008: Filter test generation and execution by severity - Unit test --- .../Util/TestGeneratorTest.php | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php index 8f8eee749..ad51d3681 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php @@ -8,6 +8,7 @@ use AspectMock\Test as AspectMock; +use Magento\FunctionalTestingFramework\Filter\FilterList; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Magento\FunctionalTestingFramework\Test\Objects\TestHookObject; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; @@ -17,6 +18,16 @@ class TestGeneratorTest extends MagentoTestCase { + /** + * After method functionality + * + * @return void + */ + public function tearDown() + { + AspectMock::clean(); + } + /** * Basic test to check exceptions for incorrect entities. * @@ -99,4 +110,53 @@ public function testAllowSkipped() $this->assertContains($actionInput, $output); $this->assertContains($beforeActionInput, $output); } + + /** + * Tests that TestGenerator createAllTestFiles correctly filters based on severity + * + * @throws \Magento\FunctionalTestingFramework\Exceptions\TestReferenceException + */ + public function testFilter() + { + // Mock filters for TestGenerator + AspectMock::double(MftfApplicationConfig::class, ['getFilterList' => new FilterList(['severity' => ["CRITICAL"]])]); + + $actionInput = 'fakeInput'; + $actionObject = new ActionObject('fakeAction', 'comment', [ + 'userInput' => $actionInput + ]); + + $annotation1 = ['severity' => ['CRITICAL']]; + $annotation2 = ['severity' => ['MINOR']]; + $test1 = new TestObject( + "test1", + ["fakeAction" => $actionObject], + $annotation1, + [], + "filename" + ); + $test2 = new TestObject( + "test2", + ["fakeAction" => $actionObject], + $annotation2, + [], + "filename" + ); + AspectMock::double(TestGenerator::class, ['loadAllTestObjects' => ["sampleTest" => $test1, "test2" => $test2]]); + + // Mock createCestFile to return name of tests that testGenerator tried to create + $generatedTests = []; + AspectMock::double(TestGenerator::class, ['createCestFile' => function ($arg1, $arg2) use (&$generatedTests){ + $generatedTests[$arg2] = true; + }]); + + $testGeneratorObject = TestGenerator::getInstance("", ["sampleTest" => $test1, "test2" => $test2]); + $testGeneratorObject->createAllTestFiles(null, []); + + // Ensure Test1 was Generated but not Test 2 + $this->assertArrayHasKey('test1Cest', $generatedTests); + $this->assertArrayNotHasKey('test2Cest', $generatedTests); + + } + } From afc5551f8d024c6a4cb1b8fe0d9dbb1a1f85bc11 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Thu, 27 Feb 2020 10:19:37 -0600 Subject: [PATCH 236/888] MQE-2008: Filter test generation and execution by severity - Static Fix --- .../Magento/FunctionalTestFramework/Util/TestGeneratorTest.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php index ad51d3681..cd930a997 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php @@ -156,7 +156,5 @@ public function testFilter() // Ensure Test1 was Generated but not Test 2 $this->assertArrayHasKey('test1Cest', $generatedTests); $this->assertArrayNotHasKey('test2Cest', $generatedTests); - } - } From a6ec117400c80c0aff10961029a3d2957e343ae1 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Thu, 27 Feb 2020 11:00:03 -0600 Subject: [PATCH 237/888] MQE-2008: Filter test generation and execution by severity --- .../FunctionalTestFramework/Util/TestGeneratorTest.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php index cd930a997..e11b0f9b2 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php @@ -119,7 +119,10 @@ public function testAllowSkipped() public function testFilter() { // Mock filters for TestGenerator - AspectMock::double(MftfApplicationConfig::class, ['getFilterList' => new FilterList(['severity' => ["CRITICAL"]])]); + AspectMock::double( + MftfApplicationConfig::class, + ['getFilterList' => new FilterList(['severity' => ["CRITICAL"]])] + ); $actionInput = 'fakeInput'; $actionObject = new ActionObject('fakeAction', 'comment', [ @@ -146,7 +149,7 @@ public function testFilter() // Mock createCestFile to return name of tests that testGenerator tried to create $generatedTests = []; - AspectMock::double(TestGenerator::class, ['createCestFile' => function ($arg1, $arg2) use (&$generatedTests){ + AspectMock::double(TestGenerator::class, ['createCestFile' => function ($arg1, $arg2) use (&$generatedTests) { $generatedTests[$arg2] = true; }]); From 75f5224674f629b44fe47b24f5536ed9c030c0d5 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Thu, 27 Feb 2020 11:40:49 -0600 Subject: [PATCH 238/888] MQE-2008: Filter test generation and execution by severity --- .../Console/BaseGenerateCommand.php | 2 +- .../Console/GenerateTestsCommand.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index 3433f23a8..273632586 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -35,7 +35,7 @@ class BaseGenerateCommand extends Command * * @var SymfonyStyle */ - private $ioStyle = null; + protected $ioStyle = null; /** * Configures the base command. diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php index f43488c0b..3ca53f8f6 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php @@ -77,7 +77,7 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output) { - $ioStyle = new SymfonyStyle($input, $output); + $this->setOutputStyle($input, $output); $tests = $input->getArgument('name'); $config = $input->getOption('config'); $json = $input->getOption('tests'); // for backward compatibility @@ -103,7 +103,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $filterList ?? [] ); } catch (\Exception $exception) { - $ioStyle->error("Test generation failed." . PHP_EOL . $exception->getMessage()); + $this->ioStyle->error("Test generation failed." . PHP_EOL . $exception->getMessage()); return 1; } @@ -151,7 +151,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $message .= !empty($filters) ? 'Filter(s): ' . implode(', ', $filters) . PHP_EOL : ''; $message .= !empty($tests) ? 'Test name(s): ' . implode(', ', $tests) . PHP_EOL : ''; $message .= !empty($json) && empty($tests) ? 'Test configuration: ' . $json . PHP_EOL : ''; - $ioStyle->note($message); + $this->ioStyle->note($message); return 1; } From c215ab0ac08e6a86884e6cda5406fe128b0aa0b9 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Thu, 27 Feb 2020 12:28:47 -0600 Subject: [PATCH 239/888] MQE-2008: Filter test generation and execution by severity - update composer.json and CHANGELOG.md --- CHANGELOG.md | 5 +++++ composer.json | 2 +- composer.lock | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4792fa8ae..a41360787 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ Magento Functional Testing Framework Changelog ================================================ +2.6.3 +----- + +### New Feature +* `--filter` option was added to `bin/mftf generate:tests` command. For more details please go to https://devdocs.magento.com/mftf/docs/commands/mftf.html#generatetests 2.6.2 ----- diff --git a/composer.json b/composer.json index ed4656a37..0ff50a2e8 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "2.6.2", + "version": "2.6.3", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index caa95e992..6f370593b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "d9ea4056a8f4501c3f2766e09edce40d", + "content-hash": "83e4e17679bff5fdd472c246dca8ac48", "packages": [ { "name": "allure-framework/allure-codeception", From 35818bb40393f552ae303746a39f7fda4cc5a246 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Thu, 27 Feb 2020 16:05:15 -0600 Subject: [PATCH 240/888] MQE-683: [Deprecation] Only use more nested assertion syntax - static check fixes --- .../Upgrade/UpdateAssertionSchema.php | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php index 6eca6a11e..c44038368 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php @@ -18,8 +18,18 @@ class UpdateAssertionSchema implements UpgradeInterface { const OLD_ASSERTION_ATTRIBUTES = ["expected", "expectedType", "actual", "actualType"]; + /** + * Current file being inspected, for error messaging + * @var string + */ private $currentFile; + + /** + * Potential errors reported during replacement. + * @var array + */ private $errors = []; + /** * Upgrades all test xml files, changing <assert> actions to be nested * @@ -40,7 +50,7 @@ public function execute(InputInterface $input) } $this->currentFile = $file->getFilename(); $contents = $file->getContents(); - // Isolate <assert ... /> but not <assert ... > + // Isolate <assert ... /> but not <assert> ... </assert> preg_match_all('/<assert[^>]*\/>/', $contents, $potentialAssertions); $newAssertions = []; $index = 0; @@ -58,6 +68,12 @@ public function execute(InputInterface $input) return ("Assertion Syntax updated in {$testsUpdated} file(s).\n" . implode("\n\t", $this->errors)); } + /** + * Detects present of attributes in file + * + * @param string $file + * @return boolean + */ private function detectOldAttributes($file) { foreach (self::OLD_ASSERTION_ATTRIBUTES as $OLD_ASSERTION_ATTRIBUTE) { @@ -68,6 +84,13 @@ private function detectOldAttributes($file) return false; } + /** + * Takes given string and attempts to convert it from single line to multi-line + * + * @param string $assertion + * @return string + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + */ private function convertOldAssertionToNew($assertion) { // <assertSomething => assertSomething @@ -112,7 +135,8 @@ private function convertOldAssertionToNew($assertion) foreach ($subElements as $type => $subElement) { if (!isset($subElement['value']) || !isset($subElement['type'])) { //don't have all the info we need to rebuild - $this->errors[] = "UNABLE TO FULLY REBUILD ASSERTION, PLEASE MANUALLY CHECK FORMAT ($assertType \"$stepKey\" in $this->currentFile)"; + $this->errors[] = "UNABLE TO FULLY REBUILD ASSERTION, PLEASE MANUALLY CHECK FORMAT " . + "($assertType \"$stepKey\" in $this->currentFile)"; continue; } $value = $subElement['value']; @@ -122,5 +146,4 @@ private function convertOldAssertionToNew($assertion) $newString .= "</$assertType>"; return $newString; } - } From 8a0233cb73377865e438492bec383566de853db1 Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Tue, 25 Feb 2020 16:27:15 -0600 Subject: [PATCH 241/888] MQE-2005: Timeout parameters in functional.suite.yml.dist --- dev/tests/functional/standalone_bootstrap.php | 2 +- etc/config/functional.suite.dist.yml | 2 ++ src/Magento/FunctionalTestingFramework/_bootstrap.php | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/dev/tests/functional/standalone_bootstrap.php b/dev/tests/functional/standalone_bootstrap.php index 486c7566b..34516236e 100755 --- a/dev/tests/functional/standalone_bootstrap.php +++ b/dev/tests/functional/standalone_bootstrap.php @@ -51,7 +51,7 @@ $env->setEnvironmentVariable('DEFAULT_TIMEZONE', DEFAULT_TIMEZONE); defined('WAIT_TIMEOUT') || define('WAIT_TIMEOUT', 30); - $env->setEnvironmentVariable('WAIT_TIMEOUT', 30); + $env->setEnvironmentVariable('WAIT_TIMEOUT', WAIT_TIMEOUT); try { new DateTimeZone(DEFAULT_TIMEZONE); diff --git a/etc/config/functional.suite.dist.yml b/etc/config/functional.suite.dist.yml index 319804d7a..10fe1212d 100644 --- a/etc/config/functional.suite.dist.yml +++ b/etc/config/functional.suite.dist.yml @@ -29,6 +29,8 @@ modules: username: "%MAGENTO_ADMIN_USERNAME%" password: "%MAGENTO_ADMIN_PASSWORD%" pageload_timeout: "%WAIT_TIMEOUT%" + request_timeout: "%WAIT_TIMEOUT%" + connection_timeout: "%WAIT_TIMEOUT%" host: "%SELENIUM_HOST%" port: "%SELENIUM_PORT%" protocol: "%SELENIUM_PROTOCOL%" diff --git a/src/Magento/FunctionalTestingFramework/_bootstrap.php b/src/Magento/FunctionalTestingFramework/_bootstrap.php index a5ce1f931..8032802c0 100644 --- a/src/Magento/FunctionalTestingFramework/_bootstrap.php +++ b/src/Magento/FunctionalTestingFramework/_bootstrap.php @@ -51,7 +51,7 @@ $env->setEnvironmentVariable('DEFAULT_TIMEZONE', DEFAULT_TIMEZONE); defined('WAIT_TIMEOUT') || define('WAIT_TIMEOUT', 30); - $env->setEnvironmentVariable('WAIT_TIMEOUT', 30); + $env->setEnvironmentVariable('WAIT_TIMEOUT', WAIT_TIMEOUT); try { new DateTimeZone(DEFAULT_TIMEZONE); From 89bd39a99963fe25b4272aaaeb773967282a9367 Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Fri, 28 Feb 2020 15:57:45 -0600 Subject: [PATCH 242/888] MQE-1057: Update metadata filenames convention --- docs/metadata.md | 18 +++--- etc/di.xml | 2 +- .../DataGenerator/etc/dataOperation.xsd | 2 +- .../Upgrade/RenameMetadataFiles.php | 62 +++++++++++++++++++ .../Upgrade/UpgradeScriptList.php | 1 + 5 files changed, 74 insertions(+), 11 deletions(-) create mode 100644 src/Magento/FunctionalTestingFramework/Upgrade/RenameMetadataFiles.php diff --git a/docs/metadata.md b/docs/metadata.md index 36ff1556e..3f6032b57 100644 --- a/docs/metadata.md +++ b/docs/metadata.md @@ -67,8 +67,8 @@ The following diagram demonstrates the XML structure of a metadata file: ## Principles {#principles} 1. A `dataType` value must match the `type` value of the corresponding entity. -2. A file name should contain data type split with `_` and must end with `-meta`. - Example: `product_attribute-meta.xml`. +2. A file name should be PascalCase and end with `Meta.xml`. + Example: `ProductAttributeMeta.xml`. 3. A metadata file may contain different types of operations (`type`) with the same data entity (`dataType`). Example: @@ -139,7 +139,7 @@ _Catalog/Data/CategoryData.xml_: Here, `type` is equal to `"category"`, which instructs the MFTF to search an operation with `dataType="category"`. Since the action is __to create__ a category, the MFTF will also search for operation with `type="create"` in _Metadata_ for `dataType="category"`. -_Catalog/Metadata/category-meta.xml_: +_Catalog/Metadata/CategoryMeta.xml_: ```xml <operation name="CreateCategory" dataType="category" type="create" auth="adminOauth" url="/V1/categories" method="POST"> @@ -187,10 +187,10 @@ Comments in the example below are used to demonstrate relation between JSON requ JSON does not support comments. </div> -Model schema for _catalogCategoryRepositoryV1SavePostBody_ with XML representation of _Catalog/Metadata/category-meta.xml_ in comments: +Model schema for _catalogCategoryRepositoryV1SavePostBody_ with XML representation of _Catalog/Metadata/CategoryMeta.xml_ in comments: ```json -{ // XML representation in the MFTF metadata format (see 'Catalog/Metadata/category-meta.xml') +{ // XML representation in the MFTF metadata format (see 'Catalog/Metadata/CategoryMeta.xml') "category": { // <object key="category" dataType="category"> "id": 0, // Skipped, because Category ID is not available on UI when you create a new category. "parent_id": 0, // <field key="parent_id">integer</field> @@ -206,9 +206,9 @@ Model schema for _catalogCategoryRepositoryV1SavePostBody_ with XML representati "string" // <value>string</value> ], // </array> "include_in_menu": true, // <field key="include_in_menu">boolean</field> - "extension_attributes": {}, // <field key="extension_attributes">empty_extension_attribute</field>, where 'empty_extension_attribute' is a reference to operation with 'dataType="empty_extension_attribute"' (see 'Catalog/Metadata/empty_extension_attribute-meta.xml') + "extension_attributes": {}, // <field key="extension_attributes">empty_extension_attribute</field>, where 'empty_extension_attribute' is a reference to operation with 'dataType="empty_extension_attribute"' (see 'Catalog/Metadata/EmptyExtensionAttributeMeta.xml') "custom_attributes": [ // <array key="custom_attributes"> - { // <value>custom_attribute</value>, where 'custom_attribute' is a reference to operation with 'dataType="custom_attribute"' (see 'Catalog/Metadata/custom_attribute-meta.xml') + { // <value>custom_attribute</value>, where 'custom_attribute' is a reference to operation with 'dataType="custom_attribute"' (see 'Catalog/Metadata/CustomAttributeMeta.xml') "attribute_code": "string", "value": "string" } @@ -343,7 +343,7 @@ You are able to create assurances with `successRegex`, and, optionally, return v The `CreateStoreGroup` operation is used to persist a store group: -Source file is _Store/Metadata/store_group-meta.xml_: +Source file is _Store/Metadata/StoreGroupMeta.xml_: ```xml <operation name="CreateStoreGroup" dataType="group" type="create" auth="adminFormKey" url="/admin/system_store/save" method="POST" successRegex="/messages-message-success/" > @@ -379,7 +379,7 @@ The operation enables you to assign the following form fields: The MFTF uses the `CreateWishlist` operation to create a wish list on storefront: -Source file is _Wishlist/Metadata/wishlist-meta.xml_ +Source file is _Wishlist/Metadata/WishlistMeta.xml_ ```xml <operation name="CreateWishlist" dataType="wishlist" type="create" auth="customerFormKey" url="/wishlist/index/add/" method="POST" successRegex="" returnRegex="~\/wishlist_id\/(\d*?)\/~" > diff --git a/etc/di.xml b/etc/di.xml index aec5e872c..5a89d9665 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -198,7 +198,7 @@ <argument name="mergeablePaths" xsi:type="array"> <item name="/operations/operation/object" xsi:type="string"/> </argument> - <argument name="fileName" xsi:type="string">*-meta.xml</argument> + <argument name="fileName" xsi:type="string">*Meta.xml</argument> <argument name="defaultScope" xsi:type="string">Metadata</argument> </arguments> </virtualType> diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd b/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd index 58fad8d8b..c2682e737 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd @@ -109,4 +109,4 @@ <xs:enumeration value="DELETE" /> </xs:restriction> </xs:simpleType> -</xs:schema> \ No newline at end of file +</xs:schema> diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/RenameMetadataFiles.php b/src/Magento/FunctionalTestingFramework/Upgrade/RenameMetadataFiles.php new file mode 100644 index 000000000..93f75dfe1 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Upgrade/RenameMetadataFiles.php @@ -0,0 +1,62 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\FunctionalTestingFramework\Upgrade; + +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Finder\Finder; + +/** + * Class RenameMetadataFiles + * @package Magento\FunctionalTestingFramework\Upgrade + */ +class RenameMetadataFiles implements UpgradeInterface +{ + /** + * Upgrades all test xml files + * + * @param InputInterface $input + * @return string + */ + public function execute(InputInterface $input) + { + $path = $input->getArgument("path"); + $finder = new Finder(); + $finder->files()->in($path)->name("*-meta.xml"); + + foreach ($finder->files() as $file) { + $oldFileName = $file->getFileName(); + $newFileName = $this->convertFileName($oldFileName); + $oldPath = $file->getPathname(); + $newPath = $file->getPath() . "/" . $newFileName; + print("Renaming " . $oldPath . " => " . $newPath . "\n"); + rename($oldPath, $newPath); + } + + return "Finished renaming -meta.xml files."; + } + + /** + * Convert filenames like: + * user_role-meta.xml => UserRoleMeta.xml + * store-meta.xml => StoreMeta.xml + * + * @param string $oldFileName + * @return string + */ + private function convertFileName(string $oldFileName) { + $stripEnding = preg_replace("/-meta.xml/", "", $oldFileName); + $hyphenToUnderscore = str_replace("-", "_", $stripEnding); + $parts = explode("_", $hyphenToUnderscore); + $ucParts = []; + foreach ($parts as $part) { + $ucParts[] = ucfirst($part); + } + $recombine = join("", $ucParts); + $addEnding = $recombine . "Meta.xml"; + return $addEnding; + } +} diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/UpgradeScriptList.php b/src/Magento/FunctionalTestingFramework/Upgrade/UpgradeScriptList.php index 245f95d82..2bd1f45c8 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/UpgradeScriptList.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/UpgradeScriptList.php @@ -29,6 +29,7 @@ public function __construct(array $scripts = []) { $this->scripts = [ 'upgradeTestSchema' => new UpdateTestSchemaPaths(), + 'renameMetadataFiles' => new RenameMetadataFiles() ] + $scripts; } From 3f4ca69c44674b4e676bc7ceefa3cd11060ae737 Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Mon, 2 Mar 2020 09:45:17 -0600 Subject: [PATCH 243/888] MQE-1057: Update metadata filenames convention - Fix static check error --- .../FunctionalTestingFramework/Upgrade/RenameMetadataFiles.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/RenameMetadataFiles.php b/src/Magento/FunctionalTestingFramework/Upgrade/RenameMetadataFiles.php index 93f75dfe1..960d34f70 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/RenameMetadataFiles.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/RenameMetadataFiles.php @@ -47,7 +47,8 @@ public function execute(InputInterface $input) * @param string $oldFileName * @return string */ - private function convertFileName(string $oldFileName) { + private function convertFileName(string $oldFileName) + { $stripEnding = preg_replace("/-meta.xml/", "", $oldFileName); $hyphenToUnderscore = str_replace("-", "_", $stripEnding); $parts = explode("_", $hyphenToUnderscore); From cdf6b84392a6007b944409b0eb06aaf5eea74d81 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 2 Mar 2020 09:46:12 -0600 Subject: [PATCH 244/888] MQE-1963: Update XSD Schema to verify that file has only single entity --- .../Console/BaseGenerateCommand.php | 6 +- .../StaticCheck/ActionGroupArgumentsCheck.php | 2 +- .../StaticCheck/TestDependencyCheck.php | 6 +- .../Suite/Util/SuiteObjectExtractor.php | 20 +++-- .../Upgrade/RemoveModuleFileInSuiteFiles.php | 30 +++++-- .../Upgrade/SplitMultipleEntitiesFiles.php | 89 ++++++++++++------- .../Util/Filesystem/RecursiveGlobUtil.php | 72 --------------- .../Util/ModuleResolver.php | 11 ++- .../AlphabeticSequenceSorter.php | 25 ++++++ .../Util/Script/ScriptUtil.php | 42 ++++++--- 10 files changed, 162 insertions(+), 141 deletions(-) delete mode 100644 src/Magento/FunctionalTestingFramework/Util/Filesystem/RecursiveGlobUtil.php create mode 100644 src/Magento/FunctionalTestingFramework/Util/ModuleResolver/AlphabeticSequenceSorter.php diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index b1718f131..f9be1b973 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -191,15 +191,15 @@ protected function getGroupAndSuiteConfiguration(array $groupOrSuiteNames) } /** - * Set Symfony Style for output + * Set Symfony IO Style * * @param InputInterface $input * @param OutputInterface $output * @return void */ - protected function setOutputStyle(InputInterface $input, OutputInterface $output) + protected function setIOStyle(InputInterface $input, OutputInterface $output) { - // For output style + // For IO style if (null === $this->ioStyle) { $this->ioStyle = new SymfonyStyle($input, $output); } diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php index 246e9427e..556ad45be 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php @@ -53,7 +53,7 @@ public function execute(InputInterface $input) { $allModules = ScriptUtil::getAllModulePaths(); - $actionGroupXmlFiles = ScriptUtil::buildFileList( + $actionGroupXmlFiles = ScriptUtil::getModuleXmlFilesByScope( $allModules, DIRECTORY_SEPARATOR . 'ActionGroup' . DIRECTORY_SEPARATOR ); diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php index 55179c634..bc1b06cc5 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php @@ -108,9 +108,9 @@ public function execute(InputInterface $input) DIRECTORY_SEPARATOR . 'Data' . DIRECTORY_SEPARATOR, ]; // These files can contain references to other modules. - $testXmlFiles = ScriptUtil::buildFileList($allModules, $filePaths[0]); - $actionGroupXmlFiles = ScriptUtil::buildFileList($allModules, $filePaths[1]); - $dataXmlFiles= ScriptUtil::buildFileList($allModules, $filePaths[2]); + $testXmlFiles = ScriptUtil::getModuleXmlFilesByScope($allModules, $filePaths[0]); + $actionGroupXmlFiles = ScriptUtil::getModuleXmlFilesByScope($allModules, $filePaths[1]); + $dataXmlFiles= ScriptUtil::getModuleXmlFilesByScope($allModules, $filePaths[2]); $this->errors = []; $this->errors += $this->findErrorsInFileSet($testXmlFiles); diff --git a/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php index abeb86da4..641588310 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php @@ -15,7 +15,7 @@ use Magento\FunctionalTestingFramework\Test\Util\TestObjectExtractor; use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Magento\FunctionalTestingFramework\Util\Validation\NameValidationUtil; -use Magento\FunctionalTestingFramework\Util\Filesystem\RecursiveGlobUtil; +use Symfony\Component\Finder\Finder; class SuiteObjectExtractor extends BaseObjectExtractor { @@ -240,17 +240,23 @@ private function extractTestObjectsFromSuiteRef($suiteReferences) */ private function resolveFilePathTestNames($filename, $moduleName = null) { - $filepath = $filename; + $filepath = null; if (!file_exists($filename) && null !== $moduleName) { $dir = FilePathFormatter::format(TESTS_MODULE_PATH) . $moduleName . DIRECTORY_SEPARATOR . 'Test'; - $filepaths = RecursiveGlobUtil::glob($filename, $dir); - if (isset($filepaths[0]) && file_exists($filepaths[0])) { - $filepath = $filepaths[0]; - } else { - throw new Exception("Could not find file ${filename}"); + if (file_exists($dir)) { + $finder = new Finder(); + $finder->files()->followLinks()->name($filename)->in($dir); + foreach ($finder as $file) { + $filepath = $file->getRealPath(); + break; + } } } + if (null === $filepath) { + throw new Exception("Could not find file ${filename}"); + } + $testObjects = []; $xml = simplexml_load_file($filepath); for ($i = 0; $i < $xml->count(); $i++) { diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/RemoveModuleFileInSuiteFiles.php b/src/Magento/FunctionalTestingFramework/Upgrade/RemoveModuleFileInSuiteFiles.php index ffbae59aa..639f24157 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/RemoveModuleFileInSuiteFiles.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/RemoveModuleFileInSuiteFiles.php @@ -11,6 +11,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\Finder\Finder; /** * Class RemoveModuleFileInSuiteFiles @@ -63,17 +64,30 @@ public function execute(InputInterface $input, OutputInterface $output) $testPaths = ScriptUtil::getAllModulePaths(); } - $xmlFiles = ScriptUtil::buildFileList( - $testPaths, - DIRECTORY_SEPARATOR . 'Suite' . DIRECTORY_SEPARATOR - ); + // Get module suite xml files + $xmlFiles = ScriptUtil::getModuleXmlFilesByScope($testPaths, 'Suite'); + $this->processXmlFiles($xmlFiles); + + // Get root suite xml files + $xmlFiles = ScriptUtil::getRootSuiteXmlFiles(); + $this->processXmlFiles($xmlFiles); + + return ("Removed module file reference in {$this->testsUpdated} suite file(s)."); + } + /** + * Process on list of xml files + * + * @param Finder $xmlFiles + * @return void + */ + private function processXmlFiles($xmlFiles) + { foreach ($xmlFiles as $file) { $contents = $file->getContents(); $filePath = $file->getRealPath(); file_put_contents($filePath, $this->removeModuleFileAttributeInSuite($contents, $filePath)); } - return ("Removed module file reference in {$this->testsUpdated} suite file(s)."); } /** @@ -91,8 +105,8 @@ private function removeModuleFileAttributeInSuite($contents, $file) function ($matches) use ($file) { if (!$this->printNotice) { $this->ioStyle->note( - '`file` attribute is removed from <module> in Suite XML schema.' . PHP_EOL - . 'The references in the following xml files are removed. Consider using <test> instead.' + '`file` is not a valid attribute for <module> in Suite XML schema.' . PHP_EOL + . 'The `file`references in the following xml files are removed. Consider using <test> instead.' ); $this->printNotice = true; } @@ -101,11 +115,11 @@ function ($matches) use ($file) { . '"' . trim($matches[0]) . '"' . PHP_EOL . 'is removed from file: ' . $file . PHP_EOL ); + $this->testsUpdated += 1; return ''; }, $contents ); - $this->testsUpdated += 1; return $contents; } diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php b/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php index 39962fc9a..4ba8905c6 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php @@ -10,6 +10,7 @@ use Magento\FunctionalTestingFramework\Util\Script\ScriptUtil; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Finder\Finder; /** * Class SplitMultipleEntitiesFiles @@ -37,6 +38,13 @@ class SplitMultipleEntitiesFiles implements UpgradeInterface */ private $output; + /** + * Total test updated + * + * @var integer + */ + private $testsUpdated = 0; + /** * Entity categories for the upgrade script * @@ -62,51 +70,66 @@ class SplitMultipleEntitiesFiles implements UpgradeInterface public function execute(InputInterface $input, OutputInterface $output) { $this->output = $output; - $testsUpdated = 0; + $this->testsUpdated = 0; $testPaths[] = $input->getArgument('path'); if (empty($testPaths[0])) { $testPaths = ScriptUtil::getAllModulePaths(); } + // Process module xml files foreach ($this->entityCategories as $type => $urn) { - $xmlFiles = ScriptUtil::buildFileList( - $testPaths, - DIRECTORY_SEPARATOR . $type . DIRECTORY_SEPARATOR - ); - - foreach ($xmlFiles as $file) { - $contents = $file->getContents(); - $entityContents = $this->getEntityContents($contents, $type); - if (count($entityContents) > 1) { - $filename = $file->getRealPath(); + $xmlFiles = ScriptUtil::getModuleXmlFilesByScope($testPaths, $type); + $this->processXmlFiles($xmlFiles, $type, $urn); + } + + // Process root suite xml files + $xmlFiles = ScriptUtil::getRootSuiteXmlFiles(); + $this->processXmlFiles($xmlFiles, 'Suite', $this->entityCategories['Suite']); + + return ("Split multiple entities in {$this->testsUpdated} file(s)."); + } + + /** + * Split on list of xml files + * + * @param Finder $xmlFiles + * @param string $type + * @param string $urn + * @return void + */ + private function processXmlFiles($xmlFiles, $type, $urn) + { + foreach ($xmlFiles as $file) { + $contents = $file->getContents(); + $entityContents = $this->getEntityContents($contents, $type); + if (count($entityContents) > 1) { + $filename = $file->getRealPath(); + if ($this->output->isVerbose()) { + $this->output->writeln('Processing file:' . $filename); + } + foreach ($entityContents as $entityName => $entityContent) { + $dir = dirname($file); + $dir .= DIRECTORY_SEPARATOR . ucfirst(basename($file, '.xml')); + $splitFileName = $this->formatName($entityName, $type); + $this->filePutContents( + $dir . DIRECTORY_SEPARATOR . $splitFileName . '.xml', + $type, + $urn, + $entityContent + ); if ($this->output->isVerbose()) { - $this->output->writeln('Processing file:' . $filename); - } - foreach ($entityContents as $entityName => $entityContent) { - $dir = dirname($file); - $dir .= DIRECTORY_SEPARATOR . ucfirst(basename($file, '.xml')); - $splitFileName = $this->formatName($entityName, $type); - $this->filePutContents( - $dir . DIRECTORY_SEPARATOR . $splitFileName . '.xml', - $type, - $urn, - $entityContent + $this->output->writeln( + 'Created file:' . $dir . DIRECTORY_SEPARATOR . $splitFileName . '.xml' ); - if ($this->output->isVerbose()) { - $this->output->writeln( - 'Created file:' . $dir . DIRECTORY_SEPARATOR . $splitFileName . '.xml' - ); - } - $testsUpdated++; - } - unlink($file); - if ($this->output->isVerbose()) { - $this->output->writeln('Unlinked file:' . $filename . PHP_EOL); } + $this->testsUpdated++; + } + unlink($file); + if ($this->output->isVerbose()) { + $this->output->writeln('Unlinked file:' . $filename . PHP_EOL); } } } - return ("Split multiple entities in {$testsUpdated} file(s)."); } /** diff --git a/src/Magento/FunctionalTestingFramework/Util/Filesystem/RecursiveGlobUtil.php b/src/Magento/FunctionalTestingFramework/Util/Filesystem/RecursiveGlobUtil.php deleted file mode 100644 index bf012d4e8..000000000 --- a/src/Magento/FunctionalTestingFramework/Util/Filesystem/RecursiveGlobUtil.php +++ /dev/null @@ -1,72 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\FunctionalTestingFramework\Util\Filesystem; - -class RecursiveGlobUtil -{ - /** - * Recursively glob full pathnames matching a pattern in a given directory - * - * @param string $pattern - * @param string $directory - * @return array - */ - public static function glob($pattern, $directory) - { - $directory = realpath($directory); - if ($directory === false) { - return []; - } - $pattern = DIRECTORY_SEPARATOR . ltrim($pattern, DIRECTORY_SEPARATOR); - $subDirectoryPattern = DIRECTORY_SEPARATOR . "*"; - - $fileList = []; - foreach (glob($directory . $subDirectoryPattern, GLOB_ONLYDIR) as $dir) { - $fileList = array_merge_recursive($fileList, self::glob($pattern, $dir)); - } - - $curFiles = glob($directory . $pattern); - if ($curFiles !== false && !empty($curFiles)) { - $fileList = array_merge_recursive($fileList, $curFiles); - } - return $fileList; - } - - /** - * Recursive glob full pathnames matching a pattern in a given directory at certain depths - * - * @param string $pattern - * @param string $directory - * @param integer $depth - * @return array - */ - public static function globAtDepth($pattern, $directory, $depth) - { - $directory = realpath($directory); - if ($directory === false) { - return []; - } - $pattern = DIRECTORY_SEPARATOR . ltrim($pattern, DIRECTORY_SEPARATOR); - $subDirectoryPattern = DIRECTORY_SEPARATOR . "*"; - - $fileList = []; - if ($depth > 0) { - foreach (glob($directory . $subDirectoryPattern, GLOB_ONLYDIR) as $dir) { - $fileList = array_merge_recursive( - $fileList, - self::globAtDepth($pattern, $dir, $depth-1) - ); - } - } elseif ($depth == 0) { - $fileList = glob($directory . $pattern); - if ($fileList === false) { - $fileList = []; - } - } - return $fileList; - } -} diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index aa9a08ddb..7290fdfbe 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -12,6 +12,8 @@ use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; use Symfony\Component\HttpFoundation\Response; +use \Magento\FunctionalTestingFramework\Util\ModuleResolver\AlphabeticSequenceSorter; +use \Magento\FunctionalTestingFramework\Util\ModuleResolver\SequenceSorterInterface; /** * Class ModuleResolver, resolve module path based on enabled modules of target Magento instance. @@ -180,9 +182,12 @@ public static function getInstance() private function __construct() { $objectManager = \Magento\FunctionalTestingFramework\ObjectManagerFactory::getObjectManager(); - $this->sequenceSorter = $objectManager->get( - \Magento\FunctionalTestingFramework\Util\ModuleResolver\SequenceSorterInterface::class - ); + + if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::UNIT_TEST_PHASE) { + $this->sequenceSorter = $objectManager->get(AlphabeticSequenceSorter::class); + } else { + $this->sequenceSorter = $objectManager->get(SequenceSorterInterface::class); + } } /** diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver/AlphabeticSequenceSorter.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver/AlphabeticSequenceSorter.php new file mode 100644 index 000000000..67e909062 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver/AlphabeticSequenceSorter.php @@ -0,0 +1,25 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\FunctionalTestingFramework\Util\ModuleResolver; + +/** + * Alphabetic sequence sorter. + */ +class AlphabeticSequenceSorter implements SequenceSorterInterface +{ + /** + * Sort files alphabetically. + * + * @param array $paths + * @return array + */ + public function sort(array $paths) + { + asort($paths); + return $paths; + } +} diff --git a/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php b/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php index f53578c39..976daa1f8 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php @@ -6,6 +6,8 @@ namespace Magento\FunctionalTestingFramework\Util\Script; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\Filesystem\FinderUtil; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Symfony\Component\Finder\Finder; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\Util\ModuleResolver; @@ -17,6 +19,8 @@ */ class ScriptUtil { + const ROOT_SUITE_DIR = 'tests/_suite'; + /** * Return all installed Magento module paths * @@ -64,28 +68,44 @@ public static function printErrorsToFile($errors, $filename, $message) } /** - * Builds list of all XML files in given modulePaths + path given - * Return empty array if Finder is not run + * Return all XML files for $scope in given module paths, empty array if no path is valid * * @param array $modulePaths - * @param string $path + * @param string $scope * @return Finder|array */ - public static function buildFileList($modulePaths, $path) + public static function getModuleXmlFilesByScope($modulePaths, $scope) { - $finderRun = false; + $found = false; + $scopePath = DIRECTORY_SEPARATOR . ucfirst($scope) . DIRECTORY_SEPARATOR; $finder = new Finder(); + foreach ($modulePaths as $modulePath) { - if (!realpath($modulePath . $path)) { + if (!realpath($modulePath . $scopePath)) { continue; } - $finder->files()->in($modulePath . $path)->name("*.xml"); - $finderRun = true; + $finder->files()->followLinks()->in($modulePath . $scopePath)->name("*.xml"); + $found = true; } - if ($finderRun) { - return $finder->files(); - } else { + return $found ? $finder->files() : []; + } + + /** + * Return root Suite XML files, empty array if root suite file is not valid + * + * @return Finder|array + * @throws TestFrameworkException + */ + public static function getRootSuiteXmlFiles() + { + //$rootSuitePath = FilePathFormatter::format(TESTS_BP) . self::ROOT_SUITE_DIR; + $rootSuitePath = FilePathFormatter::format(TESTS_BP) . 'tests/verification/_suite'; + $finder = new Finder(); + if (!realpath($rootSuitePath)) { return []; } + $finder->files()->followLinks()->in($rootSuitePath)->name("*.xml"); + + return $finder->files(); } } From 173f9b36f8f0fbd518dca9c2559b4f29d2d5b328 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Mon, 2 Mar 2020 10:53:50 -0600 Subject: [PATCH 245/888] MQE-683: [Deprecation] Only use more nested assertion syntax - Heavy updates to script - Update to AssertElementContainsAttribute action --- .../Test/Objects/ActionObject.php | 9 ++- .../Test/etc/Actions/assertActions.xsd | 24 ++++--- .../Upgrade/UpdateAssertionSchema.php | 65 ++++++++++++++----- .../Util/TestGenerator.php | 5 +- 4 files changed, 71 insertions(+), 32 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php index a3bbd3cf3..6006ef879 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php @@ -59,6 +59,7 @@ class ActionObject const ASSERTION_ATTRIBUTES = ["expectedResult" => "expected", "actualResult" => "actual"]; const ASSERTION_TYPE_ATTRIBUTE = "type"; const ASSERTION_VALUE_ATTRIBUTE = "value"; + const ASSERTION_ELEMENT_ATTRIBUTES = ["selector", "attribute"]; const DELETE_DATA_MUTUAL_EXCLUSIVE_ATTRIBUTES = ["url", "createDataKey"]; const EXTERNAL_URL_AREA_INVALID_ACTIONS = ['amOnPage']; const FUNCTION_CLOSURE_ACTIONS = ['waitForElementChange']; @@ -310,11 +311,17 @@ public function trimAssertionAttributes() } // Flatten nested Elements's type and value into key=>value entries + // Also, add selector/value attributes if they are present in nested Element foreach ($this->actionAttributes as $key => $subAttributes) { + foreach (self::ASSERTION_ELEMENT_ATTRIBUTES as $ATTRIBUTE) { + if (isset($subAttributes[$ATTRIBUTE])) { + $this->actionAttributes[$ATTRIBUTE] = $subAttributes[$ATTRIBUTE]; + } + } if (in_array($key, $relevantKeys)) { $prefix = ActionObject::ASSERTION_ATTRIBUTES[$key]; $this->actionAttributes[$prefix . ucfirst(ActionObject::ASSERTION_TYPE_ATTRIBUTE)] = - $subAttributes[ActionObject::ASSERTION_TYPE_ATTRIBUTE]; + $subAttributes[ActionObject::ASSERTION_TYPE_ATTRIBUTE] ?? "NO_TYPE"; $this->actionAttributes[$prefix] = $subAttributes[ActionObject::ASSERTION_VALUE_ATTRIBUTE]; unset($this->actionAttributes[$key]); diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/assertActions.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/assertActions.xsd index b06e156e6..ca8ebcd26 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/assertActions.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/assertActions.xsd @@ -92,7 +92,6 @@ <!-- Complex Types --> <!-- ASSERTION TYPES --> - <!-- REMOVE expected/expectedType and actual/actualType in MQE-683--> <xs:complexType name="assertionType"> <xs:choice maxOccurs="unbounded"> <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> @@ -111,7 +110,7 @@ </xs:documentation> </xs:annotation> <xs:choice maxOccurs="unbounded"> - <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> + <xs:element name="expectedResult" type="expectedElementContainsType" minOccurs="0"/> </xs:choice> <xs:attribute type="xs:string" name="expectedValue"> <xs:annotation> @@ -120,14 +119,6 @@ </xs:documentation> </xs:annotation> </xs:attribute> - <xs:attribute name="selector" use="required"/> - <xs:attribute type="xs:string" name="attribute" use="required"> - <xs:annotation> - <xs:documentation> - Attribute in given element to be assert against. - </xs:documentation> - </xs:annotation> - </xs:attribute> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -599,6 +590,19 @@ </xs:extension> </xs:simpleContent> </xs:complexType> + <xs:complexType name="expectedElementContainsType"> + <xs:annotation> + <xs:documentation> + Element containing the Expected value and selector/attributeName. + </xs:documentation> + </xs:annotation> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute type="xs:string" name="selector" use="required"/> + <xs:attribute type="xs:string" name="attribute" use="required"/> + </xs:extension> + </xs:simpleContent> + </xs:complexType> <xs:complexType name="actualResultType"> <xs:annotation> <xs:documentation> diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php index c44038368..fc1ac6011 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php @@ -54,6 +54,9 @@ public function execute(InputInterface $input) preg_match_all('/<assert[^>]*\/>/', $contents, $potentialAssertions); $newAssertions = []; $index = 0; + if (empty($potentialAssertions[0])) { + continue; + } foreach ($potentialAssertions[0] as $potentialAssertion) { $newAssertions[$index] = $this->convertOldAssertionToNew($potentialAssertion); $index++; @@ -98,8 +101,7 @@ private function convertOldAssertionToNew($assertion) $stepKey = ""; // regex to grab values - $grabValueRegex = '/(stepKey|actual|actualType|expected|expectedType|delta|message)="([^"]*)"/'; - + $grabValueRegex = '/(stepKey|actual|actualType|expected|expectedType|delta|message|selector|attribute|expectedValue|before|after|remove)=(\'[^\']*\'|"[^"]*")/'; // Make 3 arrays in $grabbedParts: // 0 contains stepKey="value" // 1 contains stepKey @@ -110,40 +112,69 @@ private function convertOldAssertionToNew($assertion) $sortedParts[$grabbedParts[1][$i]] = $grabbedParts[2][$i]; } - // Build new String - $newString = "<$assertType "; + // Build new String, trim ' and " + $trimmedParts = []; + $newString = "<$assertType"; $subElements = ["actual" => [], "expected" => []]; foreach ($sortedParts as $type => $value) { - if (in_array($type, ["stepKey", "delta", "message"])) { + $value = rtrim(ltrim($value, '"'), '"'); + $value = rtrim(ltrim($value, "'"), "'"); + $trimmedParts[$type] = $value; + if (in_array($type, ["stepKey", "delta", "message", "before", "after", "remove"])) { if ($type == "stepKey") { $stepKey = $value; } - $newString .= "$type=\"$value\""; + $newString .= " $type=\"$value\""; continue; } if ($type == "actual") { $subElements["actual"]["value"] = $value; } elseif ($type == "actualType") { $subElements["actual"]["type"] = $value; - } elseif ($type == "expected") { + } elseif ($type == "expected" || $type = "expectedValue") { $subElements["expected"]["value"] = $value; } elseif ($type == "expectedType") { $subElements["expected"]["type"] = $value; } } $newString .= ">\n"; - foreach ($subElements as $type => $subElement) { - if (!isset($subElement['value']) || !isset($subElement['type'])) { - //don't have all the info we need to rebuild - $this->errors[] = "UNABLE TO FULLY REBUILD ASSERTION, PLEASE MANUALLY CHECK FORMAT " . - "($assertType \"$stepKey\" in $this->currentFile)"; - continue; + // Guess value type if not set in either case + if (!isset($subElements["actual"]['type']) && isset($subElements["actual"]["value"])) { + $subElements["actual"]['type'] = $this->guessValueType($subElements["actual"]["value"]); + } + if (!isset($subElements["expected"]['type']) && isset($subElements["expected"]["value"])) { + $subElements["expected"]['type'] = $this->guessValueType($subElements["expected"]["value"]); + } + // Massage subElements with data for edge cases + if ($assertType == 'assertElementContainsAttribute') { + // Assert type is very edge-cased, completely different schema + $value = $subElements['expected']['value']; + $selector = $trimmedParts['selector']; + $attribute = $trimmedParts['attribute']; + $newString .= "\t\t\t<expectedResult selector=\"$selector\" attribute=\"$attribute\">$value</expectedResult>\n"; + } else { + foreach ($subElements as $type => $subElement) { + if (empty($subElement)) { + continue; + } + $value = $subElement['value']; + $typeValue = $subElement['type']; + if (empty($value)) { + $this->errors[] = "POTENTIAL ANOMALOUS OUPUT DETECTED, PLEASE MANUALLY CHECK OUTPUT " . + "($assertType \"$stepKey\" in $this->currentFile)"; + } + $newString .= "\t\t\t<{$type}Result type=\"$typeValue\">$value</{$type}Result>\n"; } - $value = $subElement['value']; - $typeValue = $subElement['type']; - $newString .= "<{$type}Result type=\"$typeValue\">$value</{$type}Result>\n"; } - $newString .= "</$assertType>"; + $newString .= " </$assertType>"; return $newString; } + + private function guessValueType($string) { + preg_match('/\$[a-zA-Z0-9]*/', $string, $matches); + if (isset($matches[0]) && $matches[0] == $string) { + return "variable"; + } + return "string"; + } } diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index ab47bce7e..98645b0d1 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -617,9 +617,6 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato } elseif (isset($customActionAttributes['url'])) { $input = $this->addUniquenessFunctionCall($customActionAttributes['url']); $url = $this->addUniquenessFunctionCall($customActionAttributes['url']); - } elseif (isset($customActionAttributes['expectedValue'])) { - //For old Assert backwards Compatibility, remove when deprecating - $assertExpected = $this->addUniquenessFunctionCall($customActionAttributes['expectedValue']); } elseif (isset($customActionAttributes['regex'])) { $input = $this->addUniquenessFunctionCall($customActionAttributes['regex']); } @@ -1234,7 +1231,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $actionObject, $selector, $this->wrapWithDoubleQuotes($attribute), - $assertExpected + $this->wrapWithDoubleQuotes($assertExpected) ); break; case "assertEmpty": From fecb9f60eba47230b6a6780ac3a09cbf26e3d01c Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Mon, 2 Mar 2020 10:59:46 -0600 Subject: [PATCH 246/888] MQE-683: [Deprecation] Only use more nested assertion syntax - Bugfix for empty value --- .../FunctionalTestingFramework/Test/Objects/ActionObject.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php index 6006ef879..e71a9894d 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php @@ -323,7 +323,7 @@ public function trimAssertionAttributes() $this->actionAttributes[$prefix . ucfirst(ActionObject::ASSERTION_TYPE_ATTRIBUTE)] = $subAttributes[ActionObject::ASSERTION_TYPE_ATTRIBUTE] ?? "NO_TYPE"; $this->actionAttributes[$prefix] = - $subAttributes[ActionObject::ASSERTION_VALUE_ATTRIBUTE]; + $subAttributes[ActionObject::ASSERTION_VALUE_ATTRIBUTE] ?? ""; unset($this->actionAttributes[$key]); } } From 65bb8c0718ae9a0658007fdc7ac1afb462a27401 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 2 Mar 2020 13:35:49 -0600 Subject: [PATCH 247/888] MQE-1962: Bump MFTF version to 3.0.0 --- composer.json | 2 +- composer.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 0ff50a2e8..5fc595478 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "2.6.3", + "version": "3.0.0", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index 6f370593b..cd692f7e6 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "83e4e17679bff5fdd472c246dca8ac48", + "content-hash": "21ca9c7fef683977c7a1bbb0591c54b0", "packages": [ { "name": "allure-framework/allure-codeception", From e5666c152c43114ec75ae57dd1567392daed5b63 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Mon, 2 Mar 2020 13:42:46 -0600 Subject: [PATCH 248/888] MQE-683: [Deprecation] Only use more nested assertion syntax - Update to conversion script --- .../Upgrade/UpdateAssertionSchema.php | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php index fc1ac6011..640680469 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php @@ -117,8 +117,17 @@ private function convertOldAssertionToNew($assertion) $newString = "<$assertType"; $subElements = ["actual" => [], "expected" => []]; foreach ($sortedParts as $type => $value) { - $value = rtrim(ltrim($value, '"'), '"'); - $value = rtrim(ltrim($value, "'"), "'"); + if (strpos($value, '"') === 0) { + $value = rtrim(ltrim($value, '"'), '"'); + } elseif(strpos($value, "'") === 0) { + $value = rtrim(ltrim($value, "'"), "'"); + } + // If value is empty string, trim again + if (str_replace(" ", "", $value) == "''") { + $value = ""; + } elseif (str_replace(" ", "", $value) == '""') { + $value = ""; + } $trimmedParts[$type] = $value; if (in_array($type, ["stepKey", "delta", "message", "before", "after", "remove"])) { if ($type == "stepKey") { @@ -131,7 +140,7 @@ private function convertOldAssertionToNew($assertion) $subElements["actual"]["value"] = $value; } elseif ($type == "actualType") { $subElements["actual"]["type"] = $value; - } elseif ($type == "expected" || $type = "expectedValue") { + } elseif ($type == "expected" or $type == "expectedValue") { $subElements["expected"]["value"] = $value; } elseif ($type == "expectedType") { $subElements["expected"]["type"] = $value; @@ -159,10 +168,6 @@ private function convertOldAssertionToNew($assertion) } $value = $subElement['value']; $typeValue = $subElement['type']; - if (empty($value)) { - $this->errors[] = "POTENTIAL ANOMALOUS OUPUT DETECTED, PLEASE MANUALLY CHECK OUTPUT " . - "($assertType \"$stepKey\" in $this->currentFile)"; - } $newString .= "\t\t\t<{$type}Result type=\"$typeValue\">$value</{$type}Result>\n"; } } From 7de33e75a197a8874d395b1d23102e28f01cf5cb Mon Sep 17 00:00:00 2001 From: Karyna Tsymbal <k.tsymbal@atwix.com> Date: Mon, 2 Mar 2020 22:58:06 +0200 Subject: [PATCH 249/888] Small fix to the Mftf Getting Started doc The command from the 'Set up an embedded MFTF -> Step 3' has to be executed from project root. --- docs/getting-started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 89d228df9..4cf13d7a7 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -200,7 +200,7 @@ Learn more about environmental settings in [Configuration][]. ### Step 3. Enable the Magento CLI commands -In the `magento2/dev/tests/acceptance` directory, run the following command to enable the MFTF to send Magento CLI commands to your Magento instance. +In the Magento project root, run the following command to enable the MFTF to send Magento CLI commands to your Magento instance. ```bash cp dev/tests/acceptance/.htaccess.sample dev/tests/acceptance/.htaccess From ac8d76ecc98b764667dc974fe2041f1d4811180a Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Mon, 2 Mar 2020 15:11:18 -0600 Subject: [PATCH 250/888] MQE-683: [Deprecation] Only use more nested assertion syntax - More fixes --- .../Upgrade/UpdateAssertionSchema.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php index 640680469..5a67bc996 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php @@ -45,9 +45,9 @@ public function execute(InputInterface $input) $fileSystem = new Filesystem(); $testsUpdated = 0; foreach ($finder->files() as $file) { - if (!$this->detectOldAttributes($file)) { - continue; - } +// if (!$this->detectOldAttributes($file)) { +// continue; +// } $this->currentFile = $file->getFilename(); $contents = $file->getContents(); // Isolate <assert ... /> but not <assert> ... </assert> @@ -157,7 +157,7 @@ private function convertOldAssertionToNew($assertion) // Massage subElements with data for edge cases if ($assertType == 'assertElementContainsAttribute') { // Assert type is very edge-cased, completely different schema - $value = $subElements['expected']['value']; + $value = $subElements['expected']['value'] ?? ""; $selector = $trimmedParts['selector']; $attribute = $trimmedParts['attribute']; $newString .= "\t\t\t<expectedResult selector=\"$selector\" attribute=\"$attribute\">$value</expectedResult>\n"; From 3eadcc16b4f91e8deabcdd92ad8d4452eb893d2b Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Mon, 2 Mar 2020 16:42:38 -0600 Subject: [PATCH 251/888] MQE-1581: Remove NONE debug level for next MFTF major release --- dev/tests/_bootstrap.php | 2 +- docs/commands/mftf.md | 8 ++++---- .../Config/MftfApplicationConfig.php | 16 +++++++++------- .../Config/Reader/Filesystem.php | 3 ++- .../Config/Reader/MftfFilesystem.php | 4 ++-- .../Console/BaseGenerateCommand.php | 3 +-- .../Console/GenerateDocsCommand.php | 2 +- .../Console/GenerateTestsCommand.php | 3 +-- .../StaticCheck/ActionGroupArgumentsCheck.php | 2 +- .../StaticCheck/TestDependencyCheck.php | 2 +- 10 files changed, 23 insertions(+), 22 deletions(-) diff --git a/dev/tests/_bootstrap.php b/dev/tests/_bootstrap.php index 3f57ad139..26582ff3d 100644 --- a/dev/tests/_bootstrap.php +++ b/dev/tests/_bootstrap.php @@ -35,7 +35,7 @@ true, \Magento\FunctionalTestingFramework\Config\MftfApplicationConfig::UNIT_TEST_PHASE, true, - \Magento\FunctionalTestingFramework\Config\MftfApplicationConfig::LEVEL_NONE, + \Magento\FunctionalTestingFramework\Config\MftfApplicationConfig::LEVEL_DEFAULT, false ); diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index e0394dc12..297addc6b 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -164,7 +164,7 @@ vendor/bin/mftf generate:tests [option] [<test name>] [<test name>] [--remove] | `-i,--time` | Set time in minutes to determine the group size when `--config=parallel` is used. The __default value__ is `10`. Example: `generate:tests --config=parallel --time=15`| | `--tests` | Defines the test configuration as a JSON string.| | `--allow-skipped` | Allows MFTF to generate and run tests marked with `<skip>.`| -| `--debug or --debug=[<none>]`| Performs schema validations on XML files. <br/> DEFAULT: `generate:tests` implicitly performs schema validation on merged files. It does not indicate the file name where the error is encountered. <br/> DEVELOPER: `--debug` performs per-file validation and returns additional debug information (such as the filename where an error occurred) when test generation fails because of an invalid XML schema. This option takes extra processing time. Use it after test generation has failed once.<br/>NONE: `--debug=none` skips debugging during test generation. Added for backward compatibility, it will be removed in the next MAJOR release.<br/>| +| `--debug` | Performs schema validations on XML files. <br/> DEFAULT: `generate:tests` implicitly performs schema validation on merged files. It does not indicate the file name where the error is encountered. <br/> DEVELOPER: `--debug` performs per-file validation and returns additional debug information (such as the filename where an error occurred) when test generation fails because of an invalid XML schema. This option takes extra processing time. Use it after test generation has failed once.<br/>| | `-r,--remove`| Removes the existing generated suites and tests cleaning up the `_generated` directory before the actual run. For example, `generate:tests SampleTest --remove` cleans up the entire `_generated` directory and generates `SampleTest` only.| #### Examples of the JSON configuration @@ -337,7 +337,7 @@ vendor/bin/mftf run:group [--skip-generate|--remove] [--] <group1> [<group2>] | --------------------- | --------------------------------------------------------------------------------------------------------- | | `-k, --skip-generate` | Skips generating from the source XML. Instead, the command executes previously-generated groups of tests. | | `-r, --remove` | Removes previously generated suites and tests before the actual generation and run. | -| `--debug or --debug=[<none>]`| Performs schema validations on XML files. `run:group` implicitly performs schema validation on merged files. It does not indicate the file name where the error is encountered. `--debug` performs per-file validation and returns additional debug information (such as the filename where an error occurred). `--debug=none` skips debugging during test run. Added for backward compatibility, it will be removed in the next MAJOR release.| +| `--debug` | Performs schema validations on XML files. `run:group` implicitly performs schema validation on merged files. It does not indicate the file name where the error is encountered. `--debug` performs per-file validation and returns additional debug information (such as the filename where an error occurred).| #### Examples @@ -369,7 +369,7 @@ vendor/bin/mftf run:test [--skip-generate|--remove] [--] <name1> [<name2>] |-----------------------|-----------------------------------------------------------------------------------------------------------| | `-k, --skip-generate` | Skips generating from the source XML. Instead, the command executes previously-generated groups of tests. | | `-r, --remove` | Remove previously generated suites and tests. | -| `--debug or --debug=[<none>]`| Performs schema validations on XML files. `run:test` implicitly performs schema validation on merged files. It does not indicate the file name where the error is encountered. `--debug` performs per-file validation and returns additional debug information (such as the filename where an error occurred). `--debug=none` skips debugging during test run. Added for backward compatibility, it will be removed in the next MAJOR release. +| `--debug` | Performs schema validations on XML files. `run:test` implicitly performs schema validation on merged files. It does not indicate the file name where the error is encountered. `--debug` performs per-file validation and returns additional debug information (such as the filename where an error occurred).| #### Examples @@ -419,7 +419,7 @@ vendor/bin/mftf run:failed | Option | Description | |-----------------------|-----------------------------------------------------------------------------------------------------------| -| `--debug or --debug=[<none>]`| Performs schema validations on XML files. `run:failed` implicitly performs schema validation on merged files. It does not indicate the file name where the error is encountered. `--debug` performs per-file validation and returns additional debug information (such as the filename where an error occurred). Use it after test run has failed once. `--debug=none` skips debugging during test run. Added for backward compatibility, it will be removed in the next MAJOR release.| +| `--debug` | Performs schema validations on XML files. `run:failed` implicitly performs schema validation on merged files. It does not indicate the file name where the error is encountered. `--debug` performs per-file validation and returns additional debug information (such as the filename where an error occurred). Use it after test run has failed once.| #### Examples diff --git a/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php b/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php index 4b215cb4f..ab06b5612 100644 --- a/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php +++ b/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php @@ -23,8 +23,7 @@ class MftfApplicationConfig */ const LEVEL_DEFAULT = "default"; const LEVEL_DEVELOPER = "developer"; - const LEVEL_NONE = "none"; - const MFTF_DEBUG_LEVEL = [self::LEVEL_DEFAULT, self::LEVEL_DEVELOPER, self::LEVEL_NONE]; + const MFTF_DEBUG_LEVEL = [self::LEVEL_DEFAULT, self::LEVEL_DEVELOPER]; /** * Contains object with test filters. @@ -89,7 +88,7 @@ private function __construct( $forceGenerate = false, $phase = self::EXECUTION_PHASE, $verboseEnabled = null, - $debugLevel = self::LEVEL_NONE, + $debugLevel = self::LEVEL_DEFAULT, $allowSkipped = false, $filters = [] ) { @@ -101,14 +100,17 @@ private function __construct( $this->phase = $phase; $this->verboseEnabled = $verboseEnabled; - switch ($debugLevel) { + if (isset($debugLevel) && !in_array(strtolower($debugLevel), self::MFTF_DEBUG_LEVEL)) { + throw new TestFrameworkException("{$debugLevel} is not a debug level. Use 'DEFAULT' or 'DEVELOPER'"); + } + switch (strtolower($debugLevel)) { case self::LEVEL_DEVELOPER: case self::LEVEL_DEFAULT: - case self::LEVEL_NONE: $this->debugLevel = $debugLevel; break; - default: + case null: $this->debugLevel = self::LEVEL_DEVELOPER; + break; } $this->allowSkipped = $allowSkipped; $this->filterList = new FilterList($filters); @@ -131,7 +133,7 @@ public static function create( $forceGenerate = false, $phase = self::EXECUTION_PHASE, $verboseEnabled = null, - $debugLevel = self::LEVEL_NONE, + $debugLevel = self::LEVEL_DEFAULT, $allowSkipped = false, $filters = [] ) { diff --git a/src/Magento/FunctionalTestingFramework/Config/Reader/Filesystem.php b/src/Magento/FunctionalTestingFramework/Config/Reader/Filesystem.php index db96b010c..ab7d64ea9 100644 --- a/src/Magento/FunctionalTestingFramework/Config/Reader/Filesystem.php +++ b/src/Magento/FunctionalTestingFramework/Config/Reader/Filesystem.php @@ -146,6 +146,7 @@ protected function readFiles($fileList) { /** @var \Magento\FunctionalTestingFramework\Config\Dom $configMerger */ $configMerger = null; + $debugLevel = MftfApplicationConfig::getConfig()->getDebugLevel(); foreach ($fileList as $key => $content) { //check if file is empty and continue to next if it is if (!$this->verifyFileEmpty($content, $fileList->getFilename())) { @@ -157,7 +158,7 @@ protected function readFiles($fileList) } else { $configMerger->merge($content); } - if (MftfApplicationConfig::getConfig()->getDebugLevel() === MftfApplicationConfig::LEVEL_DEVELOPER) { + if (strcasecmp($debugLevel, MftfApplicationConfig::LEVEL_DEVELOPER) == 0) { $this->validateSchema($configMerger, $fileList->getFilename()); } } catch (\Magento\FunctionalTestingFramework\Config\Dom\ValidationException $e) { diff --git a/src/Magento/FunctionalTestingFramework/Config/Reader/MftfFilesystem.php b/src/Magento/FunctionalTestingFramework/Config/Reader/MftfFilesystem.php index cd075e57c..3740d683f 100644 --- a/src/Magento/FunctionalTestingFramework/Config/Reader/MftfFilesystem.php +++ b/src/Magento/FunctionalTestingFramework/Config/Reader/MftfFilesystem.php @@ -42,7 +42,7 @@ public function readFiles($fileList) $configMerger->merge($content, $fileList->getFilename(), $exceptionCollector); } // run per file validation with generate:tests -d - if ($debugLevel === MftfApplicationConfig::LEVEL_DEVELOPER) { + if (strcasecmp($debugLevel, MftfApplicationConfig::LEVEL_DEVELOPER) == 0) { $this->validateSchema($configMerger, $fileList->getFilename()); } } catch (\Magento\FunctionalTestingFramework\Config\Dom\ValidationException $e) { @@ -52,7 +52,7 @@ public function readFiles($fileList) $exceptionCollector->throwException(); //run validation on merged file with generate:tests - if ($debugLevel === MftfApplicationConfig::LEVEL_DEFAULT) { + if (strcasecmp($debugLevel, MftfApplicationConfig::LEVEL_DEFAULT) == 0) { $this->validateSchema($configMerger); } diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index 9bcc27c86..07597acc5 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -58,8 +58,7 @@ protected function configure() 'debug', 'd', InputOption::VALUE_OPTIONAL, - 'Run extra validation when generating and running tests. Use option \'none\' to turn off debugging -- - added for backward compatibility, will be removed in the next MAJOR release', + 'Run extra validation when generating and running tests.', MftfApplicationConfig::LEVEL_DEFAULT ); } diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateDocsCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateDocsCommand.php index 7def3894f..ce920e39d 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateDocsCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateDocsCommand.php @@ -67,7 +67,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $force, MftfApplicationConfig::GENERATION_PHASE, false, - MftfApplicationConfig::LEVEL_NONE, + MftfApplicationConfig::LEVEL_DEFAULT, true ); diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php index 25bd68240..49ed8c6e1 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php @@ -123,8 +123,7 @@ protected function execute(InputInterface $input, OutputInterface $output) // Remove previous GENERATED_DIR if --remove option is used if ($remove) { - $this->removeGeneratedDirectory($output, $verbose || - ($debug !== MftfApplicationConfig::LEVEL_NONE)); + $this->removeGeneratedDirectory($output, $verbose); } try { diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php index 32c7661fe..ad0f8267d 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php @@ -54,7 +54,7 @@ public function execute(InputInterface $input) true, MftfApplicationConfig::UNIT_TEST_PHASE, false, - MftfApplicationConfig::LEVEL_NONE, + MftfApplicationConfig::LEVEL_DEFAULT, true ); diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php index 3c3ed6a37..e53c07573 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php @@ -96,7 +96,7 @@ public function execute(InputInterface $input) true, MftfApplicationConfig::UNIT_TEST_PHASE, false, - MftfApplicationConfig::LEVEL_NONE, + MftfApplicationConfig::LEVEL_DEFAULT, true ); From 3a901e3107a2af5bf2324d312f53466b3246aa72 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Tue, 3 Mar 2020 09:01:28 -0600 Subject: [PATCH 252/888] MQE-683: [Deprecation] Only use more nested assertion syntax - Even more fixes --- .../Upgrade/UpdateAssertionSchema.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php index 5a67bc996..05bec1d31 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php @@ -147,12 +147,12 @@ private function convertOldAssertionToNew($assertion) } } $newString .= ">\n"; - // Guess value type if not set in either case - if (!isset($subElements["actual"]['type']) && isset($subElements["actual"]["value"])) { - $subElements["actual"]['type'] = $this->guessValueType($subElements["actual"]["value"]); + // Set type to const if it's absent + if (isset($subElements["actual"]['value']) && !isset($subElements["actual"]['type'])) { + $subElements["actual"]['type'] = "const"; } - if (!isset($subElements["expected"]['type']) && isset($subElements["expected"]["value"])) { - $subElements["expected"]['type'] = $this->guessValueType($subElements["expected"]["value"]); + if (isset($subElements["expected"]['value']) && !isset($subElements["expected"]['type'])) { + $subElements["expected"]['type'] = "const"; } // Massage subElements with data for edge cases if ($assertType == 'assertElementContainsAttribute') { From a313cb9a2c8db9dea93c6bfcb40145f66043c062 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 3 Mar 2020 14:35:44 -0600 Subject: [PATCH 253/888] MQE-1963: Update XSD Schema to verify that file has only single entity --- composer.json | 1 + dev/tests/_bootstrap.php | 24 ------ .../functionalSuite/functionalSuite1.xml | 0 .../functionalSuite/functionalSuite2.xml | 0 .../functionalSuiteWithComments.xml | 0 .../Suite}/functionalSuiteExtends.xml | 0 .../Suite}/functionalSuiteHooks.xml | 0 etc/di.xml | 3 +- .../Config/FileResolver/Root.php | 21 +---- .../Page/Config/Dom.php | 65 +++++++++----- .../Page/Config/SectionDom.php | 33 ++++++-- .../Suite/Config/SuiteDom.php | 84 +++++++++++++++++++ .../Suite/Objects/SuiteObject.php | 21 ++++- .../Suite/Util/SuiteObjectExtractor.php | 69 +++------------ .../Suite/etc/mergedSuiteSchema.xsd | 6 +- .../Test/Config/ActionGroupDom.php | 12 ++- .../Test/Config/Dom.php | 19 ++++- .../Upgrade/RemoveModuleFileInSuiteFiles.php | 12 ++- .../Upgrade/SplitMultipleEntitiesFiles.php | 4 - .../Util/Script/ScriptUtil.php | 23 ----- .../SingleNodePerFileValidationUtil.php | 53 ++++++++++++ 21 files changed, 279 insertions(+), 171 deletions(-) rename dev/tests/verification/{_suite => TestModule/Suite}/functionalSuite/functionalSuite1.xml (100%) rename dev/tests/verification/{_suite => TestModule/Suite}/functionalSuite/functionalSuite2.xml (100%) rename dev/tests/verification/{_suite => TestModule/Suite}/functionalSuite/functionalSuiteWithComments.xml (100%) rename dev/tests/verification/{_suite => TestModule/Suite}/functionalSuiteExtends.xml (100%) rename dev/tests/verification/{_suite => TestModule/Suite}/functionalSuiteHooks.xml (100%) create mode 100644 src/Magento/FunctionalTestingFramework/Suite/Config/SuiteDom.php create mode 100644 src/Magento/FunctionalTestingFramework/Util/Validation/SingleNodePerFileValidationUtil.php diff --git a/composer.json b/composer.json index ed4656a37..774ae28e8 100755 --- a/composer.json +++ b/composer.json @@ -13,6 +13,7 @@ "ext-curl": "*", "ext-json": "*", "ext-openssl": "*", + "ext-dom": "*", "allure-framework/allure-codeception": "~1.3.0", "aws/aws-sdk-php": "^3.132", "codeception/codeception": "~2.4.5", diff --git a/dev/tests/_bootstrap.php b/dev/tests/_bootstrap.php index f8a1c8479..45604d040 100644 --- a/dev/tests/_bootstrap.php +++ b/dev/tests/_bootstrap.php @@ -102,30 +102,6 @@ require($unitUtilFile); } - -// Mocks suite files location getter return to get files in verification/_suite Directory -// This mocks the paths of the suite files but still parses the xml files -$suiteDirectory = TESTS_BP . DIRECTORY_SEPARATOR . "verification" . DIRECTORY_SEPARATOR . "_suite"; - -$paths = [ - $suiteDirectory . DIRECTORY_SEPARATOR . 'functionalSuite' . DIRECTORY_SEPARATOR . 'functionalSuite1.xml', - $suiteDirectory . DIRECTORY_SEPARATOR . 'functionalSuite' . DIRECTORY_SEPARATOR . 'functionalSuite2.xml', - $suiteDirectory . DIRECTORY_SEPARATOR . 'functionalSuite' . DIRECTORY_SEPARATOR . 'functionalSuiteWithComments.xml', - $suiteDirectory . DIRECTORY_SEPARATOR . 'functionalSuiteHooks.xml', - $suiteDirectory . DIRECTORY_SEPARATOR . 'functionalSuiteExtends.xml' -]; - -// create and return the iterator for these file paths -$iterator = new Magento\FunctionalTestingFramework\Util\Iterator\File($paths); -try { - AspectMock\Test::double( - Magento\FunctionalTestingFramework\Config\FileResolver\Root::class, - ['get' => $iterator] - )->make(); -} catch (Exception $e) { - echo "Suite directory not mocked."; -} - function sortInterfaces($files) { $bottom = []; diff --git a/dev/tests/verification/_suite/functionalSuite/functionalSuite1.xml b/dev/tests/verification/TestModule/Suite/functionalSuite/functionalSuite1.xml similarity index 100% rename from dev/tests/verification/_suite/functionalSuite/functionalSuite1.xml rename to dev/tests/verification/TestModule/Suite/functionalSuite/functionalSuite1.xml diff --git a/dev/tests/verification/_suite/functionalSuite/functionalSuite2.xml b/dev/tests/verification/TestModule/Suite/functionalSuite/functionalSuite2.xml similarity index 100% rename from dev/tests/verification/_suite/functionalSuite/functionalSuite2.xml rename to dev/tests/verification/TestModule/Suite/functionalSuite/functionalSuite2.xml diff --git a/dev/tests/verification/_suite/functionalSuite/functionalSuiteWithComments.xml b/dev/tests/verification/TestModule/Suite/functionalSuite/functionalSuiteWithComments.xml similarity index 100% rename from dev/tests/verification/_suite/functionalSuite/functionalSuiteWithComments.xml rename to dev/tests/verification/TestModule/Suite/functionalSuite/functionalSuiteWithComments.xml diff --git a/dev/tests/verification/_suite/functionalSuiteExtends.xml b/dev/tests/verification/TestModule/Suite/functionalSuiteExtends.xml similarity index 100% rename from dev/tests/verification/_suite/functionalSuiteExtends.xml rename to dev/tests/verification/TestModule/Suite/functionalSuiteExtends.xml diff --git a/dev/tests/verification/_suite/functionalSuiteHooks.xml b/dev/tests/verification/TestModule/Suite/functionalSuiteHooks.xml similarity index 100% rename from dev/tests/verification/_suite/functionalSuiteHooks.xml rename to dev/tests/verification/TestModule/Suite/functionalSuiteHooks.xml diff --git a/etc/di.xml b/etc/di.xml index 08a96f32e..2b90da5e1 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -356,11 +356,12 @@ <argument name="schemaPath" xsi:type="string">Magento/FunctionalTestingFramework/Suite/etc/mergedSuiteSchema.xsd</argument> </arguments> </virtualType> - <virtualType name="Magento\FunctionalTestingFramework\Config\Reader\SuiteData" type="Magento\FunctionalTestingFramework\Config\Reader\Filesystem"> + <virtualType name="Magento\FunctionalTestingFramework\Config\Reader\SuiteData" type="Magento\FunctionalTestingFramework\Config\Reader\MftfFilesystem"> <arguments> <argument name="fileResolver" xsi:type="object">Magento\FunctionalTestingFramework\Config\FileResolver\Root</argument> <argument name="converter" xsi:type="object">Magento\FunctionalTestingFramework\Config\SuiteDataConverter</argument> <argument name="schemaLocator" xsi:type="object">Magento\FunctionalTestingFramework\Config\SchemaLocator\SuiteData</argument> + <argument name="domDocumentClass" xsi:type="string">Magento\FunctionalTestingFramework\Suite\Config\SuiteDom</argument> <argument name="idAttributes" xsi:type="array"> <item name="/suites/suite" xsi:type="string">name</item> <item name="/suites/suite/(before|after)/remove" xsi:type="string">keyForRemoval</item> diff --git a/src/Magento/FunctionalTestingFramework/Config/FileResolver/Root.php b/src/Magento/FunctionalTestingFramework/Config/FileResolver/Root.php index eaabed4db..0ff6e4a77 100644 --- a/src/Magento/FunctionalTestingFramework/Config/FileResolver/Root.php +++ b/src/Magento/FunctionalTestingFramework/Config/FileResolver/Root.php @@ -27,23 +27,10 @@ class Root extends Mask public function get($filename, $scope) { // First pick up the root level test suite dir - $paths = []; - $dir = FilePathFormatter::format(TESTS_BP) . self::ROOT_SUITE_DIR; - if (is_readable($dir)) { - $directoryIterator = new \RecursiveIteratorIterator( - new \RecursiveDirectoryIterator( - $dir, - \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS - ) - ); - $regexpIterator = new \RegexIterator($directoryIterator, $filename); - /** @var \SplFileInfo $file */ - foreach ($regexpIterator as $file) { - if ($file->isFile() && $file->isReadable()) { - $paths[] = $file->getRealPath(); - } - } - } + $paths = glob( + FilePathFormatter::format(TESTS_BP) . self::ROOT_SUITE_DIR + . DIRECTORY_SEPARATOR . '*.xml' + ); // Then merge this path into the module based paths // Since we are sharing this code with Module based resolution we will unnecessarily glob against modules in the diff --git a/src/Magento/FunctionalTestingFramework/Page/Config/Dom.php b/src/Magento/FunctionalTestingFramework/Page/Config/Dom.php index 989209461..14b9b65e5 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Config/Dom.php +++ b/src/Magento/FunctionalTestingFramework/Page/Config/Dom.php @@ -12,6 +12,7 @@ use Magento\FunctionalTestingFramework\Config\Dom\NodePathMatcher; use Magento\FunctionalTestingFramework\Util\ModulePathExtractor; use Magento\FunctionalTestingFramework\Util\Validation\DuplicateNodeValidationUtil; +use Magento\FunctionalTestingFramework\Util\Validation\SingleNodePerFileValidationUtil; /** * MFTF page.xml configuration XML DOM utility @@ -36,6 +37,12 @@ class Dom extends \Magento\FunctionalTestingFramework\Config\MftfDom */ private $validationUtil; + /** SingleNodePerFileValidationUtil + * + * @var SingleNodePerFileValidationUtil + */ + private $singleNodePerFileValidationUtil; + /** * Page Dom constructor. * @param string $xml @@ -57,6 +64,7 @@ public function __construct( ) { $this->modulePathExtractor = new ModulePathExtractor(); $this->validationUtil = new DuplicateNodeValidationUtil('name', $exceptionCollector); + $this->singleNodePerFileValidationUtil = new SingleNodePerFileValidationUtil($exceptionCollector); parent::__construct( $xml, $filename, @@ -79,31 +87,44 @@ public function initDom($xml, $filename = null) { $dom = parent::initDom($xml, $filename); - $pagesNode = $dom->getElementsByTagName('pages')->item(0); - $this->validationUtil->validateChildUniqueness( - $pagesNode, - $filename, - $pagesNode->getAttribute(self::PAGE_META_NAME_ATTRIBUTE) - ); - $pageNodes = $dom->getElementsByTagName('page'); - $currentModule = - $this->modulePathExtractor->getExtensionPath($filename) - . '_' - . $this->modulePathExtractor->extractModuleName($filename); - foreach ($pageNodes as $pageNode) { - $pageModule = $pageNode->getAttribute("module"); - $pageName = $pageNode->getAttribute("name"); - if ($pageModule !== $currentModule) { - if (MftfApplicationConfig::getConfig()->verboseEnabled()) { - print( - "Page Module does not match path Module. " . - "(Page, Module): ($pageName, $pageModule) - Path Module: $currentModule" . - PHP_EOL - ); + if ($dom->getElementsByTagName('pages')->length > 0) { + /** @var \DOMElement $pagesNode */ + $pagesNode = $dom->getElementsByTagName('pages')[0]; + $this->validationUtil->validateChildUniqueness( + $pagesNode, + $filename, + $pagesNode->getAttribute(self::PAGE_META_NAME_ATTRIBUTE) + ); + + // Validate single page node per file + $this->singleNodePerFileValidationUtil->validateSingleNodeForTag( + $dom, + 'page', + $filename + ); + + if ($dom->getElementsByTagName('page')->length > 0) { + /** @var \DOMElement $pageNode */ + $pageNode = $dom->getElementsByTagName('page')[0]; + $currentModule = + $this->modulePathExtractor->getExtensionPath($filename) + . '_' + . $this->modulePathExtractor->extractModuleName($filename); + $pageModule = $pageNode->getAttribute("module"); + $pageName = $pageNode->getAttribute("name"); + if ($pageModule !== $currentModule) { + if (MftfApplicationConfig::getConfig()->verboseEnabled()) { + print( + "Page Module does not match path Module. " . + "(Page, Module): ($pageName, $pageModule) - Path Module: $currentModule" . + PHP_EOL + ); + } } + $pageNode->setAttribute(self::PAGE_META_FILENAME_ATTRIBUTE, $filename); } - $pageNode->setAttribute(self::PAGE_META_FILENAME_ATTRIBUTE, $filename); } + return $dom; } } diff --git a/src/Magento/FunctionalTestingFramework/Page/Config/SectionDom.php b/src/Magento/FunctionalTestingFramework/Page/Config/SectionDom.php index b7f5d5db9..5875f0ac1 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Config/SectionDom.php +++ b/src/Magento/FunctionalTestingFramework/Page/Config/SectionDom.php @@ -12,6 +12,7 @@ use Magento\FunctionalTestingFramework\Config\Dom\NodePathMatcher; use Magento\FunctionalTestingFramework\Util\ModulePathExtractor; use Magento\FunctionalTestingFramework\Util\Validation\DuplicateNodeValidationUtil; +use Magento\FunctionalTestingFramework\Util\Validation\SingleNodePerFileValidationUtil; /** * MFTF section.xml configuration XML DOM utility @@ -28,6 +29,12 @@ class SectionDom extends \Magento\FunctionalTestingFramework\Config\MftfDom */ private $validationUtil; + /** SingleNodePerFileValidationUtil + * + * @var SingleNodePerFileValidationUtil + */ + private $singleNodePerFileValidationUtil; + /** * Entity Dom constructor. * @param string $xml @@ -48,6 +55,7 @@ public function __construct( $errorFormat = self::ERROR_FORMAT_DEFAULT ) { $this->validationUtil = new DuplicateNodeValidationUtil('name', $exceptionCollector); + $this->singleNodePerFileValidationUtil = new SingleNodePerFileValidationUtil($exceptionCollector); parent::__construct( $xml, $filename, @@ -69,15 +77,26 @@ public function __construct( public function initDom($xml, $filename = null) { $dom = parent::initDom($xml, $filename); - $sectionNodes = $dom->getElementsByTagName('section'); - foreach ($sectionNodes as $sectionNode) { - $sectionNode->setAttribute(self::SECTION_META_FILENAME_ATTRIBUTE, $filename); - $this->validationUtil->validateChildUniqueness( - $sectionNode, - $filename, - $sectionNode->getAttribute(self::SECTION_META_NAME_ATTRIBUTE) + + if ($dom->getElementsByTagName('sections')->length > 0) { + // Validate single section node per file + $this->singleNodePerFileValidationUtil->validateSingleNodeForTag( + $dom, + 'section', + $filename ); + if ($dom->getElementsByTagName('section')->length > 0) { + /** @var \DOMElement $sectionNode */ + $sectionNode = $dom->getElementsByTagName('section')[0]; + $sectionNode->setAttribute(self::SECTION_META_FILENAME_ATTRIBUTE, $filename); + $this->validationUtil->validateChildUniqueness( + $sectionNode, + $filename, + $sectionNode->getAttribute(self::SECTION_META_NAME_ATTRIBUTE) + ); + } } + return $dom; } } diff --git a/src/Magento/FunctionalTestingFramework/Suite/Config/SuiteDom.php b/src/Magento/FunctionalTestingFramework/Suite/Config/SuiteDom.php new file mode 100644 index 000000000..c06c62024 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Suite/Config/SuiteDom.php @@ -0,0 +1,84 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\FunctionalTestingFramework\Suite\Config; + +use Magento\FunctionalTestingFramework\Exceptions\Collector\ExceptionCollector; +use Magento\FunctionalTestingFramework\Util\Validation\SingleNodePerFileValidationUtil; + +/** + * MFTF suite.xml configuration XML DOM utility + * @package Magento\FunctionalTestingFramework\Suite\Config + */ +class SuiteDom extends \Magento\FunctionalTestingFramework\Config\MftfDom +{ + const SUITE_META_FILENAME_ATTRIBUTE = "filename"; + + /** SingleNodePerFileValidationUtil + * + * @var SingleNodePerFileValidationUtil + */ + private $singleNodePerFileValidationUtil; + + /** + * Entity Dom constructor. + * @param string $xml + * @param string $filename + * @param ExceptionCollector $exceptionCollector + * @param array $idAttributes + * @param string $typeAttributeName + * @param string $schemaFile + * @param string $errorFormat + */ + public function __construct( + $xml, + $filename, + $exceptionCollector, + array $idAttributes = [], + $typeAttributeName = null, + $schemaFile = null, + $errorFormat = self::ERROR_FORMAT_DEFAULT + ) { + $this->singleNodePerFileValidationUtil = new SingleNodePerFileValidationUtil($exceptionCollector); + parent::__construct( + $xml, + $filename, + $exceptionCollector, + $idAttributes, + $typeAttributeName, + $schemaFile, + $errorFormat + ); + } + + /** + * Takes a dom element from xml and appends the filename based on location + * + * @param string $xml + * @param string|null $filename + * @return \DOMDocument + */ + public function initDom($xml, $filename = null) + { + $dom = parent::initDom($xml, $filename); + + if ($dom->getElementsByTagName('suites')->length > 0) { + // Validate single suite node per file + $this->singleNodePerFileValidationUtil->validateSingleNodeForTag( + $dom, + 'suite', + $filename + ); + if ($dom->getElementsByTagName('suite')->length > 0) { + /** @var \DOMElement $suiteNode */ + $suiteNode = $dom->getElementsByTagName('suite')[0]; + $suiteNode->setAttribute(self::SUITE_META_FILENAME_ATTRIBUTE, $filename); + } + } + + return $dom; + } +} diff --git a/src/Magento/FunctionalTestingFramework/Suite/Objects/SuiteObject.php b/src/Magento/FunctionalTestingFramework/Suite/Objects/SuiteObject.php index d7f6bd18a..729541f8d 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Objects/SuiteObject.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Objects/SuiteObject.php @@ -41,19 +41,28 @@ class SuiteObject */ private $hooks; + /** + * Filename of where the suite came from + * + * @var string + */ + private $filename; + /** * SuiteObject constructor. * @param string $name * @param TestObject[] $includeTests * @param TestObject[] $excludeTests * @param TestHookObject[] $hooks + * @param string $filename */ - public function __construct($name, $includeTests, $excludeTests, $hooks) + public function __construct($name, $includeTests, $excludeTests, $hooks, $filename = null) { $this->name = $name; $this->includeTests = $includeTests; $this->excludeTests = $excludeTests; $this->hooks = $hooks; + $this->filename = $filename; } /** @@ -146,4 +155,14 @@ public function getAfterHook() { return $this->hooks['after'] ?? null; } + + /** + * Getter for the Suite Filename + * + * @return string + */ + public function getFilename() + { + return $this->filename; + } } diff --git a/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php index 641588310..ebe18908a 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php @@ -13,9 +13,11 @@ use Magento\FunctionalTestingFramework\Test\Util\BaseObjectExtractor; use Magento\FunctionalTestingFramework\Test\Util\TestHookObjectExtractor; use Magento\FunctionalTestingFramework\Test\Util\TestObjectExtractor; +use Magento\FunctionalTestingFramework\Util\ModuleResolver; use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Magento\FunctionalTestingFramework\Util\Validation\NameValidationUtil; use Symfony\Component\Finder\Finder; +use Magento\FunctionalTestingFramework\Util\ModulePathExtractor; class SuiteObjectExtractor extends BaseObjectExtractor { @@ -221,7 +223,7 @@ private function extractTestObjectsFromSuiteRef($suiteReferences) case self::MODULE_TAG_NAME: $testObjectList = array_merge( $testObjectList, - $this->resolveModulePathTestNames($suiteRefData[self::NAME]) + $this->getTestsByModuleName($suiteRefData[self::NAME]) ); break; } @@ -231,69 +233,24 @@ private function extractTestObjectsFromSuiteRef($suiteReferences) } /** - * Takes a filepath (and optionally a module name) and resolves to a test object. + * Return all test objects for a module * - * @param string $filename - * @param null $moduleName + * @param string $moduleName * @return TestObject[] * @throws Exception */ - private function resolveFilePathTestNames($filename, $moduleName = null) + private function getTestsByModuleName($moduleName) { - $filepath = null; - if (!file_exists($filename) && null !== $moduleName) { - $dir = FilePathFormatter::format(TESTS_MODULE_PATH) . $moduleName . DIRECTORY_SEPARATOR . 'Test'; - if (file_exists($dir)) { - $finder = new Finder(); - $finder->files()->followLinks()->name($filename)->in($dir); - foreach ($finder as $file) { - $filepath = $file->getRealPath(); - break; - } - } - } - - if (null === $filepath) { - throw new Exception("Could not find file ${filename}"); - } - $testObjects = []; - $xml = simplexml_load_file($filepath); - for ($i = 0; $i < $xml->count(); $i++) { - $testName = (string)$xml->test[$i]->attributes()->name; - $testObjects[$testName] = TestObjectHandler::getInstance()->getObject($testName); - } - - return $testObjects; - } - - /** - * Takes a single module name and resolves to an array of tests contained within specified module. - * - * @param string $moduleName - * @return array - * @throws \Exception - */ - private function resolveModulePathTestNames($moduleName) - { - $testObjects = []; - $xmlFiles = glob( - FilePathFormatter::format(TESTS_MODULE_PATH) . - $moduleName . - DIRECTORY_SEPARATOR . - 'Test' . - DIRECTORY_SEPARATOR . - '*.xml' - ); - - foreach ($xmlFiles as $xmlFile) { - $testObjs = $this->resolveFilePathTestNames($xmlFile); - - foreach ($testObjs as $testObj) { - $testObjects[$testObj->getName()] = $testObj; + $pathExtractor = new ModulePathExtractor(); + $allTestObjects = TestObjectHandler::getInstance()->getAllObjects(); + foreach ($allTestObjects as $testName => $testObject) { + /** @var TestObject $testObject */ + $filename = $testObject->getFilename(); + if ($pathExtractor->extractModuleName($filename) === $moduleName) { + $testObjects[] = $testObject; } } - return $testObjects; } } diff --git a/src/Magento/FunctionalTestingFramework/Suite/etc/mergedSuiteSchema.xsd b/src/Magento/FunctionalTestingFramework/Suite/etc/mergedSuiteSchema.xsd index 912a7a585..fee742df5 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/etc/mergedSuiteSchema.xsd +++ b/src/Magento/FunctionalTestingFramework/Suite/etc/mergedSuiteSchema.xsd @@ -47,11 +47,6 @@ <xs:element type="moduleSuiteOptionType" name="module" minOccurs="0"/> </xs:choice> </xs:complexType> - <!--<xs:complexType name="suiteHookType">--> - <!--<xs:choice minOccurs="0" maxOccurs="unbounded">--> - <!--<xs:group ref="dataOperationTags" maxOccurs="unbounded" minOccurs="0"/>--> - <!--</xs:choice>--> - <!--</xs:complexType>--> <xs:complexType name="suiteType"> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element type="includeType" name="include" maxOccurs="1"/> @@ -67,6 +62,7 @@ </xs:documentation> </xs:annotation> </xs:attribute> + <xs:attribute type="xs:string" name="filename"/> </xs:complexType> <xs:complexType name="suiteConfigType"> <xs:choice minOccurs="0" maxOccurs="unbounded"> diff --git a/src/Magento/FunctionalTestingFramework/Test/Config/ActionGroupDom.php b/src/Magento/FunctionalTestingFramework/Test/Config/ActionGroupDom.php index 7eec3286d..a99432e40 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Config/ActionGroupDom.php +++ b/src/Magento/FunctionalTestingFramework/Test/Config/ActionGroupDom.php @@ -31,15 +31,23 @@ public function initDom($xml, $filename = null) if ($this->checkFilenameSuffix($filename, self::ACTION_GROUP_FILE_NAME_ENDING)) { $actionGroupsNode = $dom->getElementsByTagName('actionGroups')[0]; - $actionGroupNodes = $dom->getElementsByTagName('actionGroup'); $this->testsValidationUtil->validateChildUniqueness( $actionGroupsNode, $filename, null ); - foreach ($actionGroupNodes as $actionGroupNode) { + + // Validate single action group node per file + $this->singleNodePerFileValidationUtil->validateSingleNodeForTag( + $dom, + 'actionGroup', + $filename + ); + + if ($dom->getElementsByTagName('actionGroup')->length > 0) { /** @var \DOMElement $actionGroupNode */ + $actionGroupNode = $dom->getElementsByTagName('actionGroup')[0]; $actionGroupNode->setAttribute(self::TEST_META_FILENAME_ATTRIBUTE, $filename); $this->actionsValidationUtil->validateChildUniqueness( $actionGroupNode, diff --git a/src/Magento/FunctionalTestingFramework/Test/Config/Dom.php b/src/Magento/FunctionalTestingFramework/Test/Config/Dom.php index 12127ef32..7ded754be 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Config/Dom.php +++ b/src/Magento/FunctionalTestingFramework/Test/Config/Dom.php @@ -12,6 +12,7 @@ use Magento\FunctionalTestingFramework\Config\Dom\NodePathMatcher; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Magento\FunctionalTestingFramework\Util\Validation\DuplicateNodeValidationUtil; +use Magento\FunctionalTestingFramework\Util\Validation\SingleNodePerFileValidationUtil; /** * MFTF test.xml configuration XML DOM utility @@ -38,6 +39,12 @@ class Dom extends \Magento\FunctionalTestingFramework\Config\MftfDom */ protected $testsValidationUtil; + /** + * SingleNodePerFileValidationUtil + * @var SingleNodePerFileValidationUtil + */ + protected $singleNodePerFileValidationUtil; + /** * ExceptionCollector * @var ExceptionCollector @@ -65,6 +72,7 @@ public function __construct( ) { $this->actionsValidationUtil = new DuplicateNodeValidationUtil('stepKey', $exceptionCollector); $this->testsValidationUtil = new DuplicateNodeValidationUtil('name', $exceptionCollector); + $this->singleNodePerFileValidationUtil = new SingleNodePerFileValidationUtil($exceptionCollector); $this->exceptionCollector = $exceptionCollector; parent::__construct( $xml, @@ -91,14 +99,21 @@ public function initDom($xml, $filename = null) // Cannot rely on filename to ensure this file is a Test.xml if ($dom->getElementsByTagName('tests')->length > 0) { $testsNode = $dom->getElementsByTagName('tests')[0]; - $testNodes = $dom->getElementsByTagName('test'); $this->testsValidationUtil->validateChildUniqueness( $testsNode, $filename, null ); - foreach ($testNodes as $testNode) { + // Validate single test node per file + $this->singleNodePerFileValidationUtil->validateSingleNodeForTag( + $dom, + 'test', + $filename + ); + + if ($dom->getElementsByTagName('test')->length > 0) { /** @var \DOMElement $testNode */ + $testNode = $dom->getElementsByTagName('test')[0]; $testNode->setAttribute(self::TEST_META_FILENAME_ATTRIBUTE, $filename); if ($testNode->getAttribute(self::TEST_MERGE_POINTER_AFTER) !== "") { $this->appendMergePointerToActions( diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/RemoveModuleFileInSuiteFiles.php b/src/Magento/FunctionalTestingFramework/Upgrade/RemoveModuleFileInSuiteFiles.php index 639f24157..1cd76dc65 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/RemoveModuleFileInSuiteFiles.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/RemoveModuleFileInSuiteFiles.php @@ -68,10 +68,6 @@ public function execute(InputInterface $input, OutputInterface $output) $xmlFiles = ScriptUtil::getModuleXmlFilesByScope($testPaths, 'Suite'); $this->processXmlFiles($xmlFiles); - // Get root suite xml files - $xmlFiles = ScriptUtil::getRootSuiteXmlFiles(); - $this->processXmlFiles($xmlFiles); - return ("Removed module file reference in {$this->testsUpdated} suite file(s)."); } @@ -106,17 +102,19 @@ function ($matches) use ($file) { if (!$this->printNotice) { $this->ioStyle->note( '`file` is not a valid attribute for <module> in Suite XML schema.' . PHP_EOL - . 'The `file`references in the following xml files are removed. Consider using <test> instead.' + . 'The `file`references in the following xml files are commented out. Consider using <test> instead.' ); $this->printNotice = true; } $this->output->writeln( PHP_EOL . '"' . trim($matches[0]) . '"' . PHP_EOL - . 'is removed from file: ' . $file . PHP_EOL + . 'is commented out from file: ' . $file . PHP_EOL ); $this->testsUpdated += 1; - return ''; + $result = str_replace('<module', '<!--module', $matches[0]); + $result = str_replace('>', '--> <!-- Please replace with <test name="" -->', $result); + return $result; }, $contents ); diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php b/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php index 4ba8905c6..783d5b766 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php @@ -82,10 +82,6 @@ public function execute(InputInterface $input, OutputInterface $output) $this->processXmlFiles($xmlFiles, $type, $urn); } - // Process root suite xml files - $xmlFiles = ScriptUtil::getRootSuiteXmlFiles(); - $this->processXmlFiles($xmlFiles, 'Suite', $this->entityCategories['Suite']); - return ("Split multiple entities in {$this->testsUpdated} file(s)."); } diff --git a/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php b/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php index 976daa1f8..839320b38 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php @@ -6,8 +6,6 @@ namespace Magento\FunctionalTestingFramework\Util\Script; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; -use Magento\FunctionalTestingFramework\Util\Filesystem\FinderUtil; -use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Symfony\Component\Finder\Finder; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\Util\ModuleResolver; @@ -19,8 +17,6 @@ */ class ScriptUtil { - const ROOT_SUITE_DIR = 'tests/_suite'; - /** * Return all installed Magento module paths * @@ -89,23 +85,4 @@ public static function getModuleXmlFilesByScope($modulePaths, $scope) } return $found ? $finder->files() : []; } - - /** - * Return root Suite XML files, empty array if root suite file is not valid - * - * @return Finder|array - * @throws TestFrameworkException - */ - public static function getRootSuiteXmlFiles() - { - //$rootSuitePath = FilePathFormatter::format(TESTS_BP) . self::ROOT_SUITE_DIR; - $rootSuitePath = FilePathFormatter::format(TESTS_BP) . 'tests/verification/_suite'; - $finder = new Finder(); - if (!realpath($rootSuitePath)) { - return []; - } - $finder->files()->followLinks()->in($rootSuitePath)->name("*.xml"); - - return $finder->files(); - } } diff --git a/src/Magento/FunctionalTestingFramework/Util/Validation/SingleNodePerFileValidationUtil.php b/src/Magento/FunctionalTestingFramework/Util/Validation/SingleNodePerFileValidationUtil.php new file mode 100644 index 000000000..3f657f954 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/Validation/SingleNodePerFileValidationUtil.php @@ -0,0 +1,53 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\FunctionalTestingFramework\Util\Validation; + +use Magento\FunctionalTestingFramework\Exceptions\Collector\ExceptionCollector; + +/** + * Class SingleNodePerDocumentValidationUtil + * @package Magento\FunctionalTestingFramework\Util\Validation + */ +class SingleNodePerFileValidationUtil +{ + /** + * ExceptionColletor used to catch errors + * + * @var ExceptionCollector + */ + private $exceptionCollector; + + /** + * SingleNodePerDocumentValidationUtil constructor + * + * @param ExceptionCollector $exceptionCollector + */ + public function __construct($exceptionCollector) + { + $this->exceptionCollector = $exceptionCollector; + } + + /** + * Validate single node per dom document for a given tag name + * + * @param \DOMDocument $dom + * @param string $tag + * @param string $filename + * @return void + */ + public function validateSingleNodeForTag($dom, $tag, $filename = '') + { + $tagNodes = $dom->getElementsByTagName($tag); + $count = $tagNodes->count(); + if ( $count == 1) { + return; + } + + $errorMsg = "Single <{$tag}> node per xml file. {$count} found in file: {$filename}\n"; + $this->exceptionCollector->addError($filename, $errorMsg); + } +} From af17d022ffe7c0420ba4695d7ea423ec26165174 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Tue, 3 Mar 2020 15:03:30 -0600 Subject: [PATCH 254/888] MQE-683: [Deprecation] Only use more nested assertion syntax - Cleanup --- .../Upgrade/UpdateAssertionSchema.php | 22 ++++--------------- 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php index 05bec1d31..9c8810eee 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php @@ -31,7 +31,8 @@ class UpdateAssertionSchema implements UpgradeInterface private $errors = []; /** - * Upgrades all test xml files, changing <assert> actions to be nested + * Upgrades all test xml files, changing as many <assert> actions to be nested as possible + * WILL NOT CATCH cases where style is a mix of old and new * * @param InputInterface $input * @return string @@ -45,12 +46,9 @@ public function execute(InputInterface $input) $fileSystem = new Filesystem(); $testsUpdated = 0; foreach ($finder->files() as $file) { -// if (!$this->detectOldAttributes($file)) { -// continue; -// } $this->currentFile = $file->getFilename(); $contents = $file->getContents(); - // Isolate <assert ... /> but not <assert> ... </assert> + // Isolate <assert ... /> but never <assert> ... </assert> preg_match_all('/<assert[^>]*\/>/', $contents, $potentialAssertions); $newAssertions = []; $index = 0; @@ -98,7 +96,6 @@ private function convertOldAssertionToNew($assertion) { // <assertSomething => assertSomething $assertType = ltrim(explode(' ', $assertion)[0], '<'); - $stepKey = ""; // regex to grab values $grabValueRegex = '/(stepKey|actual|actualType|expected|expectedType|delta|message|selector|attribute|expectedValue|before|after|remove)=(\'[^\']*\'|"[^"]*")/'; @@ -130,9 +127,6 @@ private function convertOldAssertionToNew($assertion) } $trimmedParts[$type] = $value; if (in_array($type, ["stepKey", "delta", "message", "before", "after", "remove"])) { - if ($type == "stepKey") { - $stepKey = $value; - } $newString .= " $type=\"$value\""; continue; } @@ -154,7 +148,7 @@ private function convertOldAssertionToNew($assertion) if (isset($subElements["expected"]['value']) && !isset($subElements["expected"]['type'])) { $subElements["expected"]['type'] = "const"; } - // Massage subElements with data for edge cases + // Massage subElements with data for edge case if ($assertType == 'assertElementContainsAttribute') { // Assert type is very edge-cased, completely different schema $value = $subElements['expected']['value'] ?? ""; @@ -174,12 +168,4 @@ private function convertOldAssertionToNew($assertion) $newString .= " </$assertType>"; return $newString; } - - private function guessValueType($string) { - preg_match('/\$[a-zA-Z0-9]*/', $string, $matches); - if (isset($matches[0]) && $matches[0] == $string) { - return "variable"; - } - return "string"; - } } From f578c08e11578973355fb5d9eb4e5fe7c21e2a0a Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Wed, 4 Mar 2020 10:20:27 -0600 Subject: [PATCH 255/888] MQE-683: [Deprecation] Only use more nested assertion syntax - Safe update to upgrade script (better assert detection - Change back to TestGenerator to pass test again - Updated schema in AssertTest - Added back type to AssertContainsAttribute type (needed) --- .../TestModule/Test/AssertTest.xml | 224 +++++++++++++----- .../Test/etc/Actions/assertActions.xsd | 1 + .../Upgrade/UpdateAssertionSchema.php | 87 +++---- .../Util/TestGenerator.php | 2 +- 4 files changed, 206 insertions(+), 108 deletions(-) diff --git a/dev/tests/verification/TestModule/Test/AssertTest.xml b/dev/tests/verification/TestModule/Test/AssertTest.xml index 8cdc724cc..753ccedf1 100644 --- a/dev/tests/verification/TestModule/Test/AssertTest.xml +++ b/dev/tests/verification/TestModule/Test/AssertTest.xml @@ -157,47 +157,157 @@ <!-- asserts backward compatible --> <comment stepKey="commentBackwardCompatible" userInput="asserts backward compatible"/> - <assertArrayHasKey stepKey="assertArrayHasKeyBackwardCompatible" expected="apple" expectedType="string" actual="['orange' => 2, 'apple' => 1]" actualType="const" message="pass"/> - <assertArrayNotHasKey stepKey="assertArrayNotHasKeyBackwardCompatible" expected="kiwi" expectedType="string" actual="['orange' => 2, 'apple' => 1]" message="pass"/> - <assertArraySubset stepKey="assertArraySubsetBackwardCompatible" expected="[1, 2]" actual="[1, 2, 3, 5]" message="pass"/> - <assertContains stepKey="assertContainsBackwardCompatible" expected="ab" expectedType="string" actual="['item1' => 'a', 'item2' => 'ab']" message="pass"/> - <assertCount stepKey="assertCountBackwardCompatible" expected="2" expectedType="int" actual="['a', 'b']" message="pass"/> - <assertEmpty stepKey="assertEmptyBackwardCompatible" actual="[]" message="pass"/> - <assertEquals stepKey="assertEquals1BackwardCompatible" expected="text" expectedType="variable" actual="Copyright © 2013-2017 Magento, Inc. All rights reserved." actualType="string" message="pass"/> - <assertEquals stepKey="assertEquals2BackwardCompatible" expected="Copyright © 2013-2017 Magento, Inc. All rights reserved." expectedType="string" actual="text" actualType="variable" message="pass"/> - <assertFalse stepKey="assertFalse1BackwardCompatible" actual="0" actualType="bool" message="pass"/> - <assertFileNotExists stepKey="assertFileNotExists1BackwardCompatible" actual="/out.txt" actualType="string" message="pass"/> - <assertFileNotExists stepKey="assertFileNotExists2BackwardCompatible" actual="$text" actualType="variable" message="pass"/> - <assertGreaterOrEquals stepKey="assertGreaterOrEqualsBackwardCompatible" expected="2" expectedType="int" actual="5" actualType="int" message="pass"/> - <assertGreaterThan stepKey="assertGreaterThanBackwardCompatible" expected="2" expectedType="int" actual="5" actualType="int" message="pass"/> - <assertGreaterThanOrEqual stepKey="assertGreaterThanOrEqualBackwardCompatible" expected="2" expectedType="int" actual="5" actualType="int" message="pass"/> - <assertInternalType stepKey="assertInternalType1BackwardCompatible" expected="string" expectedType="string" actual="xyz" actualType="string" message="pass"/> - <assertInternalType stepKey="assertInternalType2BackwardCompatible" expected="int" expectedType="string" actual="21" actualType="int" message="pass"/> - <assertInternalType stepKey="assertInternalType3BackwardCompatible" expected="string" expectedType="string" actual="$text" actualType="variable" message="pass"/> - <assertLessOrEquals stepKey="assertLessOrEqualBackwardCompatibles" expected="5" expectedType="int" actual="2" actualType="int" message="pass"/> - <assertLessThan stepKey="assertLessThanBackwardCompatible" expected="5" expectedType="int" actual="2" actualType="int" message="pass"/> - <assertLessThanOrEqual stepKey="assertLessThanOrEqualBackwardCompatible" expected="5" expectedType="int" actual="2" actualType="int" message="pass"/> - <assertNotContains stepKey="assertNotContains1BackwardCompatible" expected="bc" expectedType="string" actual="['item1' => 'a', 'item2' => 'ab']" message="pass"/> - <assertNotContains stepKey="assertNotContains2BackwardCompatible" expected="bc" expectedType="string" actual="text" actualType="variable" message="pass"/> - <assertNotEmpty stepKey="assertNotEmpty1BackwardCompatible" actual="[1, 2]" message="pass"/> - <assertNotEmpty stepKey="assertNotEmpty2BackwardCompatible" actual="text" actualType="variable" message="pass"/> - <assertNotEquals stepKey="assertNotEqualsBackwardCompatible" expected="2" expectedType="int" actual="5" actualType="int" message="pass" delta=""/> - <assertNotNull stepKey="assertNotNull1BackwardCompatible" actual="abc" actualType="string" message="pass"/> - <assertNotNull stepKey="assertNotNull2BackwardCompatible" actual="text" actualType="variable" message="pass"/> - <assertNotRegExp stepKey="assertNotRegExpBackwardCompatible" expected="/foo/" expectedType="string" actual="bar" actualType="string" message="pass"/> - <assertNotSame stepKey="assertNotSameBackwardCompatible" expected="log" expectedType="string" actual="tag" actualType="string" message="pass"/> - <assertRegExp stepKey="assertRegExpBackwardCompatible" expected="/foo/" expectedType="string" actual="foo" actualType="string" message="pass"/> - <assertSame stepKey="assertSameBackwardCompatible" expected="bar" expectedType="string" actual="bar" actualType="string" message="pass"/> - <assertStringStartsNotWith stepKey="assertStringStartsNotWithBackwardCompatible" expected="a" expectedType="string" actual="banana" actualType="string" message="pass"/> - <assertStringStartsWith stepKey="assertStringStartsWithBackwardCompatible" expected="a" expectedType="string" actual="apple" actualType="string" message="pass"/> - <assertTrue stepKey="assertTrueBackwardCompatible" actual="1" actualType="bool" message="pass"/> - <assertElementContainsAttribute selector="#username" attribute="class" expectedValue="admin__control-text" stepKey="assertElementContainsAttributeBackwardCompatible"/> - <assertInstanceOf stepKey="assertInstanceOfBackwardCompatible" expected="User::class" actual="text" actualType="variable" message="pass"/> - <assertNotInstanceOf stepKey="assertNotInstanceOfBackwardCompatible" expected="User::class" actual="21" actualType="int" message="pass"/> - <assertFileExists stepKey="assertFileExistsBackwardCompatible" actual="text" actualType="variable" message="pass"/> - <assertIsEmpty stepKey="assertIsEmptyBackwardCompatible" actual="text" actualType="variable" message="pass"/> - <assertNull stepKey="assertNullBackwardCompatible" actual="text" actualType="variable" message="pass"/> - <expectException stepKey="expectExceptionBackwardCompatible" expected="new MyException('exception msg')" actual="function() {$this->doSomethingBad();}"/> + <assertArrayHasKey stepKey="assertArrayHasKeyBackwardCompatible" message="pass"> + <expectedResult type="string">apple</expectedResult> + <actualResult type="const">['orange' => 2, 'apple' => 1]</actualResult> + </assertArrayHasKey> + <assertArrayNotHasKey stepKey="assertArrayNotHasKeyBackwardCompatible" message="pass"> + <expectedResult type="string">kiwi</expectedResult> + <actualResult type="const">['orange' => 2, 'apple' => 1]</actualResult> + </assertArrayNotHasKey> + <assertArraySubset stepKey="assertArraySubsetBackwardCompatible" message="pass"> + <actualResult type="const">[1, 2, 3, 5]</actualResult> + <expectedResult type="const">[1, 2]</expectedResult> + </assertArraySubset> + <assertContains stepKey="assertContainsBackwardCompatible" message="pass"> + <expectedResult type="string">ab</expectedResult> + <actualResult type="const">['item1' => 'a', 'item2' => 'ab']</actualResult> + </assertContains> + <assertCount stepKey="assertCountBackwardCompatible" message="pass"> + <actualResult type="const">['a', 'b']</actualResult> + <expectedResult type="int">2</expectedResult> + </assertCount> + <assertEmpty stepKey="assertEmptyBackwardCompatible" message="pass"> + <actualResult type="const">[]</actualResult> + </assertEmpty> + <assertEquals stepKey="assertEquals1BackwardCompatible" message="pass"> + <actualResult type="string">Copyright © 2013-2017 Magento, Inc. All rights reserved.</actualResult> + <expectedResult type="variable">text</expectedResult> + </assertEquals> + <assertEquals stepKey="assertEquals2BackwardCompatible" message="pass"> + <actualResult type="variable">text</actualResult> + <expectedResult type="string">Copyright © 2013-2017 Magento, Inc. All rights reserved.</expectedResult> + </assertEquals> + <assertFalse stepKey="assertFalse1BackwardCompatible" message="pass"> + <actualResult type="bool">0</actualResult> + </assertFalse> + <assertFileNotExists stepKey="assertFileNotExists1BackwardCompatible" message="pass"> + <actualResult type="string">/out.txt</actualResult> + </assertFileNotExists> + <assertFileNotExists stepKey="assertFileNotExists2BackwardCompatible" message="pass"> + <actualResult type="variable">$text</actualResult> + </assertFileNotExists> + <assertGreaterOrEquals stepKey="assertGreaterOrEqualsBackwardCompatible" message="pass"> + <actualResult type="int">5</actualResult> + <expectedResult type="int">2</expectedResult> + </assertGreaterOrEquals> + <assertGreaterThan stepKey="assertGreaterThanBackwardCompatible" message="pass"> + <actualResult type="int">5</actualResult> + <expectedResult type="int">2</expectedResult> + </assertGreaterThan> + <assertGreaterThanOrEqual stepKey="assertGreaterThanOrEqualBackwardCompatible" message="pass"> + <actualResult type="int">5</actualResult> + <expectedResult type="int">2</expectedResult> + </assertGreaterThanOrEqual> + <assertInternalType stepKey="assertInternalType1BackwardCompatible" message="pass"> + <actualResult type="string">xyz</actualResult> + <expectedResult type="string">string</expectedResult> + </assertInternalType> + <assertInternalType stepKey="assertInternalType2BackwardCompatible" message="pass"> + <actualResult type="int">21</actualResult> + <expectedResult type="string">int</expectedResult> + </assertInternalType> + <assertInternalType stepKey="assertInternalType3BackwardCompatible" message="pass"> + <actualResult type="variable">$text</actualResult> + <expectedResult type="string">string</expectedResult> + </assertInternalType> + <assertLessOrEquals stepKey="assertLessOrEqualBackwardCompatibles" message="pass"> + <actualResult type="int">2</actualResult> + <expectedResult type="int">5</expectedResult> + </assertLessOrEquals> + <assertLessThan stepKey="assertLessThanBackwardCompatible" message="pass"> + <actualResult type="int">2</actualResult> + <expectedResult type="int">5</expectedResult> + </assertLessThan> + <assertLessThanOrEqual stepKey="assertLessThanOrEqualBackwardCompatible" message="pass"> + <actualResult type="int">2</actualResult> + <expectedResult type="int">5</expectedResult> + </assertLessThanOrEqual> + <assertNotContains stepKey="assertNotContains1BackwardCompatible" message="pass"> + <expectedResult type="string">bc</expectedResult> + <actualResult type="const">['item1' => 'a', 'item2' => 'ab']</actualResult> + </assertNotContains> + <assertNotContains stepKey="assertNotContains2BackwardCompatible" message="pass"> + <actualResult type="variable">text</actualResult> + <expectedResult type="string">bc</expectedResult> + </assertNotContains> + <assertNotEmpty stepKey="assertNotEmpty1BackwardCompatible" message="pass"> + <actualResult type="const">[1, 2]</actualResult> + </assertNotEmpty> + <assertNotEmpty stepKey="assertNotEmpty2BackwardCompatible" message="pass"> + <actualResult type="variable">text</actualResult> + </assertNotEmpty> + <assertNotEquals stepKey="assertNotEqualsBackwardCompatible" message="pass" delta=""> + <actualResult type="int">5</actualResult> + <expectedResult type="int">2</expectedResult> + </assertNotEquals> + <assertNotNull stepKey="assertNotNull1BackwardCompatible" message="pass"> + <actualResult type="string">abc</actualResult> + </assertNotNull> + <assertNotNull stepKey="assertNotNull2BackwardCompatible" message="pass"> + <actualResult type="variable">text</actualResult> + </assertNotNull> + <assertNotRegExp stepKey="assertNotRegExpBackwardCompatible" message="pass"> + <actualResult type="string">bar</actualResult> + <expectedResult type="string">/foo/</expectedResult> + </assertNotRegExp> + <assertNotSame stepKey="assertNotSameBackwardCompatible" message="pass"> + <actualResult type="string">tag</actualResult> + <expectedResult type="string">log</expectedResult> + </assertNotSame> + <assertRegExp stepKey="assertRegExpBackwardCompatible" message="pass"> + <actualResult type="string">foo</actualResult> + <expectedResult type="string">/foo/</expectedResult> + </assertRegExp> + <assertSame stepKey="assertSameBackwardCompatible" message="pass"> + <actualResult type="string">bar</actualResult> + <expectedResult type="string">bar</expectedResult> + </assertSame> + <assertStringStartsNotWith stepKey="assertStringStartsNotWithBackwardCompatible" message="pass"> + <actualResult type="string">banana</actualResult> + <expectedResult type="string">a</expectedResult> + </assertStringStartsNotWith> + <assertStringStartsWith stepKey="assertStringStartsWithBackwardCompatible" message="pass"> + <actualResult type="string">apple</actualResult> + <expectedResult type="string">a</expectedResult> + </assertStringStartsWith> + <assertTrue stepKey="assertTrueBackwardCompatible" message="pass"> + <actualResult type="bool">1</actualResult> + </assertTrue> + <assertElementContainsAttribute stepKey="assertElementContainsAttributeBackwardCompatible"> + <expectedResult selector="#username" attribute="class" type="string">admin__control-text</expectedResult> + </assertElementContainsAttribute> + <assertInstanceOf stepKey="assertInstanceOfBackwardCompatible" message="pass"> + <actualResult type="variable">text</actualResult> + <expectedResult type="const">User::class</expectedResult> + </assertInstanceOf> + <assertNotInstanceOf stepKey="assertNotInstanceOfBackwardCompatible" message="pass"> + <actualResult type="int">21</actualResult> + <expectedResult type="const">User::class</expectedResult> + </assertNotInstanceOf> + <assertFileExists stepKey="assertFileExistsBackwardCompatible" message="pass"> + <actualResult type="variable">text</actualResult> + </assertFileExists> + <assertIsEmpty stepKey="assertIsEmptyBackwardCompatible" message="pass"> + <actualResult type="variable">text</actualResult> + </assertIsEmpty> + <assertNull stepKey="assertNullBackwardCompatible" message="pass"> + <actualResult type="variable">text</actualResult> + </assertNull> + <expectException stepKey="expectExceptionBackwardCompatible"> + <expectedResult type="const">new MyException('exception msg')</expectedResult> + <actualResult type="const">function() {$this->doSomethingBad();}</actualResult> + </expectException> <!-- string type that use created data --> <comment stepKey="c2" userInput="string type that use created data"/> @@ -263,29 +373,29 @@ <fail stepKey="assert8" message="$$createData1.firstname$$ $$createData1.lastname$$"/> <!-- assertElementContainsAttribute examples --> - <assertElementContainsAttribute stepKey="assertElementContainsAttribute1" selector="#username" attribute="class"> - <expectedResult type="string">admin__control-text</expectedResult> + <assertElementContainsAttribute stepKey="assertElementContainsAttribute1"> + <expectedResult selector="#username" attribute="class" type="string">admin__control-text</expectedResult> </assertElementContainsAttribute> - <assertElementContainsAttribute stepKey="assertElementContainsAttribute2" selector="#username" attribute="name"> - <expectedResult type="string">login[username]</expectedResult> + <assertElementContainsAttribute stepKey="assertElementContainsAttribute2"> + <expectedResult selector="#username" attribute="name" type="string">login[username]</expectedResult> </assertElementContainsAttribute> - <assertElementContainsAttribute stepKey="assertElementContainsAttribute3" selector="#username" attribute="autofocus"> - <expectedResult type="string">true</expectedResult> + <assertElementContainsAttribute stepKey="assertElementContainsAttribute3"> + <expectedResult selector="#username" attribute="autofocus" type="string">true</expectedResult> </assertElementContainsAttribute> - <assertElementContainsAttribute stepKey="assertElementContainsAttribute4" selector="#username" attribute="data-validate"> - <expectedResult type="string">{required:true}</expectedResult> + <assertElementContainsAttribute stepKey="assertElementContainsAttribute4"> + <expectedResult selector="#username" attribute="data-validate" type="string">{required:true}</expectedResult> </assertElementContainsAttribute> - <assertElementContainsAttribute stepKey="assertElementContainsAttribute5" selector=".admin__menu-overlay" attribute="style"> - <expectedResult type="string">display: none;</expectedResult> + <assertElementContainsAttribute stepKey="assertElementContainsAttribute5"> + <expectedResult selector=".admin__menu-overlay" attribute="style" type="string">display: none;</expectedResult> </assertElementContainsAttribute> - <assertElementContainsAttribute stepKey="assertElementContainsAttribute6" selector=".admin__menu-overlay" attribute="border"> - <expectedResult type="string">0</expectedResult> + <assertElementContainsAttribute stepKey="assertElementContainsAttribute6"> + <expectedResult selector=".admin__menu-overlay" attribute="border" type="string">0</expectedResult> </assertElementContainsAttribute> - <assertElementContainsAttribute stepKey="assertElementContainsAttribute7" selector="#username" attribute="value"> - <expectedResult type="const">$createData2.firstname$</expectedResult> + <assertElementContainsAttribute stepKey="assertElementContainsAttribute7"> + <expectedResult selector="#username" attribute="value" type="const">$createData2.firstname$</expectedResult> </assertElementContainsAttribute> - <assertElementContainsAttribute stepKey="assertElementContainsAttribute8" selector="#username" attribute="value"> - <expectedResult type="const">$$createData1.firstname$$</expectedResult> + <assertElementContainsAttribute stepKey="assertElementContainsAttribute8"> + <expectedResult selector="#username" attribute="value" type="const">$$createData1.firstname$$</expectedResult> </assertElementContainsAttribute> <!-- assert entity resolution --> diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/assertActions.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/assertActions.xsd index ca8ebcd26..84752ee7b 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/assertActions.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/assertActions.xsd @@ -600,6 +600,7 @@ <xs:extension base="xs:string"> <xs:attribute type="xs:string" name="selector" use="required"/> <xs:attribute type="xs:string" name="attribute" use="required"/> + <xs:attribute type="assertEnum" name="type" use="required"/> </xs:extension> </xs:simpleContent> </xs:complexType> diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php index 9c8810eee..b8643f685 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php @@ -16,20 +16,6 @@ */ class UpdateAssertionSchema implements UpgradeInterface { - const OLD_ASSERTION_ATTRIBUTES = ["expected", "expectedType", "actual", "actualType"]; - - /** - * Current file being inspected, for error messaging - * @var string - */ - private $currentFile; - - /** - * Potential errors reported during replacement. - * @var array - */ - private $errors = []; - /** * Upgrades all test xml files, changing as many <assert> actions to be nested as possible * WILL NOT CATCH cases where style is a mix of old and new @@ -46,10 +32,10 @@ public function execute(InputInterface $input) $fileSystem = new Filesystem(); $testsUpdated = 0; foreach ($finder->files() as $file) { - $this->currentFile = $file->getFilename(); $contents = $file->getContents(); - // Isolate <assert ... /> but never <assert> ... </assert> - preg_match_all('/<assert[^>]*\/>/', $contents, $potentialAssertions); + // Isolate <assert ... /> but never <assert> ... </assert>, stops after finding first /> +// preg_match_all('/<assert[^>]*\/>/', $contents, $potentialAssertions); + preg_match_all('/<assert.*\/>/', $contents, $potentialAssertions); $newAssertions = []; $index = 0; if (empty($potentialAssertions[0])) { @@ -66,23 +52,7 @@ public function execute(InputInterface $input) $testsUpdated++; } - return ("Assertion Syntax updated in {$testsUpdated} file(s).\n" . implode("\n\t", $this->errors)); - } - - /** - * Detects present of attributes in file - * - * @param string $file - * @return boolean - */ - private function detectOldAttributes($file) - { - foreach (self::OLD_ASSERTION_ATTRIBUTES as $OLD_ASSERTION_ATTRIBUTE) { - if (strpos($file->getContents(), $OLD_ASSERTION_ATTRIBUTE) !== false) { - return true; - } - } - return false; + return ("Assertion Syntax updated in {$testsUpdated} file(s).\n"); } /** @@ -91,15 +61,19 @@ private function detectOldAttributes($file) * @param string $assertion * @return string * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) */ private function convertOldAssertionToNew($assertion) { // <assertSomething => assertSomething $assertType = ltrim(explode(' ', $assertion)[0], '<'); - // regex to grab values - $grabValueRegex = '/(stepKey|actual|actualType|expected|expectedType|delta|message|selector|attribute|expectedValue|before|after|remove)=(\'[^\']*\'|"[^"]*")/'; - // Make 3 arrays in $grabbedParts: + // regex to all attribute=>value pairs + $allAttributes = "stepKey|actual|actualType|expected|expectedType|expectedValue|"; + $allAttributes .= "delta|message|selector|attribute|before|after|remove"; + $grabValueRegex = '/('. $allAttributes .')=(\'[^\']*\'|"[^"]*")/'; + + // Makes 3 arrays in $grabbedParts: // 0 contains stepKey="value" // 1 contains stepKey // 2 contains value @@ -109,27 +83,33 @@ private function convertOldAssertionToNew($assertion) $sortedParts[$grabbedParts[1][$i]] = $grabbedParts[2][$i]; } - // Build new String, trim ' and " + // Begin trimming values and adding back into new string $trimmedParts = []; $newString = "<$assertType"; $subElements = ["actual" => [], "expected" => []]; foreach ($sortedParts as $type => $value) { + // If attribute="'value'", elseif attribute='"value"', new nested format will break if we leave these in if (strpos($value, '"') === 0) { $value = rtrim(ltrim($value, '"'), '"'); - } elseif(strpos($value, "'") === 0) { + } elseif (strpos($value, "'") === 0) { $value = rtrim(ltrim($value, "'"), "'"); } - // If value is empty string, trim again + // If value is empty string (" " or ' '), trim again to become empty if (str_replace(" ", "", $value) == "''") { $value = ""; } elseif (str_replace(" ", "", $value) == '""') { $value = ""; } + + // Value is ready for storage/reapply $trimmedParts[$type] = $value; if (in_array($type, ["stepKey", "delta", "message", "before", "after", "remove"])) { + // Add back as attribute safely $newString .= " $type=\"$value\""; continue; } + + // Store in subtype for child element creation if ($type == "actual") { $subElements["actual"]["value"] = $value; } elseif ($type == "actualType") { @@ -141,21 +121,28 @@ private function convertOldAssertionToNew($assertion) } } $newString .= ">\n"; - // Set type to const if it's absent - if (isset($subElements["actual"]['value']) && !isset($subElements["actual"]['type'])) { - $subElements["actual"]['type'] = "const"; - } - if (isset($subElements["expected"]['value']) && !isset($subElements["expected"]['type'])) { - $subElements["expected"]['type'] = "const"; - } - // Massage subElements with data for edge case + + // Assert type is very edge-cased, completely different schema if ($assertType == 'assertElementContainsAttribute') { - // Assert type is very edge-cased, completely different schema + // assertElementContainsAttribute type defaulted to string if not present + if (!isset($subElements["expected"]['type'])) { + $subElements["expected"]['type'] = "string"; + } $value = $subElements['expected']['value'] ?? ""; + $type = $subElements["expected"]['type']; $selector = $trimmedParts['selector']; $attribute = $trimmedParts['attribute']; - $newString .= "\t\t\t<expectedResult selector=\"$selector\" attribute=\"$attribute\">$value</expectedResult>\n"; + // @codingStandardsIgnoreStart + $newString .= "\t\t\t<expectedResult selector=\"$selector\" attribute=\"$attribute\" type=\"$type\">$value</expectedResult>\n"; + // @codingStandardsIgnoreEnd } else { + // Set type to const if it's absent, old default + if (isset($subElements["actual"]['value']) && !isset($subElements["actual"]['type'])) { + $subElements["actual"]['type'] = "const"; + } + if (isset($subElements["expected"]['value']) && !isset($subElements["expected"]['type'])) { + $subElements["expected"]['type'] = "const"; + } foreach ($subElements as $type => $subElement) { if (empty($subElement)) { continue; diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 7cdf131b3..275c01c8f 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1237,7 +1237,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $actionObject, $selector, $this->wrapWithDoubleQuotes($attribute), - $this->wrapWithDoubleQuotes($assertExpected) + $assertExpected ); break; case "assertEmpty": From 7327be14e42b85254fcb4804bbd901129edaf7a8 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Wed, 4 Mar 2020 12:06:46 -0600 Subject: [PATCH 256/888] Update filter documentation with special characters to be able to show correctly in devdocs --- docs/commands/mftf.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index e0394dc12..00924671f 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -159,7 +159,7 @@ vendor/bin/mftf generate:tests [option] [<test name>] [<test name>] [--remove] | Option | Description| | ---| --- | | `--config=[<default> or <singleRun> or <parallel>]` | Creates a single manifest file with a list of all tests. The default location is `tests/functional/Magento/FunctionalTest/_generated/testManifest.txt`.<br/> You can split the list into multiple groups using `--config=parallel`; the groups will be generated in `_generated/groups/` like `_generated/groups/group1.txt, group2.txt, ...`.<br/> Available values: `default` (default), `singleRun`(same as `default`), and `parallel`.<br/> Example: `generate:tests --config=parallel`. | -| `--filter` | Option to filter tests to be generated.<br/>Template: '<filterName>:<filterValue>'.<br/>Existing filter types: severity.<br/>Existing severity values: BLOCKER, CRITICAL, MAJOR, AVERAGE, MINOR.<br/>Example: --filter=severity:CRITICAL| +| `--filter` | Option to filter tests to be generated.<br/>Template: '<filterName>:<filterValue>'.<br/>Existing filter types: severity.<br/>Existing severity values: BLOCKER, CRITICAL, MAJOR, AVERAGE, MINOR.<br/>Example: --filter=severity:CRITICAL| | `--force` | Forces test generation, regardless of the module merge order defined in the Magento instance. Example: `generate:tests --force`. | | `-i,--time` | Set time in minutes to determine the group size when `--config=parallel` is used. The __default value__ is `10`. Example: `generate:tests --config=parallel --time=15`| | `--tests` | Defines the test configuration as a JSON string.| From f0c174cff61f033cc8510b80938b71546f5237cc Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 3 Mar 2020 15:51:43 -0600 Subject: [PATCH 257/888] MQE-1963: Update XSD Schema to verify that file has only single entity --- etc/di.xml | 14 ++++---- .../Console/GenerateTestsCommand.php | 2 +- .../Suite/Util/SuiteObjectExtractor.php | 2 +- .../Upgrade/RemoveModuleFileInSuiteFiles.php | 3 +- .../Upgrade/RenameMetadataFiles.php | 33 ++++++++++++------- .../Upgrade/SplitMultipleEntitiesFiles.php | 26 +++++++++++++-- .../SingleNodePerFileValidationUtil.php | 4 +-- 7 files changed, 57 insertions(+), 27 deletions(-) diff --git a/etc/di.xml b/etc/di.xml index 335b8372d..8d06383a5 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -88,7 +88,7 @@ <item name="/pages/page" xsi:type="string">name</item> <item name="/pages/page/section" xsi:type="string">name</item> </argument> - <argument name="fileName" xsi:type="string">/[\p{L}\p{N}_\-]+Page.xml$/</argument> + <argument name="fileName" xsi:type="string">/Page\.xml$/</argument> <argument name="defaultScope" xsi:type="string">Page</argument> </arguments> </virtualType> @@ -102,7 +102,7 @@ <item name="/sections/section" xsi:type="string">name</item> <item name="/sections/section/element" xsi:type="string">name</item> </argument> - <argument name="fileName" xsi:type="string">/[\p{L}\p{N}_\-]+Section.xml$/</argument> + <argument name="fileName" xsi:type="string">/Section\.xml$/</argument> <argument name="defaultScope" xsi:type="string">Section</argument> </arguments> </virtualType> @@ -163,7 +163,7 @@ <item name="/entities/entity/requiredEntity" xsi:type="string"/> <item name="/entities/entity/array" xsi:type="string"/> </argument> - <argument name="fileName" xsi:type="string">/[\p{L}\p{N}_\-]+Data.xml$/</argument> + <argument name="fileName" xsi:type="string">/Data\.xml$/</argument> <argument name="defaultScope" xsi:type="string">Data</argument> </arguments> </virtualType> @@ -198,7 +198,7 @@ <argument name="mergeablePaths" xsi:type="array"> <item name="/operations/operation/object" xsi:type="string"/> </argument> - <argument name="fileName" xsi:type="string">/[\p{L}\p{N}_\-]+Meta.xml$/</argument> + <argument name="fileName" xsi:type="string">/Meta\.xml$/</argument> <argument name="defaultScope" xsi:type="string">Metadata</argument> </arguments> </virtualType> @@ -229,7 +229,7 @@ <item name="/tests/test/(before|after)/(createData|updateData|getData)/field" xsi:type="string">key</item> <item name="/tests/test/annotations(/group)+" xsi:type="string">value</item> </argument> - <argument name="fileName" xsi:type="string">/[\p{L}\p{N}_\-]+.xml$/</argument> + <argument name="fileName" xsi:type="string">/\.xml$/</argument> <argument name="defaultScope" xsi:type="string">Test</argument> </arguments> </virtualType> @@ -304,7 +304,7 @@ <item name="/actionGroups/actionGroup/(createData|updateData|getData)/field" xsi:type="string">key</item> <item name="/actionGroups/actionGroup/remove" xsi:type="string">keyForRemoval</item> </argument> - <argument name="fileName" xsi:type="string">/[\p{L}\p{N}_\-]+ActionGroup.xml$/</argument> + <argument name="fileName" xsi:type="string">/ActionGroup\.xml$/</argument> <argument name="defaultScope" xsi:type="string">ActionGroup</argument> </arguments> </virtualType> @@ -372,7 +372,7 @@ <item name="/suites/suite/include/(group|test|module)" xsi:type="string">name</item> <item name="/suites/suite/exclude/(group|test|module)" xsi:type="string">name</item> </argument> - <argument name="fileName" xsi:type="string">/[\p{L}\p{N}_\-]+.xml$/</argument> + <argument name="fileName" xsi:type="string">/\.xml$/</argument> <argument name="defaultScope" xsi:type="string">Suite</argument> </arguments> </virtualType> diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php index 25bd68240..c33667f76 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php @@ -77,7 +77,7 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output) { - $this->setOutputStyle($input, $output); + $this->setIOStyle($input, $output); $tests = $input->getArgument('name'); $config = $input->getOption('config'); $json = $input->getOption('tests'); // for backward compatibility diff --git a/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php index ebe18908a..90fbddd6e 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php @@ -248,7 +248,7 @@ private function getTestsByModuleName($moduleName) /** @var TestObject $testObject */ $filename = $testObject->getFilename(); if ($pathExtractor->extractModuleName($filename) === $moduleName) { - $testObjects[] = $testObject; + $testObjects[$testName] = $testObject; } } return $testObjects; diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/RemoveModuleFileInSuiteFiles.php b/src/Magento/FunctionalTestingFramework/Upgrade/RemoveModuleFileInSuiteFiles.php index 1cd76dc65..04417ac5b 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/RemoveModuleFileInSuiteFiles.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/RemoveModuleFileInSuiteFiles.php @@ -102,7 +102,8 @@ function ($matches) use ($file) { if (!$this->printNotice) { $this->ioStyle->note( '`file` is not a valid attribute for <module> in Suite XML schema.' . PHP_EOL - . 'The `file`references in the following xml files are commented out. Consider using <test> instead.' + . 'The `file`references in the following xml files are commented out. ' + . 'Consider using <test> instead.' ); $this->printNotice = true; } diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/RenameMetadataFiles.php b/src/Magento/FunctionalTestingFramework/Upgrade/RenameMetadataFiles.php index 960d34f70..960456010 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/RenameMetadataFiles.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/RenameMetadataFiles.php @@ -6,7 +6,9 @@ namespace Magento\FunctionalTestingFramework\Upgrade; +use Magento\FunctionalTestingFramework\Util\Script\ScriptUtil; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Finder\Finder; /** @@ -18,22 +20,29 @@ class RenameMetadataFiles implements UpgradeInterface /** * Upgrades all test xml files * - * @param InputInterface $input + * @param InputInterface $input + * @param OutputInterface $output * @return string */ - public function execute(InputInterface $input) + public function execute(InputInterface $input, OutputInterface $output) { - $path = $input->getArgument("path"); - $finder = new Finder(); - $finder->files()->in($path)->name("*-meta.xml"); + $testPaths[] = $input->getArgument('path'); + if (empty($testPaths[0])) { + $testPaths = ScriptUtil::getAllModulePaths(); + } + + foreach ($testPaths as $testsPath) { + $finder = new Finder(); + $finder->files()->in($testsPath)->name("*-meta.xml"); - foreach ($finder->files() as $file) { - $oldFileName = $file->getFileName(); - $newFileName = $this->convertFileName($oldFileName); - $oldPath = $file->getPathname(); - $newPath = $file->getPath() . "/" . $newFileName; - print("Renaming " . $oldPath . " => " . $newPath . "\n"); - rename($oldPath, $newPath); + foreach ($finder->files() as $file) { + $oldFileName = $file->getFileName(); + $newFileName = $this->convertFileName($oldFileName); + $oldPath = $file->getPathname(); + $newPath = $file->getPath() . "/" . $newFileName; + print("Renaming " . $oldPath . " => " . $newPath . "\n"); + rename($oldPath, $newPath); + } } return "Finished renaming -meta.xml files."; diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php b/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php index 783d5b766..2b5e4c5d1 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php @@ -137,15 +137,35 @@ private function processXmlFiles($xmlFiles, $type, $urn) */ private function getEntityContents($contents, $type) { - $pattern = '/[\S\s]+\n(?<entity>[\s]*<' . lcfirst($type) + $nonEmptyTag = '/[\S\s]+\n(?<entity>[\s]*<' . lcfirst($type) . '[^\<\>]+name[\s]*=[\s]*"(?<name>[^\"\'\<\>\&]+)"[^\<\>]*>[\S\s]+<\/' . lcfirst($type) . '[\s]*>)+[\S\s]+/'; + $entityContents = $this->scanForPattern($contents, $type, $nonEmptyTag); + + $emptyTag = '/[\S\s]+\n(?<entity>[\s]*<' . lcfirst($type) + . '[^\<\>]+name[\s]*=[\s]*"(?<name>[^\"\'\<\>\&]+)"[^\<\>]*\/>)/'; + $entityContents = array_merge($entityContents, $this->scanForPattern($contents, $type, $emptyTag)); + + return $entityContents; + } + + /** + * Scan contents to match given pattern + * + * @param string $contents + * @param string $type + * @param string $pattern + * @return array + */ + private function scanForPattern($contents, $type, $pattern) + { preg_match($pattern, $contents, $matches); if (isset($matches['entity']) && isset($matches['name'])) { $contents = str_replace($matches['entity'], '', $contents); $entityContents[trim($matches['name'])] = $matches['entity']; - if (!empty($this->getEntityContents($contents, $type))) { - $entityContents = array_merge($entityContents, $this->getEntityContents($contents, $type)); + $restEntityContents = $this->scanForPattern($contents, $type, $pattern); + if (!empty($restEntityContents)) { + $entityContents = array_merge($entityContents, $restEntityContents); } return $entityContents; } else { diff --git a/src/Magento/FunctionalTestingFramework/Util/Validation/SingleNodePerFileValidationUtil.php b/src/Magento/FunctionalTestingFramework/Util/Validation/SingleNodePerFileValidationUtil.php index 3f657f954..c560349be 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Validation/SingleNodePerFileValidationUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/Validation/SingleNodePerFileValidationUtil.php @@ -42,8 +42,8 @@ public function __construct($exceptionCollector) public function validateSingleNodeForTag($dom, $tag, $filename = '') { $tagNodes = $dom->getElementsByTagName($tag); - $count = $tagNodes->count(); - if ( $count == 1) { + $count = $tagNodes->length; + if ($count == 1) { return; } From ef68e14febd79db33242f9dd61cf5fc3d84cce92 Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Thu, 5 Mar 2020 10:05:21 -0600 Subject: [PATCH 258/888] Revert "Merge pull request #546 from lbajsarowicz/bugfix/55-missing-url-attribute" This reverts commit 81cfd36e3713e5c2f34f2ff5af670d0063d57695, reversing changes made to 4462b2cf6c978a2554b8f1789c676f562acd261f. --- .../Test/Objects/ActionObjectTest.php | 27 +++++---- .../Test/Objects/ActionObject.php | 57 ++----------------- 2 files changed, 19 insertions(+), 65 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php index 890083d51..511c9748f 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php @@ -24,8 +24,6 @@ */ class ActionObjectTest extends MagentoTestCase { - const STUB_PAGE_URL_WITH_NO_ATTRIBUTE = '{{PageObject}}/some/path'; - /** * Before test functionality * @return void @@ -229,17 +227,16 @@ public function testResolveUrl() } /** - * {{PageObject}} should not be replaced and should throw an exception! + * {{PageObject}} should not be replaced and should elicit a warning in console * * @throws /Exception */ public function testResolveUrlWithNoAttribute() { - // Given + // Set up mocks $actionObject = new ActionObject('merge123', 'amOnPage', [ - 'url' => self::STUB_PAGE_URL_WITH_NO_ATTRIBUTE + 'url' => '{{PageObject}}' ]); - $pageObject = new PageObject('PageObject', '/replacement/url.html', 'Test', [], false, "test"); $pageObjectList = ["PageObject" => $pageObject]; $instance = AspectMock::double( @@ -248,14 +245,20 @@ public function testResolveUrlWithNoAttribute() )->make(); // bypass the private constructor AspectMock::double(PageObjectHandler::class, ['getInstance' => $instance]); - // Expect - $this->expectExceptionMessage('Can not resolve replacements: "{{PageObject}}"'); + // Call the method under test + $actionObject->resolveReferences(); + + // Expect this warning to get generated + TestLoggingUtil::getInstance()->validateMockLogStatement( + "warning", + "page url attribute not found and is required", + ['action' => $actionObject->getType(), 'url' => '{{PageObject}}', 'stepKey' => $actionObject->getStepKey()] + ); + + // Verify $expected = [ - 'url' => self::STUB_PAGE_URL_WITH_NO_ATTRIBUTE + 'url' => '{{PageObject}}' ]; - - // When - $actionObject->resolveReferences(); $this->assertEquals($expected, $actionObject->getCustomActionAttributes()); } diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php index 4cc955270..f377e2fac 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php @@ -76,9 +76,6 @@ class ActionObject const ACTION_ATTRIBUTE_USERINPUT = 'userInput'; const ACTION_TYPE_COMMENT = 'comment'; const INVISIBLE_STEP_ACTIONS = ['retrieveEntityField', 'getSecret']; - const REGEX_SINGLE_GROUP = '[\w]+'; - const REGEX_WITH_INDEX = '[\w]+\.[\w\[\]]+'; - const REGEX_WITH_PARAM = '[\w]+\.[\w]+\((?(?!}}).)+\)'; /** * The unique identifier for the action @@ -418,14 +415,6 @@ private function resolveUrlReference() $url = $this->actionAttributes[ActionObject::ACTION_ATTRIBUTE_URL]; $replacement = $this->findAndReplaceReferences(PageObjectHandler::getInstance(), $url); - - $missingReferences = $this->getMissingReferences($replacement); - if (!empty($missingReferences)) { - throw new TestReferenceException( - sprintf('Can not resolve replacements: "%s"', implode('", "', $missingReferences)) - ); - } - if ($replacement) { $this->resolvedCustomAttributes[ActionObject::ACTION_ATTRIBUTE_URL] = $replacement; $allPages = PageObjectHandler::getInstance()->getAllObjects(); @@ -439,27 +428,6 @@ private function resolveUrlReference() } } - /** - * Returns array of missing references - * - * @param string $replacement - * @return array - */ - private function getMissingReferences($replacement): array - { - $matchPatterns = [ - self::REGEX_SINGLE_GROUP, - self::REGEX_WITH_INDEX, - self::REGEX_WITH_PARAM - ]; - - preg_match_all($this->getMustachePattern($matchPatterns), $replacement, $matches); - - return array_filter($matches[1], function ($match) { - return !empty($match) && false === strpos($match, '_ENV.'); - }); - } - /** * Look up the value for EntityDataObjectName.Key and set it as the corresponding attribute in the resolved custom * attributes. @@ -553,12 +521,10 @@ private function stripAndReturnParameters($reference) */ private function findAndReplaceReferences($objectHandler, $inputString) { - $matchPatterns = [ - self::REGEX_WITH_INDEX, - self::REGEX_WITH_PARAM - ]; + //look for parameter area, if so use different regex + $regex = ActionObject::ACTION_ATTRIBUTE_VARIABLE_REGEX_PATTERN; - preg_match_all($this->getMustachePattern($matchPatterns), $inputString, $matches); + preg_match_all($regex, $inputString, $matches); $outputString = $inputString; @@ -756,11 +722,7 @@ private function resolveParameterization($isParameterized, $replacement, $match, */ private function matchParameterReferences($reference, $parameters) { - $matchPatterns = [ - self::REGEX_SINGLE_GROUP - ]; - - preg_match_all($this->getMustachePattern($matchPatterns), $reference, $varMatches); + preg_match_all('/{{[\w.]+}}/', $reference, $varMatches); $varMatches[0] = array_unique($varMatches[0]); $this->checkParameterCount($varMatches[0], $parameters, $reference); @@ -831,17 +793,6 @@ private function checkParameterCount($matches, $parameters, $reference) } } - /** - * Returns Mustache regex pattern - * - * @param array|null $patterns - * @return string - */ - private function getMustachePattern(array $patterns = []): string - { - return '/({{' .implode('}})|({{', $patterns).'}})/'; - } - /** * Returns array of deprecated usages in Action. * From 5e9359def44fdd9b2e48ec2687c4acfa4ef1eeb7 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 5 Mar 2020 14:51:24 -0600 Subject: [PATCH 259/888] MQE-1963: Update XSD Schema to verify that file has only single entity --- .../Upgrade/RemoveModuleFileInSuiteFiles.php | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/RemoveModuleFileInSuiteFiles.php b/src/Magento/FunctionalTestingFramework/Upgrade/RemoveModuleFileInSuiteFiles.php index 04417ac5b..ac36742f1 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/RemoveModuleFileInSuiteFiles.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/RemoveModuleFileInSuiteFiles.php @@ -47,6 +47,13 @@ class RemoveModuleFileInSuiteFiles implements UpgradeInterface */ private $testsUpdated = 0; + /** + * Indicate if a match and replace has happened + * + * @var boolean + */ + private $replaced = false; + /** * Scan all suite xml files, remove <module file="".../> node, and print update message * @@ -82,7 +89,12 @@ private function processXmlFiles($xmlFiles) foreach ($xmlFiles as $file) { $contents = $file->getContents(); $filePath = $file->getRealPath(); - file_put_contents($filePath, $this->removeModuleFileAttributeInSuite($contents, $filePath)); + $this->replaced = false; + $contents = $this->removeModuleFileAttributeInSuite($contents, $filePath); + if ($this->replaced) { + file_put_contents($filePath, $contents); + $this->testsUpdated++; + } } } @@ -112,9 +124,9 @@ function ($matches) use ($file) { . '"' . trim($matches[0]) . '"' . PHP_EOL . 'is commented out from file: ' . $file . PHP_EOL ); - $this->testsUpdated += 1; $result = str_replace('<module', '<!--module', $matches[0]); $result = str_replace('>', '--> <!-- Please replace with <test name="" -->', $result); + $this->replaced = true; return $result; }, $contents From 4b3cd0f1a52176c90d7c9e119539847c9fd55fc6 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 5 Mar 2020 16:40:01 -0600 Subject: [PATCH 260/888] MQE-1963: Update XSD Schema to verify that file has only single entity - DevDocs update --- docs/best-practices.md | 2 +- docs/commands/mftf.md | 8 ++++---- docs/section.md | 1 - 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/best-practices.md b/docs/best-practices.md index 2f18bc205..c0499fb12 100644 --- a/docs/best-practices.md +++ b/docs/best-practices.md @@ -113,7 +113,7 @@ Use a lower case first letter for: ## Page object 1. One `<page>` tag is allowed per page XML file. -2. Use [parameterized selectors] for constructing a selector when test specific or runtime generated information is needed. +2. Use [parameterized selectors] for constructing a selector when test-specific or runtime-generated information is needed. Do not use them for static elements. <span class="color:red"> diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index dbd5de398..0e55e97c1 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -28,7 +28,7 @@ vendor/bin/mftf build:project vendor/bin/mftf build:project --upgrade ``` -Upgrades the all installed MFTF tests after the MFTF major upgrade. +Upgrades all installed MFTF tests after a major MFTF upgrade. ### Generate all tests @@ -506,8 +506,8 @@ vendor/bin/mftf static-checks testDependencies actionGroupArguments ### `upgrade:tests` -When path argument is specified, this command will apply all the MFTF major version upgrade scripts to test components in the given path (`test.xml`, `data.xml`, etc); -otherwise it will apply all the MFTF major version upgrade scripts to all installed test components. +When the path argument is specified, this command applies all the major version MFTF upgrade scripts to the test components in the given path (test.xml, data.xml, etc). +Otherwise, it will apply all the major version MFTF upgrade scripts to all installed test components. #### Usage @@ -520,7 +520,7 @@ The command searches recursively for any `*.xml` files to upgrade. #### Examples -To upgrade all installed MFTF tests +To upgrade all installed MFTF tests: ```bash vendor/bin/mftf upgrade:tests diff --git a/docs/section.md b/docs/section.md index f5c15c70c..421c98fdd 100644 --- a/docs/section.md +++ b/docs/section.md @@ -48,7 +48,6 @@ The following conventions apply to MFTF sections: - `*Section.xml` is stored in the _Section_ directory of a module. - The name format is `{Admin|Storefront}{SectionDescription}Section.xml`. - Camel case is used for `<section>` elements. -They describe the function of the element rather than attempting to describe the selector used. - One `<section>` tag is allowed per section XML file. ## Example From 787897eb2cdd33e4f0565371476b2e0e40c794d2 Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Fri, 6 Mar 2020 10:23:10 -0600 Subject: [PATCH 261/888] MQE-1799: Throw exception during generation when leaving out .url for amOnPage --- .../Page/Handlers/PageObjectHandler.php | 3 ++- .../FunctionalTestingFramework/Test/Objects/ActionObject.php | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php b/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php index c310b9bef..2542b2760 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php @@ -67,7 +67,8 @@ private function __construct() $module = $pageData[self::MODULE] ?? null; $sectionNames = array_keys($pageData[self::SECTION] ?? []); - $parameterized = $pageData[self::PARAMETERIZED] ?? false; + $urlContainsMustaches = strpos($url, "{{") !== false && strpos($url, "}}") !== false; + $parameterized = $pageData[self::PARAMETERIZED] ?? $urlContainsMustaches ?? false; $filename = $pageData[self::FILENAME] ?? null; $deprecated = $pageData[self::OBJ_DEPRECATED] ?? null; diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php index f377e2fac..4d2d45d1f 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php @@ -420,7 +420,7 @@ private function resolveUrlReference() $allPages = PageObjectHandler::getInstance()->getAllObjects(); if ($replacement === $url && array_key_exists(trim($url, "{}"), $allPages) ) { - LoggingUtil::getInstance()->getLogger(ActionObject::class)->warning( + throw new TestReferenceException( "page url attribute not found and is required", ["action" => $this->type, "url" => $url, "stepKey" => $this->stepKey] ); From 34456fa0d49d838723b38cdba5be49086472919c Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Fri, 6 Mar 2020 10:54:30 -0600 Subject: [PATCH 262/888] MQE-1799: Throw exception during generation when leaving out .url for amOnPage --- .../Test/Objects/ActionObjectTest.php | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php index 511c9748f..24a7e2ee6 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php @@ -233,6 +233,8 @@ public function testResolveUrl() */ public function testResolveUrlWithNoAttribute() { + $this->expectException(TestReferenceException::class); + // Set up mocks $actionObject = new ActionObject('merge123', 'amOnPage', [ 'url' => '{{PageObject}}' @@ -247,19 +249,6 @@ public function testResolveUrlWithNoAttribute() // Call the method under test $actionObject->resolveReferences(); - - // Expect this warning to get generated - TestLoggingUtil::getInstance()->validateMockLogStatement( - "warning", - "page url attribute not found and is required", - ['action' => $actionObject->getType(), 'url' => '{{PageObject}}', 'stepKey' => $actionObject->getStepKey()] - ); - - // Verify - $expected = [ - 'url' => '{{PageObject}}' - ]; - $this->assertEquals($expected, $actionObject->getCustomActionAttributes()); } /** From e09facc16591f4637c58c018c081798bf33524b8 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Fri, 6 Mar 2020 11:41:05 -0600 Subject: [PATCH 263/888] MQE-1963: Enable upgrade during build for testing. --- .../Console/BuildProjectCommand.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/BuildProjectCommand.php b/src/Magento/FunctionalTestingFramework/Console/BuildProjectCommand.php index 23736925f..cc8d9776e 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BuildProjectCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BuildProjectCommand.php @@ -107,11 +107,12 @@ function ($type, $buffer) use ($output) { ); } - if ($input->getOption('upgrade')) { + // Temporary enable upgrade at build time for testing + //if ($input->getOption('upgrade')) { $upgradeCommand = new UpgradeTestsCommand(); $upgradeOptions = new ArrayInput([]); $upgradeCommand->run($upgradeOptions, $output); - } + //} } /** From 392a130052580b079f61afbd94f3a4d871fbeba0 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Fri, 6 Mar 2020 12:11:31 -0600 Subject: [PATCH 264/888] MQE-1738: MFTF PHP Compatibility Update (PHP 7.4) removed support for php7.0/7.1 --- .travis.yml | 2 -- composer.json | 2 +- composer.lock | 4 ++-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 913c74f48..fb21686b8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,5 @@ language: php php: - - 7.0 - - 7.1 - 7.2 - 7.3 install: composer install --no-interaction --prefer-source diff --git a/composer.json b/composer.json index 5fc595478..727f4c8a5 100755 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ "sort-packages": true }, "require": { - "php": "7.0.2||7.0.4||~7.0.6||~7.1.0||~7.2.0||~7.3.0", + "php": "~7.2.0||~7.3.0", "ext-curl": "*", "ext-json": "*", "ext-openssl": "*", diff --git a/composer.lock b/composer.lock index cd692f7e6..43be8f65d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "21ca9c7fef683977c7a1bbb0591c54b0", + "content-hash": "ddf9b7965d3a2369bf0f22f5172d75dc", "packages": [ { "name": "allure-framework/allure-codeception", @@ -6869,7 +6869,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "7.0.2||7.0.4||~7.0.6||~7.1.0||~7.2.0||~7.3.0", + "php": "~7.2.0||~7.3.0", "ext-curl": "*", "ext-json": "*", "ext-openssl": "*" From 47820ec548c5fd7cab585e0996da99e55988f4ad Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 9 Mar 2020 16:11:06 -0500 Subject: [PATCH 265/888] MQE-1963: Update XSD Schema to verify that file has only single entity --- .../Upgrade/SplitMultipleEntitiesFiles.php | 59 ++++--------------- 1 file changed, 11 insertions(+), 48 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php b/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php index 2b5e4c5d1..e419352b8 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php @@ -97,13 +97,20 @@ private function processXmlFiles($xmlFiles, $type, $urn) { foreach ($xmlFiles as $file) { $contents = $file->getContents(); - $entityContents = $this->getEntityContents($contents, $type); - if (count($entityContents) > 1) { + $domDocument = new \DOMDocument(); + $domDocument->loadXML($contents); + $entities = $domDocument->getElementsByTagName(lcfirst($type)); + + if ($entities->length > 1) { $filename = $file->getRealPath(); if ($this->output->isVerbose()) { $this->output->writeln('Processing file:' . $filename); } - foreach ($entityContents as $entityName => $entityContent) { + foreach ($entities as $entity) { + /** @var \DOMElement $entity*/ + $entityName = $entity->getAttribute('name'); + $entityContent = $entity->ownerDocument->saveXML($entity); + $dir = dirname($file); $dir .= DIRECTORY_SEPARATOR . ucfirst(basename($file, '.xml')); $splitFileName = $this->formatName($entityName, $type); @@ -128,50 +135,6 @@ private function processXmlFiles($xmlFiles, $type, $urn) } } - /** - * Parse contents and return array of single entity content according to entity type - * - * @param string $contents - * @param string $type - * @return array - */ - private function getEntityContents($contents, $type) - { - $nonEmptyTag = '/[\S\s]+\n(?<entity>[\s]*<' . lcfirst($type) - . '[^\<\>]+name[\s]*=[\s]*"(?<name>[^\"\'\<\>\&]+)"[^\<\>]*>[\S\s]+<\/' - . lcfirst($type) . '[\s]*>)+[\S\s]+/'; - $entityContents = $this->scanForPattern($contents, $type, $nonEmptyTag); - - $emptyTag = '/[\S\s]+\n(?<entity>[\s]*<' . lcfirst($type) - . '[^\<\>]+name[\s]*=[\s]*"(?<name>[^\"\'\<\>\&]+)"[^\<\>]*\/>)/'; - $entityContents = array_merge($entityContents, $this->scanForPattern($contents, $type, $emptyTag)); - - return $entityContents; - } - - /** - * Scan contents to match given pattern - * - * @param string $contents - * @param string $type - * @param string $pattern - * @return array - */ - private function scanForPattern($contents, $type, $pattern) - { - preg_match($pattern, $contents, $matches); - if (isset($matches['entity']) && isset($matches['name'])) { - $contents = str_replace($matches['entity'], '', $contents); - $entityContents[trim($matches['name'])] = $matches['entity']; - $restEntityContents = $this->scanForPattern($contents, $type, $pattern); - if (!empty($restEntityContents)) { - $entityContents = array_merge($entityContents, $restEntityContents); - } - return $entityContents; - } else { - return []; - } - } /** * Create file with contents and create dir if needed @@ -198,7 +161,7 @@ private function filePutContents($fullPath, $type, $urn, $contents) . '<' . lcfirst($type) . 's ' . self::XML_NAMESPACE . self::XML_SCHEMA_LOCATION . $urn . '">' . PHP_EOL - . $contents . PHP_EOL + . ' ' . $contents . PHP_EOL . '</' . lcfirst($type) . 's>' . PHP_EOL; file_put_contents($fullPath, $fullContents); From 12e0648b5481f0e7c3cbec9dcae022c06594fc3d Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 9 Mar 2020 22:03:08 -0500 Subject: [PATCH 266/888] MQE-1963: Update XSD Schema to verify that file has only single entity --- .../Upgrade/SplitMultipleEntitiesFiles.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php b/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php index e419352b8..fd7957bda 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php @@ -107,7 +107,7 @@ private function processXmlFiles($xmlFiles, $type, $urn) $this->output->writeln('Processing file:' . $filename); } foreach ($entities as $entity) { - /** @var \DOMElement $entity*/ + /** @var \DOMElement $entity */ $entityName = $entity->getAttribute('name'); $entityContent = $entity->ownerDocument->saveXML($entity); @@ -135,7 +135,6 @@ private function processXmlFiles($xmlFiles, $type, $urn) } } - /** * Create file with contents and create dir if needed * From 2e7013b58e5f633ab27e95449e0d8967c7557f52 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 5 Mar 2020 14:30:26 -0600 Subject: [PATCH 267/888] MQE-2013: fixed UpdateTestSchemaPaths upgrade script --- .../DeprecatedCommentActionGroup.xml | 2 +- .../DevDocs/Data/DeprecatedMessageData.xml | 2 +- .../tests/MFTF/DevDocs/Data/MessageData.xml | 2 +- .../DevDocs/Page/DeprecatedMFTFDocPage.xml | 2 +- .../tests/MFTF/DevDocs/Page/MFTFDocPage.xml | 2 +- .../MFTF/DevDocs/Section/ContentSection.xml | 2 +- .../Section/DeprecatedContentSection.xml | 2 +- .../DevDocs/Test/DeprecatedDevDocsTest.xml | 2 +- .../tests/MFTF/DevDocs/Test/DevDocsTest.xml | 2 +- .../ActionGroup/DeprecatedActionGroup.xml | 2 +- .../ActionGroup/XmlCommentedActionGroup.xml | 2 +- .../ActionGroup/XmlDuplicateActionGroup.xml | 2 +- .../TestModule/Data/DeprecatedData.xml | 2 +- .../TestModule/Data/ExtendedData.xml | 2 +- .../TestModule/Data/ParameterArrayData.xml | 2 +- .../Data/PersistedReplacementData.xml | 2 +- .../TestModule/Data/ReplacementData.xml | 2 +- .../TestModule/Page/DeprecatedPage.xml | 2 +- .../TestModule/Section/DeprecatedSection.xml | 2 +- .../Section/LocatorFunctionSection.xml | 2 +- .../TestModule/Section/SampleSection.xml | 2 +- .../functionalSuite/functionalSuite1.xml | 2 +- .../functionalSuite/functionalSuite2.xml | 2 +- .../functionalSuiteWithComments.xml | 2 +- .../Suite/functionalSuiteExtends.xml | 2 +- .../TestModule/Suite/functionalSuiteHooks.xml | 2 +- .../TestModule/Test/AssertTest.xml | 2 +- .../Test/CharacterReplacementTest.xml | 2 +- .../TestModule/Test/DataActionsTest.xml | 2 +- .../TestModule/Test/DataReplacementTest.xml | 2 +- .../Test/DeprecatedEntitiesTest.xml | 2 +- .../TestModule/Test/DeprecatedTest.xml | 2 +- .../TestModule/Test/ExecuteJsTest.xml | 2 +- .../TestModule/Test/ExtendedDataTest.xml | 2 +- .../TestModule/Test/HookActionsTest.xml | 2 +- .../TestModule/Test/LocatorFunctionTest.xml | 2 +- .../TestModule/Test/PageReplacementTest.xml | 2 +- .../TestModule/Test/ParameterArrayTest.xml | 2 +- .../Test/PersistedReplacementTest.xml | 2 +- .../PersistenceActionGroupAppendingTest.xml | 2 +- .../Test/PersistenceCustomFieldsTest.xml | 2 +- .../Test/SecretCredentialDataTest.xml | 2 +- .../Test/SectionReplacementTest.xml | 2 +- .../Test/XmlCommentedActionGroupTest.xml | 2 +- .../TestModule/Test/XmlCommentedTest.xml | 2 +- .../TestModuleMerged/Data/MergeData.xml | 2 +- .../TestModuleMerged/Section/MergeSection.xml | 2 +- .../Test/MergeXmlDuplicateTest.xml | 2 +- .../Upgrade/UpdateTestSchemaPaths.php | 100 ++++++++++-------- 49 files changed, 105 insertions(+), 91 deletions(-) diff --git a/dev/tests/functional/tests/MFTF/DevDocs/ActionGroup/DeprecatedCommentActionGroup.xml b/dev/tests/functional/tests/MFTF/DevDocs/ActionGroup/DeprecatedCommentActionGroup.xml index 908808a8c..6c27627d5 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/ActionGroup/DeprecatedCommentActionGroup.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/ActionGroup/DeprecatedCommentActionGroup.xml @@ -6,7 +6,7 @@ */ --> <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="DeprecatedCommentActionGroup" deprecated="This Action Group is outdated and will be deleted next release."> <comment userInput="Action group to demonstrate deprecation notices." stepKey="comment" /> </actionGroup> diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Data/DeprecatedMessageData.xml b/dev/tests/functional/tests/MFTF/DevDocs/Data/DeprecatedMessageData.xml index 5835a78af..1c2462c2f 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Data/DeprecatedMessageData.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/Data/DeprecatedMessageData.xml @@ -7,7 +7,7 @@ --> <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> <entity name="DeprecatedMessageData" deprecated="Entity is deprecated. Please use 'MessageData'."> <data key="message">Introduction to the Magento Functional Testing Framework</data> </entity> diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Data/MessageData.xml b/dev/tests/functional/tests/MFTF/DevDocs/Data/MessageData.xml index eb77e73bc..9c34b5672 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Data/MessageData.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/Data/MessageData.xml @@ -7,7 +7,7 @@ --> <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> <entity name="MessageData"> <data key="message">Introduction to the Magento Functional Testing Framework</data> </entity> diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Page/DeprecatedMFTFDocPage.xml b/dev/tests/functional/tests/MFTF/DevDocs/Page/DeprecatedMFTFDocPage.xml index ee47fe954..8be64e9ca 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Page/DeprecatedMFTFDocPage.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/Page/DeprecatedMFTFDocPage.xml @@ -7,7 +7,7 @@ --> <pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> <page name="DeprecatedMFTFDocPage" url="mftf/docs/introduction.html" area="storefront" module="MFTF_DevDocs" deprecated="New page was introduced. Please use 'MFTFDocPage'"> <section name="contentSection" /> </page> diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Page/MFTFDocPage.xml b/dev/tests/functional/tests/MFTF/DevDocs/Page/MFTFDocPage.xml index 88c577aef..9783fb0b3 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Page/MFTFDocPage.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/Page/MFTFDocPage.xml @@ -7,7 +7,7 @@ --> <pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> <page name="MFTFDocPage" url="mftf/docs/introduction.html" area="storefront" module="MFTF_DevDocs"> <section name="contentSection" /> </page> diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Section/ContentSection.xml b/dev/tests/functional/tests/MFTF/DevDocs/Section/ContentSection.xml index 15af0fa39..c318fac3f 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Section/ContentSection.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/Section/ContentSection.xml @@ -7,7 +7,7 @@ --> <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="contentSection"> <element name="pageIntro" type="text" selector=".page-intro"/> <element name="deprecatedPageIntro" type="text" selector=".page-intro-old" deprecated="New element was introduced. Please use 'contentSection.pageIntro'"/> diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Section/DeprecatedContentSection.xml b/dev/tests/functional/tests/MFTF/DevDocs/Section/DeprecatedContentSection.xml index cc316d6ed..8ed018146 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Section/DeprecatedContentSection.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/Section/DeprecatedContentSection.xml @@ -7,7 +7,7 @@ --> <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="DeprecatedContentSection" deprecated="New section was introduces. Please use 'contentSection'"> <element name="pageIntro" type="text" selector=".page-intro"/> </section> diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Test/DeprecatedDevDocsTest.xml b/dev/tests/functional/tests/MFTF/DevDocs/Test/DeprecatedDevDocsTest.xml index c93dc8011..5944a964c 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Test/DeprecatedDevDocsTest.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/Test/DeprecatedDevDocsTest.xml @@ -7,7 +7,7 @@ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="DeprecatedDevDocsTest" deprecated="Test is deprecated due to more stable test was introduces. Please use 'DevDocsTest'."> <annotations> <!-- Comment in Annotations for DevDocs Test are not affecting test generation --> diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml b/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml index c6b2575b9..592294889 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml @@ -7,7 +7,7 @@ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="DevDocsTest"> <annotations> <!-- Comment in Annotations for DevDocs Test are not affecting test generation --> diff --git a/dev/tests/verification/TestModule/ActionGroup/DeprecatedActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/DeprecatedActionGroup.xml index 8f0341c09..f447ce76e 100644 --- a/dev/tests/verification/TestModule/ActionGroup/DeprecatedActionGroup.xml +++ b/dev/tests/verification/TestModule/ActionGroup/DeprecatedActionGroup.xml @@ -6,7 +6,7 @@ */ --> <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="DeprecatedActionGroup" deprecated="Deprecated action group"> <see stepKey="deprecatedSee" userInput="{{DeprecatedData.field}}" selector="{{DeprecatedSection.deprecatedElement}}" /> </actionGroup> diff --git a/dev/tests/verification/TestModule/ActionGroup/XmlCommentedActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/XmlCommentedActionGroup.xml index a46dab939..9f1a429f7 100644 --- a/dev/tests/verification/TestModule/ActionGroup/XmlCommentedActionGroup.xml +++ b/dev/tests/verification/TestModule/ActionGroup/XmlCommentedActionGroup.xml @@ -6,7 +6,7 @@ */ --> <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="XmlCommentedActionGroup"> <arguments> <!-- Comments in arguments are not affecting test generation --> diff --git a/dev/tests/verification/TestModule/ActionGroup/XmlDuplicateActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/XmlDuplicateActionGroup.xml index af35b0134..90f7090b0 100644 --- a/dev/tests/verification/TestModule/ActionGroup/XmlDuplicateActionGroup.xml +++ b/dev/tests/verification/TestModule/ActionGroup/XmlDuplicateActionGroup.xml @@ -6,7 +6,7 @@ */ --> <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="xmlDuplicateActionGroup"> <acceptPopup stepKey="ap1"/> <acceptPopup stepKey="ap2"/> diff --git a/dev/tests/verification/TestModule/Data/DeprecatedData.xml b/dev/tests/verification/TestModule/Data/DeprecatedData.xml index 060752419..7d5f1e200 100644 --- a/dev/tests/verification/TestModule/Data/DeprecatedData.xml +++ b/dev/tests/verification/TestModule/Data/DeprecatedData.xml @@ -7,7 +7,7 @@ --> <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> <entity name="DeprecatedData" deprecated="Data entity deprecated"> <data key="field">deprecated</data> </entity> diff --git a/dev/tests/verification/TestModule/Data/ExtendedData.xml b/dev/tests/verification/TestModule/Data/ExtendedData.xml index 74fa921d0..c26715eec 100644 --- a/dev/tests/verification/TestModule/Data/ExtendedData.xml +++ b/dev/tests/verification/TestModule/Data/ExtendedData.xml @@ -7,7 +7,7 @@ --> <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> <entity name="parentData" type="data"> <data key="name">name</data> <data key="uniqueNamePre" unique="prefix">prename</data> diff --git a/dev/tests/verification/TestModule/Data/ParameterArrayData.xml b/dev/tests/verification/TestModule/Data/ParameterArrayData.xml index 3b45aedf7..38f6a2439 100644 --- a/dev/tests/verification/TestModule/Data/ParameterArrayData.xml +++ b/dev/tests/verification/TestModule/Data/ParameterArrayData.xml @@ -7,7 +7,7 @@ --> <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> <entity name="simpleParamData" type="data"> <data key="name">name</data> <data key="uniqueNamePre" unique="prefix">prename</data> diff --git a/dev/tests/verification/TestModule/Data/PersistedReplacementData.xml b/dev/tests/verification/TestModule/Data/PersistedReplacementData.xml index a8a747857..514b5eec6 100644 --- a/dev/tests/verification/TestModule/Data/PersistedReplacementData.xml +++ b/dev/tests/verification/TestModule/Data/PersistedReplacementData.xml @@ -8,7 +8,7 @@ --> <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> <entity name="ReplacementPerson" type="samplePerson"> <data key="firstname">John</data> <data key="lastName">Doe</data> diff --git a/dev/tests/verification/TestModule/Data/ReplacementData.xml b/dev/tests/verification/TestModule/Data/ReplacementData.xml index 4d91fa84e..133fe8f6e 100644 --- a/dev/tests/verification/TestModule/Data/ReplacementData.xml +++ b/dev/tests/verification/TestModule/Data/ReplacementData.xml @@ -8,7 +8,7 @@ --> <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> <entity name="simpleData" type="simpleData"> <data key="firstname">John</data> <data key="lastname">Doe</data> diff --git a/dev/tests/verification/TestModule/Page/DeprecatedPage.xml b/dev/tests/verification/TestModule/Page/DeprecatedPage.xml index 316b8b1d7..e758c3f07 100644 --- a/dev/tests/verification/TestModule/Page/DeprecatedPage.xml +++ b/dev/tests/verification/TestModule/Page/DeprecatedPage.xml @@ -7,7 +7,7 @@ --> <pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> <page name="DeprecatedPage" url="/test.html" area="storefront" module="UnknownVendor_TestModule" deprecated="Deprecated page"> <section name="SampleSection"/> </page> diff --git a/dev/tests/verification/TestModule/Section/DeprecatedSection.xml b/dev/tests/verification/TestModule/Section/DeprecatedSection.xml index a9ed20d98..954889786 100644 --- a/dev/tests/verification/TestModule/Section/DeprecatedSection.xml +++ b/dev/tests/verification/TestModule/Section/DeprecatedSection.xml @@ -7,7 +7,7 @@ --> <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="DeprecatedSection" deprecated="Deprecated section"> <element name="deprecatedElement" type="button" selector="#element" deprecated="Deprecated element"/> </section> diff --git a/dev/tests/verification/TestModule/Section/LocatorFunctionSection.xml b/dev/tests/verification/TestModule/Section/LocatorFunctionSection.xml index 28612e1b3..cc986d969 100644 --- a/dev/tests/verification/TestModule/Section/LocatorFunctionSection.xml +++ b/dev/tests/verification/TestModule/Section/LocatorFunctionSection.xml @@ -7,7 +7,7 @@ --> <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="LocatorFunctionSection"> <element name="simpleLocator" type="button" locatorFunction="contains('label', 'Name')"/> <element name="simpleLocatorOneParam" type="button" locatorFunction="contains({{arg1}}, 'Name')" parameterized="true"/> diff --git a/dev/tests/verification/TestModule/Section/SampleSection.xml b/dev/tests/verification/TestModule/Section/SampleSection.xml index 920ee6e1b..088d3e344 100644 --- a/dev/tests/verification/TestModule/Section/SampleSection.xml +++ b/dev/tests/verification/TestModule/Section/SampleSection.xml @@ -7,7 +7,7 @@ --> <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="SampleSection"> <element name="simpleElement" type="button" selector="#element"/> <element name="underscore_element" type="button" selector="#element"/> diff --git a/dev/tests/verification/TestModule/Suite/functionalSuite/functionalSuite1.xml b/dev/tests/verification/TestModule/Suite/functionalSuite/functionalSuite1.xml index 8f5f4145e..5f78e043e 100644 --- a/dev/tests/verification/TestModule/Suite/functionalSuite/functionalSuite1.xml +++ b/dev/tests/verification/TestModule/Suite/functionalSuite/functionalSuite1.xml @@ -6,7 +6,7 @@ */ --> -<suites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Suite/etc/suiteSchema.xsd"> +<suites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Suite/etc/suiteSchema.xsd"> <suite name="functionalSuite1"> <include> <group name = "include" /> diff --git a/dev/tests/verification/TestModule/Suite/functionalSuite/functionalSuite2.xml b/dev/tests/verification/TestModule/Suite/functionalSuite/functionalSuite2.xml index 5f926fbc3..c65cf6cfc 100644 --- a/dev/tests/verification/TestModule/Suite/functionalSuite/functionalSuite2.xml +++ b/dev/tests/verification/TestModule/Suite/functionalSuite/functionalSuite2.xml @@ -6,7 +6,7 @@ */ --> -<suites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Suite/etc/suiteSchema.xsd"> +<suites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Suite/etc/suiteSchema.xsd"> <suite name="functionalSuite2"> <include> <group name="include"/> diff --git a/dev/tests/verification/TestModule/Suite/functionalSuite/functionalSuiteWithComments.xml b/dev/tests/verification/TestModule/Suite/functionalSuite/functionalSuiteWithComments.xml index 471f2312d..ffc0e15db 100644 --- a/dev/tests/verification/TestModule/Suite/functionalSuite/functionalSuiteWithComments.xml +++ b/dev/tests/verification/TestModule/Suite/functionalSuite/functionalSuiteWithComments.xml @@ -6,7 +6,7 @@ */ --> -<suites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../src/Magento/FunctionalTestingFramework/Suite/etc/suiteSchema.xsd"> +<suites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Suite/etc/suiteSchema.xsd"> <suite name="functionalSuiteWithComments"> <include> <!-- Comment Block--> diff --git a/dev/tests/verification/TestModule/Suite/functionalSuiteExtends.xml b/dev/tests/verification/TestModule/Suite/functionalSuiteExtends.xml index aac3b51e5..44af78d20 100644 --- a/dev/tests/verification/TestModule/Suite/functionalSuiteExtends.xml +++ b/dev/tests/verification/TestModule/Suite/functionalSuiteExtends.xml @@ -6,7 +6,7 @@ */ --> -<suites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../src/Magento/FunctionalTestingFramework/Suite/etc/suiteSchema.xsd"> +<suites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Suite/etc/suiteSchema.xsd"> <suite name="suiteExtends"> <include> <group name="ExtendedTestInSuite"/> diff --git a/dev/tests/verification/TestModule/Suite/functionalSuiteHooks.xml b/dev/tests/verification/TestModule/Suite/functionalSuiteHooks.xml index f86f8c43c..4fc459e7d 100644 --- a/dev/tests/verification/TestModule/Suite/functionalSuiteHooks.xml +++ b/dev/tests/verification/TestModule/Suite/functionalSuiteHooks.xml @@ -6,7 +6,7 @@ */ --> -<suites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../src/Magento/FunctionalTestingFramework/Suite/etc/suiteSchema.xsd"> +<suites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Suite/etc/suiteSchema.xsd"> <suite name="functionalSuiteHooks"> <include> <test name="IncludeTest"/> diff --git a/dev/tests/verification/TestModule/Test/AssertTest.xml b/dev/tests/verification/TestModule/Test/AssertTest.xml index 8cdc724cc..6536f6cf7 100644 --- a/dev/tests/verification/TestModule/Test/AssertTest.xml +++ b/dev/tests/verification/TestModule/Test/AssertTest.xml @@ -7,7 +7,7 @@ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="AssertTest"> <before> <createData entity="ReplacementPerson" stepKey="createData1"/> diff --git a/dev/tests/verification/TestModule/Test/CharacterReplacementTest.xml b/dev/tests/verification/TestModule/Test/CharacterReplacementTest.xml index 9a8c0f17d..85b3fb34e 100644 --- a/dev/tests/verification/TestModule/Test/CharacterReplacementTest.xml +++ b/dev/tests/verification/TestModule/Test/CharacterReplacementTest.xml @@ -7,7 +7,7 @@ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="CharacterReplacementTest"> <click stepKey="charsInSectionElement" selector="{{SampleSection.underscore_element}}"/> <fillField stepKey="charsInDataRef" selector="{{SampleSection.underscore_element}}" userInput="{{simpleData.street[0]}}"/> diff --git a/dev/tests/verification/TestModule/Test/DataActionsTest.xml b/dev/tests/verification/TestModule/Test/DataActionsTest.xml index 03d7caa35..b75bc98f8 100644 --- a/dev/tests/verification/TestModule/Test/DataActionsTest.xml +++ b/dev/tests/verification/TestModule/Test/DataActionsTest.xml @@ -7,7 +7,7 @@ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="DataActionsTest"> <before> <createData entity="entity" stepKey="createdInBefore"/> diff --git a/dev/tests/verification/TestModule/Test/DataReplacementTest.xml b/dev/tests/verification/TestModule/Test/DataReplacementTest.xml index ae11b6fdc..f33a95b50 100644 --- a/dev/tests/verification/TestModule/Test/DataReplacementTest.xml +++ b/dev/tests/verification/TestModule/Test/DataReplacementTest.xml @@ -7,7 +7,7 @@ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="DataReplacementTest"> <fillField stepKey="inputReplace" selector="#selector" userInput="StringBefore {{simpleData.firstname}} StringAfter"/> <seeCurrentUrlMatches stepKey="seeInRegex" regex="~\/{{simpleData.firstname}}~i"/> diff --git a/dev/tests/verification/TestModule/Test/DeprecatedEntitiesTest.xml b/dev/tests/verification/TestModule/Test/DeprecatedEntitiesTest.xml index 733a34e80..20c7ccd0b 100644 --- a/dev/tests/verification/TestModule/Test/DeprecatedEntitiesTest.xml +++ b/dev/tests/verification/TestModule/Test/DeprecatedEntitiesTest.xml @@ -7,7 +7,7 @@ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="DeprecatedEntitiesTest"> <actionGroup ref="DeprecatedActionGroup" stepKey="deprecatedActionGroup" /> <amOnPage url="{{DeprecatedPage.url}}" stepKey="amOnPage" /> diff --git a/dev/tests/verification/TestModule/Test/DeprecatedTest.xml b/dev/tests/verification/TestModule/Test/DeprecatedTest.xml index cc5ae4994..075e8add3 100644 --- a/dev/tests/verification/TestModule/Test/DeprecatedTest.xml +++ b/dev/tests/verification/TestModule/Test/DeprecatedTest.xml @@ -7,7 +7,7 @@ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="DeprecatedTest" deprecated="Test is deprecated"> <actionGroup ref="DeprecatedActionGroup" stepKey="deprecatedActionGroup" /> <amOnPage url="{{DeprecatedPage.url}}" stepKey="amOnPage" /> diff --git a/dev/tests/verification/TestModule/Test/ExecuteJsTest.xml b/dev/tests/verification/TestModule/Test/ExecuteJsTest.xml index b361cdd28..ea80275e1 100644 --- a/dev/tests/verification/TestModule/Test/ExecuteJsTest.xml +++ b/dev/tests/verification/TestModule/Test/ExecuteJsTest.xml @@ -7,7 +7,7 @@ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="ExecuteJsEscapingTest"> <executeJS function="return $javascriptVariable" stepKey="javaVariableEscape"/> <executeJS function="return {$doNotEscape}" stepKey="mftfVariableNotEscaped"/> diff --git a/dev/tests/verification/TestModule/Test/ExtendedDataTest.xml b/dev/tests/verification/TestModule/Test/ExtendedDataTest.xml index 21f06eb3a..053b26c38 100644 --- a/dev/tests/verification/TestModule/Test/ExtendedDataTest.xml +++ b/dev/tests/verification/TestModule/Test/ExtendedDataTest.xml @@ -7,7 +7,7 @@ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="ExtendParentDataTest"> <createData entity="extendParentData" stepKey="simpleDataKey"/> <searchAndMultiSelectOption selector="#selector" parameterArray="[{{extendParentData.name}}]" stepKey="getName"/> diff --git a/dev/tests/verification/TestModule/Test/HookActionsTest.xml b/dev/tests/verification/TestModule/Test/HookActionsTest.xml index 7e3521e4f..0a26256d0 100644 --- a/dev/tests/verification/TestModule/Test/HookActionsTest.xml +++ b/dev/tests/verification/TestModule/Test/HookActionsTest.xml @@ -7,7 +7,7 @@ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="HookActionsTest"> <before> <createData entity="sampleCreatedEntity" stepKey="sampleCreateBefore"/> diff --git a/dev/tests/verification/TestModule/Test/LocatorFunctionTest.xml b/dev/tests/verification/TestModule/Test/LocatorFunctionTest.xml index f9caa59fc..eefd75e1f 100644 --- a/dev/tests/verification/TestModule/Test/LocatorFunctionTest.xml +++ b/dev/tests/verification/TestModule/Test/LocatorFunctionTest.xml @@ -7,7 +7,7 @@ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="LocatorFunctionTest"> <createData entity="ReplacementPerson" stepKey="data"/> diff --git a/dev/tests/verification/TestModule/Test/PageReplacementTest.xml b/dev/tests/verification/TestModule/Test/PageReplacementTest.xml index b6adee5d7..8cd6fe572 100644 --- a/dev/tests/verification/TestModule/Test/PageReplacementTest.xml +++ b/dev/tests/verification/TestModule/Test/PageReplacementTest.xml @@ -7,7 +7,7 @@ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="PageReplacementTest"> <createData entity="simpleData" stepKey="datakey"/> <amOnPage stepKey="noParamPage" url="{{NoParamPage.url}}"/> diff --git a/dev/tests/verification/TestModule/Test/ParameterArrayTest.xml b/dev/tests/verification/TestModule/Test/ParameterArrayTest.xml index e9bef4244..8bb57ae74 100644 --- a/dev/tests/verification/TestModule/Test/ParameterArrayTest.xml +++ b/dev/tests/verification/TestModule/Test/ParameterArrayTest.xml @@ -7,7 +7,7 @@ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="ParameterArrayTest"> <createData entity="simpleParamData" stepKey="simpleDataKey"/> <searchAndMultiSelectOption selector="#selector" parameterArray="[{{simpleParamData.name}}]" stepKey="xmlSimpleReplace"/> diff --git a/dev/tests/verification/TestModule/Test/PersistedReplacementTest.xml b/dev/tests/verification/TestModule/Test/PersistedReplacementTest.xml index 4b0f3c902..ba86a1a5d 100644 --- a/dev/tests/verification/TestModule/Test/PersistedReplacementTest.xml +++ b/dev/tests/verification/TestModule/Test/PersistedReplacementTest.xml @@ -7,7 +7,7 @@ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="PersistedReplacementTest"> <before> <createData entity="ReplacementPerson" stepKey="createData1"/> diff --git a/dev/tests/verification/TestModule/Test/PersistenceActionGroupAppendingTest.xml b/dev/tests/verification/TestModule/Test/PersistenceActionGroupAppendingTest.xml index 20a9b6a28..c76409f26 100644 --- a/dev/tests/verification/TestModule/Test/PersistenceActionGroupAppendingTest.xml +++ b/dev/tests/verification/TestModule/Test/PersistenceActionGroupAppendingTest.xml @@ -7,7 +7,7 @@ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="PersistenceActionGroupAppendingTest"> <before> <actionGroup ref="DataPersistenceAppendingActionGroup" stepKey="ACTIONGROUPBEFORE"/> diff --git a/dev/tests/verification/TestModule/Test/PersistenceCustomFieldsTest.xml b/dev/tests/verification/TestModule/Test/PersistenceCustomFieldsTest.xml index c56106693..77a85060b 100644 --- a/dev/tests/verification/TestModule/Test/PersistenceCustomFieldsTest.xml +++ b/dev/tests/verification/TestModule/Test/PersistenceCustomFieldsTest.xml @@ -7,7 +7,7 @@ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="PersistenceCustomFieldsTest"> <before> <createData entity="DefaultPerson" stepKey="createData1"> diff --git a/dev/tests/verification/TestModule/Test/SecretCredentialDataTest.xml b/dev/tests/verification/TestModule/Test/SecretCredentialDataTest.xml index 4044a86e3..d87be5d3b 100644 --- a/dev/tests/verification/TestModule/Test/SecretCredentialDataTest.xml +++ b/dev/tests/verification/TestModule/Test/SecretCredentialDataTest.xml @@ -7,7 +7,7 @@ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="secretCredentialDataTest"> <createData entity="_defaultProduct" stepKey="createProductWithFieldOverridesUsingHardcodedData1"> <field key="qty">123</field> diff --git a/dev/tests/verification/TestModule/Test/SectionReplacementTest.xml b/dev/tests/verification/TestModule/Test/SectionReplacementTest.xml index 17aeb4d69..3b066fcdf 100644 --- a/dev/tests/verification/TestModule/Test/SectionReplacementTest.xml +++ b/dev/tests/verification/TestModule/Test/SectionReplacementTest.xml @@ -7,7 +7,7 @@ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="SectionReplacementTest"> <click stepKey="selectorReplace" selector="{{SampleSection.simpleElement}}"/> <click stepKey="selectorReplaceTimeout" selector="{{SampleSection.timeoutElement}}"/> diff --git a/dev/tests/verification/TestModule/Test/XmlCommentedActionGroupTest.xml b/dev/tests/verification/TestModule/Test/XmlCommentedActionGroupTest.xml index f7fbd8dd6..b464dfc4c 100644 --- a/dev/tests/verification/TestModule/Test/XmlCommentedActionGroupTest.xml +++ b/dev/tests/verification/TestModule/Test/XmlCommentedActionGroupTest.xml @@ -6,7 +6,7 @@ */ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="XmlCommentedActionGroupTest"> <annotations> <severity value="CRITICAL"/> diff --git a/dev/tests/verification/TestModule/Test/XmlCommentedTest.xml b/dev/tests/verification/TestModule/Test/XmlCommentedTest.xml index 133588872..1da6a1fc0 100644 --- a/dev/tests/verification/TestModule/Test/XmlCommentedTest.xml +++ b/dev/tests/verification/TestModule/Test/XmlCommentedTest.xml @@ -6,7 +6,7 @@ */ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <!--< > & $abc " abc ' <click stepKey="click" userInput="$$createDataHook.firstname$$" selector="#id">/--> <test name="XmlCommentedTest"> <annotations> diff --git a/dev/tests/verification/TestModuleMerged/Data/MergeData.xml b/dev/tests/verification/TestModuleMerged/Data/MergeData.xml index 72d0dca61..531922aed 100644 --- a/dev/tests/verification/TestModuleMerged/Data/MergeData.xml +++ b/dev/tests/verification/TestModuleMerged/Data/MergeData.xml @@ -8,7 +8,7 @@ --> <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> <entity name="DefaultPerson" type="samplePerson"> <data key="mergedField">merged</data> <data key="newField">newField</data> diff --git a/dev/tests/verification/TestModuleMerged/Section/MergeSection.xml b/dev/tests/verification/TestModuleMerged/Section/MergeSection.xml index fb661e906..6bbd862ae 100644 --- a/dev/tests/verification/TestModuleMerged/Section/MergeSection.xml +++ b/dev/tests/verification/TestModuleMerged/Section/MergeSection.xml @@ -7,7 +7,7 @@ --> <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="SampleSection"> <element name="oneParamElement" type="button" selector="#element .{{var1}}" parameterized="true"/> <element name="twoParamElement" type="button" selector="#{{var1}} .{{var2}}" parameterized="true"/> diff --git a/dev/tests/verification/TestModuleMerged/Test/MergeXmlDuplicateTest.xml b/dev/tests/verification/TestModuleMerged/Test/MergeXmlDuplicateTest.xml index 2d99d5cbc..c9c731134 100644 --- a/dev/tests/verification/TestModuleMerged/Test/MergeXmlDuplicateTest.xml +++ b/dev/tests/verification/TestModuleMerged/Test/MergeXmlDuplicateTest.xml @@ -7,7 +7,7 @@ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="BasicDupedActionTest"> <before> <createData entity="simpleData" stepKey="cb3"> diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateTestSchemaPaths.php b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateTestSchemaPaths.php index 7a08b39df..09140d1cd 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateTestSchemaPaths.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateTestSchemaPaths.php @@ -9,7 +9,6 @@ use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Util\Script\ScriptUtil; use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Finder\Finder; use Symfony\Component\Console\Output\OutputInterface; @@ -19,6 +18,35 @@ */ class UpdateTestSchemaPaths implements UpgradeInterface { + /** + * OutputInterface + * + * @var OutputInterface + */ + private $output; + + /** + * Total test updated + * + * @var integer + */ + private $testsUpdated = 0; + + /** + * Entity type to urn map + * + * @var array + */ + private $typeToUrns = [ + 'ActionGroup' => 'urn:magento:mftf:Test/etc/actionGroupSchema.xsd', + 'Data' => 'urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd', + 'Metadata' => 'urn:magento:mftf:DataGenerator/etc/dataOperation.xsd', + 'Page' => 'urn:magento:mftf:Page/etc/PageObject.xsd', + 'Section' => 'urn:magento:mftf:Page/etc/SectionObject.xsd', + 'Suite' => 'urn:magento:mftf:Suite/etc/suiteSchema.xsd', + 'Test' => 'urn:magento:mftf:Test/etc/testSchema.xsd', + ]; + /** * Upgrades all test xml files, replacing relative schema paths to URN. * @@ -29,56 +57,42 @@ class UpdateTestSchemaPaths implements UpgradeInterface */ public function execute(InputInterface $input, OutputInterface $output) { - // @codingStandardsIgnoreStart - $relativeToUrn = [ - "dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd" - => "urn:magento:mftf:DataGenerator/etc/dataOperation.xsd", - "dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd" - => "urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd", - "dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd" - => "urn:magento:mftf:Page/etc/PageObject.xsd", - "dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd" - => "urn:magento:mftf:Page/etc/SectionObject.xsd", - "dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd" - => "urn:magento:mftf:Test/etc/actionGroupSchema.xsd", - "dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd" - => "urn:magento:mftf:Test/etc/testSchema.xsd", - "dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Suite/etc/suiteSchema.xsd" - => "urn:magento:mftf:Suite/etc/suiteSchema.xsd" - ]; - // @codingStandardsIgnoreEnd - - $relativePatterns = []; - $urns = []; - // Prepare array of patterns to URNs for preg_replace (replace / to escapes - foreach ($relativeToUrn as $relative => $urn) { - $relativeReplaced = str_replace('/', '\/', $relative); - $relativePatterns[] = '/[.\/]+' . $relativeReplaced . '/'; - $urns[] = $urn; - } - - $testsUpdated = 0; + $this->output = $output; + $this->testsUpdated = 0; $testPaths[] = $input->getArgument('path'); if (empty($testPaths[0])) { $testPaths = ScriptUtil::getAllModulePaths(); } - foreach ($testPaths as $testsPath) { - $finder = new Finder(); - $finder->files()->in($testsPath)->name("*.xml"); + // Process module xml files + foreach ($this->typeToUrns as $type => $urn) { + $xmlFiles = ScriptUtil::getModuleXmlFilesByScope($testPaths, $type); + $this->processXmlFiles($xmlFiles, $urn); + } + + return ("Schema Path updated to use MFTF URNs in {$this->testsUpdated} file(s)."); + } - $fileSystem = new Filesystem(); - foreach ($finder->files() as $file) { - $count = 0; - $contents = $file->getContents(); - $contents = preg_replace($relativePatterns, $urns, $contents, -1, $count); - $fileSystem->dumpFile($file->getRealPath(), $contents); - if ($count > 0) { - $testsUpdated++; + /** + * Convert xml schema location from non urn based to urn based + * + * @param Finder $xmlFiles + * @param string $urn + * @return void + */ + private function processXmlFiles($xmlFiles, $urn) + { + $pattern = '/xsi:noNamespaceSchemaLocation[\s]*=[\s]*"(?<urn>[^\<\>"\']*)"/'; + foreach ($xmlFiles as $file) { + $filePath = $file->getRealPath(); + $contents = $file->getContents(); + preg_match($pattern, $contents, $matches); + if (isset($matches['urn'])) { + if (trim($matches['urn']) !== $urn) { + file_put_contents($filePath, str_replace($matches['urn'], $urn, $contents)); + $this->testsUpdated++; } } } - - return ("Schema Path updated to use MFTF URNs in {$testsUpdated} file(s)."); } } From a5b03de001e8d0d96a7832db4a8997a14a1fa72c Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 10 Mar 2020 13:57:52 -0500 Subject: [PATCH 268/888] MQE-2013: fixed UpdateTestSchemaPaths upgrade script --- docs/commands/mftf.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 0e55e97c1..88b9d319d 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -506,16 +506,18 @@ vendor/bin/mftf static-checks testDependencies actionGroupArguments ### `upgrade:tests` -When the path argument is specified, this command applies all the major version MFTF upgrade scripts to the test components in the given path (test.xml, data.xml, etc). +When the path argument is specified, this `upgrade` command applies all the major version MFTF upgrade scripts to a `Test Module` in the given path. Otherwise, it will apply all the major version MFTF upgrade scripts to all installed test components. +`Test Module` should have the directory structure of ActionGroup, Data, Metadata, Page, Section, Test, and Suite. + #### Usage ```bash vendor/bin/mftf upgrade:tests [<path>] ``` -`<path>` is the path that contains MFTF test components that need to be upgraded. +`<path>` is the path to a MFTF `Test Module` that needs to be upgraded. The command searches recursively for any `*.xml` files to upgrade. #### Examples From 1efdb2295334f782481d04c861020c0103e698b5 Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Tue, 10 Mar 2020 15:10:21 -0500 Subject: [PATCH 269/888] MQE-2016: Add warning for test materials that violate naming convention --- .../Handlers/DataObjectHandler.php | 28 +- .../OperationDefinitionObjectHandler.php | 6 + .../Page/Handlers/PageObjectHandler.php | 7 +- .../Page/Handlers/SectionObjectHandler.php | 12 +- .../Handlers/ActionGroupObjectHandler.php | 10 +- .../Test/Handlers/TestObjectHandler.php | 9 +- .../Util/Validation/NameValidationUtil.php | 260 ++++++++++++++++++ 7 files changed, 322 insertions(+), 10 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php index a210710db..7f59f5234 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php @@ -14,6 +14,7 @@ use Magento\FunctionalTestingFramework\ObjectManagerFactory; use Magento\FunctionalTestingFramework\DataGenerator\Util\DataExtensionUtil; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; +use Magento\FunctionalTestingFramework\Util\Validation\NameValidationUtil; class DataObjectHandler implements ObjectHandlerInterface { @@ -58,6 +59,20 @@ class DataObjectHandler implements ObjectHandlerInterface */ private $extendUtil; + /** + * Validates and keeps track of entity name violations. + * + * @var NameValidationUtil + */ + private $entityNameValidator; + + /** + * Validates and keeps track of entity key violations. + * + * @var NameValidationUtil + */ + private $entityKeyValidator; + /** * Constructor */ @@ -68,6 +83,8 @@ private function __construct() if (!$parserOutput) { return; } + $this->entityNameValidator = new NameValidationUtil(); + $this->entityKeyValidator = new NameValidationUtil(); $this->entityDataObjects = $this->processParserOutput($parserOutput); $this->extendUtil = new DataExtensionUtil(); } @@ -132,6 +149,8 @@ private function processParserOutput($parserOutput) throw new XmlException(sprintf(self::DATA_NAME_ERROR_MSG, $name)); } + $filename = $rawEntity[self::_FILENAME] ?? null; + $this->entityNameValidator->validateDataEntityName($name, $filename); $type = $rawEntity[self::_TYPE] ?? null; $data = []; $deprecated = null; @@ -139,7 +158,6 @@ private function processParserOutput($parserOutput) $uniquenessData = []; $vars = []; $parentEntity = null; - $filename = $rawEntity[self::_FILENAME] ?? null; if (array_key_exists(self::_DATA, $rawEntity)) { $data = $this->processDataElements($rawEntity); @@ -188,7 +206,8 @@ private function processParserOutput($parserOutput) $entityDataObjects[$entityDataObject->getName()] = $entityDataObject; } - + $this->entityNameValidator->summarize("data entity name"); + $this->entityKeyValidator->summarize("data entity key"); return $entityDataObjects; } @@ -220,7 +239,10 @@ private function processDataElements($entityData) { $dataValues = []; foreach ($entityData[self::_DATA] as $dataElement) { - $dataElementKey = strtolower($dataElement[self::_KEY]); + $originalDataElementKey = $dataElement[self::_KEY]; + $filename = $entityData[self::_FILENAME] ?? null; + $this->entityKeyValidator->validateDataEntityKey($originalDataElementKey, $filename); + $dataElementKey = strtolower($originalDataElementKey); $dataElementValue = $dataElement[self::_VALUE] ?? ""; $dataValues[$dataElementKey] = $dataElementValue; } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php index 8c2ec7b0a..d01b36528 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php @@ -12,6 +12,7 @@ use Magento\FunctionalTestingFramework\ObjectManager\ObjectHandlerInterface; use Magento\FunctionalTestingFramework\ObjectManagerFactory; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; +use Magento\FunctionalTestingFramework\Util\Validation\NameValidationUtil; class OperationDefinitionObjectHandler implements ObjectHandlerInterface { @@ -136,7 +137,11 @@ private function initialize() $objectManager = ObjectManagerFactory::getObjectManager(); $parser = $objectManager->create(OperationDefinitionParser::class); $parserOutput = $parser->readOperationMetadata()[OperationDefinitionObjectHandler::ENTITY_OPERATION_ROOT_TAG]; + + $operationNameValidator = new NameValidationUtil(); foreach ($parserOutput as $dataDefName => $opDefArray) { + $operationNameValidator->validateMetadataOperationName($dataDefName); + $operation = $opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_TYPE]; $dataType = $opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE]; $url = $opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_URL] ?? null; @@ -230,6 +235,7 @@ private function initialize() $deprecated ); } + $operationNameValidator->summarize("metadata operation name"); } /** diff --git a/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php b/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php index c310b9bef..1fc8dfd34 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php @@ -10,6 +10,7 @@ use Magento\FunctionalTestingFramework\ObjectManagerFactory; use Magento\FunctionalTestingFramework\Page\Objects\PageObject; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; +use Magento\FunctionalTestingFramework\Util\Validation\NameValidationUtil; use Magento\FunctionalTestingFramework\XmlParser\PageParser; use Magento\FunctionalTestingFramework\Exceptions\XmlException; @@ -54,10 +55,14 @@ private function __construct() return; } + $pageNameValidator = new NameValidationUtil(); foreach ($parserOutput as $pageName => $pageData) { if (preg_match('/[^a-zA-Z0-9_]/', $pageName)) { throw new XmlException(sprintf(self::NAME_BLACKLIST_ERROR_MSG, $pageName)); } + + $filename = $pageData[self::FILENAME] ?? null; + $pageNameValidator->validatePageName($pageName, $filename); $area = $pageData[self::AREA] ?? null; $url = $pageData[self::URL] ?? null; @@ -68,7 +73,6 @@ private function __construct() $module = $pageData[self::MODULE] ?? null; $sectionNames = array_keys($pageData[self::SECTION] ?? []); $parameterized = $pageData[self::PARAMETERIZED] ?? false; - $filename = $pageData[self::FILENAME] ?? null; $deprecated = $pageData[self::OBJ_DEPRECATED] ?? null; if ($deprecated !== null) { @@ -81,6 +85,7 @@ private function __construct() $this->pageObjects[$pageName] = new PageObject($pageName, $url, $module, $sectionNames, $parameterized, $area, $filename, $deprecated); } + $pageNameValidator->summarize("page name"); } /** diff --git a/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php b/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php index 2736100fd..09d073d33 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php @@ -10,8 +10,8 @@ use Magento\FunctionalTestingFramework\ObjectManagerFactory; use Magento\FunctionalTestingFramework\Page\Objects\ElementObject; use Magento\FunctionalTestingFramework\Page\Objects\SectionObject; -use Magento\FunctionalTestingFramework\Test\Util\TestObjectExtractor; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; +use Magento\FunctionalTestingFramework\Util\Validation\NameValidationUtil; use Magento\FunctionalTestingFramework\XmlParser\SectionParser; use Magento\FunctionalTestingFramework\Exceptions\XmlException; @@ -58,6 +58,8 @@ private function __construct() return; } + $sectionNameValidator = new NameValidationUtil(); + $elementNameValidator = new NameValidationUtil(); foreach ($parserOutput as $sectionName => $sectionData) { $elements = []; @@ -65,11 +67,16 @@ private function __construct() throw new XmlException(sprintf(self::SECTION_NAME_ERROR_MSG, $sectionName)); } + $filename = $sectionData[self::FILENAME] ?? null; + $sectionNameValidator->validateSectionName($sectionName, $filename); + try { foreach ($sectionData[SectionObjectHandler::ELEMENT] as $elementName => $elementData) { if (preg_match('/[^a-zA-Z0-9_]/', $elementName)) { throw new XmlException(sprintf(self::ELEMENT_NAME_ERROR_MSG, $elementName, $sectionName)); } + + $elementNameValidator->validateElementName($elementName, $filename); $elementType = $elementData[SectionObjectHandler::TYPE] ?? null; $elementSelector = $elementData[SectionObjectHandler::SELECTOR] ?? null; $elementLocatorFunc = $elementData[SectionObjectHandler::LOCATOR_FUNCTION] ?? null; @@ -96,7 +103,6 @@ private function __construct() throw new XmlException($exception->getMessage() . " in Section '{$sectionName}'"); } - $filename = $sectionData[self::FILENAME] ?? null; $sectionDeprecated = $sectionData[self::OBJ_DEPRECATED] ?? null; if ($sectionDeprecated !== null) { @@ -113,6 +119,8 @@ private function __construct() $sectionDeprecated ); } + $sectionNameValidator->summarize("section name"); + $elementNameValidator->summarize("element name"); } /** diff --git a/src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php b/src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php index 131ae0a26..47dacf200 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php @@ -9,10 +9,10 @@ use Magento\FunctionalTestingFramework\ObjectManager\ObjectHandlerInterface; use Magento\FunctionalTestingFramework\ObjectManagerFactory; use Magento\FunctionalTestingFramework\Test\Objects\ActionGroupObject; -use Magento\FunctionalTestingFramework\Test\Objects\TestObject; use Magento\FunctionalTestingFramework\Test\Parsers\ActionGroupDataParser; use Magento\FunctionalTestingFramework\Test\Util\ActionGroupObjectExtractor; use Magento\FunctionalTestingFramework\Test\Util\ObjectExtensionUtil; +use Magento\FunctionalTestingFramework\Util\Validation\NameValidationUtil; /** * Class ActionGroupObjectHandler @@ -22,6 +22,7 @@ class ActionGroupObjectHandler implements ObjectHandlerInterface const BEFORE_AFTER_ERROR_MSG = "Merge Error - Steps cannot have both before and after attributes.\tTestStep='%s'"; const ACTION_GROUP_ROOT = 'actionGroups'; const ACTION_GROUP = 'actionGroup'; + const ACTION_GROUP_FILENAME_ATTRIBUTE = 'filename'; /** * Single instance of class var @@ -110,7 +111,13 @@ private function initActionGroups() $actionGroupObjectExtractor = new ActionGroupObjectExtractor(); $neededActionGroup = $parsedActionGroups[ActionGroupObjectHandler::ACTION_GROUP_ROOT]; + $actionGroupNameValidator = new NameValidationUtil(); foreach ($neededActionGroup as $actionGroupName => $actionGroupData) { + if (!in_array($actionGroupName, ["nodeName", "xsi:noNamespaceSchemaLocation"])) { + $filename = $actionGroupData[ActionGroupObjectHandler::ACTION_GROUP_FILENAME_ATTRIBUTE]; + $actionGroupNameValidator->validateActionGroupName($actionGroupName, $filename); + } + if (!is_array($actionGroupData)) { continue; } @@ -118,6 +125,7 @@ private function initActionGroups() $this->actionGroups[$actionGroupName] = $actionGroupObjectExtractor->extractActionGroup($actionGroupData); } + $actionGroupNameValidator->summarize("action group name"); } /** diff --git a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php index d5ed43806..8a72415f8 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php @@ -15,9 +15,8 @@ use Magento\FunctionalTestingFramework\Test\Parsers\TestDataParser; use Magento\FunctionalTestingFramework\Test\Util\ObjectExtensionUtil; use Magento\FunctionalTestingFramework\Test\Util\TestObjectExtractor; -use Magento\FunctionalTestingFramework\Test\Util\AnnotationExtractor; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; -use PHP_CodeSniffer\Tokenizers\PHP; +use Magento\FunctionalTestingFramework\Util\Validation\NameValidationUtil; /** * Class TestObjectHandler @@ -25,6 +24,7 @@ class TestObjectHandler implements ObjectHandlerInterface { const XML_ROOT = 'tests'; + const TEST_FILENAME_ATTRIBUTE = 'filename'; /** * Test Object Handler @@ -142,7 +142,10 @@ private function initTestData() } $exceptionCollector = new ExceptionCollector(); + $testNameValidator = new NameValidationUtil(); foreach ($parsedTestArray as $testName => $testData) { + $filename = $testData[TestObjectHandler::TEST_FILENAME_ATTRIBUTE]; + $testNameValidator->validateTestName($testName, $filename); if (!is_array($testData)) { continue; } @@ -153,7 +156,7 @@ private function initTestData() } } $exceptionCollector->throwException(); - + $testNameValidator->summarize("test name"); $testObjectExtractor->getAnnotationExtractor()->validateStoryTitleUniqueness(); $testObjectExtractor->getAnnotationExtractor()->validateTestCaseIdTitleUniqueness(); } diff --git a/src/Magento/FunctionalTestingFramework/Util/Validation/NameValidationUtil.php b/src/Magento/FunctionalTestingFramework/Util/Validation/NameValidationUtil.php index 60b4660fb..50918c146 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Validation/NameValidationUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/Validation/NameValidationUtil.php @@ -6,12 +6,30 @@ namespace Magento\FunctionalTestingFramework\Util\Validation; +use Exception; use Magento\FunctionalTestingFramework\Exceptions\XmlException; +use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; class NameValidationUtil { const PHP_CLASS_REGEX_PATTERN = '/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/'; + /** + * The number of violations this instance has detected. + * + * @var integer + */ + private $count; + + /** + * NameValidationUtil constructor. + * + */ + public function __construct() + { + $this->count = 0; + } + /** * Function which runs a validation against the blacklisted char defined in this class. Validation occurs to insure * allure report does not error/future devOps builds do not error against illegal char. @@ -50,4 +68,246 @@ public static function validateName($name, $type) throw new XmlException($errorMessage); } } + + /** + * Validates data entity names. + * + * @param string $str + * @param string $filename + * @throws Exception + * @return void + */ + public function validateDataEntityName($str, $filename = null) + { + if (!ctype_upper($str[0])) { + $message = "The data entity name {$str} should be PascalCase with an uppercase first letter."; + + if ($filename !== null) { + $message .= " See file {$filename}."; + } + + LoggingUtil::getInstance()->getLogger(self::class)->notification( + $message, + [], + false + ); + + $this->count++; + } + } + + /** + * Validates data entity key names. + * + * @param string $str + * @param string $filename + * @throws Exception + * @return void + */ + public function validateDataEntityKey($str, $filename = null) + { + if (!ctype_lower($str[0])) { + $message = "The data entity key {$str} should be camelCase with a lowercase first letter."; + + if ($filename !== null) { + $message .= " See file {$filename}."; + } + + LoggingUtil::getInstance()->getLogger(self::class)->notification( + $message, + [], + false + ); + + $this->count++; + } + } + + /** + * Validates metadata operation names. + * + * @param string $str + * @param string $filename + * @throws Exception + * @return void + */ + public function validateMetadataOperationName($str, $filename = null) + { + if (!ctype_upper($str[0])) { + $message = "The metadata operation name {$str} should be PascalCase with an uppercase first letter."; + + if ($filename !== null) { + $message .= " See file {$filename}."; + } + + LoggingUtil::getInstance()->getLogger(self::class)->notification( + $message, + [], + false + ); + + $this->count++; + } + } + + /** + * Validates page names. + * + * @param string $str + * @param string $filename + * @throws Exception + * @return void + */ + public function validatePageName($str, $filename = null) + { + $isPrefixAdmin = substr($str, 0, 5) === "Admin"; + $isPrefixStorefront = substr($str, 0, 10) === "Storefront"; + $isSuffixPage = substr($str, -4) === "Page"; + + if ((!$isPrefixAdmin && !$isPrefixStorefront) || !$isSuffixPage) { + $message = "The page name {$str} should follow the pattern {Admin or Storefront}{Description}Page."; + + if ($filename !== null) { + $message .= " See file {$filename}."; + } + + LoggingUtil::getInstance()->getLogger(self::class)->notification( + $message, + [], + false + ); + + $this->count++; + } + } + + /** + * Validates section names. + * + * @param string $str + * @param string $filename + * @throws Exception + * @return void + */ + public function validateSectionName($str, $filename = null) + { + $isPrefixAdmin = substr($str, 0, 5) === "Admin"; + $isPrefixStorefront = substr($str, 0, 10) === "Storefront"; + $isSuffixSection = substr($str, -7) === "Section"; + + if ((!$isPrefixAdmin && !$isPrefixStorefront) || !$isSuffixSection) { + $message = "The section name {$str} should follow the pattern {Admin or Storefront}{Description}Section."; + + if ($filename !== null) { + $message .= " See file {$filename}."; + } + + LoggingUtil::getInstance()->getLogger(self::class)->notification( + $message, + [], + false + ); + + $this->count++; + } + } + + /** + * Validates section element names. + * + * @param string $str + * @param string $filename + * @throws Exception + * @return void + */ + public function validateElementName($str, $filename = null) + { + if (!ctype_lower($str[0])) { + $message = "The element name {$str} should be camelCase with a lowercase first letter."; + + if ($filename !== null) { + $message .= " See file {$filename}."; + } + + LoggingUtil::getInstance()->getLogger(self::class)->notification( + $message, + [], + false + ); + + $this->count++; + } + } + + /** + * Validates action group names. + * + * @param string $str + * @param string $filename + * @throws Exception + * @return void + */ + public function validateActionGroupName($str, $filename = null) + { + if (!ctype_upper($str[0])) { + $message = "The action group name {$str} should be PascalCase with an uppercase first letter."; + + if ($filename !== null) { + $message .= " See file {$filename}."; + } + + LoggingUtil::getInstance()->getLogger(self::class)->notification( + $message, + [], + false + ); + + $this->count++; + } + } + + /** + * Validates test names. + * + * @param string $str + * @param string $filename + * @throws Exception + * @return void + */ + public function validateTestName($str, $filename = null) + { + if (!ctype_upper($str[0])) { + $message = "The test name {$str} should be PascalCase with an uppercase first letter."; + + if ($filename !== null) { + $message .= " See file {$filename}."; + } + + LoggingUtil::getInstance()->getLogger(self::class)->notification( + $message, + [], + false + ); + + $this->count++; + } + } + + /** + * Outputs the number of validations detected by this instance. + * + * @param string $type + * @throws Exception + * @return void + */ + public function summarize($type) + { + if ($this->count > 0) { + LoggingUtil::getInstance()->getLogger(self::class)->notification( + "{$this->count} {$type} violations detected. See mftf.log for details.", + [], + true + ); + } + } } From ab4dfb4ce5027b8815911c37301cf6b70958a4ca Mon Sep 17 00:00:00 2001 From: Lukasz Bajsarowicz <lukasz.bajsarowicz@gmail.com> Date: Wed, 11 Mar 2020 01:36:17 +0100 Subject: [PATCH 270/888] DevDocs: Test merging precedence --- docs/img/mftf-extending-precedence.png | Bin 0 -> 127088 bytes docs/merging.md | 10 ++++++++++ 2 files changed, 10 insertions(+) create mode 100644 docs/img/mftf-extending-precedence.png diff --git a/docs/img/mftf-extending-precedence.png b/docs/img/mftf-extending-precedence.png new file mode 100644 index 0000000000000000000000000000000000000000..deed5231f5592ca4a2f7dac8876361774f49b2c0 GIT binary patch literal 127088 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 literal 0 HcmV?d00001 diff --git a/docs/merging.md b/docs/merging.md index e4b91fb5f..9cb48c41f 100644 --- a/docs/merging.md +++ b/docs/merging.md @@ -27,6 +27,15 @@ For example: Although a file name does not influence merging, we recommend using the same file names in merging updates. This makes it easier to search later on. +## Merging precedence + +**Magento Functional Testing Framework** uses Module's `<sequence>` to merge all XML configurations into Codeception instructions. If there's no Sequence specified, MFTF would use: + +1. Vendor modules (Magento & Vendors) located in `vendor/` +1. Tests located in `app/code/*/*/Test/Mftf` + +![Usual precedence for merging MFTF Tests and resources][mftfExtendingPrecedence image] + ## Add a test You cannot add another [`<test>`][tests] using merging functionality. @@ -570,3 +579,4 @@ The `_defaultSample` results corresponds to: [`<sections>`]: ./section.md [`<tests>`]: ./test.md [`<action groups>`]: ./test/action-groups.md +[mftfExtendingPrecedence image]: img/mftf-extending-precedence.png From 86b55333c08e7c56903fd95dd1f7c472b8a53418 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Wed, 11 Mar 2020 09:29:54 -0500 Subject: [PATCH 271/888] MQE-2028: DevDoc & MFTF Notice for MFTF 3.0.0 specific upgrade instructions - Changelog instructions added --- CHANGELOG.md | 10 +++++++ docs/update.md | 79 -------------------------------------------------- 2 files changed, 10 insertions(+), 79 deletions(-) delete mode 100644 docs/update.md diff --git a/CHANGELOG.md b/CHANGELOG.md index a41360787..9b581c8ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ Magento Functional Testing Framework Changelog ================================================ +3.0.0 +----- +### Upgrade Instructions +* Run `bin/mftf reset --hard` to remove old generated configurations. +* Run `bin/mftf upgrade:tests`. [See command page for details](./docs/commands/mftf.md#upgradetests). +* After running the above command, you will need to manually update some tests: + * Remove all occurrences of `<executeInSelenium>` and `<performOn>` +* Lastly, try to generate and all tests. Tests should all be generating as a result of the upgrades. + If not, the most likely issue will be changed XML schema. You will need to check error messaging and search your codebase for the attributes listed. + 2.6.3 ----- diff --git a/docs/update.md b/docs/update.md deleted file mode 100644 index 129742346..000000000 --- a/docs/update.md +++ /dev/null @@ -1,79 +0,0 @@ -# Update the Magento Functional Testing Framework - -<div class="bs-callout bs-callout-info" markdown="1"> -[Find your version][] of the MFTF. - -The latest Magento 2.3 release supports MFTF 2.3.13. -The latest Magento 2.2 release supports MFTF 2.3.8. -</div> - -Magento tests and the framework are stored in different repositories. - -Magento tests are stored in the same repository as the Magento code base. -When you pull changes in the Magento code, you're potentially pulling corresponding tests as well. - -The MFTF is installed separately as a dependency using Composer. -When pulling the latest Magento code, update the corresponding Composer dependencies in the `magento2` root directory. -This ensures that the MFTF is up to date. - -## Update the MFTF from 2.3.x - -To update the MFTF to the latest patch: - -1. Verify that the Magento [WYSIWYG settings][] and [Security settings][] are set appropriately. -1. Check details about backward incompatible changes in the [Changelog][] and update your new or customized tests. -1. Get the latest framework version using Composer: - - ```bash - composer update - ``` - -1. Generate the updated tests: - - ```bash - vendor/bin/mftf generate:tests - ``` - -## Update the MFTF from 2.2 - -To update the MFTF from the previous minor version: - -1. When you update Magento, verify that the Magento [WYSIWYG settings][] and [Security settings][] are set appropriately. -1. Starting at the `magento2/` root directory remove the `vendor/` directory: - - ```bash - rm -rf vendor/ - ``` - -1. Get the latest framework version from the Composer dependencies: - - ```bash - composer install - ``` - -1. Run the `upgrade:tests` using the new command line tool: - - ```bash - vendor/bin/mftf upgrade:tests app - ``` - -1. If you are using Phpstorm, update the urn catalog: - - ```bash - vendor/bin/mftf generate:urn-catalog .idea/ - ``` - -1. Update your own tests, including data, metadata, and so on, if they contain tags that are unsupported in the newer version. - - Check details about backward incompatible changes and review new MFTF release documentation in the [Changelog][]. - -1. Generate newly pulled tests: - - ```bash - vendor/bin/mftf generate:tests - ``` - -<!-- Link Definitions --> -[Changelog]: https://github.com/magento/magento2-functional-testing-framework/blob/master/CHANGELOG.md -[WYSIWYG settings]: getting-started.md#wysiwyg-settings -[Security settings]: getting-started.md#security-settings From 21e7f2d4dbd5aab4096739db6381e7406e9edf19 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Wed, 11 Mar 2020 09:58:54 -0500 Subject: [PATCH 272/888] MQE-683: [Deprecation] Only use more nested assertion syntax - CR Fixes --- .../Test/etc/Actions/assertActions.xsd | 23 ------------------- .../Upgrade/UpdateAssertionSchema.php | 1 - 2 files changed, 24 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/assertActions.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/assertActions.xsd index 84752ee7b..22f306382 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/assertActions.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/assertActions.xsd @@ -49,22 +49,6 @@ </xs:group> <!-- Data Attributes --> - <xs:attribute type="xs:string" name="expected"> - <xs:annotation> - <xs:documentation> - Assertion's Expected value. Cast by expectedType. - </xs:documentation> - </xs:annotation> - </xs:attribute> - - <xs:attribute type="xs:string" name="actual"> - <xs:annotation> - <xs:documentation> - Assertion's Actual value. Cast by actualType. - </xs:documentation> - </xs:annotation> - </xs:attribute> - <xs:attribute type="xs:string" name="message"> <xs:annotation> <xs:documentation> @@ -112,13 +96,6 @@ <xs:choice maxOccurs="unbounded"> <xs:element name="expectedResult" type="expectedElementContainsType" minOccurs="0"/> </xs:choice> - <xs:attribute type="xs:string" name="expectedValue"> - <xs:annotation> - <xs:documentation> - Assertion's Expected value. Cast by expectedType. - </xs:documentation> - </xs:annotation> - </xs:attribute> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php index b8643f685..6e834b8de 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php @@ -34,7 +34,6 @@ public function execute(InputInterface $input) foreach ($finder->files() as $file) { $contents = $file->getContents(); // Isolate <assert ... /> but never <assert> ... </assert>, stops after finding first /> -// preg_match_all('/<assert[^>]*\/>/', $contents, $potentialAssertions); preg_match_all('/<assert.*\/>/', $contents, $potentialAssertions); $newAssertions = []; $index = 0; From 2827d98f3f1a38c942206ccc8c5c261aae0e69c1 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Wed, 11 Mar 2020 10:00:42 -0500 Subject: [PATCH 273/888] MQE-2028: DevDoc & MFTF Notice for MFTF 3.0.0 specific upgrade - Added version callout for docs. --- docs/introduction.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/introduction.md b/docs/introduction.md index 61c1eaef3..d68f67cf2 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -1,5 +1,10 @@ # Introduction to the Magento Functional Testing Framework +<div class="bs-callout bs-callout-info" markdown="1"> +These are the docs for the latest MFTF release. +To find older documentation, please refer to the `docs` folder inside you desired release in Github. +</div> + [Find your MFTF version][] of the MFTF. The Magento Functional Testing Framework (MFTF) aims to replace the [Functional Testing Framework] in future releases. From b3db4a209afca989283ac8edeb34a04352747108 Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Wed, 11 Mar 2020 10:25:57 -0500 Subject: [PATCH 274/888] MQE-2016: Add warning for test materials that violate naming convention --- .../Handlers/DataObjectHandler.php | 16 +- .../OperationDefinitionObjectHandler.php | 7 +- .../Page/Handlers/PageObjectHandler.php | 4 +- .../Page/Handlers/SectionObjectHandler.php | 12 +- .../Handlers/ActionGroupObjectHandler.php | 8 +- .../Test/Handlers/TestObjectHandler.php | 4 +- .../Util/Validation/NameValidationUtil.php | 173 +++--------------- 7 files changed, 58 insertions(+), 166 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php index 7f59f5234..26b603915 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php @@ -150,7 +150,11 @@ private function processParserOutput($parserOutput) } $filename = $rawEntity[self::_FILENAME] ?? null; - $this->entityNameValidator->validateDataEntityName($name, $filename); + $this->entityNameValidator->validatePascalCase( + $name, + NameValidationUtil::DATA_ENTITY_NAME, + $filename + ); $type = $rawEntity[self::_TYPE] ?? null; $data = []; $deprecated = null; @@ -206,8 +210,8 @@ private function processParserOutput($parserOutput) $entityDataObjects[$entityDataObject->getName()] = $entityDataObject; } - $this->entityNameValidator->summarize("data entity name"); - $this->entityKeyValidator->summarize("data entity key"); + $this->entityNameValidator->summarize(NameValidationUtil::DATA_ENTITY_NAME); + $this->entityKeyValidator->summarize(NameValidationUtil::DATA_ENTITY_KEY); return $entityDataObjects; } @@ -241,7 +245,11 @@ private function processDataElements($entityData) foreach ($entityData[self::_DATA] as $dataElement) { $originalDataElementKey = $dataElement[self::_KEY]; $filename = $entityData[self::_FILENAME] ?? null; - $this->entityKeyValidator->validateDataEntityKey($originalDataElementKey, $filename); + $this->entityKeyValidator->validateCamelCase( + $originalDataElementKey, + NameValidationUtil::DATA_ENTITY_KEY, + $filename + ); $dataElementKey = strtolower($originalDataElementKey); $dataElementValue = $dataElement[self::_VALUE] ?? ""; $dataValues[$dataElementKey] = $dataElementValue; diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php index d01b36528..2c8ab7530 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php @@ -140,7 +140,10 @@ private function initialize() $operationNameValidator = new NameValidationUtil(); foreach ($parserOutput as $dataDefName => $opDefArray) { - $operationNameValidator->validateMetadataOperationName($dataDefName); + $operationNameValidator->validatePascalCase( + $dataDefName, + NameValidationUtil::METADATA_OPERATION_NAME + ); $operation = $opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_TYPE]; $dataType = $opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE]; @@ -235,7 +238,7 @@ private function initialize() $deprecated ); } - $operationNameValidator->summarize("metadata operation name"); + $operationNameValidator->summarize(NameValidationUtil::METADATA_OPERATION_NAME); } /** diff --git a/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php b/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php index 1fc8dfd34..5be765074 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php @@ -62,7 +62,7 @@ private function __construct() } $filename = $pageData[self::FILENAME] ?? null; - $pageNameValidator->validatePageName($pageName, $filename); + $pageNameValidator->validateAffixes($pageName, NameValidationUtil::PAGE, $filename); $area = $pageData[self::AREA] ?? null; $url = $pageData[self::URL] ?? null; @@ -85,7 +85,7 @@ private function __construct() $this->pageObjects[$pageName] = new PageObject($pageName, $url, $module, $sectionNames, $parameterized, $area, $filename, $deprecated); } - $pageNameValidator->summarize("page name"); + $pageNameValidator->summarize(NameValidationUtil::PAGE . " name"); } /** diff --git a/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php b/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php index 09d073d33..5d658bac0 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php @@ -68,7 +68,7 @@ private function __construct() } $filename = $sectionData[self::FILENAME] ?? null; - $sectionNameValidator->validateSectionName($sectionName, $filename); + $sectionNameValidator->validateAffixes($sectionName, NameValidationUtil::SECTION, $filename); try { foreach ($sectionData[SectionObjectHandler::ELEMENT] as $elementName => $elementData) { @@ -76,7 +76,11 @@ private function __construct() throw new XmlException(sprintf(self::ELEMENT_NAME_ERROR_MSG, $elementName, $sectionName)); } - $elementNameValidator->validateElementName($elementName, $filename); + $elementNameValidator->validateCamelCase( + $elementName, + NameValidationUtil::SECTION_ELEMENT_NAME, + $filename + ); $elementType = $elementData[SectionObjectHandler::TYPE] ?? null; $elementSelector = $elementData[SectionObjectHandler::SELECTOR] ?? null; $elementLocatorFunc = $elementData[SectionObjectHandler::LOCATOR_FUNCTION] ?? null; @@ -119,8 +123,8 @@ private function __construct() $sectionDeprecated ); } - $sectionNameValidator->summarize("section name"); - $elementNameValidator->summarize("element name"); + $sectionNameValidator->summarize(NameValidationUtil::SECTION . " name"); + $elementNameValidator->summarize(NameValidationUtil::SECTION_ELEMENT_NAME); } /** diff --git a/src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php b/src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php index 47dacf200..7f1d49d5c 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php @@ -115,7 +115,11 @@ private function initActionGroups() foreach ($neededActionGroup as $actionGroupName => $actionGroupData) { if (!in_array($actionGroupName, ["nodeName", "xsi:noNamespaceSchemaLocation"])) { $filename = $actionGroupData[ActionGroupObjectHandler::ACTION_GROUP_FILENAME_ATTRIBUTE]; - $actionGroupNameValidator->validateActionGroupName($actionGroupName, $filename); + $actionGroupNameValidator->validatePascalCase( + $actionGroupName, + NameValidationUtil::ACTION_GROUP_NAME, + $filename + ); } if (!is_array($actionGroupData)) { @@ -125,7 +129,7 @@ private function initActionGroups() $this->actionGroups[$actionGroupName] = $actionGroupObjectExtractor->extractActionGroup($actionGroupData); } - $actionGroupNameValidator->summarize("action group name"); + $actionGroupNameValidator->summarize(NameValidationUtil::ACTION_GROUP_NAME); } /** diff --git a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php index 8a72415f8..109237a77 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php @@ -145,7 +145,7 @@ private function initTestData() $testNameValidator = new NameValidationUtil(); foreach ($parsedTestArray as $testName => $testData) { $filename = $testData[TestObjectHandler::TEST_FILENAME_ATTRIBUTE]; - $testNameValidator->validateTestName($testName, $filename); + $testNameValidator->validatePascalCase($testName, NameValidationUtil::TEST_NAME, $filename); if (!is_array($testData)) { continue; } @@ -156,7 +156,7 @@ private function initTestData() } } $exceptionCollector->throwException(); - $testNameValidator->summarize("test name"); + $testNameValidator->summarize(NameValidationUtil::TEST_NAME); $testObjectExtractor->getAnnotationExtractor()->validateStoryTitleUniqueness(); $testObjectExtractor->getAnnotationExtractor()->validateTestCaseIdTitleUniqueness(); } diff --git a/src/Magento/FunctionalTestingFramework/Util/Validation/NameValidationUtil.php b/src/Magento/FunctionalTestingFramework/Util/Validation/NameValidationUtil.php index 50918c146..0112af14e 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Validation/NameValidationUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/Validation/NameValidationUtil.php @@ -14,6 +14,15 @@ class NameValidationUtil { const PHP_CLASS_REGEX_PATTERN = '/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/'; + const DATA_ENTITY_NAME = "data entity name"; + const DATA_ENTITY_KEY = "data entity key"; + const METADATA_OPERATION_NAME = "metadata operation name"; + const PAGE = "Page"; + const SECTION = "Section"; + const SECTION_ELEMENT_NAME = "section element name"; + const ACTION_GROUP_NAME = "action group name"; + const TEST_NAME = "test name"; + /** * The number of violations this instance has detected. * @@ -70,17 +79,18 @@ public static function validateName($name, $type) } /** - * Validates data entity names. + * Validates that the string is PascalCase. * * @param string $str + * @param string $type * @param string $filename * @throws Exception * @return void */ - public function validateDataEntityName($str, $filename = null) + public function validatePascalCase($str, $type, $filename = null) { if (!ctype_upper($str[0])) { - $message = "The data entity name {$str} should be PascalCase with an uppercase first letter."; + $message = "The {$type} {$str} should be PascalCase with an uppercase first letter."; if ($filename !== null) { $message .= " See file {$filename}."; @@ -97,44 +107,18 @@ public function validateDataEntityName($str, $filename = null) } /** - * Validates data entity key names. + * Validates that the string is camelCase. * * @param string $str + * @param string $type * @param string $filename * @throws Exception * @return void */ - public function validateDataEntityKey($str, $filename = null) + public function validateCamelCase($str, $type, $filename = null) { if (!ctype_lower($str[0])) { - $message = "The data entity key {$str} should be camelCase with a lowercase first letter."; - - if ($filename !== null) { - $message .= " See file {$filename}."; - } - - LoggingUtil::getInstance()->getLogger(self::class)->notification( - $message, - [], - false - ); - - $this->count++; - } - } - - /** - * Validates metadata operation names. - * - * @param string $str - * @param string $filename - * @throws Exception - * @return void - */ - public function validateMetadataOperationName($str, $filename = null) - { - if (!ctype_upper($str[0])) { - $message = "The metadata operation name {$str} should be PascalCase with an uppercase first letter."; + $message = "The {$type} {$str} should be camelCase with a lowercase first letter."; if ($filename !== null) { $message .= " See file {$filename}."; @@ -151,133 +135,22 @@ public function validateMetadataOperationName($str, $filename = null) } /** - * Validates page names. - * - * @param string $str - * @param string $filename - * @throws Exception - * @return void - */ - public function validatePageName($str, $filename = null) - { - $isPrefixAdmin = substr($str, 0, 5) === "Admin"; - $isPrefixStorefront = substr($str, 0, 10) === "Storefront"; - $isSuffixPage = substr($str, -4) === "Page"; - - if ((!$isPrefixAdmin && !$isPrefixStorefront) || !$isSuffixPage) { - $message = "The page name {$str} should follow the pattern {Admin or Storefront}{Description}Page."; - - if ($filename !== null) { - $message .= " See file {$filename}."; - } - - LoggingUtil::getInstance()->getLogger(self::class)->notification( - $message, - [], - false - ); - - $this->count++; - } - } - - /** - * Validates section names. + * Validates that the string is of the pattern {Admin or Storefront}{Description}{Type}. * * @param string $str + * @param string $type * @param string $filename * @throws Exception * @return void */ - public function validateSectionName($str, $filename = null) + public function validateAffixes($str, $type, $filename = null) { $isPrefixAdmin = substr($str, 0, 5) === "Admin"; $isPrefixStorefront = substr($str, 0, 10) === "Storefront"; - $isSuffixSection = substr($str, -7) === "Section"; - - if ((!$isPrefixAdmin && !$isPrefixStorefront) || !$isSuffixSection) { - $message = "The section name {$str} should follow the pattern {Admin or Storefront}{Description}Section."; - - if ($filename !== null) { - $message .= " See file {$filename}."; - } - - LoggingUtil::getInstance()->getLogger(self::class)->notification( - $message, - [], - false - ); - - $this->count++; - } - } - - /** - * Validates section element names. - * - * @param string $str - * @param string $filename - * @throws Exception - * @return void - */ - public function validateElementName($str, $filename = null) - { - if (!ctype_lower($str[0])) { - $message = "The element name {$str} should be camelCase with a lowercase first letter."; + $isSuffixType = substr($str, -strlen($type)) === $type; - if ($filename !== null) { - $message .= " See file {$filename}."; - } - - LoggingUtil::getInstance()->getLogger(self::class)->notification( - $message, - [], - false - ); - - $this->count++; - } - } - - /** - * Validates action group names. - * - * @param string $str - * @param string $filename - * @throws Exception - * @return void - */ - public function validateActionGroupName($str, $filename = null) - { - if (!ctype_upper($str[0])) { - $message = "The action group name {$str} should be PascalCase with an uppercase first letter."; - - if ($filename !== null) { - $message .= " See file {$filename}."; - } - - LoggingUtil::getInstance()->getLogger(self::class)->notification( - $message, - [], - false - ); - - $this->count++; - } - } - - /** - * Validates test names. - * - * @param string $str - * @param string $filename - * @throws Exception - * @return void - */ - public function validateTestName($str, $filename = null) - { - if (!ctype_upper($str[0])) { - $message = "The test name {$str} should be PascalCase with an uppercase first letter."; + if ((!$isPrefixAdmin && !$isPrefixStorefront) || !$isSuffixType) { + $message = "The {$type} name {$str} should follow the pattern {Admin or Storefront}{Description}{$type}."; if ($filename !== null) { $message .= " See file {$filename}."; From 9dc906193ac37b271723befd17be5ce80d343310 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Wed, 11 Mar 2020 10:55:17 -0500 Subject: [PATCH 275/888] MQE-1581: Remove NONE debug level for next MFTF major release Updated new file script util with LEVEL_DEFAULT --- .../FunctionalTestingFramework/Util/Script/ScriptUtil.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php b/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php index 839320b38..e1534d655 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php @@ -29,7 +29,7 @@ public static function getAllModulePaths() true, MftfApplicationConfig::UNIT_TEST_PHASE, false, - MftfApplicationConfig::LEVEL_NONE, + MftfApplicationConfig::LEVEL_DEFAULT, true ); From 8977af8ffd446aea5f9ff7bdc8068ba970e20f4e Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Wed, 11 Mar 2020 13:39:36 -0500 Subject: [PATCH 276/888] MQE-2017: Remove dead code: MetadataGenUtil --- .../FormData/MetadataGenUtil.php | 170 ------ .../FormData/_generateMetadataFile.php | 23 - .../FormData/input.yml.sample | 4 - .../FormData/views/operation.mustache | 13 - .../FormData/views/partials/field.mustache | 1 - .../FormData/views/partials/object.mustache | 10 - .../Swagger/MetadataGenerator.php | 533 ------------------ .../Swagger/_generateMetadataFile.php | 10 - .../MetadataGenerator/Swagger/autoload.php | 17 - .../MetadataGenerator/Swagger/magento.json | 1 - .../Swagger/views/definition.mustache | 14 - .../Swagger/views/operation.mustache | 16 - .../Swagger/views/partials/array1.mustache | 12 - .../Swagger/views/partials/array2.mustache | 12 - .../Swagger/views/partials/array3.mustache | 12 - .../Swagger/views/partials/field.mustache | 9 - .../Swagger/views/partials/field2.mustache | 9 - .../Swagger/views/partials/param.mustache | 9 - .../Swagger/views/partials/value.mustache | 9 - 19 files changed, 884 deletions(-) delete mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/MetadataGenUtil.php delete mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/_generateMetadataFile.php delete mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/input.yml.sample delete mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/views/operation.mustache delete mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/views/partials/field.mustache delete mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/views/partials/object.mustache delete mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/MetadataGenerator.php delete mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/_generateMetadataFile.php delete mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/autoload.php delete mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/magento.json delete mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/definition.mustache delete mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/operation.mustache delete mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/array1.mustache delete mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/array2.mustache delete mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/array3.mustache delete mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/field.mustache delete mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/field2.mustache delete mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/param.mustache delete mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/value.mustache diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/MetadataGenUtil.php b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/MetadataGenUtil.php deleted file mode 100644 index 2cd3f7011..000000000 --- a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/MetadataGenUtil.php +++ /dev/null @@ -1,170 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\FunctionalTestingFramework\Util\MetadataGenerator\FormData; - -use Mustache_Engine; -use Mustache_Loader_FilesystemLoader; - -class MetadataGenUtil -{ - const OUTPUT_DIR = '_output'; - const INPUT_TXT_FILE = 'input.yml'; - - /** - * Mustache Engine instance for the templating. - * - * @var Mustache_Engine - */ - private $mustacheEngine; - - /** - * Name of the operation (e.g. createCategory) - * - * @var string - */ - private $operationName; - - /** - * Data type of the operation (e.g. category) - * - * @var string - */ - private $operationDataType; - - /** - * Url path for the operation (e.g. /admin/system_config/save/section/payment) - * - * @var string - */ - private $operationUrl; - - /** - * The raw parameter data to be converted into metadata - * (e.g. entity[param1]=value1&entity[param2]=value2&entity[param3]=value3&entityField=field1) - * - * @var string - */ - private $inputString; - - /** - * The relative filepath for the *meta.xml file to be generated. - * - * @var string - */ - private $filepath; - - /** - * MetadataGenUtil constructor. - * - * @param string $operationName - * @param string $operationDataType - * @param string $operationUrl - * @param string $inputString - */ - public function __construct($operationName, $operationDataType, $operationUrl, $inputString) - { - $this->operationName = $operationName; - $this->operationDataType = $operationDataType; - $this->operationUrl = $operationUrl; - $this->inputString = $inputString; - - $this->filepath = self::OUTPUT_DIR . DIRECTORY_SEPARATOR . $this->operationDataType . "-meta.xml"; - } - - /** - * Function which takes params from constructor, transforms into data array and outputs a representative metadata - * file for MFTF to consume and send requests. - * - * @return void - */ - public function generateMetadataFile() - { - // Load Mustache templates - $this->mustacheEngine = new Mustache_Engine( - ['loader' => new Mustache_Loader_FilesystemLoader("views"), - 'partials_loader' => new Mustache_Loader_FilesystemLoader( - "views" . DIRECTORY_SEPARATOR . "partials" - )] - ); - - // parse the string params into an array - parse_str($this->inputString, $results); - $data = $this->convertResultToEntry($results, $this->operationDataType); - $data = $this->appendParentParams($data); - $output = $this->mustacheEngine->render('operation', $data); - $this->cleanAndCreateOutputDir(); - file_put_contents( - $this->filepath, - $output - ); - } - - /** - * Function which takes the top level params from the user and returns an array appended with the needed config. - * - * @param array $data - * @return array - */ - private function appendParentParams($data) - { - $result = $data; - $result['operationName'] = $this->operationName; - $result['operationDataType'] = $this->operationDataType; - $result['operationUrl'] = $this->operationUrl; - - return $result; - } - - /** - * Function which is called recursively to generate the mustache array for the template enging. Makes decisions - * about type and format based on parameter array. - * - * @param array $results - * @param string $defaultDataType - * @return array - */ - private function convertResultToEntry($results, $defaultDataType) - { - $data = []; - - foreach ($results as $key => $result) { - $entry = []; - if (is_array($result)) { - $entry = array_merge($entry, ['objectName' => $key]); - $res = $this->convertResultToEntry($result, $defaultDataType); - if (!array_key_exists('objects', $res)) { - $entry = array_merge($entry, ['objects' => null]); - $entry = array_merge($entry, ['dataType' => $key]); - } else { - $entry = array_merge($entry, ['hasChildObj' => true]); - $entry = array_merge($entry, ['dataType' => $defaultDataType]); - } - $data['objects'][] = array_merge($entry, $res); - } else { - $data['fields'][] = ['fieldName' => $key]; - } - } - - return $data; - } - - /** - * Function which cleans any previously created fileand creates the _output dir. - * - * @return void - */ - private function cleanAndCreateOutputDir() - { - if (!file_exists(self::OUTPUT_DIR)) { - mkdir(self::OUTPUT_DIR); - } - - if (file_exists($this->filepath)) { - unlink($this->filepath); - } - } -} diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/_generateMetadataFile.php b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/_generateMetadataFile.php deleted file mode 100644 index fce54be41..000000000 --- a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/_generateMetadataFile.php +++ /dev/null @@ -1,23 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -require_once '../../../../../../vendor/autoload.php'; - -const INPUT_TXT_FILE = 'input.yml'; - -// parse the input.yml file for context -$inputCfg = \Symfony\Component\Yaml\Yaml::parse(file_get_contents(INPUT_TXT_FILE)); - -// create new MetadataGenUtil Object -$metadataGenUtil = new Magento\FunctionalTestingFramework\Util\MetadataGenerator\FormData\MetadataGenUtil( - $inputCfg['operationName'], - $inputCfg['operationDataType'], - $inputCfg['operationUrl'], - $inputCfg['inputString'] -); - -//generate the metadata file in the _output dir -$metadataGenUtil->generateMetadataFile(); diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/input.yml.sample b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/input.yml.sample deleted file mode 100644 index 503aef067..000000000 --- a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/input.yml.sample +++ /dev/null @@ -1,4 +0,0 @@ -operationName: createMyEntity -operationDataType: myEntityType -operationUrl: /admin/system_config/save/someEntity -inputString: entity[param1]=value1&entity[param2]=value2&entity[param3]=value3&entityField=field1 diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/views/operation.mustache b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/views/operation.mustache deleted file mode 100644 index 28321504d..000000000 --- a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/views/operation.mustache +++ /dev/null @@ -1,13 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../DataGenerator/etc/dataOperation.xsd"> - <operation name="{{operationName}}" dataType="{{operationDataType}}" type="create" auth="adminFormKey" url="{{operationUrl}}" method="POST"> - {{>object}} - </operation> -</config> diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/views/partials/field.mustache b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/views/partials/field.mustache deleted file mode 100644 index 284835ef2..000000000 --- a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/views/partials/field.mustache +++ /dev/null @@ -1 +0,0 @@ -<field key="{{fieldName}}">string</field> diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/views/partials/object.mustache b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/views/partials/object.mustache deleted file mode 100644 index 7d3aaf5ca..000000000 --- a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/views/partials/object.mustache +++ /dev/null @@ -1,10 +0,0 @@ -{{#objects}} -<object key="{{objectName}}" dataType="{{dataType}}"> -{{#fields}} - {{> field}} -{{/fields}} -{{#hasChildObj}} - {{> object}} -{{/hasChildObj}} -</object> -{{/objects}} diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/MetadataGenerator.php b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/MetadataGenerator.php deleted file mode 100644 index 10d75bf8e..000000000 --- a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/MetadataGenerator.php +++ /dev/null @@ -1,533 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\FunctionalTestingFramework\Util\MetadataGenerator\Swagger; - -use Doctrine\Common\Collections\ArrayCollection; -use Epfremme\Swagger\Entity\Schemas\SchemaInterface; -use Epfremme\Swagger\Entity\Schemas\ObjectSchema; -use Epfremme\Swagger\Entity\Schemas\RefSchema; -use Epfremme\Swagger\Entity\Schemas\ArraySchema; -use Epfremme\Swagger\Factory\SwaggerFactory; -use Epfremme\Swagger\Entity\Swagger; -use Epfremme\Swagger\Entity\Operation; -use Epfremme\Swagger\Entity\Parameters\BodyParameter; -use Epfremme\Swagger\Entity\Parameters\AbstractTypedParameter; -use Mustache_Engine; -use Mustache_Loader_FilesystemLoader; - -class MetadataGenerator -{ - const OUTPUT_DIR = '_operations'; - const OUTPUT_DIR2 = '_definitions'; - const INPUT_TXT_FILE = 'magento.json'; - const AUTH = 'adminOauth'; - const TEMPLATE_VAR_DEF_TYPE = 'create'; - - const TEMPLATE_VAR_OP_NAME = 'operationName'; - const TEMPLATE_VAR_OP_DATATYPE = 'operationDataType'; - const TEMPLATE_VAR_OP_TYPE = 'operationType'; - const TEMPLATE_VAR_OP_AUTH = 'auth'; - const TEMPLATE_VAR_OP_URL = 'operationUrl'; - const TEMPLATE_VAR_OP_METHOD = 'method'; - - const TEMPLATE_VAR_OP_FIELD = 'fields'; - const TEMPLATE_VAR_FIELD_NAME = 'fieldName'; - const TEMPLATE_VAR_FIELD_TYPE = 'fieldType'; - const TEMPLATE_VAR_FIELD_IS_REQUIRED = 'isRequired'; - - const TEMPLATE_VAR_OP_PARAM = 'params'; - const TEMPLATE_VAR_PARAM_NAME = 'paramName'; - const TEMPLATE_VAR_PARAM_TYPE = 'paramType'; - - const TEMPLATE_VAR_OP_ARRAY = 'arrays'; - const TEMPLATE_VAR_ARRAY_KEY = 'arrayKey'; - const TEMPLATE_VAR_ARRAY_IS_REQUIRED = 'isRequiredArray'; - const TEMPLATE_VAR_VALUES = 'values'; - const TEMPLATE_VAR_VALUE = 'value'; - - const REF_REGEX = "~#/definitions/([\S]+)~"; - - /** - * Mustache Engine instance for the templating. - * - * @var Mustache_Engine - */ - private $mustache_engine; - - /** - * Swagger built from json. - * - * @var Swagger - */ - private static $swagger; - - /** - * Path params. - * - * @var string - */ - private $pathParams; - - /** - * Array to hold operation query params. - * - * @var array - */ - private $params; - - /** - * Array to hold operation fields. - * - * @var array - */ - private $fields; - - /** - * The relative filepath for the *meta.xml file to be generated. - * - * @var string - */ - private $filepath; - - /** - * Operation method mapping. - * - * @var array - */ - private static $methodMapping = [ - 'POST' => 'create', - 'DELETE' => 'delete', - 'PUT' => 'update', - 'GET' => 'get', - ]; - - /** - * Build and initialize generator. - */ - public function __construct() - { - self::buildSwaggerSpec(); - $this->initMustacheTemplates(); - } - - /** - * Parse swagger spec from input json file. - * TODO: read swagger spec from magento server. - * - * @return void - */ - public function generateMetadataFromSwagger() - { - $paths = self::$swagger->getPaths(); - - foreach ($paths->getIterator() as $pathKey => $path) { - $operations = $path->getOperations(); - foreach ($operations->getIterator() as $operationKey => $operation) { - $this->renderOperation($operation, $pathKey, $operationKey); - } - } - - $definitions = self::$swagger->getDefinitions(); - foreach ($definitions->getIterator() as $defKey => $definition) { - $this->renderDefinition($defKey, $definition); - } - } - - /** - * Render swagger operations. - * - * @param Operation $operation - * @param string $path - * @param string $method - * @return void - */ - private function renderOperation($operation, $path, $method) - { - $operationArray = []; - $this->pathParams = ''; - $this->params = []; - $this->fields = []; - $operationMethod = strtoupper($method); - $operationDataType = ucfirst($operation->getOperationId()); - - $operationArray[self::TEMPLATE_VAR_OP_NAME] = self::$methodMapping[$operationMethod] . $operationDataType; - $operationArray[self::TEMPLATE_VAR_OP_DATATYPE] = $operationDataType; - $operationArray[self::TEMPLATE_VAR_OP_METHOD] = $operationMethod; - $operationArray[self::TEMPLATE_VAR_OP_AUTH] = self::AUTH; - $operationArray[self::TEMPLATE_VAR_OP_TYPE] = self::$methodMapping[$operationMethod]; - $operationArray[self::TEMPLATE_VAR_OP_URL] = $path; - - $params = $operation->getParameters(); - if (!empty($params)) { - $this->parseParams($params, $path); - $operationArray[self::TEMPLATE_VAR_OP_FIELD] = $this->fields; - $operationArray[self::TEMPLATE_VAR_OP_PARAM] = $this->params; - } - - if (!empty($this->pathParams)) { - $operationArray[self::TEMPLATE_VAR_OP_URL] .= $this->pathParams; - } - - $this->generateMetaDataFile( - self::OUTPUT_DIR, - $operationDataType, - 'operation', - $operationArray - ); - } - - /** - * Render swagger definitions. - * - * @param string $defKey - * @param ObjectSchema|ArraySchema $definition - * @return void - */ - private function renderDefinition($defKey, $definition) - { - $operationArray = []; - $this->fields = []; - - $operationArray[self::TEMPLATE_VAR_OP_NAME] = $defKey; - $operationArray[self::TEMPLATE_VAR_OP_DATATYPE] = $defKey; - $operationArray[self::TEMPLATE_VAR_OP_TYPE] = self::TEMPLATE_VAR_DEF_TYPE; - - if ($definition instanceof ObjectSchema) { - $properties = $definition->getProperties(); - if (!empty($properties)) { - $dataField = []; - $dataArray = []; - foreach ($properties->getIterator() as $propertyKey => $property) { - if ($property instanceof ArraySchema) { - $dataArray[] = $this->parseSchema($property, $propertyKey, 1, 1); - } else { - $dataField[] = $this->parseSchema($property, $propertyKey, 0, 1); - } - } - if (!empty($dataField)) { - $operationArray[self::TEMPLATE_VAR_OP_FIELD] = $dataField; - } - if (!empty($dataArray)) { - foreach ($dataArray as $array) { - $operationArray[self::TEMPLATE_VAR_OP_ARRAY.'1'][] = $array[self::TEMPLATE_VAR_OP_ARRAY.'1']; - } - } - } - } elseif ($definition instanceof ArraySchema) { - $operationArray = array_merge($operationArray, $this->parseSchema($definition, $defKey, 1, 1)); - } - - $this->generateMetaDataFile( - self::OUTPUT_DIR2, - $defKey, - 'definition', - $operationArray - ); - } - - /** - * Parse schema and return an array that will be consumed by mustache template engine. - * - * @param SchemaInterface $schema - * @param string $name - * @param boolean $forArray - * @param integer $depth - * @return array - */ - private function parseSchema($schema, $name, $forArray, $depth) - { - $data = []; - - if ($schema instanceof RefSchema) { - $ref = $schema->getRef(); - preg_match(self::REF_REGEX, $ref, $matches); - if (count($matches) == 2) { - if (!$forArray) { - $data[self::TEMPLATE_VAR_FIELD_NAME] = $name; - $data[self::TEMPLATE_VAR_FIELD_TYPE] = $matches[1]; - } else { - $data[self::TEMPLATE_VAR_VALUES][] = [self::TEMPLATE_VAR_VALUE => $matches[1]]; - } - } - } elseif ($schema instanceof ArraySchema) { - $values = []; - $items = $schema->getItems(); - $data[self::TEMPLATE_VAR_OP_ARRAY.$depth][self::TEMPLATE_VAR_ARRAY_KEY] = $name; - if ($items instanceof ArrayCollection) { - foreach ($items->getIterator() as $itemKey => $item) { - $values[] = $this->parseSchema($item, $itemKey, 1, $depth+1); - } - $data[self::TEMPLATE_VAR_VALUES] = $values; - $data[self::TEMPLATE_VAR_OP_ARRAY.$depth] = $data; - } else { - $data[self::TEMPLATE_VAR_OP_ARRAY.$depth] = array_merge( - $data[self::TEMPLATE_VAR_OP_ARRAY.$depth], - $this->parseSchema($items, $name, 1, $depth+1) - ); - } - } else { - if (method_exists($schema, 'getType')) { - if (!$forArray) { - $data[self::TEMPLATE_VAR_FIELD_NAME] = $name; - $data[self::TEMPLATE_VAR_FIELD_TYPE] = $schema->getType(); - } else { - $data[self::TEMPLATE_VAR_VALUES][] = [self::TEMPLATE_VAR_VALUE => $schema->getType()]; - } - } - } - return $data; - } - - /** - * Parse params for an operation. - * - * @param ArrayCollection $params - * @param string $path - * @return void - */ - private function parseParams($params, $path) - { - foreach ($params->getIterator() as $paramKey => $param) { - if (empty($param)) { - continue; - } - - $paramIn = $param->getIn(); - if ($paramIn == 'body') { - $this->setBodyParams($param); - } elseif ($paramIn == 'path') { - $this->setPathParams($param, $path); - } elseif ($paramIn == 'query') { - $this->setQueryParams($param); - } - } - } - - /** - * Set body params for an operation. - * - * @param BodyParameter $param - * @return void - */ - private function setBodyParams($param) - { - $this->fields = []; - $required = []; - - $paramSchema = $param->getSchema(); - $paramSchemaRequired = $paramSchema->getRequired(); - if (!empty($paramSchemaRequired)) { - foreach ($paramSchemaRequired as $i => $key) { - $required[] = $key; - } - } - $paramSchemaProperties = $paramSchema->getProperties(); - foreach ($paramSchemaProperties->getIterator() as $paramPropertyKey => $paramSchemaProperty) { - $field = []; - $field[self::TEMPLATE_VAR_FIELD_NAME] = $paramPropertyKey; - $field[self::TEMPLATE_VAR_FIELD_TYPE] = $paramSchemaProperty->getType(); - if ($field[self::TEMPLATE_VAR_FIELD_TYPE] == 'ref') { - preg_match(self::REF_REGEX, $paramSchemaProperty->getRef(), $matches); - if (count($matches) == 2) { - $field[self::TEMPLATE_VAR_FIELD_TYPE] = $matches[1]; - } - } - if (in_array($paramPropertyKey, $required)) { - $field[self::TEMPLATE_VAR_FIELD_IS_REQUIRED] = 'true'; - } else { - $field[self::TEMPLATE_VAR_FIELD_IS_REQUIRED] = 'false'; - } - $this->fields[] = $field; - } - } - - /** - * Set path params for an operation. - * - * @param AbstractTypedParameter $param - * @param string $path - * @return void - */ - private function setPathParams($param, $path) - { - $pathParamStr = '{' . $param->getName() . '}'; - if (strpos($path, $pathParamStr) === false) { - $this->pathParams .= '/' . $pathParamStr; - } - } - - /** - * Set query params for an operation. - * - * @param AbstractTypedParameter $param - * @return void - */ - private function setQueryParams($param) - { - $query = []; - $query[self::TEMPLATE_VAR_PARAM_NAME] = $param->getName(); - $query[self::TEMPLATE_VAR_PARAM_TYPE] = $param->getType(); - - $this->params[] = $query; - } - - /** - * Build swagger spec from factory. - * - * @return void - */ - private static function buildSwaggerSpec() - { - $factory = new SwaggerFactory(); - self::$swagger = $factory->build(self::INPUT_TXT_FILE); - } - - /** - * Function which initializes mustache templates for file generation. - * - * @return void - */ - private function initMustacheTemplates() - { - $this->mustache_engine = new Mustache_Engine( - ['loader' => new Mustache_Loader_FilesystemLoader("views"), - 'partials_loader' => new Mustache_Loader_FilesystemLoader( - "views" . DIRECTORY_SEPARATOR . "partials" - )] - ); - } - - /** - * Render template and generate a metadata file. - * - * @param string $relativeDir - * @param string $fileName - * @param string $template - * @param array $data - * @return void - */ - private function generateMetaDataFile($relativeDir, $fileName, $template, $data) - { - $this->filepath = $relativeDir . DIRECTORY_SEPARATOR . $fileName . "-meta.xml"; - $result = $this->mustache_engine->render($template, $data); - $this->cleanAndCreateOutputDir(); - file_put_contents( - $this->filepath, - $result - ); - } - - /** - * Function which cleans any previously created fileand creates the _output dir. - * - * @return void - */ - private function cleanAndCreateOutputDir() - { - if (!file_exists(self::OUTPUT_DIR)) { - mkdir(self::OUTPUT_DIR); - } - - if (!file_exists(self::OUTPUT_DIR2)) { - mkdir(self::OUTPUT_DIR2); - } - - if (file_exists($this->filepath)) { - unlink($this->filepath); - } - } - /* - private static function debugData() { - $paramsExample = ['params' => - [ - 'paramName' => 'name', - 'paramType' => 'type' - ], - [ - 'paramName' => 'name', - 'paramType' => 'type' - ], - [ - 'paramName' => 'name', - 'paramType' => 'type' - ], - ]; - $fieldsExample = ['fields' => - [ - 'fieldName' => 'name', - 'fieldType' => 'type', - 'isRequired' => true, - ], - [ - 'fieldName' => 'name', - 'fieldType' => 'type', - 'isRequired' => true, - ], - [ - 'fieldName' => 'name', - 'fieldType' => 'type', - 'isRequired' => true, - ], - ]; - $arraysExample = ['arrays1' => - [ - 'arrayKey' => 'someKey', - 'values' => [ - 'type1', - 'type2', - ], - 'arrays2' => [ - 'arrayKey' => 'otherKey', - 'values' => [ - 'type3', - 'type4', - ], - 'arrays3' => [ - 'arrayKey' => 'anotherKey', - 'values' => [ - 'type5', - 'type6', - ], - ], - ], - ], - [ - 'arrayKey' => 'someKey', - 'values' => [ - [ - 'value' => 'type1', - ], - [ - 'value' => 'type2', - ], - ], - 'arrays2' => [ - 'arrayKey' => 'otherKey', - 'values' => [ - [ - 'value' => 'type3', - ], - [ - 'value' => 'type4', - ], - ], - 'arrays3' => [ - 'arrayKey' => 'anotherKey', - 'values' => [ - [ - 'value' => 'type5', - ], - [ - 'value' => 'type6', - ], - ], - ], - ], - ], - ]; - } - */ -} diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/_generateMetadataFile.php b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/_generateMetadataFile.php deleted file mode 100644 index c759b045e..000000000 --- a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/_generateMetadataFile.php +++ /dev/null @@ -1,10 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -require_once 'autoload.php'; - -// create a MetadataGenerator Object -$generator = new Magento\FunctionalTestingFramework\Util\MetadataGenerator\Swagger\MetadataGenerator(); -$generator->generateMetadataFromSwagger(); diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/autoload.php b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/autoload.php deleted file mode 100644 index e7108d0f4..000000000 --- a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/autoload.php +++ /dev/null @@ -1,17 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -use Doctrine\Common\Annotations\AnnotationRegistry; - -$loader = require '../../../../../../vendor/autoload.php'; - -AnnotationRegistry::registerAutoloadNamespace( - 'JMS\Serializer\Annotation', - "../../../../../vendor/jms/serializer/src" -); - -AnnotationRegistry::registerLoader([$loader, 'loadClass']); - -return $loader; diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/magento.json b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/magento.json deleted file mode 100644 index 07f40e979..000000000 --- a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/magento.json +++ /dev/null @@ -1 +0,0 @@ -{"swagger":"2.0","info":{"version":"2.2","title":"Magento Enterprise"},"host":"magento3.loc","basePath":"/index.php/rest/all","schemes":["http"],"tags":[{"name":"storeStoreRepositoryV1","description":"Store repository interface"},{"name":"storeGroupRepositoryV1","description":"Group repository interface"},{"name":"storeWebsiteRepositoryV1","description":"Website repository interface"},{"name":"storeStoreConfigManagerV1","description":"Store config manager interface"},{"name":"directoryCurrencyInformationAcquirerV1","description":"Currency information acquirer interface"},{"name":"directoryCountryInformationAcquirerV1","description":"Country information acquirer interface"},{"name":"eavAttributeSetRepositoryV1","description":"Interface AttributeSetRepositoryInterface"},{"name":"eavAttributeSetManagementV1","description":"Interface AttributeSetManagementInterface"},{"name":"customerGroupRepositoryV1","description":"Customer group CRUD interface"},{"name":"customerGroupManagementV1","description":"Interface for managing customer groups."},{"name":"customerCustomerGroupConfigV1","description":"Interface for system configuration operations for customer groups."},{"name":"customerCustomerMetadataV1","description":"Interface for retrieval information about customer attributes metadata."},{"name":"customerAddressMetadataV1","description":"Interface for retrieval information about customer address attributes metadata."},{"name":"customerCustomerRepositoryV1","description":"Customer CRUD interface."},{"name":"customerAccountManagementV1","description":"Interface for managing customers accounts."},{"name":"customerAddressRepositoryV1","description":"Customer address CRUD interface."},{"name":"backendModuleServiceV1","description":"Interface for module service."},{"name":"cmsPageRepositoryV1","description":"CMS page CRUD interface."},{"name":"cmsBlockRepositoryV1","description":"CMS block CRUD interface."},{"name":"catalogProductRepositoryV1","description":""},{"name":"catalogProductAttributeTypesListV1","description":""},{"name":"catalogProductAttributeRepositoryV1","description":"Interface RepositoryInterface must be implemented in new model"},{"name":"catalogCategoryAttributeRepositoryV1","description":"Interface RepositoryInterface must be implemented in new model"},{"name":"catalogCategoryAttributeOptionManagementV1","description":"Interface RepositoryInterface must be implemented in new model"},{"name":"catalogProductTypeListV1","description":""},{"name":"catalogAttributeSetRepositoryV1","description":""},{"name":"catalogAttributeSetManagementV1","description":""},{"name":"catalogProductAttributeManagementV1","description":""},{"name":"catalogProductAttributeGroupRepositoryV1","description":""},{"name":"catalogProductAttributeOptionManagementV1","description":""},{"name":"catalogProductMediaAttributeManagementV1","description":""},{"name":"catalogProductAttributeMediaGalleryManagementV1","description":""},{"name":"catalogProductTierPriceManagementV1","description":""},{"name":"catalogTierPriceStorageV1","description":"Tier prices storage."},{"name":"catalogBasePriceStorageV1","description":"Base prices storage."},{"name":"catalogCostStorageV1","description":"Product cost storage."},{"name":"catalogSpecialPriceStorageV1","description":"Special price storage presents efficient price API and is used to retrieve, update or delete special prices."},{"name":"catalogCategoryRepositoryV1","description":""},{"name":"catalogCategoryManagementV1","description":""},{"name":"catalogCategoryListV1","description":""},{"name":"catalogProductCustomOptionTypeListV1","description":""},{"name":"catalogProductCustomOptionRepositoryV1","description":""},{"name":"catalogProductLinkTypeListV1","description":""},{"name":"catalogProductLinkManagementV1","description":""},{"name":"catalogProductLinkRepositoryV1","description":"Interface Product links handling interface"},{"name":"catalogCategoryLinkManagementV1","description":""},{"name":"catalogCategoryLinkRepositoryV1","description":""},{"name":"catalogProductWebsiteLinkRepositoryV1","description":"Interface ProductWebsiteLinkRepositoryInterface"},{"name":"catalogProductRenderListV1","description":"Interface which provides product renders information for products"},{"name":"catalogInventoryStockRegistryV1","description":"Interface StockRegistryInterface"},{"name":"bundleProductLinkManagementV1","description":"Interface for Management of ProductLink"},{"name":"bundleProductOptionRepositoryV1","description":"Interface ProductOptionRepositoryInterface"},{"name":"bundleProductOptionTypeListV1","description":"Interface ProductOptionTypeListInterface"},{"name":"bundleProductOptionManagementV1","description":"Option manager for bundle products"},{"name":"quoteCartRepositoryV1","description":"Interface CartRepositoryInterface"},{"name":"quoteCartManagementV1","description":"Interface CartManagementInterface"},{"name":"quoteGuestCartRepositoryV1","description":"Cart Repository interface for guest carts."},{"name":"quoteGuestCartManagementV1","description":"Cart Management interface for guest carts."},{"name":"quoteShippingMethodManagementV1","description":"Interface ShippingMethodManagementInterface"},{"name":"quoteShipmentEstimationV1","description":"Interface ShipmentManagementInterface"},{"name":"quoteGuestShippingMethodManagementV1","description":"Shipping method management interface for guest carts."},{"name":"quoteGuestShipmentEstimationV1","description":"Interface GuestShipmentEstimationInterface"},{"name":"quoteCartItemRepositoryV1","description":"Interface CartItemRepositoryInterface"},{"name":"quoteGuestCartItemRepositoryV1","description":"Cart Item repository interface for guest carts."},{"name":"quotePaymentMethodManagementV1","description":"Interface PaymentMethodManagementInterface"},{"name":"quoteGuestPaymentMethodManagementV1","description":"Payment method management interface for guest carts."},{"name":"quoteBillingAddressManagementV1","description":"Interface BillingAddressManagementInterface"},{"name":"quoteGuestBillingAddressManagementV1","description":"Billing address management interface for guest carts."},{"name":"quoteCouponManagementV1","description":"Coupon management service interface."},{"name":"quoteGuestCouponManagementV1","description":"Coupon management interface for guest carts."},{"name":"quoteCartTotalRepositoryV1","description":"Interface CartTotalRepositoryInterface"},{"name":"quoteGuestCartTotalManagementV1","description":"Bundled API to collect totals for cart based on shipping/payment methods and additional data."},{"name":"quoteGuestCartTotalRepositoryV1","description":"Cart totals repository interface for guest carts."},{"name":"quoteCartTotalManagementV1","description":"Bundled API to collect totals for cart based on shipping/payment methods and additional data."},{"name":"searchV1","description":"Search API for all requests"},{"name":"salesOrderRepositoryV1","description":"Order repository interface. An order is a document that a web store issues to a customer. Magento generates a sales order that lists the product items, billing and shipping addresses, and shipping and payment methods. A corresponding external document, known as a purchase order, is emailed to the customer."},{"name":"salesOrderManagementV1","description":"Order management interface. An order is a document that a web store issues to a customer. Magento generates a sales order that lists the product items, billing and shipping addresses, and shipping and payment methods. A corresponding external document, known as a purchase order, is emailed to the customer."},{"name":"salesOrderAddressRepositoryV1","description":"Order address repository interface. An order is a document that a web store issues to a customer. Magento generates a sales order that lists the product items, billing and shipping addresses, and shipping and payment methods. A corresponding external document, known as a purchase order, is emailed to the customer."},{"name":"salesOrderItemRepositoryV1","description":"Order item repository interface. An order is a document that a web store issues to a customer. Magento generates a sales order that lists the product items, billing and shipping addresses, and shipping and payment methods. A corresponding external document, known as a purchase order, is emailed to the customer."},{"name":"salesInvoiceRepositoryV1","description":"Invoice repository interface. An invoice is a record of the receipt of payment for an order."},{"name":"salesInvoiceManagementV1","description":"Invoice management interface. An invoice is a record of the receipt of payment for an order."},{"name":"salesInvoiceCommentRepositoryV1","description":"Invoice comment repository interface. An invoice is a record of the receipt of payment for an order. An invoice can include comments that detail the invoice history."},{"name":"salesRefundInvoiceV1","description":"Interface RefundInvoiceInterface"},{"name":"salesCreditmemoManagementV1","description":"Credit memo add comment interface. After a customer places and pays for an order and an invoice has been issued, the merchant can create a credit memo to refund all or part of the amount paid for any returned or undelivered items. The memo restores funds to the customer account so that the customer can make future purchases."},{"name":"salesCreditmemoRepositoryV1","description":"Credit memo repository interface. After a customer places and pays for an order and an invoice has been issued, the merchant can create a credit memo to refund all or part of the amount paid for any returned or undelivered items. The memo restores funds to the customer account so that the customer can make future purchases."},{"name":"salesCreditmemoCommentRepositoryV1","description":"Credit memo comment repository interface. After a customer places and pays for an order and an invoice has been issued, the merchant can create a credit memo to refund all or part of the amount paid for any returned or undelivered items. The memo restores funds to the customer account so that the customer can make future purchases. A credit memo usually includes comments that detail why the credit memo amount was credited to the customer."},{"name":"salesRefundOrderV1","description":"Interface RefundOrderInterface"},{"name":"salesShipmentRepositoryV1","description":"Shipment repository interface. A shipment is a delivery package that contains products. A shipment document accompanies the shipment. This document lists the products and their quantities in the delivery package."},{"name":"salesShipmentManagementV1","description":"Shipment management interface. A shipment is a delivery package that contains products. A shipment document accompanies the shipment. This document lists the products and their quantities in the delivery package."},{"name":"salesShipmentCommentRepositoryV1","description":"Shipment comment repository interface. A shipment is a delivery package that contains products. A shipment document accompanies the shipment. This document lists the products and their quantities in the delivery package. A shipment document can contain comments."},{"name":"salesShipmentTrackRepositoryV1","description":"Shipment track repository interface. A shipment is a delivery package that contains products. A shipment document accompanies the shipment. This document lists the products and their quantities in the delivery package."},{"name":"salesShipOrderV1","description":"Class ShipOrderInterface"},{"name":"salesTransactionRepositoryV1","description":"Transaction repository interface. A transaction is an interaction between a merchant and a customer such as a purchase, a credit, a refund, and so on."},{"name":"salesInvoiceOrderV1","description":"Class InvoiceOrderInterface"},{"name":"checkoutGuestShippingInformationManagementV1","description":"Interface for managing guest shipping address information"},{"name":"checkoutShippingInformationManagementV1","description":"Interface for managing customer shipping address information"},{"name":"checkoutTotalsInformationManagementV1","description":"Interface for quote totals calculation"},{"name":"checkoutGuestTotalsInformationManagementV1","description":"Interface for guest quote totals calculation"},{"name":"checkoutGuestPaymentInformationManagementV1","description":"Interface for managing guest payment information"},{"name":"checkoutPaymentInformationManagementV1","description":"Interface for managing quote payment information"},{"name":"downloadableLinkRepositoryV1","description":"Interface LinkRepositoryInterface"},{"name":"downloadableSampleRepositoryV1","description":"Interface SampleRepositoryInterface"},{"name":"checkoutAgreementsCheckoutAgreementsRepositoryV1","description":"Interface CheckoutAgreementsRepositoryInterface"},{"name":"configurableProductLinkManagementV1","description":"Manage children products of configurable product"},{"name":"configurableProductConfigurableProductManagementV1","description":"Interface ConfigurableProductManagementInterface"},{"name":"configurableProductOptionRepositoryV1","description":"Manage options of configurable product"},{"name":"customerBalanceBalanceManagementV1","description":"Customer balance(store credit) operations"},{"name":"giftCardAccountGiftCardAccountManagementV1","description":"Interface GiftCardAccountManagementInterface"},{"name":"giftCardAccountGuestGiftCardAccountManagementV1","description":"Interface GuestGiftCardAccountManagementInterface"},{"name":"taxTaxRateRepositoryV1","description":"Tax rate CRUD interface."},{"name":"taxTaxRuleRepositoryV1","description":"Tax rule CRUD interface."},{"name":"taxTaxClassRepositoryV1","description":"Tax class CRUD interface."},{"name":"giftMessageCartRepositoryV1","description":"Interface CartRepositoryInterface"},{"name":"giftMessageItemRepositoryV1","description":"Interface ItemRepositoryInterface"},{"name":"giftMessageGuestCartRepositoryV1","description":"Interface GuestCartRepositoryInterface"},{"name":"giftMessageGuestItemRepositoryV1","description":"Interface GuestItemRepositoryInterface"},{"name":"giftWrappingWrappingRepositoryV1","description":"Interface WrappingRepositoryInterface"},{"name":"salesRuleRuleRepositoryV1","description":"Sales rule CRUD interface"},{"name":"salesRuleCouponRepositoryV1","description":"Coupon CRUD interface"},{"name":"salesRuleCouponManagementV1","description":"Coupon management interface"},{"name":"giftRegistryShippingMethodManagementV1","description":"Interface ShippingMethodManagementInterface"},{"name":"giftRegistryGuestCartShippingMethodManagementV1","description":"Interface ShippingMethodManagementInterface"},{"name":"rewardRewardManagementV1","description":"Interface RewardManagementInterface"},{"name":"rmaTrackManagementV1","description":"Interface TrackManagementInterface"},{"name":"rmaRmaRepositoryV1","description":"Interface RmaRepositoryInterface"},{"name":"rmaCommentManagementV1","description":"Interface CommentRepositoryInterface"},{"name":"rmaRmaManagementV1","description":"Interface RmaManagementInterface"},{"name":"rmaRmaAttributesManagementV1","description":"Interface RmaAttributesManagementInterface"},{"name":"integrationAdminTokenServiceV1","description":"Interface providing token generation for Admins"},{"name":"integrationCustomerTokenServiceV1","description":"Interface providing token generation for Customers"},{"name":"testModule1AllSoapAndRestV1","description":""},{"name":"testModule1AllSoapAndRestV2","description":""},{"name":"testModule2SubsetRestV1","description":""},{"name":"testModule3ErrorV1","description":""},{"name":"testModule4DataObjectServiceV1","description":""},{"name":"testModule5AllSoapAndRestV1","description":"Both SOAP and REST Version ONE"},{"name":"testModule5OverrideServiceV1","description":""},{"name":"testModule5AllSoapAndRestV2","description":"Both SOAP and REST Version TWO"},{"name":"testModuleDefaultHydratorCustomerPersistenceV1","description":"Customer CRUD interface"},{"name":"testModuleJoinDirectivesTestRepositoryV1","description":"Interface TestRepositoryInterface"},{"name":"testModuleMSCAllSoapAndRestV1","description":""},{"name":"worldpayGuestPaymentInformationManagementProxyV1","description":"Interface GuestPaymentInformationManagementProxyInterface"}],"paths":{"/V1/store/storeViews":{"get":{"tags":["storeStoreRepositoryV1"],"description":"Retrieve list of all stores","operationId":"storeStoreRepositoryV1GetListGet","responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/store-data-store-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/store/storeGroups":{"get":{"tags":["storeGroupRepositoryV1"],"description":"Retrieve list of all groups","operationId":"storeGroupRepositoryV1GetListGet","responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/store-data-group-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/store/websites":{"get":{"tags":["storeWebsiteRepositoryV1"],"description":"Retrieve list of all websites","operationId":"storeWebsiteRepositoryV1GetListGet","responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/store-data-website-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/store/storeConfigs":{"get":{"tags":["storeStoreConfigManagerV1"],"description":"","operationId":"storeStoreConfigManagerV1GetStoreConfigsGet","parameters":[{"name":"storeCodes","in":"query","type":"array","items":{"type":"string"},"required":false}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/store-data-store-config-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/directory/currency":{"get":{"tags":["directoryCurrencyInformationAcquirerV1"],"description":"Get currency information for the store.","operationId":"directoryCurrencyInformationAcquirerV1GetCurrencyInfoGet","responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/directory-data-currency-information-interface"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/directory/countries":{"get":{"tags":["directoryCountryInformationAcquirerV1"],"description":"Get all countries and regions information for the store.","operationId":"directoryCountryInformationAcquirerV1GetCountriesInfoGet","responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/directory-data-country-information-interface"}}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/directory/countries/{countryId}":{"get":{"tags":["directoryCountryInformationAcquirerV1"],"description":"Get country and region information for the store.","operationId":"directoryCountryInformationAcquirerV1GetCountryInfoGet","parameters":[{"name":"countryId","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/directory-data-country-information-interface"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/eav/attribute-sets/list":{"get":{"tags":["eavAttributeSetRepositoryV1"],"description":"Retrieve list of Attribute Sets This call returns an array of objects, but detailed information about each object\u2019s attributes might not be included. See http://devdocs.magento.com/codelinks/attributes.html#AttributeSetRepositoryInterface to determine which call to use to get detailed information about all attributes for an object.","operationId":"eavAttributeSetRepositoryV1GetListGet","parameters":[{"name":"searchCriteria[filterGroups][][filters][][field]","in":"query","type":"string","description":"Field"},{"name":"searchCriteria[filterGroups][][filters][][value]","in":"query","type":"string","description":"Value"},{"name":"searchCriteria[filterGroups][][filters][][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"searchCriteria[sortOrders][][field]","in":"query","type":"string","description":"Sorting field."},{"name":"searchCriteria[sortOrders][][direction]","in":"query","type":"string","description":"Sorting direction."},{"name":"searchCriteria[pageSize]","in":"query","type":"integer","description":"Page size."},{"name":"searchCriteria[currentPage]","in":"query","type":"integer","description":"Current page."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/eav-data-attribute-set-search-results-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/eav/attribute-sets/{attributeSetId}":{"get":{"tags":["eavAttributeSetRepositoryV1"],"description":"Retrieve attribute set information based on given ID","operationId":"eavAttributeSetRepositoryV1GetGet","parameters":[{"name":"attributeSetId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/eav-data-attribute-set-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"delete":{"tags":["eavAttributeSetRepositoryV1"],"description":"Remove attribute set by given ID","operationId":"eavAttributeSetRepositoryV1DeleteByIdDelete","parameters":[{"name":"attributeSetId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"put":{"tags":["eavAttributeSetRepositoryV1"],"description":"Save attribute set data","operationId":"eavAttributeSetRepositoryV1SavePut","parameters":[{"name":"attributeSetId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["attributeSet"],"properties":{"attributeSet":{"$ref":"#/definitions/eav-data-attribute-set-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/eav-data-attribute-set-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/eav/attribute-sets":{"post":{"tags":["eavAttributeSetManagementV1"],"description":"Create attribute set from data","operationId":"eavAttributeSetManagementV1CreatePost","parameters":[{"name":"$body","in":"body","schema":{"required":["entityTypeCode","attributeSet","skeletonId"],"properties":{"entityTypeCode":{"type":"string"},"attributeSet":{"$ref":"#/definitions/eav-data-attribute-set-interface"},"skeletonId":{"type":"integer"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/eav-data-attribute-set-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/customerGroups/{id}":{"get":{"tags":["customerGroupRepositoryV1"],"description":"Get customer group by group ID.","operationId":"customerGroupRepositoryV1GetByIdGet","parameters":[{"name":"id","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/customer-data-group-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"put":{"tags":["customerGroupRepositoryV1"],"description":"Save customer group.","operationId":"customerGroupRepositoryV1SavePut","parameters":[{"name":"id","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["group"],"properties":{"group":{"$ref":"#/definitions/customer-data-group-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/customer-data-group-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"delete":{"tags":["customerGroupRepositoryV1"],"description":"Delete customer group by ID.","operationId":"customerGroupRepositoryV1DeleteByIdDelete","parameters":[{"name":"id","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean","description":"true on success"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/customerGroups/search":{"get":{"tags":["customerGroupRepositoryV1"],"description":"Retrieve customer groups. The list of groups can be filtered to exclude the NOT_LOGGED_IN group using the first parameter and/or it can be filtered by tax class. This call returns an array of objects, but detailed information about each object\u2019s attributes might not be included. See http://devdocs.magento.com/codelinks/attributes.html#GroupRepositoryInterface to determine which call to use to get detailed information about all attributes for an object.","operationId":"customerGroupRepositoryV1GetListGet","parameters":[{"name":"searchCriteria[filterGroups][][filters][][field]","in":"query","type":"string","description":"Field"},{"name":"searchCriteria[filterGroups][][filters][][value]","in":"query","type":"string","description":"Value"},{"name":"searchCriteria[filterGroups][][filters][][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"searchCriteria[sortOrders][][field]","in":"query","type":"string","description":"Sorting field."},{"name":"searchCriteria[sortOrders][][direction]","in":"query","type":"string","description":"Sorting direction."},{"name":"searchCriteria[pageSize]","in":"query","type":"integer","description":"Page size."},{"name":"searchCriteria[currentPage]","in":"query","type":"integer","description":"Current page."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/customer-data-group-search-results-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/customerGroups":{"post":{"tags":["customerGroupRepositoryV1"],"description":"Save customer group.","operationId":"customerGroupRepositoryV1SavePost","parameters":[{"name":"$body","in":"body","schema":{"required":["group"],"properties":{"group":{"$ref":"#/definitions/customer-data-group-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/customer-data-group-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/customerGroups/default/{storeId}":{"get":{"tags":["customerGroupManagementV1"],"description":"Get default customer group.","operationId":"customerGroupManagementV1GetDefaultGroupGet","parameters":[{"name":"storeId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/customer-data-group-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/customerGroups/default":{"get":{"tags":["customerGroupManagementV1"],"description":"Get default customer group.","operationId":"customerGroupManagementV1GetDefaultGroupGet","parameters":[{"name":"storeId","in":"query","type":"integer","required":false}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/customer-data-group-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/customerGroups/{id}/permissions":{"get":{"tags":["customerGroupManagementV1"],"description":"Check if customer group can be deleted.","operationId":"customerGroupManagementV1IsReadonlyGet","parameters":[{"name":"id","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/customerGroups/default/{id}":{"put":{"tags":["customerCustomerGroupConfigV1"],"description":"Set system default customer group.","operationId":"customerCustomerGroupConfigV1SetDefaultCustomerGroupPut","parameters":[{"name":"id","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/attributeMetadata/customer/attribute/{attributeCode}":{"get":{"tags":["customerCustomerMetadataV1"],"description":"Retrieve attribute metadata.","operationId":"customerCustomerMetadataV1GetAttributeMetadataGet","parameters":[{"name":"attributeCode","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/customer-data-attribute-metadata-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/attributeMetadata/customer/form/{formCode}":{"get":{"tags":["customerCustomerMetadataV1"],"description":"Retrieve all attributes filtered by form code","operationId":"customerCustomerMetadataV1GetAttributesGet","parameters":[{"name":"formCode","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/customer-data-attribute-metadata-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/attributeMetadata/customer":{"get":{"tags":["customerCustomerMetadataV1"],"description":"Get all attribute metadata.","operationId":"customerCustomerMetadataV1GetAllAttributesMetadataGet","responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/customer-data-attribute-metadata-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/attributeMetadata/customer/custom":{"get":{"tags":["customerCustomerMetadataV1"],"description":"Get custom attributes metadata for the given data interface.","operationId":"customerCustomerMetadataV1GetCustomAttributesMetadataGet","parameters":[{"name":"dataInterfaceName","in":"query","type":"string","required":false}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/customer-data-attribute-metadata-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/attributeMetadata/customerAddress/attribute/{attributeCode}":{"get":{"tags":["customerAddressMetadataV1"],"description":"Retrieve attribute metadata.","operationId":"customerAddressMetadataV1GetAttributeMetadataGet","parameters":[{"name":"attributeCode","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/customer-data-attribute-metadata-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/attributeMetadata/customerAddress/form/{formCode}":{"get":{"tags":["customerAddressMetadataV1"],"description":"Retrieve all attributes filtered by form code","operationId":"customerAddressMetadataV1GetAttributesGet","parameters":[{"name":"formCode","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/customer-data-attribute-metadata-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/attributeMetadata/customerAddress":{"get":{"tags":["customerAddressMetadataV1"],"description":"Get all attribute metadata.","operationId":"customerAddressMetadataV1GetAllAttributesMetadataGet","responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/customer-data-attribute-metadata-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/attributeMetadata/customerAddress/custom":{"get":{"tags":["customerAddressMetadataV1"],"description":"Get custom attributes metadata for the given data interface.","operationId":"customerAddressMetadataV1GetCustomAttributesMetadataGet","parameters":[{"name":"dataInterfaceName","in":"query","type":"string","required":false}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/customer-data-attribute-metadata-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/customers/{customerId}":{"get":{"tags":["customerCustomerRepositoryV1"],"description":"Get customer by customer ID.","operationId":"customerCustomerRepositoryV1GetByIdGet","parameters":[{"name":"customerId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/customer-data-customer-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"delete":{"tags":["customerCustomerRepositoryV1"],"description":"Delete customer by ID.","operationId":"customerCustomerRepositoryV1DeleteByIdDelete","parameters":[{"name":"customerId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean","description":"true on success"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/customers/{id}":{"put":{"tags":["customerCustomerRepositoryV1"],"description":"Create or update a customer.","operationId":"customerCustomerRepositoryV1SavePut","parameters":[{"name":"id","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["customer"],"properties":{"customer":{"$ref":"#/definitions/customer-data-customer-interface"},"passwordHash":{"type":"string"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/customer-data-customer-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/customers/me":{"put":{"tags":["customerCustomerRepositoryV1"],"description":"Create or update a customer.","operationId":"customerCustomerRepositoryV1SavePut","parameters":[{"name":"$body","in":"body","schema":{"required":["customer"],"properties":{"customer":{"$ref":"#/definitions/customer-data-customer-interface"},"passwordHash":{"type":"string"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/customer-data-customer-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"get":{"tags":["customerCustomerRepositoryV1"],"description":"Get customer by customer ID.","operationId":"customerCustomerRepositoryV1GetByIdGet","responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/customer-data-customer-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/customers/search":{"get":{"tags":["customerCustomerRepositoryV1"],"description":"Retrieve customers which match a specified criteria. This call returns an array of objects, but detailed information about each object\u2019s attributes might not be included. See http://devdocs.magento.com/codelinks/attributes.html#CustomerRepositoryInterface to determine which call to use to get detailed information about all attributes for an object.","operationId":"customerCustomerRepositoryV1GetListGet","parameters":[{"name":"searchCriteria[filterGroups][][filters][][field]","in":"query","type":"string","description":"Field"},{"name":"searchCriteria[filterGroups][][filters][][value]","in":"query","type":"string","description":"Value"},{"name":"searchCriteria[filterGroups][][filters][][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"searchCriteria[sortOrders][][field]","in":"query","type":"string","description":"Sorting field."},{"name":"searchCriteria[sortOrders][][direction]","in":"query","type":"string","description":"Sorting direction."},{"name":"searchCriteria[pageSize]","in":"query","type":"integer","description":"Page size."},{"name":"searchCriteria[currentPage]","in":"query","type":"integer","description":"Current page."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/customer-data-customer-search-results-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/customers":{"post":{"tags":["customerAccountManagementV1"],"description":"Create customer account. Perform necessary business operations like sending email.","operationId":"customerAccountManagementV1CreateAccountPost","parameters":[{"name":"$body","in":"body","schema":{"required":["customer"],"properties":{"customer":{"$ref":"#/definitions/customer-data-customer-interface"},"password":{"type":"string"},"redirectUrl":{"type":"string"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/customer-data-customer-interface"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/customers/me/activate":{"put":{"tags":["customerAccountManagementV1"],"description":"Activate a customer account using a key that was sent in a confirmation email.","operationId":"customerAccountManagementV1ActivateByIdPut","parameters":[{"name":"$body","in":"body","schema":{"required":["confirmationKey"],"properties":{"confirmationKey":{"type":"string"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/customer-data-customer-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/customers/{email}/activate":{"put":{"tags":["customerAccountManagementV1"],"description":"Activate a customer account using a key that was sent in a confirmation email.","operationId":"customerAccountManagementV1ActivatePut","parameters":[{"name":"email","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["confirmationKey"],"properties":{"confirmationKey":{"type":"string"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/customer-data-customer-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/customers/me/password":{"put":{"tags":["customerAccountManagementV1"],"description":"Change customer password.","operationId":"customerAccountManagementV1ChangePasswordByIdPut","parameters":[{"name":"$body","in":"body","schema":{"required":["currentPassword","newPassword"],"properties":{"currentPassword":{"type":"string"},"newPassword":{"type":"string"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean","description":"true on success"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/customers/{customerId}/password/resetLinkToken/{resetPasswordLinkToken}":{"get":{"tags":["customerAccountManagementV1"],"description":"Check if password reset token is valid.","operationId":"customerAccountManagementV1ValidateResetPasswordLinkTokenGet","parameters":[{"name":"customerId","in":"path","type":"integer","required":true},{"name":"resetPasswordLinkToken","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean","description":"True if the token is valid"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/customers/password":{"put":{"tags":["customerAccountManagementV1"],"description":"Send an email to the customer with a password reset link.","operationId":"customerAccountManagementV1InitiatePasswordResetPut","parameters":[{"name":"$body","in":"body","schema":{"required":["email","template"],"properties":{"email":{"type":"string"},"template":{"type":"string"},"websiteId":{"type":"integer"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean","description":"true on success"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/customers/{customerId}/confirm":{"get":{"tags":["customerAccountManagementV1"],"description":"Gets the account confirmation status.","operationId":"customerAccountManagementV1GetConfirmationStatusGet","parameters":[{"name":"customerId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"string"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/customers/confirm":{"post":{"tags":["customerAccountManagementV1"],"description":"Resend confirmation email.","operationId":"customerAccountManagementV1ResendConfirmationPost","parameters":[{"name":"$body","in":"body","schema":{"required":["email","websiteId"],"properties":{"email":{"type":"string"},"websiteId":{"type":"integer"},"redirectUrl":{"type":"string"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean","description":"true on success"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/customers/validate":{"put":{"tags":["customerAccountManagementV1"],"description":"Validate customer data.","operationId":"customerAccountManagementV1ValidatePut","parameters":[{"name":"$body","in":"body","schema":{"required":["customer"],"properties":{"customer":{"$ref":"#/definitions/customer-data-customer-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/customer-data-validation-results-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/customers/{customerId}/permissions/readonly":{"get":{"tags":["customerAccountManagementV1"],"description":"Check if customer can be deleted.","operationId":"customerAccountManagementV1IsReadonlyGet","parameters":[{"name":"customerId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/customers/isEmailAvailable":{"post":{"tags":["customerAccountManagementV1"],"description":"Check if given email is associated with a customer account in given website.","operationId":"customerAccountManagementV1IsEmailAvailablePost","parameters":[{"name":"$body","in":"body","schema":{"required":["customerEmail"],"properties":{"customerEmail":{"type":"string"},"websiteId":{"type":"integer","description":"If not set, will use the current websiteId"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/customers/me/billingAddress":{"get":{"tags":["customerAccountManagementV1"],"description":"Retrieve default billing address for the given customerId.","operationId":"customerAccountManagementV1GetDefaultBillingAddressGet","responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/customer-data-address-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/customers/{customerId}/billingAddress":{"get":{"tags":["customerAccountManagementV1"],"description":"Retrieve default billing address for the given customerId.","operationId":"customerAccountManagementV1GetDefaultBillingAddressGet","parameters":[{"name":"customerId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/customer-data-address-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/customers/me/shippingAddress":{"get":{"tags":["customerAccountManagementV1"],"description":"Retrieve default shipping address for the given customerId.","operationId":"customerAccountManagementV1GetDefaultShippingAddressGet","responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/customer-data-address-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/customers/{customerId}/shippingAddress":{"get":{"tags":["customerAccountManagementV1"],"description":"Retrieve default shipping address for the given customerId.","operationId":"customerAccountManagementV1GetDefaultShippingAddressGet","parameters":[{"name":"customerId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/customer-data-address-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/customers/addresses/{addressId}":{"get":{"tags":["customerAddressRepositoryV1"],"description":"Retrieve customer address.","operationId":"customerAddressRepositoryV1GetByIdGet","parameters":[{"name":"addressId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/customer-data-address-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/addresses/{addressId}":{"delete":{"tags":["customerAddressRepositoryV1"],"description":"Delete customer address by ID.","operationId":"customerAddressRepositoryV1DeleteByIdDelete","parameters":[{"name":"addressId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean","description":"true on success"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/modules":{"get":{"tags":["backendModuleServiceV1"],"description":"Returns an array of enabled modules","operationId":"backendModuleServiceV1GetModulesGet","responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"type":"string"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/cmsPage/{pageId}":{"get":{"tags":["cmsPageRepositoryV1"],"description":"Retrieve page.","operationId":"cmsPageRepositoryV1GetByIdGet","parameters":[{"name":"pageId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/cms-data-page-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"delete":{"tags":["cmsPageRepositoryV1"],"description":"Delete page by ID.","operationId":"cmsPageRepositoryV1DeleteByIdDelete","parameters":[{"name":"pageId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean","description":"true on success"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/cmsPage/search":{"get":{"tags":["cmsPageRepositoryV1"],"description":"Retrieve pages matching the specified criteria.","operationId":"cmsPageRepositoryV1GetListGet","parameters":[{"name":"searchCriteria[filterGroups][][filters][][field]","in":"query","type":"string","description":"Field"},{"name":"searchCriteria[filterGroups][][filters][][value]","in":"query","type":"string","description":"Value"},{"name":"searchCriteria[filterGroups][][filters][][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"searchCriteria[sortOrders][][field]","in":"query","type":"string","description":"Sorting field."},{"name":"searchCriteria[sortOrders][][direction]","in":"query","type":"string","description":"Sorting direction."},{"name":"searchCriteria[pageSize]","in":"query","type":"integer","description":"Page size."},{"name":"searchCriteria[currentPage]","in":"query","type":"integer","description":"Current page."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/cms-data-page-search-results-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/cmsPage":{"post":{"tags":["cmsPageRepositoryV1"],"description":"Save page.","operationId":"cmsPageRepositoryV1SavePost","parameters":[{"name":"$body","in":"body","schema":{"required":["page"],"properties":{"page":{"$ref":"#/definitions/cms-data-page-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/cms-data-page-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/cmsPage/{id}":{"put":{"tags":["cmsPageRepositoryV1"],"description":"Save page.","operationId":"cmsPageRepositoryV1SavePut","parameters":[{"name":"id","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["page"],"properties":{"page":{"$ref":"#/definitions/cms-data-page-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/cms-data-page-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/cmsBlock/{blockId}":{"get":{"tags":["cmsBlockRepositoryV1"],"description":"Retrieve block.","operationId":"cmsBlockRepositoryV1GetByIdGet","parameters":[{"name":"blockId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/cms-data-block-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"delete":{"tags":["cmsBlockRepositoryV1"],"description":"Delete block by ID.","operationId":"cmsBlockRepositoryV1DeleteByIdDelete","parameters":[{"name":"blockId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean","description":"true on success"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/cmsBlock/search":{"get":{"tags":["cmsBlockRepositoryV1"],"description":"Retrieve blocks matching the specified criteria.","operationId":"cmsBlockRepositoryV1GetListGet","parameters":[{"name":"searchCriteria[filterGroups][][filters][][field]","in":"query","type":"string","description":"Field"},{"name":"searchCriteria[filterGroups][][filters][][value]","in":"query","type":"string","description":"Value"},{"name":"searchCriteria[filterGroups][][filters][][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"searchCriteria[sortOrders][][field]","in":"query","type":"string","description":"Sorting field."},{"name":"searchCriteria[sortOrders][][direction]","in":"query","type":"string","description":"Sorting direction."},{"name":"searchCriteria[pageSize]","in":"query","type":"integer","description":"Page size."},{"name":"searchCriteria[currentPage]","in":"query","type":"integer","description":"Current page."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/cms-data-block-search-results-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/cmsBlock":{"post":{"tags":["cmsBlockRepositoryV1"],"description":"Save block.","operationId":"cmsBlockRepositoryV1SavePost","parameters":[{"name":"$body","in":"body","schema":{"required":["block"],"properties":{"block":{"$ref":"#/definitions/cms-data-block-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/cms-data-block-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/cmsBlock/{id}":{"put":{"tags":["cmsBlockRepositoryV1"],"description":"Save block.","operationId":"cmsBlockRepositoryV1SavePut","parameters":[{"name":"id","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["block"],"properties":{"block":{"$ref":"#/definitions/cms-data-block-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/cms-data-block-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products":{"post":{"tags":["catalogProductRepositoryV1"],"description":"Create product","operationId":"catalogProductRepositoryV1SavePost","parameters":[{"name":"$body","in":"body","schema":{"required":["product"],"properties":{"product":{"$ref":"#/definitions/catalog-data-product-interface"},"saveOptions":{"type":"boolean"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/catalog-data-product-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"get":{"tags":["catalogProductRepositoryV1"],"description":"Get product list","operationId":"catalogProductRepositoryV1GetListGet","parameters":[{"name":"searchCriteria[filterGroups][][filters][][field]","in":"query","type":"string","description":"Field"},{"name":"searchCriteria[filterGroups][][filters][][value]","in":"query","type":"string","description":"Value"},{"name":"searchCriteria[filterGroups][][filters][][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"searchCriteria[sortOrders][][field]","in":"query","type":"string","description":"Sorting field."},{"name":"searchCriteria[sortOrders][][direction]","in":"query","type":"string","description":"Sorting direction."},{"name":"searchCriteria[pageSize]","in":"query","type":"integer","description":"Page size."},{"name":"searchCriteria[currentPage]","in":"query","type":"integer","description":"Current page."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/catalog-data-product-search-results-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/{sku}":{"put":{"tags":["catalogProductRepositoryV1"],"description":"Create product","operationId":"catalogProductRepositoryV1SavePut","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["product"],"properties":{"product":{"$ref":"#/definitions/catalog-data-product-interface"},"saveOptions":{"type":"boolean"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/catalog-data-product-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"delete":{"tags":["catalogProductRepositoryV1"],"description":"","operationId":"catalogProductRepositoryV1DeleteByIdDelete","parameters":[{"name":"sku","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean","description":"Will returned True if deleted"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"get":{"tags":["catalogProductRepositoryV1"],"description":"Get info about product by product SKU","operationId":"catalogProductRepositoryV1GetGet","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"editMode","in":"query","type":"boolean","required":false},{"name":"storeId","in":"query","type":"integer","required":false},{"name":"forceReload","in":"query","type":"boolean","required":false}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/catalog-data-product-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/attributes/types":{"get":{"tags":["catalogProductAttributeTypesListV1"],"description":"Retrieve list of product attribute types","operationId":"catalogProductAttributeTypesListV1GetItemsGet","responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/catalog-data-product-attribute-type-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/attributes/{attributeCode}":{"get":{"tags":["catalogProductAttributeRepositoryV1"],"description":"Retrieve specific attribute","operationId":"catalogProductAttributeRepositoryV1GetGet","parameters":[{"name":"attributeCode","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/catalog-data-product-attribute-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"put":{"tags":["catalogProductAttributeRepositoryV1"],"description":"Save attribute data","operationId":"catalogProductAttributeRepositoryV1SavePut","parameters":[{"name":"attributeCode","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["attribute"],"properties":{"attribute":{"$ref":"#/definitions/catalog-data-product-attribute-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/catalog-data-product-attribute-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"delete":{"tags":["catalogProductAttributeRepositoryV1"],"description":"Delete Attribute by id","operationId":"catalogProductAttributeRepositoryV1DeleteByIdDelete","parameters":[{"name":"attributeCode","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/attributes":{"get":{"tags":["catalogProductAttributeRepositoryV1"],"description":"Retrieve all attributes for entity type","operationId":"catalogProductAttributeRepositoryV1GetListGet","parameters":[{"name":"searchCriteria[filterGroups][][filters][][field]","in":"query","type":"string","description":"Field"},{"name":"searchCriteria[filterGroups][][filters][][value]","in":"query","type":"string","description":"Value"},{"name":"searchCriteria[filterGroups][][filters][][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"searchCriteria[sortOrders][][field]","in":"query","type":"string","description":"Sorting field."},{"name":"searchCriteria[sortOrders][][direction]","in":"query","type":"string","description":"Sorting direction."},{"name":"searchCriteria[pageSize]","in":"query","type":"integer","description":"Page size."},{"name":"searchCriteria[currentPage]","in":"query","type":"integer","description":"Current page."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/catalog-data-product-attribute-search-results-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"post":{"tags":["catalogProductAttributeRepositoryV1"],"description":"Save attribute data","operationId":"catalogProductAttributeRepositoryV1SavePost","parameters":[{"name":"$body","in":"body","schema":{"required":["attribute"],"properties":{"attribute":{"$ref":"#/definitions/catalog-data-product-attribute-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/catalog-data-product-attribute-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/categories/attributes/{attributeCode}":{"get":{"tags":["catalogCategoryAttributeRepositoryV1"],"description":"Retrieve specific attribute","operationId":"catalogCategoryAttributeRepositoryV1GetGet","parameters":[{"name":"attributeCode","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/catalog-data-category-attribute-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/categories/attributes":{"get":{"tags":["catalogCategoryAttributeRepositoryV1"],"description":"Retrieve all attributes for entity type","operationId":"catalogCategoryAttributeRepositoryV1GetListGet","parameters":[{"name":"searchCriteria[filterGroups][][filters][][field]","in":"query","type":"string","description":"Field"},{"name":"searchCriteria[filterGroups][][filters][][value]","in":"query","type":"string","description":"Value"},{"name":"searchCriteria[filterGroups][][filters][][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"searchCriteria[sortOrders][][field]","in":"query","type":"string","description":"Sorting field."},{"name":"searchCriteria[sortOrders][][direction]","in":"query","type":"string","description":"Sorting direction."},{"name":"searchCriteria[pageSize]","in":"query","type":"integer","description":"Page size."},{"name":"searchCriteria[currentPage]","in":"query","type":"integer","description":"Current page."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/catalog-data-category-attribute-search-results-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/categories/attributes/{attributeCode}/options":{"get":{"tags":["catalogCategoryAttributeOptionManagementV1"],"description":"Retrieve list of attribute options","operationId":"catalogCategoryAttributeOptionManagementV1GetItemsGet","parameters":[{"name":"attributeCode","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/eav-data-attribute-option-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/types":{"get":{"tags":["catalogProductTypeListV1"],"description":"Retrieve available product types","operationId":"catalogProductTypeListV1GetProductTypesGet","responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/catalog-data-product-type-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/attribute-sets/sets/list":{"get":{"tags":["catalogAttributeSetRepositoryV1"],"description":"Retrieve list of Attribute Sets","operationId":"catalogAttributeSetRepositoryV1GetListGet","parameters":[{"name":"searchCriteria[filterGroups][][filters][][field]","in":"query","type":"string","description":"Field"},{"name":"searchCriteria[filterGroups][][filters][][value]","in":"query","type":"string","description":"Value"},{"name":"searchCriteria[filterGroups][][filters][][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"searchCriteria[sortOrders][][field]","in":"query","type":"string","description":"Sorting field."},{"name":"searchCriteria[sortOrders][][direction]","in":"query","type":"string","description":"Sorting direction."},{"name":"searchCriteria[pageSize]","in":"query","type":"integer","description":"Page size."},{"name":"searchCriteria[currentPage]","in":"query","type":"integer","description":"Current page."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/eav-data-attribute-set-search-results-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/attribute-sets/{attributeSetId}":{"get":{"tags":["catalogAttributeSetRepositoryV1"],"description":"Retrieve attribute set information based on given ID","operationId":"catalogAttributeSetRepositoryV1GetGet","parameters":[{"name":"attributeSetId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/eav-data-attribute-set-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"delete":{"tags":["catalogAttributeSetRepositoryV1"],"description":"Remove attribute set by given ID","operationId":"catalogAttributeSetRepositoryV1DeleteByIdDelete","parameters":[{"name":"attributeSetId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"put":{"tags":["catalogAttributeSetRepositoryV1"],"description":"Save attribute set data","operationId":"catalogAttributeSetRepositoryV1SavePut","parameters":[{"name":"attributeSetId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["attributeSet"],"properties":{"attributeSet":{"$ref":"#/definitions/eav-data-attribute-set-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/eav-data-attribute-set-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/attribute-sets":{"post":{"tags":["catalogAttributeSetManagementV1"],"description":"Create attribute set from data","operationId":"catalogAttributeSetManagementV1CreatePost","parameters":[{"name":"$body","in":"body","schema":{"required":["attributeSet","skeletonId"],"properties":{"attributeSet":{"$ref":"#/definitions/eav-data-attribute-set-interface"},"skeletonId":{"type":"integer"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/eav-data-attribute-set-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/attribute-sets/{attributeSetId}/attributes":{"get":{"tags":["catalogProductAttributeManagementV1"],"description":"Retrieve related attributes based on given attribute set ID","operationId":"catalogProductAttributeManagementV1GetAttributesGet","parameters":[{"name":"attributeSetId","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/catalog-data-product-attribute-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/attribute-sets/attributes":{"post":{"tags":["catalogProductAttributeManagementV1"],"description":"Assign attribute to attribute set","operationId":"catalogProductAttributeManagementV1AssignPost","parameters":[{"name":"$body","in":"body","schema":{"required":["attributeSetId","attributeGroupId","attributeCode","sortOrder"],"properties":{"attributeSetId":{"type":"integer"},"attributeGroupId":{"type":"integer"},"attributeCode":{"type":"string"},"sortOrder":{"type":"integer"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/attribute-sets/{attributeSetId}/attributes/{attributeCode}":{"delete":{"tags":["catalogProductAttributeManagementV1"],"description":"Remove attribute from attribute set","operationId":"catalogProductAttributeManagementV1UnassignDelete","parameters":[{"name":"attributeSetId","in":"path","type":"string","required":true},{"name":"attributeCode","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/attribute-sets/groups/list":{"get":{"tags":["catalogProductAttributeGroupRepositoryV1"],"description":"Retrieve list of attribute groups","operationId":"catalogProductAttributeGroupRepositoryV1GetListGet","parameters":[{"name":"searchCriteria[filterGroups][][filters][][field]","in":"query","type":"string","description":"Field"},{"name":"searchCriteria[filterGroups][][filters][][value]","in":"query","type":"string","description":"Value"},{"name":"searchCriteria[filterGroups][][filters][][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"searchCriteria[sortOrders][][field]","in":"query","type":"string","description":"Sorting field."},{"name":"searchCriteria[sortOrders][][direction]","in":"query","type":"string","description":"Sorting direction."},{"name":"searchCriteria[pageSize]","in":"query","type":"integer","description":"Page size."},{"name":"searchCriteria[currentPage]","in":"query","type":"integer","description":"Current page."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/eav-data-attribute-group-search-results-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/attribute-sets/groups":{"post":{"tags":["catalogProductAttributeGroupRepositoryV1"],"description":"Save attribute group","operationId":"catalogProductAttributeGroupRepositoryV1SavePost","parameters":[{"name":"$body","in":"body","schema":{"required":["group"],"properties":{"group":{"$ref":"#/definitions/eav-data-attribute-group-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/eav-data-attribute-group-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/attribute-sets/{attributeSetId}/groups":{"put":{"tags":["catalogProductAttributeGroupRepositoryV1"],"description":"Save attribute group","operationId":"catalogProductAttributeGroupRepositoryV1SavePut","parameters":[{"name":"attributeSetId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["group"],"properties":{"group":{"$ref":"#/definitions/eav-data-attribute-group-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/eav-data-attribute-group-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/attribute-sets/groups/{groupId}":{"delete":{"tags":["catalogProductAttributeGroupRepositoryV1"],"description":"Remove attribute group by id","operationId":"catalogProductAttributeGroupRepositoryV1DeleteByIdDelete","parameters":[{"name":"groupId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/attributes/{attributeCode}/options":{"get":{"tags":["catalogProductAttributeOptionManagementV1"],"description":"Retrieve list of attribute options","operationId":"catalogProductAttributeOptionManagementV1GetItemsGet","parameters":[{"name":"attributeCode","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/eav-data-attribute-option-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"post":{"tags":["catalogProductAttributeOptionManagementV1"],"description":"Add option to attribute","operationId":"catalogProductAttributeOptionManagementV1AddPost","parameters":[{"name":"attributeCode","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["option"],"properties":{"option":{"$ref":"#/definitions/eav-data-attribute-option-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/attributes/{attributeCode}/options/{optionId}":{"delete":{"tags":["catalogProductAttributeOptionManagementV1"],"description":"Delete option from attribute","operationId":"catalogProductAttributeOptionManagementV1DeleteDelete","parameters":[{"name":"attributeCode","in":"path","type":"string","required":true},{"name":"optionId","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/media/types/{attributeSetName}":{"get":{"tags":["catalogProductMediaAttributeManagementV1"],"description":"Retrieve the list of media attributes (fronted input type is media_image) assigned to the given attribute set.","operationId":"catalogProductMediaAttributeManagementV1GetListGet","parameters":[{"name":"attributeSetName","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","description":"list of media attributes","items":{"$ref":"#/definitions/catalog-data-product-attribute-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/{sku}/media/{entryId}":{"get":{"tags":["catalogProductAttributeMediaGalleryManagementV1"],"description":"Return information about gallery entry","operationId":"catalogProductAttributeMediaGalleryManagementV1GetGet","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"entryId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/catalog-data-product-attribute-media-gallery-entry-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"put":{"tags":["catalogProductAttributeMediaGalleryManagementV1"],"description":"Update gallery entry","operationId":"catalogProductAttributeMediaGalleryManagementV1UpdatePut","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"entryId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["entry"],"properties":{"entry":{"$ref":"#/definitions/catalog-data-product-attribute-media-gallery-entry-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"delete":{"tags":["catalogProductAttributeMediaGalleryManagementV1"],"description":"Remove gallery entry","operationId":"catalogProductAttributeMediaGalleryManagementV1RemoveDelete","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"entryId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/{sku}/media":{"post":{"tags":["catalogProductAttributeMediaGalleryManagementV1"],"description":"Create new gallery entry","operationId":"catalogProductAttributeMediaGalleryManagementV1CreatePost","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["entry"],"properties":{"entry":{"$ref":"#/definitions/catalog-data-product-attribute-media-gallery-entry-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer","description":"gallery entry ID"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"get":{"tags":["catalogProductAttributeMediaGalleryManagementV1"],"description":"Retrieve the list of gallery entries associated with given product","operationId":"catalogProductAttributeMediaGalleryManagementV1GetListGet","parameters":[{"name":"sku","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/catalog-data-product-attribute-media-gallery-entry-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/{sku}/group-prices/{customerGroupId}/tiers":{"get":{"tags":["catalogProductTierPriceManagementV1"],"description":"Get tier price of product","operationId":"catalogProductTierPriceManagementV1GetListGet","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"customerGroupId","in":"path","type":"string","required":true,"description":"'all' can be used to specify 'ALL GROUPS'"}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/catalog-data-product-tier-price-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/{sku}/group-prices/{customerGroupId}/tiers/{qty}/price/{price}":{"post":{"tags":["catalogProductTierPriceManagementV1"],"description":"Create tier price for product","operationId":"catalogProductTierPriceManagementV1AddPost","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"customerGroupId","in":"path","type":"string","required":true,"description":"'all' can be used to specify 'ALL GROUPS'"},{"name":"price","in":"path","type":"number","required":true},{"name":"qty","in":"path","type":"number","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/{sku}/group-prices/{customerGroupId}/tiers/{qty}":{"delete":{"tags":["catalogProductTierPriceManagementV1"],"description":"Remove tier price from product","operationId":"catalogProductTierPriceManagementV1RemoveDelete","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"customerGroupId","in":"path","type":"string","required":true,"description":"'all' can be used to specify 'ALL GROUPS'"},{"name":"qty","in":"path","type":"number","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/tier-prices-information":{"post":{"tags":["catalogTierPriceStorageV1"],"description":"Return product prices. In case of at least one of skus is not found exception will be thrown.","operationId":"catalogTierPriceStorageV1GetPost","parameters":[{"name":"$body","in":"body","schema":{"required":["skus"],"properties":{"skus":{"type":"array","items":{"type":"string"}}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/catalog-data-tier-price-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/tier-prices":{"post":{"tags":["catalogTierPriceStorageV1"],"description":"Add or update product prices. If any items will have invalid price, price type, website id, sku, customer group or quantity, they will be marked as failed and excluded from update list and \\Magento\\Catalog\\Api\\Data\\PriceUpdateResultInterface[] with problem description will be returned. If there were no failed items during update empty array will be returned. If error occurred during the update exception will be thrown.","operationId":"catalogTierPriceStorageV1UpdatePost","parameters":[{"name":"$body","in":"body","schema":{"required":["prices"],"properties":{"prices":{"type":"array","items":{"$ref":"#/definitions/catalog-data-tier-price-interface"}}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/catalog-data-price-update-result-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"put":{"tags":["catalogTierPriceStorageV1"],"description":"Remove existing tier prices and replace them with the new ones. If any items will have invalid price, price type, website id, sku, customer group or quantity, they will be marked as failed and excluded from replace list and \\Magento\\Catalog\\Api\\Data\\PriceUpdateResultInterface[] with problem description will be returned. If there were no failed items during update empty array will be returned. If error occurred during the update exception will be thrown.","operationId":"catalogTierPriceStorageV1ReplacePut","parameters":[{"name":"$body","in":"body","schema":{"required":["prices"],"properties":{"prices":{"type":"array","items":{"$ref":"#/definitions/catalog-data-tier-price-interface"}}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/catalog-data-price-update-result-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/tier-prices-delete":{"post":{"tags":["catalogTierPriceStorageV1"],"description":"Delete product tier prices. If any items will have invalid price, price type, website id, sku, customer group or quantity, they will be marked as failed and excluded from delete list and \\Magento\\Catalog\\Api\\Data\\PriceUpdateResultInterface[] with problem description will be returned. If there were no failed items during update empty array will be returned. If error occurred during the update exception will be thrown.","operationId":"catalogTierPriceStorageV1DeletePost","parameters":[{"name":"$body","in":"body","schema":{"required":["prices"],"properties":{"prices":{"type":"array","items":{"$ref":"#/definitions/catalog-data-tier-price-interface"}}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/catalog-data-price-update-result-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/base-prices-information":{"post":{"tags":["catalogBasePriceStorageV1"],"description":"Return product prices. In case of at least one of skus is not found exception will be thrown.","operationId":"catalogBasePriceStorageV1GetPost","parameters":[{"name":"$body","in":"body","schema":{"required":["skus"],"properties":{"skus":{"type":"array","items":{"type":"string"}}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/catalog-data-base-price-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/base-prices":{"post":{"tags":["catalogBasePriceStorageV1"],"description":"Add or update product prices. Input item should correspond \\Magento\\Catalog\\Api\\Data\\CostInterface. If any items will have invalid price, store id or sku, they will be marked as failed and excluded from update list and \\Magento\\Catalog\\Api\\Data\\PriceUpdateResultInterface[] with problem description will be returned. If there were no failed items during update empty array will be returned. If error occurred during the update exception will be thrown.","operationId":"catalogBasePriceStorageV1UpdatePost","parameters":[{"name":"$body","in":"body","schema":{"required":["prices"],"properties":{"prices":{"type":"array","items":{"$ref":"#/definitions/catalog-data-base-price-interface"}}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/catalog-data-price-update-result-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/cost-information":{"post":{"tags":["catalogCostStorageV1"],"description":"Return product prices. In case of at least one of skus is not found exception will be thrown.","operationId":"catalogCostStorageV1GetPost","parameters":[{"name":"$body","in":"body","schema":{"required":["skus"],"properties":{"skus":{"type":"array","items":{"type":"string"}}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/catalog-data-cost-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/cost":{"post":{"tags":["catalogCostStorageV1"],"description":"Add or update product cost. Input item should correspond to \\Magento\\Catalog\\Api\\Data\\CostInterface. If any items will have invalid cost, store id or sku, they will be marked as failed and excluded from update list and \\Magento\\Catalog\\Api\\Data\\PriceUpdateResultInterface[] with problem description will be returned. If there were no failed items during update empty array will be returned. If error occurred during the update exception will be thrown.","operationId":"catalogCostStorageV1UpdatePost","parameters":[{"name":"$body","in":"body","schema":{"required":["prices"],"properties":{"prices":{"type":"array","items":{"$ref":"#/definitions/catalog-data-cost-interface"}}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/catalog-data-price-update-result-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/cost-delete":{"post":{"tags":["catalogCostStorageV1"],"description":"Delete product cost. In case of at least one of skus is not found exception will be thrown. If error occurred during the delete exception will be thrown.","operationId":"catalogCostStorageV1DeletePost","parameters":[{"name":"$body","in":"body","schema":{"required":["skus"],"properties":{"skus":{"type":"array","items":{"type":"string"}}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean","description":"Will return True if deleted."}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/special-price-information":{"post":{"tags":["catalogSpecialPriceStorageV1"],"description":"Return product's special price. In case of at least one of skus is not found exception will be thrown.","operationId":"catalogSpecialPriceStorageV1GetPost","parameters":[{"name":"$body","in":"body","schema":{"required":["skus"],"properties":{"skus":{"type":"array","items":{"type":"string"}}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/catalog-data-special-price-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/special-price":{"post":{"tags":["catalogSpecialPriceStorageV1"],"description":"Add or update product's special price. If any items will have invalid price, store id, sku or dates, they will be marked as failed and excluded from update list and \\Magento\\Catalog\\Api\\Data\\PriceUpdateResultInterface[] with problem description will be returned. If there were no failed items during update empty array will be returned. If error occurred during the update exception will be thrown.","operationId":"catalogSpecialPriceStorageV1UpdatePost","parameters":[{"name":"$body","in":"body","schema":{"required":["prices"],"properties":{"prices":{"type":"array","items":{"$ref":"#/definitions/catalog-data-special-price-interface"}}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/catalog-data-price-update-result-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/special-price-delete":{"post":{"tags":["catalogSpecialPriceStorageV1"],"description":"Delete product's special price. If any items will have invalid price, store id, sku or dates, they will be marked as failed and excluded from delete list and \\Magento\\Catalog\\Api\\Data\\PriceUpdateResultInterface[] with problem description will be returned. If there were no failed items during update empty array will be returned. If error occurred during the delete exception will be thrown.","operationId":"catalogSpecialPriceStorageV1DeletePost","parameters":[{"name":"$body","in":"body","schema":{"required":["prices"],"properties":{"prices":{"type":"array","items":{"$ref":"#/definitions/catalog-data-special-price-interface"}}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/catalog-data-price-update-result-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/categories/{categoryId}":{"delete":{"tags":["catalogCategoryRepositoryV1"],"description":"Delete category by identifier","operationId":"catalogCategoryRepositoryV1DeleteByIdentifierDelete","parameters":[{"name":"categoryId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean","description":"Will returned True if deleted"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"get":{"tags":["catalogCategoryRepositoryV1"],"description":"Get info about category by category id","operationId":"catalogCategoryRepositoryV1GetGet","parameters":[{"name":"categoryId","in":"path","type":"integer","required":true},{"name":"storeId","in":"query","type":"integer","required":false}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/catalog-data-category-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/categories":{"post":{"tags":["catalogCategoryRepositoryV1"],"description":"Create category service","operationId":"catalogCategoryRepositoryV1SavePost","parameters":[{"name":"$body","in":"body","schema":{"required":["category"],"properties":{"category":{"$ref":"#/definitions/catalog-data-category-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/catalog-data-category-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"get":{"tags":["catalogCategoryManagementV1"],"description":"Retrieve list of categories","operationId":"catalogCategoryManagementV1GetTreeGet","parameters":[{"name":"rootCategoryId","in":"query","type":"integer","required":false},{"name":"depth","in":"query","type":"integer","required":false}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/catalog-data-category-tree-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/categories/{id}":{"put":{"tags":["catalogCategoryRepositoryV1"],"description":"Create category service","operationId":"catalogCategoryRepositoryV1SavePut","parameters":[{"name":"id","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["category"],"properties":{"category":{"$ref":"#/definitions/catalog-data-category-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/catalog-data-category-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/categories/{categoryId}/move":{"put":{"tags":["catalogCategoryManagementV1"],"description":"Move category","operationId":"catalogCategoryManagementV1MovePut","parameters":[{"name":"categoryId","in":"path","type":"integer","required":true},{"name":"$body","in":"body","schema":{"required":["parentId"],"properties":{"parentId":{"type":"integer"},"afterId":{"type":"integer"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/categories/list":{"get":{"tags":["catalogCategoryListV1"],"description":"Get category list","operationId":"catalogCategoryListV1GetListGet","parameters":[{"name":"searchCriteria[filterGroups][][filters][][field]","in":"query","type":"string","description":"Field"},{"name":"searchCriteria[filterGroups][][filters][][value]","in":"query","type":"string","description":"Value"},{"name":"searchCriteria[filterGroups][][filters][][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"searchCriteria[sortOrders][][field]","in":"query","type":"string","description":"Sorting field."},{"name":"searchCriteria[sortOrders][][direction]","in":"query","type":"string","description":"Sorting direction."},{"name":"searchCriteria[pageSize]","in":"query","type":"integer","description":"Page size."},{"name":"searchCriteria[currentPage]","in":"query","type":"integer","description":"Current page."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/catalog-data-category-search-results-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/options/types":{"get":{"tags":["catalogProductCustomOptionTypeListV1"],"description":"Get custom option types","operationId":"catalogProductCustomOptionTypeListV1GetItemsGet","responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/catalog-data-product-custom-option-type-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/{sku}/options":{"get":{"tags":["catalogProductCustomOptionRepositoryV1"],"description":"Get the list of custom options for a specific product","operationId":"catalogProductCustomOptionRepositoryV1GetListGet","parameters":[{"name":"sku","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/catalog-data-product-custom-option-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/{sku}/options/{optionId}":{"get":{"tags":["catalogProductCustomOptionRepositoryV1"],"description":"Get custom option for a specific product","operationId":"catalogProductCustomOptionRepositoryV1GetGet","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"optionId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/catalog-data-product-custom-option-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"delete":{"tags":["catalogProductCustomOptionRepositoryV1"],"description":"","operationId":"catalogProductCustomOptionRepositoryV1DeleteByIdentifierDelete","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"optionId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/options":{"post":{"tags":["catalogProductCustomOptionRepositoryV1"],"description":"Save Custom Option","operationId":"catalogProductCustomOptionRepositoryV1SavePost","parameters":[{"name":"$body","in":"body","schema":{"required":["option"],"properties":{"option":{"$ref":"#/definitions/catalog-data-product-custom-option-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/catalog-data-product-custom-option-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/options/{optionId}":{"put":{"tags":["catalogProductCustomOptionRepositoryV1"],"description":"Save Custom Option","operationId":"catalogProductCustomOptionRepositoryV1SavePut","parameters":[{"name":"optionId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["option"],"properties":{"option":{"$ref":"#/definitions/catalog-data-product-custom-option-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/catalog-data-product-custom-option-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/links/types":{"get":{"tags":["catalogProductLinkTypeListV1"],"description":"Retrieve information about available product link types","operationId":"catalogProductLinkTypeListV1GetItemsGet","responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/catalog-data-product-link-type-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/links/{type}/attributes":{"get":{"tags":["catalogProductLinkTypeListV1"],"description":"Provide a list of the product link type attributes","operationId":"catalogProductLinkTypeListV1GetItemAttributesGet","parameters":[{"name":"type","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/catalog-data-product-link-attribute-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/{sku}/links/{type}":{"get":{"tags":["catalogProductLinkManagementV1"],"description":"Provide the list of links for a specific product","operationId":"catalogProductLinkManagementV1GetLinkedItemsByTypeGet","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"type","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/catalog-data-product-link-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/{sku}/links":{"post":{"tags":["catalogProductLinkManagementV1"],"description":"Assign a product link to another product","operationId":"catalogProductLinkManagementV1SetProductLinksPost","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/definitions/catalog-data-product-link-interface"}}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"put":{"tags":["catalogProductLinkRepositoryV1"],"description":"Save product link","operationId":"catalogProductLinkRepositoryV1SavePut","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["entity"],"properties":{"entity":{"$ref":"#/definitions/catalog-data-product-link-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/{sku}/links/{type}/{linkedProductSku}":{"delete":{"tags":["catalogProductLinkRepositoryV1"],"description":"","operationId":"catalogProductLinkRepositoryV1DeleteByIdDelete","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"type","in":"path","type":"string","required":true},{"name":"linkedProductSku","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/categories/{categoryId}/products":{"get":{"tags":["catalogCategoryLinkManagementV1"],"description":"Get products assigned to category","operationId":"catalogCategoryLinkManagementV1GetAssignedProductsGet","parameters":[{"name":"categoryId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/catalog-data-category-product-link-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"post":{"tags":["catalogCategoryLinkRepositoryV1"],"description":"Assign a product to the required category","operationId":"catalogCategoryLinkRepositoryV1SavePost","parameters":[{"name":"categoryId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["productLink"],"properties":{"productLink":{"$ref":"#/definitions/catalog-data-category-product-link-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean","description":"will returned True if assigned"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"put":{"tags":["catalogCategoryLinkRepositoryV1"],"description":"Assign a product to the required category","operationId":"catalogCategoryLinkRepositoryV1SavePut","parameters":[{"name":"categoryId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["productLink"],"properties":{"productLink":{"$ref":"#/definitions/catalog-data-category-product-link-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean","description":"will returned True if assigned"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/categories/{categoryId}/products/{sku}":{"delete":{"tags":["catalogCategoryLinkRepositoryV1"],"description":"Remove the product assignment from the category by category id and sku","operationId":"catalogCategoryLinkRepositoryV1DeleteByIdsDelete","parameters":[{"name":"categoryId","in":"path","type":"string","required":true},{"name":"sku","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean","description":"will returned True if products successfully deleted"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/{sku}/websites":{"post":{"tags":["catalogProductWebsiteLinkRepositoryV1"],"description":"Assign a product to the website","operationId":"catalogProductWebsiteLinkRepositoryV1SavePost","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["productWebsiteLink"],"properties":{"productWebsiteLink":{"$ref":"#/definitions/catalog-data-product-website-link-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean","description":"will returned True if website successfully assigned to product"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"put":{"tags":["catalogProductWebsiteLinkRepositoryV1"],"description":"Assign a product to the website","operationId":"catalogProductWebsiteLinkRepositoryV1SavePut","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["productWebsiteLink"],"properties":{"productWebsiteLink":{"$ref":"#/definitions/catalog-data-product-website-link-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean","description":"will returned True if website successfully assigned to product"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/{sku}/websites/{websiteId}":{"delete":{"tags":["catalogProductWebsiteLinkRepositoryV1"],"description":"Remove the website assignment from the product by product sku","operationId":"catalogProductWebsiteLinkRepositoryV1DeleteByIdDelete","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"websiteId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean","description":"will returned True if website successfully unassigned from product"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products-render-info":{"get":{"tags":["catalogProductRenderListV1"],"description":"Collect and retrieve the list of product render info This info contains raw prices and formated prices, product name, stock status, store_id, etc","operationId":"catalogProductRenderListV1GetListGet","parameters":[{"name":"searchCriteria[filterGroups][][filters][][field]","in":"query","type":"string","description":"Field"},{"name":"searchCriteria[filterGroups][][filters][][value]","in":"query","type":"string","description":"Value"},{"name":"searchCriteria[filterGroups][][filters][][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"searchCriteria[sortOrders][][field]","in":"query","type":"string","description":"Sorting field."},{"name":"searchCriteria[sortOrders][][direction]","in":"query","type":"string","description":"Sorting direction."},{"name":"searchCriteria[pageSize]","in":"query","type":"integer","description":"Page size."},{"name":"searchCriteria[currentPage]","in":"query","type":"integer","description":"Current page."},{"name":"storeId","in":"query","type":"integer","required":true},{"name":"currencyCode","in":"query","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/catalog-data-product-render-search-results-interface"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/stockItems/{productSku}":{"get":{"tags":["catalogInventoryStockRegistryV1"],"description":"","operationId":"catalogInventoryStockRegistryV1GetStockItemBySkuGet","parameters":[{"name":"productSku","in":"path","type":"string","required":true},{"name":"scopeId","in":"query","type":"integer","required":false}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/catalog-inventory-data-stock-item-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/{productSku}/stockItems/{itemId}":{"put":{"tags":["catalogInventoryStockRegistryV1"],"description":"","operationId":"catalogInventoryStockRegistryV1UpdateStockItemBySkuPut","parameters":[{"name":"productSku","in":"path","type":"string","required":true},{"name":"itemId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["stockItem"],"properties":{"stockItem":{"$ref":"#/definitions/catalog-inventory-data-stock-item-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/stockItems/lowStock/":{"get":{"tags":["catalogInventoryStockRegistryV1"],"description":"Retrieves a list of SKU's with low inventory qty","operationId":"catalogInventoryStockRegistryV1GetLowStockItemsGet","parameters":[{"name":"scopeId","in":"query","type":"integer","required":true},{"name":"qty","in":"query","type":"number","required":true},{"name":"currentPage","in":"query","type":"integer","required":false},{"name":"pageSize","in":"query","type":"integer","required":false}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/catalog-inventory-data-stock-status-collection-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/stockStatuses/{productSku}":{"get":{"tags":["catalogInventoryStockRegistryV1"],"description":"","operationId":"catalogInventoryStockRegistryV1GetStockStatusBySkuGet","parameters":[{"name":"productSku","in":"path","type":"string","required":true},{"name":"scopeId","in":"query","type":"integer","required":false}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/catalog-inventory-data-stock-status-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/bundle-products/{sku}/links/{optionId}":{"post":{"tags":["bundleProductLinkManagementV1"],"description":"Add child product to specified Bundle option by product sku","operationId":"bundleProductLinkManagementV1AddChildByProductSkuPost","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"optionId","in":"path","type":"integer","required":true},{"name":"$body","in":"body","schema":{"required":["linkedProduct"],"properties":{"linkedProduct":{"$ref":"#/definitions/bundle-data-link-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/bundle-products/{sku}/links/{id}":{"put":{"tags":["bundleProductLinkManagementV1"],"description":"","operationId":"bundleProductLinkManagementV1SaveChildPut","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"id","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["linkedProduct"],"properties":{"linkedProduct":{"$ref":"#/definitions/bundle-data-link-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/bundle-products/{productSku}/children":{"get":{"tags":["bundleProductLinkManagementV1"],"description":"Get all children for Bundle product","operationId":"bundleProductLinkManagementV1GetChildrenGet","parameters":[{"name":"productSku","in":"path","type":"string","required":true},{"name":"optionId","in":"query","type":"integer","required":false}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/bundle-data-link-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/bundle-products/{sku}/options/{optionId}/children/{childSku}":{"delete":{"tags":["bundleProductLinkManagementV1"],"description":"Remove product from Bundle product option","operationId":"bundleProductLinkManagementV1RemoveChildDelete","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"optionId","in":"path","type":"integer","required":true},{"name":"childSku","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/bundle-products/{sku}/options/all":{"get":{"tags":["bundleProductOptionRepositoryV1"],"description":"Get all options for bundle product","operationId":"bundleProductOptionRepositoryV1GetListGet","parameters":[{"name":"sku","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/bundle-data-option-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/bundle-products/{sku}/options/{optionId}":{"get":{"tags":["bundleProductOptionRepositoryV1"],"description":"Get option for bundle product","operationId":"bundleProductOptionRepositoryV1GetGet","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"optionId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/bundle-data-option-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"delete":{"tags":["bundleProductOptionRepositoryV1"],"description":"Remove bundle option","operationId":"bundleProductOptionRepositoryV1DeleteByIdDelete","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"optionId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/bundle-products/options/types":{"get":{"tags":["bundleProductOptionTypeListV1"],"description":"Get all types for options for bundle products","operationId":"bundleProductOptionTypeListV1GetItemsGet","responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/bundle-data-option-type-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/bundle-products/options/add":{"post":{"tags":["bundleProductOptionManagementV1"],"description":"Add new option for bundle product","operationId":"bundleProductOptionManagementV1SavePost","parameters":[{"name":"$body","in":"body","schema":{"required":["option"],"properties":{"option":{"$ref":"#/definitions/bundle-data-option-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/bundle-products/options/{optionId}":{"put":{"tags":["bundleProductOptionManagementV1"],"description":"Add new option for bundle product","operationId":"bundleProductOptionManagementV1SavePut","parameters":[{"name":"optionId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["option"],"properties":{"option":{"$ref":"#/definitions/bundle-data-option-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/{cartId}":{"get":{"tags":["quoteCartRepositoryV1"],"description":"Enables an administrative user to return information for a specified cart.","operationId":"quoteCartRepositoryV1GetGet","parameters":[{"name":"cartId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/quote-data-cart-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"put":{"tags":["quoteCartManagementV1"],"description":"Assigns a specified customer to a specified shopping cart.","operationId":"quoteCartManagementV1AssignCustomerPut","parameters":[{"name":"cartId","in":"path","type":"integer","required":true,"description":"The cart ID."},{"name":"$body","in":"body","schema":{"required":["customerId","storeId"],"properties":{"customerId":{"type":"integer","description":"The customer ID."},"storeId":{"type":"integer"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/search":{"get":{"tags":["quoteCartRepositoryV1"],"description":"Enables administrative users to list carts that match specified search criteria. This call returns an array of objects, but detailed information about each object\u2019s attributes might not be included. See http://devdocs.magento.com/codelinks/attributes.html#CartRepositoryInterface to determine which call to use to get detailed information about all attributes for an object.","operationId":"quoteCartRepositoryV1GetListGet","parameters":[{"name":"searchCriteria[filterGroups][][filters][][field]","in":"query","type":"string","description":"Field"},{"name":"searchCriteria[filterGroups][][filters][][value]","in":"query","type":"string","description":"Value"},{"name":"searchCriteria[filterGroups][][filters][][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"searchCriteria[sortOrders][][field]","in":"query","type":"string","description":"Sorting field."},{"name":"searchCriteria[sortOrders][][direction]","in":"query","type":"string","description":"Sorting direction."},{"name":"searchCriteria[pageSize]","in":"query","type":"integer","description":"Page size."},{"name":"searchCriteria[currentPage]","in":"query","type":"integer","description":"Current page."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/quote-data-cart-search-results-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/mine":{"put":{"tags":["quoteCartRepositoryV1"],"description":"Save quote","operationId":"quoteCartRepositoryV1SavePut","parameters":[{"name":"$body","in":"body","schema":{"required":["quote"],"properties":{"quote":{"$ref":"#/definitions/quote-data-cart-interface"}},"type":"object"}}],"responses":{"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"post":{"tags":["quoteCartManagementV1"],"description":"Creates an empty cart and quote for a specified customer if customer does not have a cart yet.","operationId":"quoteCartManagementV1CreateEmptyCartForCustomerPost","responses":{"200":{"description":"200 Success.","schema":{"type":"integer","description":"new cart ID if customer did not have a cart or ID of the existing cart otherwise."}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"get":{"tags":["quoteCartManagementV1"],"description":"Returns information for the cart for a specified customer.","operationId":"quoteCartManagementV1GetCartForCustomerGet","responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/quote-data-cart-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/":{"post":{"tags":["quoteCartManagementV1"],"description":"Creates an empty cart and quote for a guest.","operationId":"quoteCartManagementV1CreateEmptyCartPost","responses":{"200":{"description":"200 Success.","schema":{"type":"integer","description":"Cart ID."}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/customers/{customerId}/carts":{"post":{"tags":["quoteCartManagementV1"],"description":"Creates an empty cart and quote for a specified customer if customer does not have a cart yet.","operationId":"quoteCartManagementV1CreateEmptyCartForCustomerPost","parameters":[{"name":"customerId","in":"path","type":"integer","required":true,"description":"The customer ID."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer","description":"new cart ID if customer did not have a cart or ID of the existing cart otherwise."}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/mine/order":{"put":{"tags":["quoteCartManagementV1"],"description":"Places an order for a specified cart.","operationId":"quoteCartManagementV1PlaceOrderPut","parameters":[{"name":"$body","in":"body","schema":{"properties":{"paymentMethod":{"$ref":"#/definitions/quote-data-payment-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer","description":"Order ID."}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/{cartId}/order":{"put":{"tags":["quoteCartManagementV1"],"description":"Places an order for a specified cart.","operationId":"quoteCartManagementV1PlaceOrderPut","parameters":[{"name":"cartId","in":"path","type":"integer","required":true,"description":"The cart ID."},{"name":"$body","in":"body","schema":{"properties":{"paymentMethod":{"$ref":"#/definitions/quote-data-payment-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer","description":"Order ID."}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/guest-carts/{cartId}":{"get":{"tags":["quoteGuestCartRepositoryV1"],"description":"Enable a guest user to return information for a specified cart.","operationId":"quoteGuestCartRepositoryV1GetGet","parameters":[{"name":"cartId","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/quote-data-cart-interface"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"put":{"tags":["quoteGuestCartManagementV1"],"description":"Assign a specified customer to a specified shopping cart.","operationId":"quoteGuestCartManagementV1AssignCustomerPut","parameters":[{"name":"cartId","in":"path","type":"string","required":true,"description":"The cart ID."},{"name":"$body","in":"body","schema":{"required":["customerId","storeId"],"properties":{"customerId":{"type":"integer","description":"The customer ID."},"storeId":{"type":"integer"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/guest-carts":{"post":{"tags":["quoteGuestCartManagementV1"],"description":"Enable an customer or guest user to create an empty cart and quote for an anonymous customer.","operationId":"quoteGuestCartManagementV1CreateEmptyCartPost","responses":{"200":{"description":"200 Success.","schema":{"type":"string","description":"Cart ID."}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/guest-carts/{cartId}/order":{"put":{"tags":["quoteGuestCartManagementV1"],"description":"Place an order for a specified cart.","operationId":"quoteGuestCartManagementV1PlaceOrderPut","parameters":[{"name":"cartId","in":"path","type":"string","required":true,"description":"The cart ID."},{"name":"$body","in":"body","schema":{"properties":{"paymentMethod":{"$ref":"#/definitions/quote-data-payment-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer","description":"Order ID."}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/{cartId}/shipping-methods":{"get":{"tags":["quoteShippingMethodManagementV1"],"description":"Lists applicable shipping methods for a specified quote.","operationId":"quoteShippingMethodManagementV1GetListGet","parameters":[{"name":"cartId","in":"path","type":"integer","required":true,"description":"The shopping cart ID."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","description":"An array of shipping methods.","items":{"$ref":"#/definitions/quote-data-shipping-method-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/{cartId}/estimate-shipping-methods-by-address-id":{"post":{"tags":["quoteShippingMethodManagementV1"],"description":"Estimate shipping","operationId":"quoteShippingMethodManagementV1EstimateByAddressIdPost","parameters":[{"name":"cartId","in":"path","type":"integer","required":true,"description":"The shopping cart ID."},{"name":"$body","in":"body","schema":{"required":["addressId"],"properties":{"addressId":{"type":"integer","description":"The estimate address id"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","description":"An array of shipping methods.","items":{"$ref":"#/definitions/quote-data-shipping-method-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/mine/shipping-methods":{"get":{"tags":["quoteShippingMethodManagementV1"],"description":"Lists applicable shipping methods for a specified quote.","operationId":"quoteShippingMethodManagementV1GetListGet","responses":{"200":{"description":"200 Success.","schema":{"type":"array","description":"An array of shipping methods.","items":{"$ref":"#/definitions/quote-data-shipping-method-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/mine/estimate-shipping-methods-by-address-id":{"post":{"tags":["quoteShippingMethodManagementV1"],"description":"Estimate shipping","operationId":"quoteShippingMethodManagementV1EstimateByAddressIdPost","parameters":[{"name":"$body","in":"body","schema":{"required":["addressId"],"properties":{"addressId":{"type":"integer","description":"The estimate address id"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","description":"An array of shipping methods.","items":{"$ref":"#/definitions/quote-data-shipping-method-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/{cartId}/estimate-shipping-methods":{"post":{"tags":["quoteShipmentEstimationV1"],"description":"Estimate shipping by address and return list of available shipping methods","operationId":"quoteShipmentEstimationV1EstimateByExtendedAddressPost","parameters":[{"name":"cartId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["address"],"properties":{"address":{"$ref":"#/definitions/quote-data-address-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","description":"An array of shipping methods","items":{"$ref":"#/definitions/quote-data-shipping-method-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/mine/estimate-shipping-methods":{"post":{"tags":["quoteShipmentEstimationV1"],"description":"Estimate shipping by address and return list of available shipping methods","operationId":"quoteShipmentEstimationV1EstimateByExtendedAddressPost","parameters":[{"name":"$body","in":"body","schema":{"required":["address"],"properties":{"address":{"$ref":"#/definitions/quote-data-address-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","description":"An array of shipping methods","items":{"$ref":"#/definitions/quote-data-shipping-method-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/guest-carts/{cartId}/shipping-methods":{"get":{"tags":["quoteGuestShippingMethodManagementV1"],"description":"List applicable shipping methods for a specified quote.","operationId":"quoteGuestShippingMethodManagementV1GetListGet","parameters":[{"name":"cartId","in":"path","type":"string","required":true,"description":"The shopping cart ID."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","description":"An array of shipping methods.","items":{"$ref":"#/definitions/quote-data-shipping-method-interface"}}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/guest-carts/{cartId}/estimate-shipping-methods":{"post":{"tags":["quoteGuestShipmentEstimationV1"],"description":"Estimate shipping by address and return list of available shipping methods","operationId":"quoteGuestShipmentEstimationV1EstimateByExtendedAddressPost","parameters":[{"name":"cartId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["address"],"properties":{"address":{"$ref":"#/definitions/quote-data-address-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","description":"An array of shipping methods","items":{"$ref":"#/definitions/quote-data-shipping-method-interface"}}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/{cartId}/items":{"get":{"tags":["quoteCartItemRepositoryV1"],"description":"Lists items that are assigned to a specified cart.","operationId":"quoteCartItemRepositoryV1GetListGet","parameters":[{"name":"cartId","in":"path","type":"integer","required":true,"description":"The cart ID."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","description":"Array of items.","items":{"$ref":"#/definitions/quote-data-cart-item-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/{quoteId}/items":{"post":{"tags":["quoteCartItemRepositoryV1"],"description":"Add/update the specified cart item.","operationId":"quoteCartItemRepositoryV1SavePost","parameters":[{"name":"quoteId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["cartItem"],"properties":{"cartItem":{"$ref":"#/definitions/quote-data-cart-item-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/quote-data-cart-item-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/{cartId}/items/{itemId}":{"put":{"tags":["quoteCartItemRepositoryV1"],"description":"Add/update the specified cart item.","operationId":"quoteCartItemRepositoryV1SavePut","parameters":[{"name":"cartId","in":"path","type":"string","required":true},{"name":"itemId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["cartItem"],"properties":{"cartItem":{"$ref":"#/definitions/quote-data-cart-item-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/quote-data-cart-item-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"delete":{"tags":["quoteCartItemRepositoryV1"],"description":"Removes the specified item from the specified cart.","operationId":"quoteCartItemRepositoryV1DeleteByIdDelete","parameters":[{"name":"cartId","in":"path","type":"integer","required":true,"description":"The cart ID."},{"name":"itemId","in":"path","type":"integer","required":true,"description":"The item ID of the item to be removed."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/mine/items":{"get":{"tags":["quoteCartItemRepositoryV1"],"description":"Lists items that are assigned to a specified cart.","operationId":"quoteCartItemRepositoryV1GetListGet","responses":{"200":{"description":"200 Success.","schema":{"type":"array","description":"Array of items.","items":{"$ref":"#/definitions/quote-data-cart-item-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"post":{"tags":["quoteCartItemRepositoryV1"],"description":"Add/update the specified cart item.","operationId":"quoteCartItemRepositoryV1SavePost","parameters":[{"name":"$body","in":"body","schema":{"required":["cartItem"],"properties":{"cartItem":{"$ref":"#/definitions/quote-data-cart-item-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/quote-data-cart-item-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/mine/items/{itemId}":{"put":{"tags":["quoteCartItemRepositoryV1"],"description":"Add/update the specified cart item.","operationId":"quoteCartItemRepositoryV1SavePut","parameters":[{"name":"itemId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["cartItem"],"properties":{"cartItem":{"$ref":"#/definitions/quote-data-cart-item-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/quote-data-cart-item-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"delete":{"tags":["quoteCartItemRepositoryV1"],"description":"Removes the specified item from the specified cart.","operationId":"quoteCartItemRepositoryV1DeleteByIdDelete","parameters":[{"name":"itemId","in":"path","type":"integer","required":true,"description":"The item ID of the item to be removed."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/guest-carts/{cartId}/items":{"get":{"tags":["quoteGuestCartItemRepositoryV1"],"description":"List items that are assigned to a specified cart.","operationId":"quoteGuestCartItemRepositoryV1GetListGet","parameters":[{"name":"cartId","in":"path","type":"string","required":true,"description":"The cart ID."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","description":"Array of items.","items":{"$ref":"#/definitions/quote-data-cart-item-interface"}}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"post":{"tags":["quoteGuestCartItemRepositoryV1"],"description":"Add/update the specified cart item.","operationId":"quoteGuestCartItemRepositoryV1SavePost","parameters":[{"name":"cartId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["cartItem"],"properties":{"cartItem":{"$ref":"#/definitions/quote-data-cart-item-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/quote-data-cart-item-interface"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/guest-carts/{cartId}/items/{itemId}":{"put":{"tags":["quoteGuestCartItemRepositoryV1"],"description":"Add/update the specified cart item.","operationId":"quoteGuestCartItemRepositoryV1SavePut","parameters":[{"name":"cartId","in":"path","type":"string","required":true},{"name":"itemId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["cartItem"],"properties":{"cartItem":{"$ref":"#/definitions/quote-data-cart-item-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/quote-data-cart-item-interface"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"delete":{"tags":["quoteGuestCartItemRepositoryV1"],"description":"Remove the specified item from the specified cart.","operationId":"quoteGuestCartItemRepositoryV1DeleteByIdDelete","parameters":[{"name":"cartId","in":"path","type":"string","required":true,"description":"The cart ID."},{"name":"itemId","in":"path","type":"integer","required":true,"description":"The item ID of the item to be removed."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/{cartId}/selected-payment-method":{"get":{"tags":["quotePaymentMethodManagementV1"],"description":"Returns the payment method for a specified shopping cart.","operationId":"quotePaymentMethodManagementV1GetGet","parameters":[{"name":"cartId","in":"path","type":"integer","required":true,"description":"The cart ID."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/quote-data-payment-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"put":{"tags":["quotePaymentMethodManagementV1"],"description":"Adds a specified payment method to a specified shopping cart.","operationId":"quotePaymentMethodManagementV1SetPut","parameters":[{"name":"cartId","in":"path","type":"integer","required":true,"description":"The cart ID."},{"name":"$body","in":"body","schema":{"required":["method"],"properties":{"method":{"$ref":"#/definitions/quote-data-payment-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"string","description":"redirect url or error message."}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/{cartId}/payment-methods":{"get":{"tags":["quotePaymentMethodManagementV1"],"description":"Lists available payment methods for a specified shopping cart. This call returns an array of objects, but detailed information about each object\u2019s attributes might not be included. See http://devdocs.magento.com/codelinks/attributes.html#PaymentMethodManagementInterface to determine which call to use to get detailed information about all attributes for an object.","operationId":"quotePaymentMethodManagementV1GetListGet","parameters":[{"name":"cartId","in":"path","type":"integer","required":true,"description":"The cart ID."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","description":"Array of payment methods.","items":{"$ref":"#/definitions/quote-data-payment-method-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/mine/selected-payment-method":{"get":{"tags":["quotePaymentMethodManagementV1"],"description":"Returns the payment method for a specified shopping cart.","operationId":"quotePaymentMethodManagementV1GetGet","responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/quote-data-payment-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"put":{"tags":["quotePaymentMethodManagementV1"],"description":"Adds a specified payment method to a specified shopping cart.","operationId":"quotePaymentMethodManagementV1SetPut","parameters":[{"name":"$body","in":"body","schema":{"required":["method"],"properties":{"method":{"$ref":"#/definitions/quote-data-payment-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"string","description":"redirect url or error message."}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/mine/payment-methods":{"get":{"tags":["quotePaymentMethodManagementV1"],"description":"Lists available payment methods for a specified shopping cart. This call returns an array of objects, but detailed information about each object\u2019s attributes might not be included. See http://devdocs.magento.com/codelinks/attributes.html#PaymentMethodManagementInterface to determine which call to use to get detailed information about all attributes for an object.","operationId":"quotePaymentMethodManagementV1GetListGet","responses":{"200":{"description":"200 Success.","schema":{"type":"array","description":"Array of payment methods.","items":{"$ref":"#/definitions/quote-data-payment-method-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/guest-carts/{cartId}/selected-payment-method":{"get":{"tags":["quoteGuestPaymentMethodManagementV1"],"description":"Return the payment method for a specified shopping cart.","operationId":"quoteGuestPaymentMethodManagementV1GetGet","parameters":[{"name":"cartId","in":"path","type":"string","required":true,"description":"The cart ID."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/quote-data-payment-interface"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"put":{"tags":["quoteGuestPaymentMethodManagementV1"],"description":"Add a specified payment method to a specified shopping cart.","operationId":"quoteGuestPaymentMethodManagementV1SetPut","parameters":[{"name":"cartId","in":"path","type":"string","required":true,"description":"The cart ID."},{"name":"$body","in":"body","schema":{"required":["method"],"properties":{"method":{"$ref":"#/definitions/quote-data-payment-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer","description":"Payment method ID."}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/guest-carts/{cartId}/payment-methods":{"get":{"tags":["quoteGuestPaymentMethodManagementV1"],"description":"List available payment methods for a specified shopping cart. This call returns an array of objects, but detailed information about each object\u2019s attributes might not be included. See http://devdocs.magento.com/codelinks/attributes.html#GuestPaymentMethodManagementInterface to determine which call to use to get detailed information about all attributes for an object.","operationId":"quoteGuestPaymentMethodManagementV1GetListGet","parameters":[{"name":"cartId","in":"path","type":"string","required":true,"description":"The cart ID."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","description":"Array of payment methods.","items":{"$ref":"#/definitions/quote-data-payment-method-interface"}}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/{cartId}/billing-address":{"get":{"tags":["quoteBillingAddressManagementV1"],"description":"Returns the billing address for a specified quote.","operationId":"quoteBillingAddressManagementV1GetGet","parameters":[{"name":"cartId","in":"path","type":"integer","required":true,"description":"The cart ID."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/quote-data-address-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"post":{"tags":["quoteBillingAddressManagementV1"],"description":"Assigns a specified billing address to a specified cart.","operationId":"quoteBillingAddressManagementV1AssignPost","parameters":[{"name":"cartId","in":"path","type":"integer","required":true,"description":"The cart ID."},{"name":"$body","in":"body","schema":{"required":["address"],"properties":{"address":{"$ref":"#/definitions/quote-data-address-interface"},"useForShipping":{"type":"boolean"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer","description":"Address ID."}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/mine/billing-address":{"get":{"tags":["quoteBillingAddressManagementV1"],"description":"Returns the billing address for a specified quote.","operationId":"quoteBillingAddressManagementV1GetGet","responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/quote-data-address-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"post":{"tags":["quoteBillingAddressManagementV1"],"description":"Assigns a specified billing address to a specified cart.","operationId":"quoteBillingAddressManagementV1AssignPost","parameters":[{"name":"$body","in":"body","schema":{"required":["address"],"properties":{"address":{"$ref":"#/definitions/quote-data-address-interface"},"useForShipping":{"type":"boolean"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer","description":"Address ID."}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/guest-carts/{cartId}/billing-address":{"get":{"tags":["quoteGuestBillingAddressManagementV1"],"description":"Return the billing address for a specified quote.","operationId":"quoteGuestBillingAddressManagementV1GetGet","parameters":[{"name":"cartId","in":"path","type":"string","required":true,"description":"The cart ID."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/quote-data-address-interface"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"post":{"tags":["quoteGuestBillingAddressManagementV1"],"description":"Assign a specified billing address to a specified cart.","operationId":"quoteGuestBillingAddressManagementV1AssignPost","parameters":[{"name":"cartId","in":"path","type":"string","required":true,"description":"The cart ID."},{"name":"$body","in":"body","schema":{"required":["address"],"properties":{"address":{"$ref":"#/definitions/quote-data-address-interface"},"useForShipping":{"type":"boolean"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer","description":"Address ID."}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/{cartId}/coupons":{"get":{"tags":["quoteCouponManagementV1"],"description":"Returns information for a coupon in a specified cart.","operationId":"quoteCouponManagementV1GetGet","parameters":[{"name":"cartId","in":"path","type":"integer","required":true,"description":"The cart ID."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"string","description":"The coupon code data."}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"delete":{"tags":["quoteCouponManagementV1"],"description":"Deletes a coupon from a specified cart.","operationId":"quoteCouponManagementV1RemoveDelete","parameters":[{"name":"cartId","in":"path","type":"integer","required":true,"description":"The cart ID."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/{cartId}/coupons/{couponCode}":{"put":{"tags":["quoteCouponManagementV1"],"description":"Adds a coupon by code to a specified cart.","operationId":"quoteCouponManagementV1SetPut","parameters":[{"name":"cartId","in":"path","type":"integer","required":true,"description":"The cart ID."},{"name":"couponCode","in":"path","type":"string","required":true,"description":"The coupon code data."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/mine/coupons":{"get":{"tags":["quoteCouponManagementV1"],"description":"Returns information for a coupon in a specified cart.","operationId":"quoteCouponManagementV1GetGet","responses":{"200":{"description":"200 Success.","schema":{"type":"string","description":"The coupon code data."}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"delete":{"tags":["quoteCouponManagementV1"],"description":"Deletes a coupon from a specified cart.","operationId":"quoteCouponManagementV1RemoveDelete","responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/mine/coupons/{couponCode}":{"put":{"tags":["quoteCouponManagementV1"],"description":"Adds a coupon by code to a specified cart.","operationId":"quoteCouponManagementV1SetPut","parameters":[{"name":"couponCode","in":"path","type":"string","required":true,"description":"The coupon code data."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/guest-carts/{cartId}/coupons":{"get":{"tags":["quoteGuestCouponManagementV1"],"description":"Return information for a coupon in a specified cart.","operationId":"quoteGuestCouponManagementV1GetGet","parameters":[{"name":"cartId","in":"path","type":"string","required":true,"description":"The cart ID."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"string","description":"The coupon code data."}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"delete":{"tags":["quoteGuestCouponManagementV1"],"description":"Delete a coupon from a specified cart.","operationId":"quoteGuestCouponManagementV1RemoveDelete","parameters":[{"name":"cartId","in":"path","type":"string","required":true,"description":"The cart ID."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/guest-carts/{cartId}/coupons/{couponCode}":{"put":{"tags":["quoteGuestCouponManagementV1"],"description":"Add a coupon by code to a specified cart.","operationId":"quoteGuestCouponManagementV1SetPut","parameters":[{"name":"cartId","in":"path","type":"string","required":true,"description":"The cart ID."},{"name":"couponCode","in":"path","type":"string","required":true,"description":"The coupon code data."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/{cartId}/totals":{"get":{"tags":["quoteCartTotalRepositoryV1"],"description":"Returns quote totals data for a specified cart.","operationId":"quoteCartTotalRepositoryV1GetGet","parameters":[{"name":"cartId","in":"path","type":"integer","required":true,"description":"The cart ID."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/quote-data-totals-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/mine/totals":{"get":{"tags":["quoteCartTotalRepositoryV1"],"description":"Returns quote totals data for a specified cart.","operationId":"quoteCartTotalRepositoryV1GetGet","responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/quote-data-totals-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/guest-carts/{cartId}/collect-totals":{"put":{"tags":["quoteGuestCartTotalManagementV1"],"description":"Set shipping/billing methods and additional data for cart and collect totals for guest.","operationId":"quoteGuestCartTotalManagementV1CollectTotalsPut","parameters":[{"name":"cartId","in":"path","type":"string","required":true,"description":"The cart ID."},{"name":"$body","in":"body","schema":{"required":["paymentMethod"],"properties":{"paymentMethod":{"$ref":"#/definitions/quote-data-payment-interface"},"shippingCarrierCode":{"type":"string","description":"The carrier code."},"shippingMethodCode":{"type":"string","description":"The shipping method code."},"additionalData":{"$ref":"#/definitions/quote-data-totals-additional-data-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/quote-data-totals-interface"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/guest-carts/{cartId}/totals":{"get":{"tags":["quoteGuestCartTotalRepositoryV1"],"description":"Return quote totals data for a specified cart.","operationId":"quoteGuestCartTotalRepositoryV1GetGet","parameters":[{"name":"cartId","in":"path","type":"string","required":true,"description":"The cart ID."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/quote-data-totals-interface"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/mine/collect-totals":{"put":{"tags":["quoteCartTotalManagementV1"],"description":"Set shipping/billing methods and additional data for cart and collect totals.","operationId":"quoteCartTotalManagementV1CollectTotalsPut","parameters":[{"name":"$body","in":"body","schema":{"required":["paymentMethod"],"properties":{"paymentMethod":{"$ref":"#/definitions/quote-data-payment-interface"},"shippingCarrierCode":{"type":"string","description":"The carrier code."},"shippingMethodCode":{"type":"string","description":"The shipping method code."},"additionalData":{"$ref":"#/definitions/quote-data-totals-additional-data-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/quote-data-totals-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/search":{"get":{"tags":["searchV1"],"description":"Make Full Text Search and return found Documents","operationId":"searchV1SearchGet","parameters":[{"name":"searchCriteria[requestName]","in":"query","type":"string"},{"name":"searchCriteria[filterGroups][][filters][][field]","in":"query","type":"string","description":"Field"},{"name":"searchCriteria[filterGroups][][filters][][value]","in":"query","type":"string","description":"Value"},{"name":"searchCriteria[filterGroups][][filters][][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"searchCriteria[sortOrders][][field]","in":"query","type":"string","description":"Sorting field."},{"name":"searchCriteria[sortOrders][][direction]","in":"query","type":"string","description":"Sorting direction."},{"name":"searchCriteria[pageSize]","in":"query","type":"integer","description":"Page size."},{"name":"searchCriteria[currentPage]","in":"query","type":"integer","description":"Current page."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/framework-search-search-result-interface"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/orders/{id}":{"get":{"tags":["salesOrderRepositoryV1"],"description":"Loads a specified order.","operationId":"salesOrderRepositoryV1GetGet","parameters":[{"name":"id","in":"path","type":"integer","required":true,"description":"The order ID."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-data-order-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/orders":{"get":{"tags":["salesOrderRepositoryV1"],"description":"Lists orders that match specified search criteria. This call returns an array of objects, but detailed information about each object\u2019s attributes might not be included. See http://devdocs.magento.com/codelinks/attributes.html#OrderRepositoryInterface to determine which call to use to get detailed information about all attributes for an object.","operationId":"salesOrderRepositoryV1GetListGet","parameters":[{"name":"searchCriteria[filterGroups][][filters][][field]","in":"query","type":"string","description":"Field"},{"name":"searchCriteria[filterGroups][][filters][][value]","in":"query","type":"string","description":"Value"},{"name":"searchCriteria[filterGroups][][filters][][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"searchCriteria[sortOrders][][field]","in":"query","type":"string","description":"Sorting field."},{"name":"searchCriteria[sortOrders][][direction]","in":"query","type":"string","description":"Sorting direction."},{"name":"searchCriteria[pageSize]","in":"query","type":"integer","description":"Page size."},{"name":"searchCriteria[currentPage]","in":"query","type":"integer","description":"Current page."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-data-order-search-result-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/orders/create":{"put":{"tags":["salesOrderRepositoryV1"],"description":"Performs persist operations for a specified order.","operationId":"salesOrderRepositoryV1SavePut","parameters":[{"name":"$body","in":"body","schema":{"required":["entity"],"properties":{"entity":{"$ref":"#/definitions/sales-data-order-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-data-order-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/orders/":{"post":{"tags":["salesOrderRepositoryV1"],"description":"Performs persist operations for a specified order.","operationId":"salesOrderRepositoryV1SavePost","parameters":[{"name":"$body","in":"body","schema":{"required":["entity"],"properties":{"entity":{"$ref":"#/definitions/sales-data-order-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-data-order-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/orders/{id}/statuses":{"get":{"tags":["salesOrderManagementV1"],"description":"Gets the status for a specified order.","operationId":"salesOrderManagementV1GetStatusGet","parameters":[{"name":"id","in":"path","type":"integer","required":true,"description":"The order ID."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"string","description":"Order status."}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/orders/{id}/cancel":{"post":{"tags":["salesOrderManagementV1"],"description":"Cancels a specified order.","operationId":"salesOrderManagementV1CancelPost","parameters":[{"name":"id","in":"path","type":"integer","required":true,"description":"The order ID."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/orders/{id}/emails":{"post":{"tags":["salesOrderManagementV1"],"description":"Emails a user a specified order.","operationId":"salesOrderManagementV1NotifyPost","parameters":[{"name":"id","in":"path","type":"integer","required":true,"description":"The order ID."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/orders/{id}/hold":{"post":{"tags":["salesOrderManagementV1"],"description":"Holds a specified order.","operationId":"salesOrderManagementV1HoldPost","parameters":[{"name":"id","in":"path","type":"integer","required":true,"description":"The order ID."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/orders/{id}/unhold":{"post":{"tags":["salesOrderManagementV1"],"description":"Releases a specified order from hold status.","operationId":"salesOrderManagementV1UnHoldPost","parameters":[{"name":"id","in":"path","type":"integer","required":true,"description":"The order ID."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/orders/{id}/comments":{"post":{"tags":["salesOrderManagementV1"],"description":"Adds a comment to a specified order.","operationId":"salesOrderManagementV1AddCommentPost","parameters":[{"name":"id","in":"path","type":"integer","required":true,"description":"The order ID."},{"name":"$body","in":"body","schema":{"required":["statusHistory"],"properties":{"statusHistory":{"$ref":"#/definitions/sales-data-order-status-history-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"get":{"tags":["salesOrderManagementV1"],"description":"Lists comments for a specified order.","operationId":"salesOrderManagementV1GetCommentsListGet","parameters":[{"name":"id","in":"path","type":"integer","required":true,"description":"The order ID."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-data-order-status-history-search-result-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/orders/{parent_id}":{"put":{"tags":["salesOrderAddressRepositoryV1"],"description":"Performs persist operations for a specified order address.","operationId":"salesOrderAddressRepositoryV1SavePut","parameters":[{"name":"parent_id","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["entity"],"properties":{"entity":{"$ref":"#/definitions/sales-data-order-address-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-data-order-address-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/orders/items/{id}":{"get":{"tags":["salesOrderItemRepositoryV1"],"description":"Loads a specified order item.","operationId":"salesOrderItemRepositoryV1GetGet","parameters":[{"name":"id","in":"path","type":"integer","required":true,"description":"The order item ID."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-data-order-item-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/orders/items":{"get":{"tags":["salesOrderItemRepositoryV1"],"description":"Lists order items that match specified search criteria. This call returns an array of objects, but detailed information about each object\u2019s attributes might not be included. See http://devdocs.magento.com/codelinks/attributes.html#OrderItemRepositoryInterface to determine which call to use to get detailed information about all attributes for an object.","operationId":"salesOrderItemRepositoryV1GetListGet","parameters":[{"name":"searchCriteria[filterGroups][][filters][][field]","in":"query","type":"string","description":"Field"},{"name":"searchCriteria[filterGroups][][filters][][value]","in":"query","type":"string","description":"Value"},{"name":"searchCriteria[filterGroups][][filters][][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"searchCriteria[sortOrders][][field]","in":"query","type":"string","description":"Sorting field."},{"name":"searchCriteria[sortOrders][][direction]","in":"query","type":"string","description":"Sorting direction."},{"name":"searchCriteria[pageSize]","in":"query","type":"integer","description":"Page size."},{"name":"searchCriteria[currentPage]","in":"query","type":"integer","description":"Current page."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-data-order-item-search-result-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/invoices/{id}":{"get":{"tags":["salesInvoiceRepositoryV1"],"description":"Loads a specified invoice.","operationId":"salesInvoiceRepositoryV1GetGet","parameters":[{"name":"id","in":"path","type":"integer","required":true,"description":"The invoice ID."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-data-invoice-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/invoices":{"get":{"tags":["salesInvoiceRepositoryV1"],"description":"Lists invoices that match specified search criteria. This call returns an array of objects, but detailed information about each object\u2019s attributes might not be included. See http://devdocs.magento.com/codelinks/attributes.html#InvoiceRepositoryInterface to determine which call to use to get detailed information about all attributes for an object.","operationId":"salesInvoiceRepositoryV1GetListGet","parameters":[{"name":"searchCriteria[filterGroups][][filters][][field]","in":"query","type":"string","description":"Field"},{"name":"searchCriteria[filterGroups][][filters][][value]","in":"query","type":"string","description":"Value"},{"name":"searchCriteria[filterGroups][][filters][][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"searchCriteria[sortOrders][][field]","in":"query","type":"string","description":"Sorting field."},{"name":"searchCriteria[sortOrders][][direction]","in":"query","type":"string","description":"Sorting direction."},{"name":"searchCriteria[pageSize]","in":"query","type":"integer","description":"Page size."},{"name":"searchCriteria[currentPage]","in":"query","type":"integer","description":"Current page."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-data-invoice-search-result-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/invoices/":{"post":{"tags":["salesInvoiceRepositoryV1"],"description":"Performs persist operations for a specified invoice.","operationId":"salesInvoiceRepositoryV1SavePost","parameters":[{"name":"$body","in":"body","schema":{"required":["entity"],"properties":{"entity":{"$ref":"#/definitions/sales-data-invoice-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-data-invoice-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/invoices/{id}/comments":{"get":{"tags":["salesInvoiceManagementV1"],"description":"Lists comments for a specified invoice.","operationId":"salesInvoiceManagementV1GetCommentsListGet","parameters":[{"name":"id","in":"path","type":"integer","required":true,"description":"The invoice ID."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-data-invoice-comment-search-result-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/invoices/{id}/emails":{"post":{"tags":["salesInvoiceManagementV1"],"description":"Emails a user a specified invoice.","operationId":"salesInvoiceManagementV1NotifyPost","parameters":[{"name":"id","in":"path","type":"integer","required":true,"description":"The invoice ID."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/invoices/{id}/void":{"post":{"tags":["salesInvoiceManagementV1"],"description":"Voids a specified invoice.","operationId":"salesInvoiceManagementV1SetVoidPost","parameters":[{"name":"id","in":"path","type":"integer","required":true,"description":"The invoice ID."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/invoices/{id}/capture":{"post":{"tags":["salesInvoiceManagementV1"],"description":"Sets invoice capture.","operationId":"salesInvoiceManagementV1SetCapturePost","parameters":[{"name":"id","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"string"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/invoices/comments":{"post":{"tags":["salesInvoiceCommentRepositoryV1"],"description":"Performs persist operations for a specified invoice comment.","operationId":"salesInvoiceCommentRepositoryV1SavePost","parameters":[{"name":"$body","in":"body","schema":{"required":["entity"],"properties":{"entity":{"$ref":"#/definitions/sales-data-invoice-comment-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-data-invoice-comment-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/invoice/{invoiceId}/refund":{"post":{"tags":["salesRefundInvoiceV1"],"description":"Create refund for invoice","operationId":"salesRefundInvoiceV1ExecutePost","parameters":[{"name":"invoiceId","in":"path","type":"integer","required":true},{"name":"$body","in":"body","schema":{"properties":{"items":{"type":"array","items":{"$ref":"#/definitions/sales-data-creditmemo-item-creation-interface"}},"isOnline":{"type":"boolean"},"notify":{"type":"boolean"},"appendComment":{"type":"boolean"},"comment":{"$ref":"#/definitions/sales-data-creditmemo-comment-creation-interface"},"arguments":{"$ref":"#/definitions/sales-data-creditmemo-creation-arguments-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/creditmemo/{id}/comments":{"get":{"tags":["salesCreditmemoManagementV1"],"description":"Lists comments for a specified credit memo.","operationId":"salesCreditmemoManagementV1GetCommentsListGet","parameters":[{"name":"id","in":"path","type":"integer","required":true,"description":"The credit memo ID."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-data-creditmemo-comment-search-result-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"post":{"tags":["salesCreditmemoCommentRepositoryV1"],"description":"Performs persist operations for a specified entity.","operationId":"salesCreditmemoCommentRepositoryV1SavePost","parameters":[{"name":"id","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["entity"],"properties":{"entity":{"$ref":"#/definitions/sales-data-creditmemo-comment-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-data-creditmemo-comment-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/creditmemo/{id}":{"put":{"tags":["salesCreditmemoManagementV1"],"description":"Cancels a specified credit memo.","operationId":"salesCreditmemoManagementV1CancelPut","parameters":[{"name":"id","in":"path","type":"integer","required":true,"description":"The credit memo ID."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"get":{"tags":["salesCreditmemoRepositoryV1"],"description":"Loads a specified credit memo.","operationId":"salesCreditmemoRepositoryV1GetGet","parameters":[{"name":"id","in":"path","type":"integer","required":true,"description":"The credit memo ID."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-data-creditmemo-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/creditmemo/{id}/emails":{"post":{"tags":["salesCreditmemoManagementV1"],"description":"Emails a user a specified credit memo.","operationId":"salesCreditmemoManagementV1NotifyPost","parameters":[{"name":"id","in":"path","type":"integer","required":true,"description":"The credit memo ID."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/creditmemo/refund":{"post":{"tags":["salesCreditmemoManagementV1"],"description":"Prepare creditmemo to refund and save it.","operationId":"salesCreditmemoManagementV1RefundPost","parameters":[{"name":"$body","in":"body","schema":{"required":["creditmemo"],"properties":{"creditmemo":{"$ref":"#/definitions/sales-data-creditmemo-interface"},"offlineRequested":{"type":"boolean"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-data-creditmemo-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/creditmemos":{"get":{"tags":["salesCreditmemoRepositoryV1"],"description":"Lists credit memos that match specified search criteria. This call returns an array of objects, but detailed information about each object\u2019s attributes might not be included. See http://devdocs.magento.com/codelinks/attributes.html#CreditmemoRepositoryInterface to determine which call to use to get detailed information about all attributes for an object.","operationId":"salesCreditmemoRepositoryV1GetListGet","parameters":[{"name":"searchCriteria[filterGroups][][filters][][field]","in":"query","type":"string","description":"Field"},{"name":"searchCriteria[filterGroups][][filters][][value]","in":"query","type":"string","description":"Value"},{"name":"searchCriteria[filterGroups][][filters][][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"searchCriteria[sortOrders][][field]","in":"query","type":"string","description":"Sorting field."},{"name":"searchCriteria[sortOrders][][direction]","in":"query","type":"string","description":"Sorting direction."},{"name":"searchCriteria[pageSize]","in":"query","type":"integer","description":"Page size."},{"name":"searchCriteria[currentPage]","in":"query","type":"integer","description":"Current page."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-data-creditmemo-search-result-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/creditmemo":{"post":{"tags":["salesCreditmemoRepositoryV1"],"description":"Performs persist operations for a specified credit memo.","operationId":"salesCreditmemoRepositoryV1SavePost","parameters":[{"name":"$body","in":"body","schema":{"required":["entity"],"properties":{"entity":{"$ref":"#/definitions/sales-data-creditmemo-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-data-creditmemo-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/order/{orderId}/refund":{"post":{"tags":["salesRefundOrderV1"],"description":"Create offline refund for order","operationId":"salesRefundOrderV1ExecutePost","parameters":[{"name":"orderId","in":"path","type":"integer","required":true},{"name":"$body","in":"body","schema":{"properties":{"items":{"type":"array","items":{"$ref":"#/definitions/sales-data-creditmemo-item-creation-interface"}},"notify":{"type":"boolean"},"appendComment":{"type":"boolean"},"comment":{"$ref":"#/definitions/sales-data-creditmemo-comment-creation-interface"},"arguments":{"$ref":"#/definitions/sales-data-creditmemo-creation-arguments-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/shipment/{id}":{"get":{"tags":["salesShipmentRepositoryV1"],"description":"Loads a specified shipment.","operationId":"salesShipmentRepositoryV1GetGet","parameters":[{"name":"id","in":"path","type":"integer","required":true,"description":"The shipment ID."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-data-shipment-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/shipments":{"get":{"tags":["salesShipmentRepositoryV1"],"description":"Lists shipments that match specified search criteria. This call returns an array of objects, but detailed information about each object\u2019s attributes might not be included. See http://devdocs.magento.com/codelinks/attributes.html#ShipmentRepositoryInterface to determine which call to use to get detailed information about all attributes for an object.","operationId":"salesShipmentRepositoryV1GetListGet","parameters":[{"name":"searchCriteria[filterGroups][][filters][][field]","in":"query","type":"string","description":"Field"},{"name":"searchCriteria[filterGroups][][filters][][value]","in":"query","type":"string","description":"Value"},{"name":"searchCriteria[filterGroups][][filters][][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"searchCriteria[sortOrders][][field]","in":"query","type":"string","description":"Sorting field."},{"name":"searchCriteria[sortOrders][][direction]","in":"query","type":"string","description":"Sorting direction."},{"name":"searchCriteria[pageSize]","in":"query","type":"integer","description":"Page size."},{"name":"searchCriteria[currentPage]","in":"query","type":"integer","description":"Current page."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-data-shipment-search-result-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/shipment/":{"post":{"tags":["salesShipmentRepositoryV1"],"description":"Performs persist operations for a specified shipment.","operationId":"salesShipmentRepositoryV1SavePost","parameters":[{"name":"$body","in":"body","schema":{"required":["entity"],"properties":{"entity":{"$ref":"#/definitions/sales-data-shipment-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-data-shipment-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/shipment/{id}/comments":{"get":{"tags":["salesShipmentManagementV1"],"description":"Lists comments for a specified shipment.","operationId":"salesShipmentManagementV1GetCommentsListGet","parameters":[{"name":"id","in":"path","type":"integer","required":true,"description":"The shipment ID."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-data-shipment-comment-search-result-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"post":{"tags":["salesShipmentCommentRepositoryV1"],"description":"Performs persist operations for a specified shipment comment.","operationId":"salesShipmentCommentRepositoryV1SavePost","parameters":[{"name":"id","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["entity"],"properties":{"entity":{"$ref":"#/definitions/sales-data-shipment-comment-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-data-shipment-comment-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/shipment/{id}/emails":{"post":{"tags":["salesShipmentManagementV1"],"description":"Emails user a specified shipment.","operationId":"salesShipmentManagementV1NotifyPost","parameters":[{"name":"id","in":"path","type":"integer","required":true,"description":"The shipment ID."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/shipment/{id}/label":{"get":{"tags":["salesShipmentManagementV1"],"description":"Gets a specified shipment label.","operationId":"salesShipmentManagementV1GetLabelGet","parameters":[{"name":"id","in":"path","type":"integer","required":true,"description":"The shipment label ID."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"string","description":"Shipment label."}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/shipment/track":{"post":{"tags":["salesShipmentTrackRepositoryV1"],"description":"Performs persist operations for a specified shipment track.","operationId":"salesShipmentTrackRepositoryV1SavePost","parameters":[{"name":"$body","in":"body","schema":{"required":["entity"],"properties":{"entity":{"$ref":"#/definitions/sales-data-shipment-track-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-data-shipment-track-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/shipment/track/{id}":{"delete":{"tags":["salesShipmentTrackRepositoryV1"],"description":"Deletes a specified shipment track by ID.","operationId":"salesShipmentTrackRepositoryV1DeleteByIdDelete","parameters":[{"name":"id","in":"path","type":"integer","required":true,"description":"The shipment track ID."}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/order/{orderId}/ship":{"post":{"tags":["salesShipOrderV1"],"description":"Creates new Shipment for given Order.","operationId":"salesShipOrderV1ExecutePost","parameters":[{"name":"orderId","in":"path","type":"integer","required":true},{"name":"$body","in":"body","schema":{"properties":{"items":{"type":"array","items":{"$ref":"#/definitions/sales-data-shipment-item-creation-interface"}},"notify":{"type":"boolean"},"appendComment":{"type":"boolean"},"comment":{"$ref":"#/definitions/sales-data-shipment-comment-creation-interface"},"tracks":{"type":"array","items":{"$ref":"#/definitions/sales-data-shipment-track-creation-interface"}},"packages":{"type":"array","items":{"$ref":"#/definitions/sales-data-shipment-package-creation-interface"}},"arguments":{"$ref":"#/definitions/sales-data-shipment-creation-arguments-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer","description":"Id of created Shipment."}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/transactions/{id}":{"get":{"tags":["salesTransactionRepositoryV1"],"description":"Loads a specified transaction.","operationId":"salesTransactionRepositoryV1GetGet","parameters":[{"name":"id","in":"path","type":"integer","required":true,"description":"The transaction ID."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-data-transaction-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/transactions":{"get":{"tags":["salesTransactionRepositoryV1"],"description":"Lists transactions that match specified search criteria. This call returns an array of objects, but detailed information about each object\u2019s attributes might not be included. See http://devdocs.magento.com/codelinks/attributes.html#TransactionRepositoryInterface to determine which call to use to get detailed information about all attributes for an object.","operationId":"salesTransactionRepositoryV1GetListGet","parameters":[{"name":"searchCriteria[filterGroups][][filters][][field]","in":"query","type":"string","description":"Field"},{"name":"searchCriteria[filterGroups][][filters][][value]","in":"query","type":"string","description":"Value"},{"name":"searchCriteria[filterGroups][][filters][][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"searchCriteria[sortOrders][][field]","in":"query","type":"string","description":"Sorting field."},{"name":"searchCriteria[sortOrders][][direction]","in":"query","type":"string","description":"Sorting direction."},{"name":"searchCriteria[pageSize]","in":"query","type":"integer","description":"Page size."},{"name":"searchCriteria[currentPage]","in":"query","type":"integer","description":"Current page."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-data-transaction-search-result-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/order/{orderId}/invoice":{"post":{"tags":["salesInvoiceOrderV1"],"description":"","operationId":"salesInvoiceOrderV1ExecutePost","parameters":[{"name":"orderId","in":"path","type":"integer","required":true},{"name":"$body","in":"body","schema":{"properties":{"capture":{"type":"boolean"},"items":{"type":"array","items":{"$ref":"#/definitions/sales-data-invoice-item-creation-interface"}},"notify":{"type":"boolean"},"appendComment":{"type":"boolean"},"comment":{"$ref":"#/definitions/sales-data-invoice-comment-creation-interface"},"arguments":{"$ref":"#/definitions/sales-data-invoice-creation-arguments-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/guest-carts/{cartId}/shipping-information":{"post":{"tags":["checkoutGuestShippingInformationManagementV1"],"description":"","operationId":"checkoutGuestShippingInformationManagementV1SaveAddressInformationPost","parameters":[{"name":"cartId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["addressInformation"],"properties":{"addressInformation":{"$ref":"#/definitions/checkout-data-shipping-information-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/checkout-data-payment-details-interface"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/mine/shipping-information":{"post":{"tags":["checkoutShippingInformationManagementV1"],"description":"","operationId":"checkoutShippingInformationManagementV1SaveAddressInformationPost","parameters":[{"name":"$body","in":"body","schema":{"required":["addressInformation"],"properties":{"addressInformation":{"$ref":"#/definitions/checkout-data-shipping-information-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/checkout-data-payment-details-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/{cartId}/shipping-information":{"post":{"tags":["checkoutShippingInformationManagementV1"],"description":"","operationId":"checkoutShippingInformationManagementV1SaveAddressInformationPost","parameters":[{"name":"cartId","in":"path","type":"integer","required":true},{"name":"$body","in":"body","schema":{"required":["addressInformation"],"properties":{"addressInformation":{"$ref":"#/definitions/checkout-data-shipping-information-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/checkout-data-payment-details-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/{cartId}/totals-information":{"post":{"tags":["checkoutTotalsInformationManagementV1"],"description":"Calculate quote totals based on address and shipping method.","operationId":"checkoutTotalsInformationManagementV1CalculatePost","parameters":[{"name":"cartId","in":"path","type":"integer","required":true},{"name":"$body","in":"body","schema":{"required":["addressInformation"],"properties":{"addressInformation":{"$ref":"#/definitions/checkout-data-totals-information-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/quote-data-totals-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/mine/totals-information":{"post":{"tags":["checkoutTotalsInformationManagementV1"],"description":"Calculate quote totals based on address and shipping method.","operationId":"checkoutTotalsInformationManagementV1CalculatePost","parameters":[{"name":"$body","in":"body","schema":{"required":["addressInformation"],"properties":{"addressInformation":{"$ref":"#/definitions/checkout-data-totals-information-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/quote-data-totals-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/guest-carts/{cartId}/totals-information":{"post":{"tags":["checkoutGuestTotalsInformationManagementV1"],"description":"Calculate quote totals based on address and shipping method.","operationId":"checkoutGuestTotalsInformationManagementV1CalculatePost","parameters":[{"name":"cartId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["addressInformation"],"properties":{"addressInformation":{"$ref":"#/definitions/checkout-data-totals-information-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/quote-data-totals-interface"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/guest-carts/{cartId}/payment-information":{"post":{"tags":["checkoutGuestPaymentInformationManagementV1"],"description":"Set payment information and place order for a specified cart.","operationId":"checkoutGuestPaymentInformationManagementV1SavePaymentInformationAndPlaceOrderPost","parameters":[{"name":"cartId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["email","paymentMethod"],"properties":{"email":{"type":"string"},"paymentMethod":{"$ref":"#/definitions/quote-data-payment-interface"},"billingAddress":{"$ref":"#/definitions/quote-data-address-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer","description":"Order ID."}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"get":{"tags":["checkoutGuestPaymentInformationManagementV1"],"description":"Get payment information","operationId":"checkoutGuestPaymentInformationManagementV1GetPaymentInformationGet","parameters":[{"name":"cartId","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/checkout-data-payment-details-interface"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/guest-carts/{cartId}/set-payment-information":{"post":{"tags":["checkoutGuestPaymentInformationManagementV1"],"description":"Set payment information for a specified cart.","operationId":"checkoutGuestPaymentInformationManagementV1SavePaymentInformationPost","parameters":[{"name":"cartId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["email","paymentMethod"],"properties":{"email":{"type":"string"},"paymentMethod":{"$ref":"#/definitions/quote-data-payment-interface"},"billingAddress":{"$ref":"#/definitions/quote-data-address-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer","description":"Order ID."}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/mine/payment-information":{"post":{"tags":["checkoutPaymentInformationManagementV1"],"description":"Set payment information and place order for a specified cart.","operationId":"checkoutPaymentInformationManagementV1SavePaymentInformationAndPlaceOrderPost","parameters":[{"name":"$body","in":"body","schema":{"required":["paymentMethod"],"properties":{"paymentMethod":{"$ref":"#/definitions/quote-data-payment-interface"},"billingAddress":{"$ref":"#/definitions/quote-data-address-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer","description":"Order ID."}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"get":{"tags":["checkoutPaymentInformationManagementV1"],"description":"Get payment information","operationId":"checkoutPaymentInformationManagementV1GetPaymentInformationGet","responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/checkout-data-payment-details-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/mine/set-payment-information":{"post":{"tags":["checkoutPaymentInformationManagementV1"],"description":"Set payment information for a specified cart.","operationId":"checkoutPaymentInformationManagementV1SavePaymentInformationPost","parameters":[{"name":"$body","in":"body","schema":{"required":["paymentMethod"],"properties":{"paymentMethod":{"$ref":"#/definitions/quote-data-payment-interface"},"billingAddress":{"$ref":"#/definitions/quote-data-address-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer","description":"Order ID."}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/{sku}/downloadable-links":{"get":{"tags":["downloadableLinkRepositoryV1"],"description":"List of links with associated samples","operationId":"downloadableLinkRepositoryV1GetListGet","parameters":[{"name":"sku","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/downloadable-data-link-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"post":{"tags":["downloadableLinkRepositoryV1"],"description":"Update downloadable link of the given product (link type and its resources cannot be changed)","operationId":"downloadableLinkRepositoryV1SavePost","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["link"],"properties":{"link":{"$ref":"#/definitions/downloadable-data-link-interface"},"isGlobalScopeContent":{"type":"boolean"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/{sku}/downloadable-links/{id}":{"put":{"tags":["downloadableLinkRepositoryV1"],"description":"Update downloadable link of the given product (link type and its resources cannot be changed)","operationId":"downloadableLinkRepositoryV1SavePut","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"id","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["link"],"properties":{"link":{"$ref":"#/definitions/downloadable-data-link-interface"},"isGlobalScopeContent":{"type":"boolean"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/downloadable-links/{id}":{"delete":{"tags":["downloadableLinkRepositoryV1"],"description":"Delete downloadable link","operationId":"downloadableLinkRepositoryV1DeleteDelete","parameters":[{"name":"id","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/{sku}/downloadable-links/samples":{"get":{"tags":["downloadableSampleRepositoryV1"],"description":"List of samples for downloadable product","operationId":"downloadableSampleRepositoryV1GetListGet","parameters":[{"name":"sku","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/downloadable-data-sample-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"post":{"tags":["downloadableSampleRepositoryV1"],"description":"Update downloadable sample of the given product","operationId":"downloadableSampleRepositoryV1SavePost","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["sample"],"properties":{"sample":{"$ref":"#/definitions/downloadable-data-sample-interface"},"isGlobalScopeContent":{"type":"boolean"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/{sku}/downloadable-links/samples/{id}":{"put":{"tags":["downloadableSampleRepositoryV1"],"description":"Update downloadable sample of the given product","operationId":"downloadableSampleRepositoryV1SavePut","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"id","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["sample"],"properties":{"sample":{"$ref":"#/definitions/downloadable-data-sample-interface"},"isGlobalScopeContent":{"type":"boolean"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/products/downloadable-links/samples/{id}":{"delete":{"tags":["downloadableSampleRepositoryV1"],"description":"Delete downloadable sample","operationId":"downloadableSampleRepositoryV1DeleteDelete","parameters":[{"name":"id","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/licence":{"get":{"tags":["checkoutAgreementsCheckoutAgreementsRepositoryV1"],"description":"Lists active checkout agreements.","operationId":"checkoutAgreementsCheckoutAgreementsRepositoryV1GetListGet","responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/checkout-agreements-data-agreement-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/configurable-products/{sku}/children":{"get":{"tags":["configurableProductLinkManagementV1"],"description":"Get all children for Configurable product","operationId":"configurableProductLinkManagementV1GetChildrenGet","parameters":[{"name":"sku","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/catalog-data-product-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/configurable-products/{sku}/children/{childSku}":{"delete":{"tags":["configurableProductLinkManagementV1"],"description":"Remove configurable product option","operationId":"configurableProductLinkManagementV1RemoveChildDelete","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"childSku","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/configurable-products/{sku}/child":{"post":{"tags":["configurableProductLinkManagementV1"],"description":"","operationId":"configurableProductLinkManagementV1AddChildPost","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["childSku"],"properties":{"childSku":{"type":"string"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/configurable-products/variation":{"put":{"tags":["configurableProductConfigurableProductManagementV1"],"description":"Generate variation based on same product","operationId":"configurableProductConfigurableProductManagementV1GenerateVariationPut","parameters":[{"name":"$body","in":"body","schema":{"required":["product","options"],"properties":{"product":{"$ref":"#/definitions/catalog-data-product-interface"},"options":{"type":"array","items":{"$ref":"#/definitions/configurable-product-data-option-interface"}}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/catalog-data-product-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/configurable-products/{sku}/options/{id}":{"get":{"tags":["configurableProductOptionRepositoryV1"],"description":"Get option for configurable product","operationId":"configurableProductOptionRepositoryV1GetGet","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"id","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/configurable-product-data-option-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"put":{"tags":["configurableProductOptionRepositoryV1"],"description":"Save option","operationId":"configurableProductOptionRepositoryV1SavePut","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"id","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["option"],"properties":{"option":{"$ref":"#/definitions/configurable-product-data-option-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"delete":{"tags":["configurableProductOptionRepositoryV1"],"description":"Remove option from configurable product","operationId":"configurableProductOptionRepositoryV1DeleteByIdDelete","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"id","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/configurable-products/{sku}/options/all":{"get":{"tags":["configurableProductOptionRepositoryV1"],"description":"Get all options for configurable product","operationId":"configurableProductOptionRepositoryV1GetListGet","parameters":[{"name":"sku","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/configurable-product-data-option-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/configurable-products/{sku}/options":{"post":{"tags":["configurableProductOptionRepositoryV1"],"description":"Save option","operationId":"configurableProductOptionRepositoryV1SavePost","parameters":[{"name":"sku","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["option"],"properties":{"option":{"$ref":"#/definitions/configurable-product-data-option-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/mine/balance/apply":{"post":{"tags":["customerBalanceBalanceManagementV1"],"description":"Apply store credit","operationId":"customerBalanceBalanceManagementV1ApplyPost","responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/{quoteId}/giftCards":{"get":{"tags":["giftCardAccountGiftCardAccountManagementV1"],"description":"Return GiftCard Account cards","operationId":"giftCardAccountGiftCardAccountManagementV1GetListByQuoteIdGet","parameters":[{"name":"quoteId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/gift-card-account-data-gift-card-account-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/{cartId}/giftCards":{"put":{"tags":["giftCardAccountGiftCardAccountManagementV1"],"description":"","operationId":"giftCardAccountGiftCardAccountManagementV1SaveByQuoteIdPut","parameters":[{"name":"cartId","in":"path","type":"integer","required":true},{"name":"$body","in":"body","schema":{"required":["giftCardAccountData"],"properties":{"giftCardAccountData":{"$ref":"#/definitions/gift-card-account-data-gift-card-account-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/{cartId}/giftCards/{giftCardCode}":{"delete":{"tags":["giftCardAccountGiftCardAccountManagementV1"],"description":"Remove GiftCard Account entity","operationId":"giftCardAccountGiftCardAccountManagementV1DeleteByQuoteIdDelete","parameters":[{"name":"cartId","in":"path","type":"integer","required":true},{"name":"giftCardCode","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/mine/giftCards/{giftCardCode}":{"delete":{"tags":["giftCardAccountGiftCardAccountManagementV1"],"description":"Remove GiftCard Account entity","operationId":"giftCardAccountGiftCardAccountManagementV1DeleteByQuoteIdDelete","parameters":[{"name":"giftCardCode","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/mine/giftCards":{"post":{"tags":["giftCardAccountGiftCardAccountManagementV1"],"description":"","operationId":"giftCardAccountGiftCardAccountManagementV1SaveByQuoteIdPost","parameters":[{"name":"$body","in":"body","schema":{"required":["giftCardAccountData"],"properties":{"giftCardAccountData":{"$ref":"#/definitions/gift-card-account-data-gift-card-account-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/mine/checkGiftCard/{giftCardCode}":{"get":{"tags":["giftCardAccountGiftCardAccountManagementV1"],"description":"","operationId":"giftCardAccountGiftCardAccountManagementV1CheckGiftCardGet","parameters":[{"name":"giftCardCode","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"number"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/guest-carts/{cartId}/giftCards/{giftCardCode}":{"delete":{"tags":["giftCardAccountGuestGiftCardAccountManagementV1"],"description":"Remove GiftCard Account entity","operationId":"giftCardAccountGuestGiftCardAccountManagementV1DeleteByQuoteIdDelete","parameters":[{"name":"cartId","in":"path","type":"string","required":true},{"name":"giftCardCode","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/guest-carts/{cartId}/giftCards":{"post":{"tags":["giftCardAccountGuestGiftCardAccountManagementV1"],"description":"","operationId":"giftCardAccountGuestGiftCardAccountManagementV1AddGiftCardPost","parameters":[{"name":"cartId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["giftCardAccountData"],"properties":{"giftCardAccountData":{"$ref":"#/definitions/gift-card-account-data-gift-card-account-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/guest-carts/{cartId}/checkGiftCard/{giftCardCode}":{"get":{"tags":["giftCardAccountGuestGiftCardAccountManagementV1"],"description":"","operationId":"giftCardAccountGuestGiftCardAccountManagementV1CheckGiftCardGet","parameters":[{"name":"cartId","in":"path","type":"string","required":true},{"name":"giftCardCode","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"number"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/taxRates":{"post":{"tags":["taxTaxRateRepositoryV1"],"description":"Create or update tax rate","operationId":"taxTaxRateRepositoryV1SavePost","parameters":[{"name":"$body","in":"body","schema":{"required":["taxRate"],"properties":{"taxRate":{"$ref":"#/definitions/tax-data-tax-rate-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/tax-data-tax-rate-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"put":{"tags":["taxTaxRateRepositoryV1"],"description":"Create or update tax rate","operationId":"taxTaxRateRepositoryV1SavePut","parameters":[{"name":"$body","in":"body","schema":{"required":["taxRate"],"properties":{"taxRate":{"$ref":"#/definitions/tax-data-tax-rate-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/tax-data-tax-rate-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/taxRates/{rateId}":{"get":{"tags":["taxTaxRateRepositoryV1"],"description":"Get tax rate","operationId":"taxTaxRateRepositoryV1GetGet","parameters":[{"name":"rateId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/tax-data-tax-rate-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"delete":{"tags":["taxTaxRateRepositoryV1"],"description":"Delete tax rate","operationId":"taxTaxRateRepositoryV1DeleteByIdDelete","parameters":[{"name":"rateId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/taxRates/search":{"get":{"tags":["taxTaxRateRepositoryV1"],"description":"Search TaxRates This call returns an array of objects, but detailed information about each object\u2019s attributes might not be included. See http://devdocs.magento.com/codelinks/attributes.html#TaxRateRepositoryInterface to determine which call to use to get detailed information about all attributes for an object.","operationId":"taxTaxRateRepositoryV1GetListGet","parameters":[{"name":"searchCriteria[filterGroups][][filters][][field]","in":"query","type":"string","description":"Field"},{"name":"searchCriteria[filterGroups][][filters][][value]","in":"query","type":"string","description":"Value"},{"name":"searchCriteria[filterGroups][][filters][][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"searchCriteria[sortOrders][][field]","in":"query","type":"string","description":"Sorting field."},{"name":"searchCriteria[sortOrders][][direction]","in":"query","type":"string","description":"Sorting direction."},{"name":"searchCriteria[pageSize]","in":"query","type":"integer","description":"Page size."},{"name":"searchCriteria[currentPage]","in":"query","type":"integer","description":"Current page."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/tax-data-tax-rate-search-results-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/taxRules":{"post":{"tags":["taxTaxRuleRepositoryV1"],"description":"Save TaxRule","operationId":"taxTaxRuleRepositoryV1SavePost","parameters":[{"name":"$body","in":"body","schema":{"required":["rule"],"properties":{"rule":{"$ref":"#/definitions/tax-data-tax-rule-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/tax-data-tax-rule-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"put":{"tags":["taxTaxRuleRepositoryV1"],"description":"Save TaxRule","operationId":"taxTaxRuleRepositoryV1SavePut","parameters":[{"name":"$body","in":"body","schema":{"required":["rule"],"properties":{"rule":{"$ref":"#/definitions/tax-data-tax-rule-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/tax-data-tax-rule-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/taxRules/{ruleId}":{"delete":{"tags":["taxTaxRuleRepositoryV1"],"description":"Delete TaxRule","operationId":"taxTaxRuleRepositoryV1DeleteByIdDelete","parameters":[{"name":"ruleId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"get":{"tags":["taxTaxRuleRepositoryV1"],"description":"Get TaxRule","operationId":"taxTaxRuleRepositoryV1GetGet","parameters":[{"name":"ruleId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/tax-data-tax-rule-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/taxRules/search":{"get":{"tags":["taxTaxRuleRepositoryV1"],"description":"Search TaxRules This call returns an array of objects, but detailed information about each object\u2019s attributes might not be included. See http://devdocs.magento.com/codelinks/attributes.html#TaxRuleRepositoryInterface to determine which call to use to get detailed information about all attributes for an object.","operationId":"taxTaxRuleRepositoryV1GetListGet","parameters":[{"name":"searchCriteria[filterGroups][][filters][][field]","in":"query","type":"string","description":"Field"},{"name":"searchCriteria[filterGroups][][filters][][value]","in":"query","type":"string","description":"Value"},{"name":"searchCriteria[filterGroups][][filters][][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"searchCriteria[sortOrders][][field]","in":"query","type":"string","description":"Sorting field."},{"name":"searchCriteria[sortOrders][][direction]","in":"query","type":"string","description":"Sorting direction."},{"name":"searchCriteria[pageSize]","in":"query","type":"integer","description":"Page size."},{"name":"searchCriteria[currentPage]","in":"query","type":"integer","description":"Current page."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/tax-data-tax-rule-search-results-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/taxClasses":{"post":{"tags":["taxTaxClassRepositoryV1"],"description":"Create a Tax Class","operationId":"taxTaxClassRepositoryV1SavePost","parameters":[{"name":"$body","in":"body","schema":{"required":["taxClass"],"properties":{"taxClass":{"$ref":"#/definitions/tax-data-tax-class-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"string","description":"id for the newly created Tax class"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/taxClasses/{taxClassId}":{"get":{"tags":["taxTaxClassRepositoryV1"],"description":"Get a tax class with the given tax class id.","operationId":"taxTaxClassRepositoryV1GetGet","parameters":[{"name":"taxClassId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/tax-data-tax-class-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"delete":{"tags":["taxTaxClassRepositoryV1"],"description":"Delete a tax class with the given tax class id.","operationId":"taxTaxClassRepositoryV1DeleteByIdDelete","parameters":[{"name":"taxClassId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean","description":"True if the tax class was deleted, false otherwise"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/taxClasses/{classId}":{"put":{"tags":["taxTaxClassRepositoryV1"],"description":"Create a Tax Class","operationId":"taxTaxClassRepositoryV1SavePut","parameters":[{"name":"classId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["taxClass"],"properties":{"taxClass":{"$ref":"#/definitions/tax-data-tax-class-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"string","description":"id for the newly created Tax class"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/taxClasses/search":{"get":{"tags":["taxTaxClassRepositoryV1"],"description":"Retrieve tax classes which match a specific criteria. This call returns an array of objects, but detailed information about each object\u2019s attributes might not be included. See http://devdocs.magento.com/codelinks/attributes.html#TaxClassRepositoryInterface to determine which call to use to get detailed information about all attributes for an object.","operationId":"taxTaxClassRepositoryV1GetListGet","parameters":[{"name":"searchCriteria[filterGroups][][filters][][field]","in":"query","type":"string","description":"Field"},{"name":"searchCriteria[filterGroups][][filters][][value]","in":"query","type":"string","description":"Value"},{"name":"searchCriteria[filterGroups][][filters][][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"searchCriteria[sortOrders][][field]","in":"query","type":"string","description":"Sorting field."},{"name":"searchCriteria[sortOrders][][direction]","in":"query","type":"string","description":"Sorting direction."},{"name":"searchCriteria[pageSize]","in":"query","type":"integer","description":"Page size."},{"name":"searchCriteria[currentPage]","in":"query","type":"integer","description":"Current page."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/tax-data-tax-class-search-results-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/{cartId}/gift-message":{"get":{"tags":["giftMessageCartRepositoryV1"],"description":"Return the gift message for a specified order.","operationId":"giftMessageCartRepositoryV1GetGet","parameters":[{"name":"cartId","in":"path","type":"integer","required":true,"description":"The shopping cart ID."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/gift-message-data-message-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"post":{"tags":["giftMessageCartRepositoryV1"],"description":"Set the gift message for an entire order.","operationId":"giftMessageCartRepositoryV1SavePost","parameters":[{"name":"cartId","in":"path","type":"integer","required":true,"description":"The cart ID."},{"name":"$body","in":"body","schema":{"required":["giftMessage"],"properties":{"giftMessage":{"$ref":"#/definitions/gift-message-data-message-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/mine/gift-message":{"get":{"tags":["giftMessageCartRepositoryV1"],"description":"Return the gift message for a specified order.","operationId":"giftMessageCartRepositoryV1GetGet","responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/gift-message-data-message-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"post":{"tags":["giftMessageCartRepositoryV1"],"description":"Set the gift message for an entire order.","operationId":"giftMessageCartRepositoryV1SavePost","parameters":[{"name":"$body","in":"body","schema":{"required":["giftMessage"],"properties":{"giftMessage":{"$ref":"#/definitions/gift-message-data-message-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/{cartId}/gift-message/{itemId}":{"get":{"tags":["giftMessageItemRepositoryV1"],"description":"Return the gift message for a specified item in a specified shopping cart.","operationId":"giftMessageItemRepositoryV1GetGet","parameters":[{"name":"cartId","in":"path","type":"integer","required":true,"description":"The shopping cart ID."},{"name":"itemId","in":"path","type":"integer","required":true,"description":"The item ID."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/gift-message-data-message-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"post":{"tags":["giftMessageItemRepositoryV1"],"description":"Set the gift message for a specified item in a specified shopping cart.","operationId":"giftMessageItemRepositoryV1SavePost","parameters":[{"name":"cartId","in":"path","type":"integer","required":true,"description":"The cart ID."},{"name":"itemId","in":"path","type":"integer","required":true,"description":"The item ID."},{"name":"$body","in":"body","schema":{"required":["giftMessage"],"properties":{"giftMessage":{"$ref":"#/definitions/gift-message-data-message-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/carts/mine/gift-message/{itemId}":{"get":{"tags":["giftMessageItemRepositoryV1"],"description":"Return the gift message for a specified item in a specified shopping cart.","operationId":"giftMessageItemRepositoryV1GetGet","parameters":[{"name":"itemId","in":"path","type":"integer","required":true,"description":"The item ID."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/gift-message-data-message-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"post":{"tags":["giftMessageItemRepositoryV1"],"description":"Set the gift message for a specified item in a specified shopping cart.","operationId":"giftMessageItemRepositoryV1SavePost","parameters":[{"name":"itemId","in":"path","type":"integer","required":true,"description":"The item ID."},{"name":"$body","in":"body","schema":{"required":["giftMessage"],"properties":{"giftMessage":{"$ref":"#/definitions/gift-message-data-message-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/guest-carts/{cartId}/gift-message":{"get":{"tags":["giftMessageGuestCartRepositoryV1"],"description":"Return the gift message for a specified order.","operationId":"giftMessageGuestCartRepositoryV1GetGet","parameters":[{"name":"cartId","in":"path","type":"string","required":true,"description":"The shopping cart ID."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/gift-message-data-message-interface"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"post":{"tags":["giftMessageGuestCartRepositoryV1"],"description":"Set the gift message for an entire order.","operationId":"giftMessageGuestCartRepositoryV1SavePost","parameters":[{"name":"cartId","in":"path","type":"string","required":true,"description":"The cart ID."},{"name":"$body","in":"body","schema":{"required":["giftMessage"],"properties":{"giftMessage":{"$ref":"#/definitions/gift-message-data-message-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/guest-carts/{cartId}/gift-message/{itemId}":{"get":{"tags":["giftMessageGuestItemRepositoryV1"],"description":"Return the gift message for a specified item in a specified shopping cart.","operationId":"giftMessageGuestItemRepositoryV1GetGet","parameters":[{"name":"cartId","in":"path","type":"string","required":true,"description":"The shopping cart ID."},{"name":"itemId","in":"path","type":"integer","required":true,"description":"The item ID."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/gift-message-data-message-interface"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"post":{"tags":["giftMessageGuestItemRepositoryV1"],"description":"Set the gift message for a specified item in a specified shopping cart.","operationId":"giftMessageGuestItemRepositoryV1SavePost","parameters":[{"name":"cartId","in":"path","type":"string","required":true,"description":"The cart ID."},{"name":"itemId","in":"path","type":"integer","required":true,"description":"The item ID."},{"name":"$body","in":"body","schema":{"required":["giftMessage"],"properties":{"giftMessage":{"$ref":"#/definitions/gift-message-data-message-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/gift-wrappings/{id}":{"get":{"tags":["giftWrappingWrappingRepositoryV1"],"description":"Return data object for specified wrapping ID and store.","operationId":"giftWrappingWrappingRepositoryV1GetGet","parameters":[{"name":"id","in":"path","type":"integer","required":true},{"name":"storeId","in":"query","type":"integer","required":false}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/gift-wrapping-data-wrapping-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"delete":{"tags":["giftWrappingWrappingRepositoryV1"],"description":"Delete gift wrapping","operationId":"giftWrappingWrappingRepositoryV1DeleteByIdDelete","parameters":[{"name":"id","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/gift-wrappings":{"post":{"tags":["giftWrappingWrappingRepositoryV1"],"description":"Create/Update new gift wrapping with data object values","operationId":"giftWrappingWrappingRepositoryV1SavePost","parameters":[{"name":"$body","in":"body","schema":{"required":["data"],"properties":{"data":{"$ref":"#/definitions/gift-wrapping-data-wrapping-interface"},"storeId":{"type":"integer"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/gift-wrapping-data-wrapping-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"get":{"tags":["giftWrappingWrappingRepositoryV1"],"description":"Return list of gift wrapping data objects based on search criteria","operationId":"giftWrappingWrappingRepositoryV1GetListGet","parameters":[{"name":"searchCriteria[filterGroups][][filters][][field]","in":"query","type":"string","description":"Field"},{"name":"searchCriteria[filterGroups][][filters][][value]","in":"query","type":"string","description":"Value"},{"name":"searchCriteria[filterGroups][][filters][][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"searchCriteria[sortOrders][][field]","in":"query","type":"string","description":"Sorting field."},{"name":"searchCriteria[sortOrders][][direction]","in":"query","type":"string","description":"Sorting direction."},{"name":"searchCriteria[pageSize]","in":"query","type":"integer","description":"Page size."},{"name":"searchCriteria[currentPage]","in":"query","type":"integer","description":"Current page."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/gift-wrapping-data-wrapping-search-results-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/gift-wrappings/{wrappingId}":{"put":{"tags":["giftWrappingWrappingRepositoryV1"],"description":"Create/Update new gift wrapping with data object values","operationId":"giftWrappingWrappingRepositoryV1SavePut","parameters":[{"name":"wrappingId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["data"],"properties":{"data":{"$ref":"#/definitions/gift-wrapping-data-wrapping-interface"},"storeId":{"type":"integer"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/gift-wrapping-data-wrapping-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/salesRules/{ruleId}":{"get":{"tags":["salesRuleRuleRepositoryV1"],"description":"Get rule by ID.","operationId":"salesRuleRuleRepositoryV1GetByIdGet","parameters":[{"name":"ruleId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-rule-data-rule-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"put":{"tags":["salesRuleRuleRepositoryV1"],"description":"Save sales rule.","operationId":"salesRuleRuleRepositoryV1SavePut","parameters":[{"name":"ruleId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["rule"],"properties":{"rule":{"$ref":"#/definitions/sales-rule-data-rule-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-rule-data-rule-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"delete":{"tags":["salesRuleRuleRepositoryV1"],"description":"Delete rule by ID.","operationId":"salesRuleRuleRepositoryV1DeleteByIdDelete","parameters":[{"name":"ruleId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean","description":"true on success"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/salesRules/search":{"get":{"tags":["salesRuleRuleRepositoryV1"],"description":"Retrieve sales rules that match te specified criteria. This call returns an array of objects, but detailed information about each object\u2019s attributes might not be included. See http://devdocs.magento.com/codelinks/attributes.html#RuleRepositoryInterface to determine which call to use to get detailed information about all attributes for an object.","operationId":"salesRuleRuleRepositoryV1GetListGet","parameters":[{"name":"searchCriteria[filterGroups][][filters][][field]","in":"query","type":"string","description":"Field"},{"name":"searchCriteria[filterGroups][][filters][][value]","in":"query","type":"string","description":"Value"},{"name":"searchCriteria[filterGroups][][filters][][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"searchCriteria[sortOrders][][field]","in":"query","type":"string","description":"Sorting field."},{"name":"searchCriteria[sortOrders][][direction]","in":"query","type":"string","description":"Sorting direction."},{"name":"searchCriteria[pageSize]","in":"query","type":"integer","description":"Page size."},{"name":"searchCriteria[currentPage]","in":"query","type":"integer","description":"Current page."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-rule-data-rule-search-result-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/salesRules":{"post":{"tags":["salesRuleRuleRepositoryV1"],"description":"Save sales rule.","operationId":"salesRuleRuleRepositoryV1SavePost","parameters":[{"name":"$body","in":"body","schema":{"required":["rule"],"properties":{"rule":{"$ref":"#/definitions/sales-rule-data-rule-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-rule-data-rule-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/coupons/{couponId}":{"get":{"tags":["salesRuleCouponRepositoryV1"],"description":"Get coupon by coupon id.","operationId":"salesRuleCouponRepositoryV1GetByIdGet","parameters":[{"name":"couponId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-rule-data-coupon-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"put":{"tags":["salesRuleCouponRepositoryV1"],"description":"Save a coupon.","operationId":"salesRuleCouponRepositoryV1SavePut","parameters":[{"name":"couponId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["coupon"],"properties":{"coupon":{"$ref":"#/definitions/sales-rule-data-coupon-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-rule-data-coupon-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"delete":{"tags":["salesRuleCouponRepositoryV1"],"description":"Delete coupon by coupon id.","operationId":"salesRuleCouponRepositoryV1DeleteByIdDelete","parameters":[{"name":"couponId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean","description":"true on success"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/coupons/search":{"get":{"tags":["salesRuleCouponRepositoryV1"],"description":"Retrieve a coupon using the specified search criteria. This call returns an array of objects, but detailed information about each object\u2019s attributes might not be included. See http://devdocs.magento.com/codelinks/attributes.html#CouponRepositoryInterface to determine which call to use to get detailed information about all attributes for an object.","operationId":"salesRuleCouponRepositoryV1GetListGet","parameters":[{"name":"searchCriteria[filterGroups][][filters][][field]","in":"query","type":"string","description":"Field"},{"name":"searchCriteria[filterGroups][][filters][][value]","in":"query","type":"string","description":"Value"},{"name":"searchCriteria[filterGroups][][filters][][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"searchCriteria[sortOrders][][field]","in":"query","type":"string","description":"Sorting field."},{"name":"searchCriteria[sortOrders][][direction]","in":"query","type":"string","description":"Sorting direction."},{"name":"searchCriteria[pageSize]","in":"query","type":"integer","description":"Page size."},{"name":"searchCriteria[currentPage]","in":"query","type":"integer","description":"Current page."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-rule-data-coupon-search-result-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/coupons":{"post":{"tags":["salesRuleCouponRepositoryV1"],"description":"Save a coupon.","operationId":"salesRuleCouponRepositoryV1SavePost","parameters":[{"name":"$body","in":"body","schema":{"required":["coupon"],"properties":{"coupon":{"$ref":"#/definitions/sales-rule-data-coupon-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-rule-data-coupon-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/coupons/generate":{"post":{"tags":["salesRuleCouponManagementV1"],"description":"Generate coupon for a rule","operationId":"salesRuleCouponManagementV1GeneratePost","parameters":[{"name":"$body","in":"body","schema":{"required":["couponSpec"],"properties":{"couponSpec":{"$ref":"#/definitions/sales-rule-data-coupon-generation-spec-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"type":"string"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/coupons/deleteByIds":{"post":{"tags":["salesRuleCouponManagementV1"],"description":"Delete coupon by coupon ids.","operationId":"salesRuleCouponManagementV1DeleteByIdsPost","parameters":[{"name":"$body","in":"body","schema":{"required":["ids"],"properties":{"ids":{"type":"array","items":{"type":"integer"}},"ignoreInvalidCoupons":{"type":"boolean"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-rule-data-coupon-mass-delete-result-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/coupons/deleteByCodes":{"post":{"tags":["salesRuleCouponManagementV1"],"description":"Delete coupon by coupon codes.","operationId":"salesRuleCouponManagementV1DeleteByCodesPost","parameters":[{"name":"$body","in":"body","schema":{"required":["codes"],"properties":{"codes":{"type":"array","items":{"type":"string"}},"ignoreInvalidCoupons":{"type":"boolean"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/sales-rule-data-coupon-mass-delete-result-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/giftregistry/mine/estimate-shipping-methods":{"post":{"tags":["giftRegistryShippingMethodManagementV1"],"description":"Estimate shipping","operationId":"giftRegistryShippingMethodManagementV1EstimateByRegistryIdPost","parameters":[{"name":"$body","in":"body","schema":{"required":["registryId"],"properties":{"registryId":{"type":"integer","description":"The estimate registry id"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","description":"An array of shipping methods.","items":{"$ref":"#/definitions/quote-data-shipping-method-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/guest-giftregistry/{cartId}/estimate-shipping-methods":{"post":{"tags":["giftRegistryGuestCartShippingMethodManagementV1"],"description":"Estimate shipping","operationId":"giftRegistryGuestCartShippingMethodManagementV1EstimateByRegistryIdPost","parameters":[{"name":"cartId","in":"path","type":"string","required":true,"description":"The shopping cart ID."},{"name":"$body","in":"body","schema":{"required":["registryId"],"properties":{"registryId":{"type":"integer","description":"The estimate registry id"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","description":"An array of shipping methods.","items":{"$ref":"#/definitions/quote-data-shipping-method-interface"}}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/reward/mine/use-reward":{"post":{"tags":["rewardRewardManagementV1"],"description":"Set reward points to quote","operationId":"rewardRewardManagementV1SetPost","responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/returns/{id}/tracking-numbers":{"post":{"tags":["rmaTrackManagementV1"],"description":"Add track","operationId":"rmaTrackManagementV1AddTrackPost","parameters":[{"name":"id","in":"path","type":"integer","required":true},{"name":"$body","in":"body","schema":{"required":["track"],"properties":{"track":{"$ref":"#/definitions/rma-data-track-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"get":{"tags":["rmaTrackManagementV1"],"description":"Get track list","operationId":"rmaTrackManagementV1GetTracksGet","parameters":[{"name":"id","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/rma-data-track-search-result-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/returns/{id}/tracking-numbers/{trackId}":{"delete":{"tags":["rmaTrackManagementV1"],"description":"Remove track by id","operationId":"rmaTrackManagementV1RemoveTrackByIdDelete","parameters":[{"name":"id","in":"path","type":"integer","required":true},{"name":"trackId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/returns/{id}/labels":{"get":{"tags":["rmaTrackManagementV1"],"description":"Get shipping label int the PDF format","operationId":"rmaTrackManagementV1GetShippingLabelPdfGet","parameters":[{"name":"id","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"string"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/returns/{id}":{"get":{"tags":["rmaRmaRepositoryV1"],"description":"Return data object for specified RMA id","operationId":"rmaRmaRepositoryV1GetGet","parameters":[{"name":"id","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/rma-data-rma-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"delete":{"tags":["rmaRmaRepositoryV1"],"description":"Delete RMA","operationId":"rmaRmaRepositoryV1DeleteDelete","parameters":[{"name":"id","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["rmaDataObject"],"properties":{"rmaDataObject":{"$ref":"#/definitions/rma-data-rma-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"put":{"tags":["rmaRmaManagementV1"],"description":"Save RMA","operationId":"rmaRmaManagementV1SaveRmaPut","parameters":[{"name":"id","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["rmaDataObject"],"properties":{"rmaDataObject":{"$ref":"#/definitions/rma-data-rma-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/rma-data-rma-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/returns/{id}/comments":{"post":{"tags":["rmaCommentManagementV1"],"description":"Add comment","operationId":"rmaCommentManagementV1AddCommentPost","parameters":[{"name":"id","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["data"],"properties":{"data":{"$ref":"#/definitions/rma-data-comment-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"get":{"tags":["rmaCommentManagementV1"],"description":"Comments list","operationId":"rmaCommentManagementV1CommentsListGet","parameters":[{"name":"id","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/rma-data-comment-search-result-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/returns":{"post":{"tags":["rmaRmaManagementV1"],"description":"Save RMA","operationId":"rmaRmaManagementV1SaveRmaPost","parameters":[{"name":"$body","in":"body","schema":{"required":["rmaDataObject"],"properties":{"rmaDataObject":{"$ref":"#/definitions/rma-data-rma-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/rma-data-rma-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"get":{"tags":["rmaRmaManagementV1"],"description":"Return list of rma data objects based on search criteria","operationId":"rmaRmaManagementV1SearchGet","parameters":[{"name":"searchCriteria[filterGroups][][filters][][field]","in":"query","type":"string","description":"Field"},{"name":"searchCriteria[filterGroups][][filters][][value]","in":"query","type":"string","description":"Value"},{"name":"searchCriteria[filterGroups][][filters][][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"searchCriteria[sortOrders][][field]","in":"query","type":"string","description":"Sorting field."},{"name":"searchCriteria[sortOrders][][direction]","in":"query","type":"string","description":"Sorting direction."},{"name":"searchCriteria[pageSize]","in":"query","type":"integer","description":"Page size."},{"name":"searchCriteria[currentPage]","in":"query","type":"integer","description":"Current page."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/rma-data-rma-search-result-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/returnsAttributeMetadata/{attributeCode}":{"get":{"tags":["rmaRmaAttributesManagementV1"],"description":"Retrieve attribute metadata.","operationId":"rmaRmaAttributesManagementV1GetAttributeMetadataGet","parameters":[{"name":"attributeCode","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/customer-data-attribute-metadata-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/returnsAttributeMetadata/form/{formCode}":{"get":{"tags":["rmaRmaAttributesManagementV1"],"description":"Retrieve all attributes filtered by form code","operationId":"rmaRmaAttributesManagementV1GetAttributesGet","parameters":[{"name":"formCode","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/customer-data-attribute-metadata-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/returnsAttributeMetadata":{"get":{"tags":["rmaRmaAttributesManagementV1"],"description":"Get all attribute metadata.","operationId":"rmaRmaAttributesManagementV1GetAllAttributesMetadataGet","responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/customer-data-attribute-metadata-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/returnsAttributeMetadata/custom":{"get":{"tags":["rmaRmaAttributesManagementV1"],"description":"Get custom attribute metadata for the given Data object's attribute set","operationId":"rmaRmaAttributesManagementV1GetCustomAttributesMetadataGet","parameters":[{"name":"dataObjectClassName","in":"query","type":"string","description":"Data object class name","required":false}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/framework-metadata-object-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/integration/admin/token":{"post":{"tags":["integrationAdminTokenServiceV1"],"description":"Create access token for admin given the admin credentials.","operationId":"integrationAdminTokenServiceV1CreateAdminAccessTokenPost","parameters":[{"name":"$body","in":"body","schema":{"required":["username","password"],"properties":{"username":{"type":"string"},"password":{"type":"string"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"string","description":"Token created"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/integration/customer/token":{"post":{"tags":["integrationCustomerTokenServiceV1"],"description":"Create access token for admin given the customer credentials.","operationId":"integrationCustomerTokenServiceV1CreateCustomerAccessTokenPost","parameters":[{"name":"$body","in":"body","schema":{"required":["username","password"],"properties":{"username":{"type":"string"},"password":{"type":"string"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"string","description":"Token created"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/testmodule1/overwritten":{"get":{"tags":["testModule1AllSoapAndRestV1"],"description":"","operationId":"testModule1AllSoapAndRestV1ItemGet","responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module1-v1-entity-item"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/testmodule1/testOptionalParam":{"post":{"tags":["testModule1AllSoapAndRestV1"],"description":"","operationId":"testModule1AllSoapAndRestV1TestOptionalParamPost","parameters":[{"name":"$body","in":"body","schema":{"properties":{"name":{"type":"string"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module1-v1-entity-item"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/testmodule1/{itemId}":{"get":{"tags":["testModule1AllSoapAndRestV1"],"description":"","operationId":"testModule1AllSoapAndRestV1ItemGet","parameters":[{"name":"itemId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module1-v1-entity-item"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"put":{"tags":["testModule1AllSoapAndRestV1"],"description":"","operationId":"testModule1AllSoapAndRestV1UpdatePut","parameters":[{"name":"itemId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["entityItem"],"properties":{"entityItem":{"$ref":"#/definitions/test-module1-v1-entity-item"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module1-v1-entity-item"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/testmodule1":{"get":{"tags":["testModule1AllSoapAndRestV1"],"description":"","operationId":"testModule1AllSoapAndRestV1ItemsGet","responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/test-module1-v1-entity-item"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"post":{"tags":["testModule1AllSoapAndRestV1"],"description":"","operationId":"testModule1AllSoapAndRestV1CreatePost","parameters":[{"name":"$body","in":"body","schema":{"required":["name"],"properties":{"name":{"type":"string"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module1-v1-entity-item"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/testmodule1/resource1/{itemId}":{"get":{"tags":["testModule1AllSoapAndRestV1"],"description":"","operationId":"testModule1AllSoapAndRestV1ItemGet","parameters":[{"name":"itemId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module1-v1-entity-item"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/testmodule1/itemAnyType":{"post":{"tags":["testModule1AllSoapAndRestV1"],"description":"","operationId":"testModule1AllSoapAndRestV1ItemAnyTypePost","parameters":[{"name":"$body","in":"body","schema":{"required":["entityItem"],"properties":{"entityItem":{"$ref":"#/definitions/test-module1-v1-entity-item"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module1-v1-entity-item"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/testmodule1/itemPreconfigured":{"get":{"tags":["testModule1AllSoapAndRestV1"],"description":"","operationId":"testModule1AllSoapAndRestV1GetPreconfiguredItemGet","responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module1-v1-entity-item"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V2/testmodule1/{id}":{"get":{"tags":["testModule1AllSoapAndRestV2"],"description":"Get item.","operationId":"testModule1AllSoapAndRestV2ItemGet","parameters":[{"name":"id","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module1-v2-entity-item"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"put":{"tags":["testModule1AllSoapAndRestV2"],"description":"Update item.","operationId":"testModule1AllSoapAndRestV2UpdatePut","parameters":[{"name":"id","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["entityItem"],"properties":{"entityItem":{"$ref":"#/definitions/test-module1-v2-entity-item"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module1-v2-entity-item"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"delete":{"tags":["testModule1AllSoapAndRestV2"],"description":"Delete an item.","operationId":"testModule1AllSoapAndRestV2DeleteDelete","parameters":[{"name":"id","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module1-v2-entity-item"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V2/testmodule1":{"get":{"tags":["testModule1AllSoapAndRestV2"],"description":"Retrieve a list of items.","operationId":"testModule1AllSoapAndRestV2ItemsGet","parameters":[{"name":"filters[][field]","in":"query","type":"string","description":"Field"},{"name":"filters[][value]","in":"query","type":"string","description":"Value"},{"name":"filters[][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"sortOrder","in":"query","type":"string","required":false}],"responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/test-module1-v2-entity-item"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"post":{"tags":["testModule1AllSoapAndRestV2"],"description":"Create item.","operationId":"testModule1AllSoapAndRestV2CreatePost","parameters":[{"name":"$body","in":"body","schema":{"required":["name"],"properties":{"name":{"type":"string"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module1-v2-entity-item"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/testModule2SubsetRest/{id}":{"get":{"tags":["testModule2SubsetRestV1"],"description":"Return a single item.","operationId":"testModule2SubsetRestV1ItemGet","parameters":[{"name":"id","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module2-v1-entity-item"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/testModule2SubsetRest":{"get":{"tags":["testModule2SubsetRestV1"],"description":"Return multiple items.","operationId":"testModule2SubsetRestV1ItemsGet","responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/test-module2-v1-entity-item"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/errortest/success":{"get":{"tags":["testModule3ErrorV1"],"description":"","operationId":"testModule3ErrorV1SuccessGet","responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module3-v1-entity-parameter"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/errortest/notfound":{"get":{"tags":["testModule3ErrorV1"],"description":"","operationId":"testModule3ErrorV1ResourceNotFoundExceptionGet","responses":{"200":{"description":"200 Success.","schema":{"type":"integer","description":"Status"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/errortest/serviceexception":{"get":{"tags":["testModule3ErrorV1"],"description":"","operationId":"testModule3ErrorV1ServiceExceptionGet","responses":{"200":{"description":"200 Success.","schema":{"type":"integer","description":"Status"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/errortest/unauthorized":{"get":{"tags":["testModule3ErrorV1"],"description":"","operationId":"testModule3ErrorV1AuthorizationExceptionGet","responses":{"200":{"description":"200 Success.","schema":{"type":"integer","description":"Status"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/errortest/otherException":{"get":{"tags":["testModule3ErrorV1"],"description":"","operationId":"testModule3ErrorV1OtherExceptionGet","responses":{"200":{"description":"200 Success.","schema":{"type":"integer","description":"Status"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/errortest/returnIncompatibleDataType":{"get":{"tags":["testModule3ErrorV1"],"description":"","operationId":"testModule3ErrorV1ReturnIncompatibleDataTypeGet","responses":{"200":{"description":"200 Success.","schema":{"type":"integer","description":"Status"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/errortest/webapiException":{"get":{"tags":["testModule3ErrorV1"],"description":"","operationId":"testModule3ErrorV1WebapiExceptionGet","responses":{"200":{"description":"200 Success.","schema":{"type":"integer","description":"Status"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/errortest/inputException":{"post":{"tags":["testModule3ErrorV1"],"description":"","operationId":"testModule3ErrorV1InputExceptionPost","parameters":[{"name":"$body","in":"body","schema":{"required":["wrappedErrorParameters"],"properties":{"wrappedErrorParameters":{"type":"array","items":{"$ref":"#/definitions/test-module3-v1-entity-wrapped-error-parameter"}}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer","description":"Status"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/testmodule4/{id}":{"get":{"tags":["testModule4DataObjectServiceV1"],"description":"","operationId":"testModule4DataObjectServiceV1GetDataGet","parameters":[{"name":"id","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module4-v1-entity-data-object-response"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"post":{"tags":["testModule4DataObjectServiceV1"],"description":"","operationId":"testModule4DataObjectServiceV1UpdateDataPost","parameters":[{"name":"id","in":"path","type":"integer","required":true},{"name":"$body","in":"body","schema":{"required":["request"],"properties":{"request":{"$ref":"#/definitions/test-module4-v1-entity-data-object-request"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module4-v1-entity-data-object-response"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/testmodule4/scalar/{id}":{"get":{"tags":["testModule4DataObjectServiceV1"],"description":"Test return scalar value","operationId":"testModule4DataObjectServiceV1ScalarResponseGet","parameters":[{"name":"id","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/testmodule4/{id}/nested":{"post":{"tags":["testModule4DataObjectServiceV1"],"description":"","operationId":"testModule4DataObjectServiceV1NestedDataPost","parameters":[{"name":"id","in":"path","type":"integer","required":true},{"name":"$body","in":"body","schema":{"required":["request"],"properties":{"request":{"$ref":"#/definitions/test-module4-v1-entity-nested-data-object-request"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module4-v1-entity-data-object-response"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/testmodule4/extensibleDataObject/{id}":{"post":{"tags":["testModule4DataObjectServiceV1"],"description":"","operationId":"testModule4DataObjectServiceV1ExtensibleDataObjectPost","parameters":[{"name":"id","in":"path","type":"integer","required":true},{"name":"$body","in":"body","schema":{"required":["request"],"properties":{"request":{"$ref":"#/definitions/test-module4-v1-entity-extensible-request-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module4-v1-entity-data-object-response"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/TestModule5/{entityId}":{"get":{"tags":["testModule5AllSoapAndRestV1"],"description":"Retrieve an item.","operationId":"testModule5AllSoapAndRestV1ItemGet","parameters":[{"name":"entityId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module5-v1-entity-all-soap-and-rest"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"put":{"tags":["testModule5AllSoapAndRestV1"],"description":"Update existing item.","operationId":"testModule5AllSoapAndRestV1UpdatePut","parameters":[{"name":"entityId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["entityItem"],"properties":{"entityItem":{"$ref":"#/definitions/test-module5-v1-entity-all-soap-and-rest"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module5-v1-entity-all-soap-and-rest"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/TestModule5":{"get":{"tags":["testModule5AllSoapAndRestV1"],"description":"Retrieve all items.","operationId":"testModule5AllSoapAndRestV1ItemsGet","responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/test-module5-v1-entity-all-soap-and-rest"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"post":{"tags":["testModule5AllSoapAndRestV1"],"description":"Create a new item.","operationId":"testModule5AllSoapAndRestV1CreatePost","parameters":[{"name":"$body","in":"body","schema":{"required":["item"],"properties":{"item":{"$ref":"#/definitions/test-module5-v1-entity-all-soap-and-rest"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module5-v1-entity-all-soap-and-rest"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/TestModule5/{parentId}/nestedResource/{entityId}":{"put":{"tags":["testModule5AllSoapAndRestV1"],"description":"Update existing item.","operationId":"testModule5AllSoapAndRestV1NestedUpdatePut","parameters":[{"name":"parentId","in":"path","type":"string","required":true},{"name":"entityId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["entityItem"],"properties":{"entityItem":{"$ref":"#/definitions/test-module5-v1-entity-all-soap-and-rest"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module5-v1-entity-all-soap-and-rest"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/TestModule5/OverrideService/{parentId}/nestedResource/{entityId}":{"put":{"tags":["testModule5OverrideServiceV1"],"description":"Update existing item.","operationId":"testModule5OverrideServiceV1ScalarUpdatePut","parameters":[{"name":"entityId","in":"path","type":"string","required":true},{"name":"parentId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["name","orders"],"properties":{"name":{"type":"string"},"orders":{"type":"boolean"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module5-v1-entity-all-soap-and-rest"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V2/TestModule5/{id}":{"get":{"tags":["testModule5AllSoapAndRestV2"],"description":"Retrieve existing item.","operationId":"testModule5AllSoapAndRestV2ItemGet","parameters":[{"name":"id","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module5-v2-entity-all-soap-and-rest"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"put":{"tags":["testModule5AllSoapAndRestV2"],"description":"Update one item.","operationId":"testModule5AllSoapAndRestV2UpdatePut","parameters":[{"name":"id","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["item"],"properties":{"item":{"$ref":"#/definitions/test-module5-v2-entity-all-soap-and-rest"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module5-v2-entity-all-soap-and-rest"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"delete":{"tags":["testModule5AllSoapAndRestV2"],"description":"Delete existing item.","operationId":"testModule5AllSoapAndRestV2DeleteDelete","parameters":[{"name":"id","in":"path","type":"string","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module5-v2-entity-all-soap-and-rest"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V2/TestModule5":{"get":{"tags":["testModule5AllSoapAndRestV2"],"description":"Retrieve a list of all existing items.","operationId":"testModule5AllSoapAndRestV2ItemsGet","responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/test-module5-v2-entity-all-soap-and-rest"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"post":{"tags":["testModule5AllSoapAndRestV2"],"description":"Add new item.","operationId":"testModule5AllSoapAndRestV2CreatePost","parameters":[{"name":"$body","in":"body","schema":{"required":["item"],"properties":{"item":{"$ref":"#/definitions/test-module5-v2-entity-all-soap-and-rest"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module5-v2-entity-all-soap-and-rest"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/TestModuleDefaultHydrator":{"post":{"tags":["testModuleDefaultHydratorCustomerPersistenceV1"],"description":"Create customer","operationId":"testModuleDefaultHydratorCustomerPersistenceV1SavePost","parameters":[{"name":"$body","in":"body","schema":{"required":["customer"],"properties":{"customer":{"$ref":"#/definitions/customer-data-customer-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/customer-data-customer-interface"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/TestModuleDefaultHydrator/{id}":{"get":{"tags":["testModuleDefaultHydratorCustomerPersistenceV1"],"description":"Retrieve customer by id","operationId":"testModuleDefaultHydratorCustomerPersistenceV1GetByIdGet","parameters":[{"name":"id","in":"path","type":"integer","required":true},{"name":"websiteId","in":"query","type":"integer","required":false}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/customer-data-customer-interface"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"delete":{"tags":["testModuleDefaultHydratorCustomerPersistenceV1"],"description":"Delete customer by id","operationId":"testModuleDefaultHydratorCustomerPersistenceV1DeleteDelete","parameters":[{"name":"id","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"type":"boolean"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"put":{"tags":["testModuleDefaultHydratorCustomerPersistenceV1"],"description":"Create customer","operationId":"testModuleDefaultHydratorCustomerPersistenceV1SavePut","parameters":[{"name":"id","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["customer"],"properties":{"customer":{"$ref":"#/definitions/customer-data-customer-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/customer-data-customer-interface"}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/TestModuleJoinDirectives":{"get":{"tags":["testModuleJoinDirectivesTestRepositoryV1"],"description":"Get list of quotes","operationId":"testModuleJoinDirectivesTestRepositoryV1GetListGet","parameters":[{"name":"searchCriteria[filterGroups][][filters][][field]","in":"query","type":"string","description":"Field"},{"name":"searchCriteria[filterGroups][][filters][][value]","in":"query","type":"string","description":"Value"},{"name":"searchCriteria[filterGroups][][filters][][conditionType]","in":"query","type":"string","description":"Condition type"},{"name":"searchCriteria[sortOrders][][field]","in":"query","type":"string","description":"Sorting field."},{"name":"searchCriteria[sortOrders][][direction]","in":"query","type":"string","description":"Sorting direction."},{"name":"searchCriteria[pageSize]","in":"query","type":"integer","description":"Page size."},{"name":"searchCriteria[currentPage]","in":"query","type":"integer","description":"Current page."}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/quote-data-cart-search-results-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/testmoduleMSC/overwritten":{"get":{"tags":["testModuleMSCAllSoapAndRestV1"],"description":"","operationId":"testModuleMSCAllSoapAndRestV1ItemGet","responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module-ms-cdata-item-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/testmoduleMSC/testOptionalParam":{"post":{"tags":["testModuleMSCAllSoapAndRestV1"],"description":"","operationId":"testModuleMSCAllSoapAndRestV1TestOptionalParamPost","parameters":[{"name":"$body","in":"body","schema":{"properties":{"name":{"type":"string"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module-ms-cdata-item-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/testmoduleMSC/{itemId}":{"get":{"tags":["testModuleMSCAllSoapAndRestV1"],"description":"","operationId":"testModuleMSCAllSoapAndRestV1ItemGet","parameters":[{"name":"itemId","in":"path","type":"integer","required":true}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module-ms-cdata-item-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"put":{"tags":["testModuleMSCAllSoapAndRestV1"],"description":"","operationId":"testModuleMSCAllSoapAndRestV1UpdatePut","parameters":[{"name":"itemId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["entityItem"],"properties":{"entityItem":{"$ref":"#/definitions/test-module-ms-cdata-item-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module-ms-cdata-item-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/testmoduleMSC":{"get":{"tags":["testModuleMSCAllSoapAndRestV1"],"description":"","operationId":"testModuleMSCAllSoapAndRestV1ItemsGet","responses":{"200":{"description":"200 Success.","schema":{"type":"array","items":{"$ref":"#/definitions/test-module-ms-cdata-item-interface"}}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}},"post":{"tags":["testModuleMSCAllSoapAndRestV1"],"description":"","operationId":"testModuleMSCAllSoapAndRestV1CreatePost","parameters":[{"name":"$body","in":"body","schema":{"required":["name"],"properties":{"name":{"type":"string"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module-ms-cdata-item-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/testmoduleMSC/itemAnyType":{"post":{"tags":["testModuleMSCAllSoapAndRestV1"],"description":"","operationId":"testModuleMSCAllSoapAndRestV1ItemAnyTypePost","parameters":[{"name":"$body","in":"body","schema":{"required":["entityItem"],"properties":{"entityItem":{"$ref":"#/definitions/test-module-ms-cdata-item-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module-ms-cdata-item-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/testmoduleMSC/itemPreconfigured":{"get":{"tags":["testModuleMSCAllSoapAndRestV1"],"description":"","operationId":"testModuleMSCAllSoapAndRestV1GetPreconfiguredItemGet","responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module-ms-cdata-item-interface"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}},"/V1/worldpay-guest-carts/{cartId}/payment-information":{"post":{"tags":["worldpayGuestPaymentInformationManagementProxyV1"],"description":"Proxy handler for guest place order","operationId":"worldpayGuestPaymentInformationManagementProxyV1SavePaymentInformationAndPlaceOrderPost","parameters":[{"name":"cartId","in":"path","type":"string","required":true},{"name":"$body","in":"body","schema":{"required":["email","paymentMethod"],"properties":{"email":{"type":"string"},"paymentMethod":{"$ref":"#/definitions/quote-data-payment-interface"},"billingAddress":{"$ref":"#/definitions/quote-data-address-interface"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"type":"integer","description":"Order ID."}},"400":{"description":"400 Bad Request","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}}},"definitions":{"error-response":{"type":"object","properties":{"message":{"type":"string","description":"Error message"},"errors":{"$ref":"#/definitions/error-errors"},"code":{"type":"integer","description":"Error code"},"parameters":{"$ref":"#/definitions/error-parameters"},"trace":{"type":"string","description":"Stack trace"}},"required":["message"]},"error-errors":{"type":"array","description":"Errors list","items":{"$ref":"#/definitions/error-errors-item"}},"error-errors-item":{"type":"object","description":"Error details","properties":{"message":{"type":"string","description":"Error message"},"parameters":{"$ref":"#/definitions/error-parameters"}}},"error-parameters":{"type":"array","description":"Error parameters list","items":{"$ref":"#/definitions/error-parameters-item"}},"error-parameters-item":{"type":"object","description":"Error parameters item","properties":{"resources":{"type":"string","description":"ACL resource"},"fieldName":{"type":"string","description":"Missing or invalid field name"},"fieldValue":{"type":"string","description":"Incorrect field value"}}},"store-data-store-interface":{"type":"object","description":"Store interface","properties":{"id":{"type":"integer"},"code":{"type":"string"},"name":{"type":"string","description":"Store name"},"website_id":{"type":"integer"},"store_group_id":{"type":"integer"},"extension_attributes":{"$ref":"#/definitions/store-data-store-extension-interface"}},"required":["id","code","name","website_id","store_group_id"]},"store-data-store-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Store\\Api\\Data\\StoreInterface"},"store-data-group-interface":{"type":"object","description":"Group interface","properties":{"id":{"type":"integer"},"website_id":{"type":"integer"},"root_category_id":{"type":"integer"},"default_store_id":{"type":"integer"},"name":{"type":"string"},"code":{"type":"string","description":"Group code."},"extension_attributes":{"$ref":"#/definitions/store-data-group-extension-interface"}},"required":["id","website_id","root_category_id","default_store_id","name","code"]},"store-data-group-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Store\\Api\\Data\\GroupInterface"},"store-data-website-interface":{"type":"object","description":"Website interface","properties":{"id":{"type":"integer"},"code":{"type":"string"},"name":{"type":"string","description":"Website name"},"default_group_id":{"type":"integer"},"extension_attributes":{"$ref":"#/definitions/store-data-website-extension-interface"}},"required":["id","code","name","default_group_id"]},"store-data-website-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Store\\Api\\Data\\WebsiteInterface"},"store-data-store-config-interface":{"type":"object","description":"StoreConfig interface","properties":{"id":{"type":"integer","description":"Store id"},"code":{"type":"string","description":"Store code"},"website_id":{"type":"integer","description":"Website id of the store"},"locale":{"type":"string","description":"Store locale"},"base_currency_code":{"type":"string","description":"Base currency code"},"default_display_currency_code":{"type":"string","description":"Default display currency code"},"timezone":{"type":"string","description":"Timezone of the store"},"weight_unit":{"type":"string","description":"The unit of weight"},"base_url":{"type":"string","description":"Base URL for the store"},"base_link_url":{"type":"string","description":"Base link URL for the store"},"base_static_url":{"type":"string","description":"Base static URL for the store"},"base_media_url":{"type":"string","description":"Base media URL for the store"},"secure_base_url":{"type":"string","description":"Secure base URL for the store"},"secure_base_link_url":{"type":"string","description":"Secure base link URL for the store"},"secure_base_static_url":{"type":"string","description":"Secure base static URL for the store"},"secure_base_media_url":{"type":"string","description":"Secure base media URL for the store"},"extension_attributes":{"$ref":"#/definitions/store-data-store-config-extension-interface"}},"required":["id","code","website_id","locale","base_currency_code","default_display_currency_code","timezone","weight_unit","base_url","base_link_url","base_static_url","base_media_url","secure_base_url","secure_base_link_url","secure_base_static_url","secure_base_media_url"]},"store-data-store-config-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Store\\Api\\Data\\StoreConfigInterface"},"directory-data-currency-information-interface":{"type":"object","description":"Currency Information interface.","properties":{"base_currency_code":{"type":"string","description":"The base currency code for the store."},"base_currency_symbol":{"type":"string","description":"The currency symbol of the base currency for the store."},"default_display_currency_code":{"type":"string","description":"The default display currency code for the store."},"default_display_currency_symbol":{"type":"string","description":"The currency symbol of the default display currency for the store."},"available_currency_codes":{"type":"array","description":"The list of allowed currency codes for the store.","items":{"type":"string"}},"exchange_rates":{"type":"array","description":"The list of exchange rate information for the store.","items":{"$ref":"#/definitions/directory-data-exchange-rate-interface"}},"extension_attributes":{"$ref":"#/definitions/directory-data-currency-information-extension-interface"}},"required":["base_currency_code","base_currency_symbol","default_display_currency_code","default_display_currency_symbol","available_currency_codes","exchange_rates"]},"directory-data-exchange-rate-interface":{"type":"object","description":"Exchange Rate interface.","properties":{"currency_to":{"type":"string","description":"The currency code associated with the exchange rate."},"rate":{"type":"number","description":"The exchange rate for the associated currency and the store's base currency."},"extension_attributes":{"$ref":"#/definitions/directory-data-exchange-rate-extension-interface"}},"required":["currency_to","rate"]},"directory-data-exchange-rate-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Directory\\Api\\Data\\ExchangeRateInterface"},"directory-data-currency-information-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Directory\\Api\\Data\\CurrencyInformationInterface"},"directory-data-country-information-interface":{"type":"object","description":"Country Information interface.","properties":{"id":{"type":"string","description":"The country id for the store."},"two_letter_abbreviation":{"type":"string","description":"The country 2 letter abbreviation for the store."},"three_letter_abbreviation":{"type":"string","description":"The country 3 letter abbreviation for the store."},"full_name_locale":{"type":"string","description":"The country full name (in store locale) for the store."},"full_name_english":{"type":"string","description":"The country full name (in English) for the store."},"available_regions":{"type":"array","description":"The available regions for the store.","items":{"$ref":"#/definitions/directory-data-region-information-interface"}},"extension_attributes":{"$ref":"#/definitions/directory-data-country-information-extension-interface"}},"required":["id","two_letter_abbreviation","three_letter_abbreviation","full_name_locale","full_name_english"]},"directory-data-region-information-interface":{"type":"object","description":"Region Information interface.","properties":{"id":{"type":"string","description":"Region id"},"code":{"type":"string","description":"Region code"},"name":{"type":"string","description":"Region name"},"extension_attributes":{"$ref":"#/definitions/directory-data-region-information-extension-interface"}},"required":["id","code","name"]},"directory-data-region-information-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Directory\\Api\\Data\\RegionInformationInterface"},"directory-data-country-information-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Directory\\Api\\Data\\CountryInformationInterface"},"eav-data-attribute-set-search-results-interface":{"type":"object","description":"Interface AttributeSetSearchResultsInterface","properties":{"items":{"type":"array","description":"Attribute sets list.","items":{"$ref":"#/definitions/eav-data-attribute-set-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"eav-data-attribute-set-interface":{"type":"object","description":"Interface AttributeSetInterface","properties":{"attribute_set_id":{"type":"integer","description":"Attribute set ID"},"attribute_set_name":{"type":"string","description":"Attribute set name"},"sort_order":{"type":"integer","description":"Attribute set sort order index"},"entity_type_id":{"type":"integer","description":"Attribute set entity type id"},"extension_attributes":{"$ref":"#/definitions/eav-data-attribute-set-extension-interface"}},"required":["attribute_set_name","sort_order"]},"eav-data-attribute-set-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Eav\\Api\\Data\\AttributeSetInterface"},"framework-search-criteria-interface":{"type":"object","description":"Search criteria interface.","properties":{"filter_groups":{"type":"array","description":"A list of filter groups.","items":{"$ref":"#/definitions/framework-search-filter-group"}},"sort_orders":{"type":"array","description":"Sort order.","items":{"$ref":"#/definitions/framework-sort-order"}},"page_size":{"type":"integer","description":"Page size."},"current_page":{"type":"integer","description":"Current page."}},"required":["filter_groups"]},"framework-search-filter-group":{"type":"object","description":"Groups two or more filters together using a logical OR","properties":{"filters":{"type":"array","description":"A list of filters in this group","items":{"$ref":"#/definitions/framework-filter"}}}},"framework-filter":{"type":"object","description":"Filter which can be used by any methods from service layer.","properties":{"field":{"type":"string","description":"Field"},"value":{"type":"string","description":"Value"},"condition_type":{"type":"string","description":"Condition type"}},"required":["field","value"]},"framework-sort-order":{"type":"object","description":"Data object for sort order.","properties":{"field":{"type":"string","description":"Sorting field."},"direction":{"type":"string","description":"Sorting direction."}},"required":["field","direction"]},"customer-data-group-interface":{"type":"object","description":"Customer group interface.","properties":{"id":{"type":"integer","description":"Id"},"code":{"type":"string","description":"Code"},"tax_class_id":{"type":"integer","description":"Tax class id"},"tax_class_name":{"type":"string","description":"Tax class name"},"extension_attributes":{"$ref":"#/definitions/customer-data-group-extension-interface"}},"required":["code","tax_class_id"]},"customer-data-group-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Customer\\Api\\Data\\GroupInterface"},"customer-data-group-search-results-interface":{"type":"object","description":"Interface for customer groups search results.","properties":{"items":{"type":"array","description":"Customer groups list.","items":{"$ref":"#/definitions/customer-data-group-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"customer-data-attribute-metadata-interface":{"type":"object","description":"Customer attribute metadata interface.","properties":{"frontend_input":{"type":"string","description":"HTML for input element."},"input_filter":{"type":"string","description":"Template used for input (e.g. \"date\")"},"store_label":{"type":"string","description":"Label of the store."},"validation_rules":{"type":"array","description":"Validation rules.","items":{"$ref":"#/definitions/customer-data-validation-rule-interface"}},"multiline_count":{"type":"integer","description":"Of lines of the attribute value."},"visible":{"type":"boolean","description":"Attribute is visible on frontend."},"required":{"type":"boolean","description":"Attribute is required."},"data_model":{"type":"string","description":"Data model for attribute."},"options":{"type":"array","description":"Options of the attribute (key => value pairs for select)","items":{"$ref":"#/definitions/customer-data-option-interface"}},"frontend_class":{"type":"string","description":"Class which is used to display the attribute on frontend."},"user_defined":{"type":"boolean","description":"Current attribute has been defined by a user."},"sort_order":{"type":"integer","description":"Attributes sort order."},"frontend_label":{"type":"string","description":"Label which supposed to be displayed on frontend."},"note":{"type":"string","description":"The note attribute for the element."},"system":{"type":"boolean","description":"This is a system attribute."},"backend_type":{"type":"string","description":"Backend type."},"is_used_in_grid":{"type":"boolean","description":"It is used in customer grid"},"is_visible_in_grid":{"type":"boolean","description":"It is visible in customer grid"},"is_filterable_in_grid":{"type":"boolean","description":"It is filterable in customer grid"},"is_searchable_in_grid":{"type":"boolean","description":"It is searchable in customer grid"},"attribute_code":{"type":"string","description":"Code of the attribute."}},"required":["frontend_input","input_filter","store_label","validation_rules","multiline_count","visible","required","data_model","options","frontend_class","user_defined","sort_order","frontend_label","note","system","backend_type","attribute_code"]},"customer-data-validation-rule-interface":{"type":"object","description":"Validation rule interface.","properties":{"name":{"type":"string","description":"Validation rule name"},"value":{"type":"string","description":"Validation rule value"}},"required":["name","value"]},"customer-data-option-interface":{"type":"object","description":"Option interface.","properties":{"label":{"type":"string","description":"Option label"},"value":{"type":"string","description":"Option value"},"options":{"type":"array","description":"Nested options","items":{"$ref":"#/definitions/customer-data-option-interface"}}},"required":["label"]},"customer-data-customer-interface":{"type":"object","description":"Customer interface.","properties":{"id":{"type":"integer","description":"Customer id"},"group_id":{"type":"integer","description":"Group id"},"default_billing":{"type":"string","description":"Default billing address id"},"default_shipping":{"type":"string","description":"Default shipping address id"},"confirmation":{"type":"string","description":"Confirmation"},"created_at":{"type":"string","description":"Created at time"},"updated_at":{"type":"string","description":"Updated at time"},"created_in":{"type":"string","description":"Created in area"},"dob":{"type":"string","description":"Date of birth"},"email":{"type":"string","description":"Email address"},"firstname":{"type":"string","description":"First name"},"lastname":{"type":"string","description":"Last name"},"middlename":{"type":"string","description":"Middle name"},"prefix":{"type":"string","description":"Prefix"},"suffix":{"type":"string","description":"Suffix"},"gender":{"type":"integer","description":"Gender"},"store_id":{"type":"integer","description":"Store id"},"taxvat":{"type":"string","description":"Tax Vat"},"website_id":{"type":"integer","description":"Website id"},"addresses":{"type":"array","description":"Customer addresses.","items":{"$ref":"#/definitions/customer-data-address-interface"}},"disable_auto_group_change":{"type":"integer","description":"Disable auto group change flag."},"extension_attributes":{"$ref":"#/definitions/customer-data-customer-extension-interface"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["email","firstname","lastname"]},"customer-data-address-interface":{"type":"object","description":"Customer address interface.","properties":{"id":{"type":"integer","description":"ID"},"customer_id":{"type":"integer","description":"Customer ID"},"region":{"$ref":"#/definitions/customer-data-region-interface"},"region_id":{"type":"integer","description":"Region ID"},"country_id":{"type":"string","description":"Country code in ISO_3166-2 format"},"street":{"type":"array","description":"Street","items":{"type":"string"}},"company":{"type":"string","description":"Company"},"telephone":{"type":"string","description":"Telephone number"},"fax":{"type":"string","description":"Fax number"},"postcode":{"type":"string","description":"Postcode"},"city":{"type":"string","description":"City name"},"firstname":{"type":"string","description":"First name"},"lastname":{"type":"string","description":"Last name"},"middlename":{"type":"string","description":"Middle name"},"prefix":{"type":"string","description":"Prefix"},"suffix":{"type":"string","description":"Suffix"},"vat_id":{"type":"string","description":"Vat id"},"default_shipping":{"type":"boolean","description":"If this address is default shipping address."},"default_billing":{"type":"boolean","description":"If this address is default billing address"},"extension_attributes":{"$ref":"#/definitions/customer-data-address-extension-interface"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}}},"customer-data-region-interface":{"type":"object","description":"Customer address region interface.","properties":{"region_code":{"type":"string","description":"Region code"},"region":{"type":"string","description":"Region"},"region_id":{"type":"integer","description":"Region id"},"extension_attributes":{"$ref":"#/definitions/customer-data-region-extension-interface"}},"required":["region_code","region","region_id"]},"customer-data-region-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Customer\\Api\\Data\\RegionInterface"},"customer-data-address-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Customer\\Api\\Data\\AddressInterface"},"framework-attribute-interface":{"type":"object","description":"Interface for custom attribute value.","properties":{"attribute_code":{"type":"string","description":"Attribute code"},"value":{"type":"string","description":"Attribute value"}},"required":["attribute_code","value"]},"customer-data-customer-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Customer\\Api\\Data\\CustomerInterface","properties":{"is_subscribed":{"type":"boolean"},"extension_attribute":{"$ref":"#/definitions/test-module-default-hydrator-data-extension-attribute-interface"}}},"test-module-default-hydrator-data-extension-attribute-interface":{"type":"object","description":"","properties":{"id":{"type":"integer","description":"ID"},"customer_id":{"type":"integer","description":"Customer ID"},"value":{"type":"string","description":"Value"}}},"customer-data-customer-search-results-interface":{"type":"object","description":"Interface for customer search results.","properties":{"items":{"type":"array","description":"Customers list.","items":{"$ref":"#/definitions/customer-data-customer-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"customer-data-validation-results-interface":{"type":"object","description":"Validation results interface.","properties":{"valid":{"type":"boolean","description":"If the provided data is valid."},"messages":{"type":"array","description":"Error messages as array in case of validation failure, else return empty array.","items":{"type":"string"}}},"required":["valid","messages"]},"cms-data-page-interface":{"type":"object","description":"CMS page interface.","properties":{"id":{"type":"integer","description":"ID"},"identifier":{"type":"string","description":"Identifier"},"title":{"type":"string","description":"Title"},"page_layout":{"type":"string","description":"Page layout"},"meta_title":{"type":"string","description":"Meta title"},"meta_keywords":{"type":"string","description":"Meta keywords"},"meta_description":{"type":"string","description":"Meta description"},"content_heading":{"type":"string","description":"Content heading"},"content":{"type":"string","description":"Content"},"creation_time":{"type":"string","description":"Creation time"},"update_time":{"type":"string","description":"Update time"},"sort_order":{"type":"string","description":"Sort order"},"layout_update_xml":{"type":"string","description":"Layout update xml"},"custom_theme":{"type":"string","description":"Custom theme"},"custom_root_template":{"type":"string","description":"Custom root template"},"custom_layout_update_xml":{"type":"string","description":"Custom layout update xml"},"custom_theme_from":{"type":"string","description":"Custom theme from"},"custom_theme_to":{"type":"string","description":"Custom theme to"},"active":{"type":"boolean","description":"Active"}},"required":["identifier"]},"cms-data-page-search-results-interface":{"type":"object","description":"Interface for cms page search results.","properties":{"items":{"type":"array","description":"Pages list.","items":{"$ref":"#/definitions/cms-data-page-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"cms-data-block-interface":{"type":"object","description":"CMS block interface.","properties":{"id":{"type":"integer","description":"ID"},"identifier":{"type":"string","description":"Identifier"},"title":{"type":"string","description":"Title"},"content":{"type":"string","description":"Content"},"creation_time":{"type":"string","description":"Creation time"},"update_time":{"type":"string","description":"Update time"},"active":{"type":"boolean","description":"Active"}},"required":["identifier"]},"cms-data-block-search-results-interface":{"type":"object","description":"Interface for cms block search results.","properties":{"items":{"type":"array","description":"Blocks list.","items":{"$ref":"#/definitions/cms-data-block-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"catalog-data-product-interface":{"type":"object","description":"","properties":{"id":{"type":"integer","description":"Id"},"sku":{"type":"string","description":"Sku"},"name":{"type":"string","description":"Name"},"attribute_set_id":{"type":"integer","description":"Attribute set id"},"price":{"type":"number","description":"Price"},"status":{"type":"integer","description":"Status"},"visibility":{"type":"integer","description":"Visibility"},"type_id":{"type":"string","description":"Type id"},"created_at":{"type":"string","description":"Created date"},"updated_at":{"type":"string","description":"Updated date"},"weight":{"type":"number","description":"Weight"},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-extension-interface"},"product_links":{"type":"array","description":"Product links info","items":{"$ref":"#/definitions/catalog-data-product-link-interface"}},"options":{"type":"array","description":"List of product options","items":{"$ref":"#/definitions/catalog-data-product-custom-option-interface"}},"media_gallery_entries":{"type":"array","description":"Media gallery entries","items":{"$ref":"#/definitions/catalog-data-product-attribute-media-gallery-entry-interface"}},"tier_prices":{"type":"array","description":"List of product tier prices","items":{"$ref":"#/definitions/catalog-data-product-tier-price-interface"}},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["sku"]},"catalog-data-product-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductInterface","properties":{"website_ids":{"type":"array","items":{"type":"integer"}},"category_links":{"type":"array","items":{"$ref":"#/definitions/catalog-data-category-link-interface"}},"stock_item":{"$ref":"#/definitions/catalog-inventory-data-stock-item-interface"},"bundle_product_options":{"type":"array","items":{"$ref":"#/definitions/bundle-data-option-interface"}},"downloadable_product_links":{"type":"array","items":{"$ref":"#/definitions/downloadable-data-link-interface"}},"downloadable_product_samples":{"type":"array","items":{"$ref":"#/definitions/downloadable-data-sample-interface"}},"giftcard_amounts":{"type":"array","items":{"$ref":"#/definitions/gift-card-data-giftcard-amount-interface"}},"configurable_product_options":{"type":"array","items":{"$ref":"#/definitions/configurable-product-data-option-interface"}},"configurable_product_links":{"type":"array","items":{"type":"integer"}}}},"catalog-data-category-link-interface":{"type":"object","description":"","properties":{"position":{"type":"integer"},"category_id":{"type":"string","description":"Category id"},"extension_attributes":{"$ref":"#/definitions/catalog-data-category-link-extension-interface"}},"required":["category_id"]},"catalog-data-category-link-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\CategoryLinkInterface"},"catalog-inventory-data-stock-item-interface":{"type":"object","description":"Interface StockItem","properties":{"item_id":{"type":"integer"},"product_id":{"type":"integer"},"stock_id":{"type":"integer","description":"Stock identifier"},"qty":{"type":"number"},"is_in_stock":{"type":"boolean","description":"Stock Availability"},"is_qty_decimal":{"type":"boolean"},"show_default_notification_message":{"type":"boolean"},"use_config_min_qty":{"type":"boolean"},"min_qty":{"type":"number","description":"Minimal quantity available for item status in stock"},"use_config_min_sale_qty":{"type":"integer"},"min_sale_qty":{"type":"number","description":"Minimum Qty Allowed in Shopping Cart or NULL when there is no limitation"},"use_config_max_sale_qty":{"type":"boolean"},"max_sale_qty":{"type":"number","description":"Maximum Qty Allowed in Shopping Cart data wrapper"},"use_config_backorders":{"type":"boolean"},"backorders":{"type":"integer","description":"Backorders status"},"use_config_notify_stock_qty":{"type":"boolean"},"notify_stock_qty":{"type":"number","description":"Notify for Quantity Below data wrapper"},"use_config_qty_increments":{"type":"boolean"},"qty_increments":{"type":"number","description":"Quantity Increments data wrapper"},"use_config_enable_qty_inc":{"type":"boolean"},"enable_qty_increments":{"type":"boolean","description":"Whether Quantity Increments is enabled"},"use_config_manage_stock":{"type":"boolean"},"manage_stock":{"type":"boolean","description":"Can Manage Stock"},"low_stock_date":{"type":"string"},"is_decimal_divided":{"type":"boolean"},"stock_status_changed_auto":{"type":"integer"},"extension_attributes":{"$ref":"#/definitions/catalog-inventory-data-stock-item-extension-interface"}},"required":["qty","is_in_stock","is_qty_decimal","show_default_notification_message","use_config_min_qty","min_qty","use_config_min_sale_qty","min_sale_qty","use_config_max_sale_qty","max_sale_qty","use_config_backorders","backorders","use_config_notify_stock_qty","notify_stock_qty","use_config_qty_increments","qty_increments","use_config_enable_qty_inc","enable_qty_increments","use_config_manage_stock","manage_stock","low_stock_date","is_decimal_divided","stock_status_changed_auto"]},"catalog-inventory-data-stock-item-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\CatalogInventory\\Api\\Data\\StockItemInterface"},"bundle-data-option-interface":{"type":"object","description":"Interface OptionInterface","properties":{"option_id":{"type":"integer","description":"Option id"},"title":{"type":"string","description":"Option title"},"required":{"type":"boolean","description":"Is required option"},"type":{"type":"string","description":"Input type"},"position":{"type":"integer","description":"Option position"},"sku":{"type":"string","description":"Product sku"},"product_links":{"type":"array","description":"Product links","items":{"$ref":"#/definitions/bundle-data-link-interface"}},"extension_attributes":{"$ref":"#/definitions/bundle-data-option-extension-interface"}}},"bundle-data-link-interface":{"type":"object","description":"Interface LinkInterface","properties":{"id":{"type":"string","description":"The identifier"},"sku":{"type":"string","description":"Linked product sku"},"option_id":{"type":"integer","description":"Option id"},"qty":{"type":"number","description":"Qty"},"position":{"type":"integer","description":"Position"},"is_default":{"type":"boolean","description":"Is default"},"price":{"type":"number","description":"Price"},"price_type":{"type":"integer","description":"Price type"},"can_change_quantity":{"type":"integer","description":"Whether quantity could be changed"},"extension_attributes":{"$ref":"#/definitions/bundle-data-link-extension-interface"}},"required":["is_default","price","price_type"]},"bundle-data-link-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Bundle\\Api\\Data\\LinkInterface"},"bundle-data-option-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Bundle\\Api\\Data\\OptionInterface"},"downloadable-data-link-interface":{"type":"object","description":"","properties":{"id":{"type":"integer","description":"Sample(or link) id"},"title":{"type":"string"},"sort_order":{"type":"integer"},"is_shareable":{"type":"integer","description":"Shareable status"},"price":{"type":"number","description":"Price"},"number_of_downloads":{"type":"integer","description":"Of downloads per user"},"link_type":{"type":"string"},"link_file":{"type":"string","description":"relative file path"},"link_file_content":{"$ref":"#/definitions/downloadable-data-file-content-interface"},"link_url":{"type":"string","description":"Link url or null when type is 'file'"},"sample_type":{"type":"string"},"sample_file":{"type":"string","description":"relative file path"},"sample_file_content":{"$ref":"#/definitions/downloadable-data-file-content-interface"},"sample_url":{"type":"string","description":"file URL"},"extension_attributes":{"$ref":"#/definitions/downloadable-data-link-extension-interface"}},"required":["sort_order","is_shareable","price","link_type","sample_type"]},"downloadable-data-file-content-interface":{"type":"object","description":"","properties":{"file_data":{"type":"string","description":"Data (base64 encoded content)"},"name":{"type":"string","description":"File name"},"extension_attributes":{"$ref":"#/definitions/downloadable-data-file-content-extension-interface"}},"required":["file_data","name"]},"downloadable-data-file-content-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Downloadable\\Api\\Data\\File\\ContentInterface"},"downloadable-data-link-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Downloadable\\Api\\Data\\LinkInterface"},"downloadable-data-sample-interface":{"type":"object","description":"","properties":{"id":{"type":"integer","description":"Sample(or link) id"},"title":{"type":"string","description":"Title"},"sort_order":{"type":"integer","description":"Order index for sample"},"sample_type":{"type":"string"},"sample_file":{"type":"string","description":"relative file path"},"sample_file_content":{"$ref":"#/definitions/downloadable-data-file-content-interface"},"sample_url":{"type":"string","description":"file URL"},"extension_attributes":{"$ref":"#/definitions/downloadable-data-sample-extension-interface"}},"required":["title","sort_order","sample_type"]},"downloadable-data-sample-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Downloadable\\Api\\Data\\SampleInterface"},"gift-card-data-giftcard-amount-interface":{"type":"object","description":"Interface GiftcardAmountInterface: this interface is used to serialize and deserialize EAV attribute giftcard_amounts","properties":{"attribute_id":{"type":"integer"},"website_id":{"type":"integer"},"value":{"type":"number"},"website_value":{"type":"number"},"extension_attributes":{"$ref":"#/definitions/gift-card-data-giftcard-amount-extension-interface"}},"required":["attribute_id","website_id","value","website_value"]},"gift-card-data-giftcard-amount-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\GiftCard\\Api\\Data\\GiftcardAmountInterface"},"configurable-product-data-option-interface":{"type":"object","description":"Interface OptionInterface","properties":{"id":{"type":"integer"},"attribute_id":{"type":"string"},"label":{"type":"string"},"position":{"type":"integer"},"is_use_default":{"type":"boolean"},"values":{"type":"array","items":{"$ref":"#/definitions/configurable-product-data-option-value-interface"}},"extension_attributes":{"$ref":"#/definitions/configurable-product-data-option-extension-interface"},"product_id":{"type":"integer"}}},"configurable-product-data-option-value-interface":{"type":"object","description":"Interface OptionValueInterface","properties":{"value_index":{"type":"integer"},"extension_attributes":{"$ref":"#/definitions/configurable-product-data-option-value-extension-interface"}},"required":["value_index"]},"configurable-product-data-option-value-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\ConfigurableProduct\\Api\\Data\\OptionValueInterface"},"configurable-product-data-option-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\ConfigurableProduct\\Api\\Data\\OptionInterface"},"catalog-data-product-link-interface":{"type":"object","description":"","properties":{"sku":{"type":"string","description":"SKU"},"link_type":{"type":"string","description":"Link type"},"linked_product_sku":{"type":"string","description":"Linked product sku"},"linked_product_type":{"type":"string","description":"Linked product type (simple, virtual, etc)"},"position":{"type":"integer","description":"Linked item position"},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-link-extension-interface"}},"required":["sku","link_type","linked_product_sku","linked_product_type","position"]},"catalog-data-product-link-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductLinkInterface","properties":{"qty":{"type":"number"}}},"catalog-data-product-custom-option-interface":{"type":"object","description":"","properties":{"product_sku":{"type":"string","description":"Product SKU"},"option_id":{"type":"integer","description":"Option id"},"title":{"type":"string","description":"Option title"},"type":{"type":"string","description":"Option type"},"sort_order":{"type":"integer","description":"Sort order"},"is_require":{"type":"boolean","description":"Is require"},"price":{"type":"number","description":"Price"},"price_type":{"type":"string","description":"Price type"},"sku":{"type":"string","description":"Sku"},"file_extension":{"type":"string"},"max_characters":{"type":"integer"},"image_size_x":{"type":"integer"},"image_size_y":{"type":"integer"},"values":{"type":"array","items":{"$ref":"#/definitions/catalog-data-product-custom-option-values-interface"}},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-custom-option-extension-interface"}},"required":["product_sku","title","type","sort_order","is_require"]},"catalog-data-product-custom-option-values-interface":{"type":"object","description":"","properties":{"title":{"type":"string","description":"Option title"},"sort_order":{"type":"integer","description":"Sort order"},"price":{"type":"number","description":"Price"},"price_type":{"type":"string","description":"Price type"},"sku":{"type":"string","description":"Sku"},"option_type_id":{"type":"integer","description":"Option type id"}},"required":["title","sort_order","price","price_type"]},"catalog-data-product-custom-option-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductCustomOptionInterface"},"catalog-data-product-attribute-media-gallery-entry-interface":{"type":"object","description":"","properties":{"id":{"type":"integer","description":"Gallery entry ID"},"media_type":{"type":"string","description":"Media type"},"label":{"type":"string","description":"Gallery entry alternative text"},"position":{"type":"integer","description":"Gallery entry position (sort order)"},"disabled":{"type":"boolean","description":"If gallery entry is hidden from product page"},"types":{"type":"array","description":"Gallery entry image types (thumbnail, image, small_image etc)","items":{"type":"string"}},"file":{"type":"string","description":"File path"},"content":{"$ref":"#/definitions/framework-data-image-content-interface"},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-attribute-media-gallery-entry-extension-interface"}},"required":["media_type","label","position","disabled","types"]},"framework-data-image-content-interface":{"type":"object","description":"Image Content data interface","properties":{"base64_encoded_data":{"type":"string","description":"Media data (base64 encoded content)"},"type":{"type":"string","description":"MIME type"},"name":{"type":"string","description":"Image name"}},"required":["base64_encoded_data","type","name"]},"catalog-data-product-attribute-media-gallery-entry-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductAttributeMediaGalleryEntryInterface","properties":{"video_content":{"$ref":"#/definitions/framework-data-video-content-interface"}}},"framework-data-video-content-interface":{"type":"object","description":"Video Content data interface","properties":{"media_type":{"type":"string","description":"MIME type"},"video_provider":{"type":"string","description":"Provider"},"video_url":{"type":"string","description":"Video URL"},"video_title":{"type":"string","description":"Title"},"video_description":{"type":"string","description":"Video Description"},"video_metadata":{"type":"string","description":"Metadata"}},"required":["media_type","video_provider","video_url","video_title","video_description","video_metadata"]},"catalog-data-product-tier-price-interface":{"type":"object","description":"","properties":{"customer_group_id":{"type":"integer","description":"Customer group id"},"qty":{"type":"number","description":"Tier qty"},"value":{"type":"number","description":"Price value"},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-tier-price-extension-interface"}},"required":["customer_group_id","qty","value"]},"catalog-data-product-tier-price-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductTierPriceInterface","properties":{"percentage_value":{"type":"number"},"website_id":{"type":"integer"}}},"catalog-data-product-search-results-interface":{"type":"object","description":"","properties":{"items":{"type":"array","description":"Attributes list.","items":{"$ref":"#/definitions/catalog-data-product-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"catalog-data-product-attribute-type-interface":{"type":"object","description":"","properties":{"value":{"type":"string","description":"Value"},"label":{"type":"string","description":"Type label"},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-attribute-type-extension-interface"}},"required":["value","label"]},"catalog-data-product-attribute-type-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductAttributeTypeInterface"},"catalog-data-product-attribute-interface":{"type":"object","description":"","properties":{"is_wysiwyg_enabled":{"type":"boolean","description":"WYSIWYG flag"},"is_html_allowed_on_front":{"type":"boolean","description":"The HTML tags are allowed on the frontend"},"used_for_sort_by":{"type":"boolean","description":"It is used for sorting in product listing"},"is_filterable":{"type":"boolean","description":"It used in layered navigation"},"is_filterable_in_search":{"type":"boolean","description":"It is used in search results layered navigation"},"is_used_in_grid":{"type":"boolean","description":"It is used in catalog product grid"},"is_visible_in_grid":{"type":"boolean","description":"It is visible in catalog product grid"},"is_filterable_in_grid":{"type":"boolean","description":"It is filterable in catalog product grid"},"position":{"type":"integer","description":"Position"},"apply_to":{"type":"array","description":"Apply to value for the element","items":{"type":"string"}},"is_searchable":{"type":"string","description":"The attribute can be used in Quick Search"},"is_visible_in_advanced_search":{"type":"string","description":"The attribute can be used in Advanced Search"},"is_comparable":{"type":"string","description":"The attribute can be compared on the frontend"},"is_used_for_promo_rules":{"type":"string","description":"The attribute can be used for promo rules"},"is_visible_on_front":{"type":"string","description":"The attribute is visible on the frontend"},"used_in_product_listing":{"type":"string","description":"The attribute can be used in product listing"},"is_visible":{"type":"boolean","description":"Attribute is visible on frontend."},"scope":{"type":"string","description":"Attribute scope"},"extension_attributes":{"$ref":"#/definitions/catalog-data-eav-attribute-extension-interface"},"attribute_id":{"type":"integer","description":"Id of the attribute."},"attribute_code":{"type":"string","description":"Code of the attribute."},"frontend_input":{"type":"string","description":"HTML for input element."},"entity_type_id":{"type":"string","description":"Entity type id"},"is_required":{"type":"boolean","description":"Attribute is required."},"options":{"type":"array","description":"Options of the attribute (key => value pairs for select)","items":{"$ref":"#/definitions/eav-data-attribute-option-interface"}},"is_user_defined":{"type":"boolean","description":"Current attribute has been defined by a user."},"default_frontend_label":{"type":"string","description":"Frontend label for default store"},"frontend_labels":{"type":"array","description":"Frontend label for each store","items":{"$ref":"#/definitions/eav-data-attribute-frontend-label-interface"}},"note":{"type":"string","description":"The note attribute for the element."},"backend_type":{"type":"string","description":"Backend type."},"backend_model":{"type":"string","description":"Backend model"},"source_model":{"type":"string","description":"Source model"},"default_value":{"type":"string","description":"Default value for the element."},"is_unique":{"type":"string","description":"This is a unique attribute"},"frontend_class":{"type":"string","description":"Frontend class of attribute"},"validation_rules":{"type":"array","description":"Validation rules.","items":{"$ref":"#/definitions/eav-data-attribute-validation-rule-interface"}},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["attribute_code","frontend_input","entity_type_id","is_required","frontend_labels"]},"catalog-data-eav-attribute-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\EavAttributeInterface"},"eav-data-attribute-option-interface":{"type":"object","description":"Created from:","properties":{"label":{"type":"string","description":"Option label"},"value":{"type":"string","description":"Option value"},"sort_order":{"type":"integer","description":"Option order"},"is_default":{"type":"boolean","description":"Default"},"store_labels":{"type":"array","description":"Option label for store scopes","items":{"$ref":"#/definitions/eav-data-attribute-option-label-interface"}}},"required":["label","value"]},"eav-data-attribute-option-label-interface":{"type":"object","description":"Interface AttributeOptionLabelInterface","properties":{"store_id":{"type":"integer","description":"Store id"},"label":{"type":"string","description":"Option label"}}},"eav-data-attribute-frontend-label-interface":{"type":"object","description":"Interface AttributeFrontendLabelInterface","properties":{"store_id":{"type":"integer","description":"Store id"},"label":{"type":"string","description":"Option label"}}},"eav-data-attribute-validation-rule-interface":{"type":"object","description":"Interface AttributeValidationRuleInterface","properties":{"key":{"type":"string","description":"Object key"},"value":{"type":"string","description":"Object value"}},"required":["key","value"]},"catalog-data-product-attribute-search-results-interface":{"type":"object","description":"","properties":{"items":{"type":"array","description":"Attributes list.","items":{"$ref":"#/definitions/catalog-data-product-attribute-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"catalog-data-category-attribute-interface":{"type":"object","description":"","properties":{"is_wysiwyg_enabled":{"type":"boolean","description":"WYSIWYG flag"},"is_html_allowed_on_front":{"type":"boolean","description":"The HTML tags are allowed on the frontend"},"used_for_sort_by":{"type":"boolean","description":"It is used for sorting in product listing"},"is_filterable":{"type":"boolean","description":"It used in layered navigation"},"is_filterable_in_search":{"type":"boolean","description":"It is used in search results layered navigation"},"is_used_in_grid":{"type":"boolean","description":"It is used in catalog product grid"},"is_visible_in_grid":{"type":"boolean","description":"It is visible in catalog product grid"},"is_filterable_in_grid":{"type":"boolean","description":"It is filterable in catalog product grid"},"position":{"type":"integer","description":"Position"},"apply_to":{"type":"array","description":"Apply to value for the element","items":{"type":"string"}},"is_searchable":{"type":"string","description":"The attribute can be used in Quick Search"},"is_visible_in_advanced_search":{"type":"string","description":"The attribute can be used in Advanced Search"},"is_comparable":{"type":"string","description":"The attribute can be compared on the frontend"},"is_used_for_promo_rules":{"type":"string","description":"The attribute can be used for promo rules"},"is_visible_on_front":{"type":"string","description":"The attribute is visible on the frontend"},"used_in_product_listing":{"type":"string","description":"The attribute can be used in product listing"},"is_visible":{"type":"boolean","description":"Attribute is visible on frontend."},"scope":{"type":"string","description":"Attribute scope"},"extension_attributes":{"$ref":"#/definitions/catalog-data-eav-attribute-extension-interface"},"attribute_id":{"type":"integer","description":"Id of the attribute."},"attribute_code":{"type":"string","description":"Code of the attribute."},"frontend_input":{"type":"string","description":"HTML for input element."},"entity_type_id":{"type":"string","description":"Entity type id"},"is_required":{"type":"boolean","description":"Attribute is required."},"options":{"type":"array","description":"Options of the attribute (key => value pairs for select)","items":{"$ref":"#/definitions/eav-data-attribute-option-interface"}},"is_user_defined":{"type":"boolean","description":"Current attribute has been defined by a user."},"default_frontend_label":{"type":"string","description":"Frontend label for default store"},"frontend_labels":{"type":"array","description":"Frontend label for each store","items":{"$ref":"#/definitions/eav-data-attribute-frontend-label-interface"}},"note":{"type":"string","description":"The note attribute for the element."},"backend_type":{"type":"string","description":"Backend type."},"backend_model":{"type":"string","description":"Backend model"},"source_model":{"type":"string","description":"Source model"},"default_value":{"type":"string","description":"Default value for the element."},"is_unique":{"type":"string","description":"This is a unique attribute"},"frontend_class":{"type":"string","description":"Frontend class of attribute"},"validation_rules":{"type":"array","description":"Validation rules.","items":{"$ref":"#/definitions/eav-data-attribute-validation-rule-interface"}},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["attribute_code","frontend_input","entity_type_id","is_required","frontend_labels"]},"catalog-data-category-attribute-search-results-interface":{"type":"object","description":"","properties":{"items":{"type":"array","description":"Attributes list.","items":{"$ref":"#/definitions/catalog-data-category-attribute-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"catalog-data-product-type-interface":{"type":"object","description":"Product type details","properties":{"name":{"type":"string","description":"Product type code"},"label":{"type":"string","description":"Product type label"},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-type-extension-interface"}},"required":["name","label"]},"catalog-data-product-type-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductTypeInterface"},"eav-data-attribute-group-search-results-interface":{"type":"object","description":"Interface AttributeGroupSearchResultsInterface","properties":{"items":{"type":"array","description":"Attribute sets list.","items":{"$ref":"#/definitions/eav-data-attribute-group-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"eav-data-attribute-group-interface":{"type":"object","description":"Interface AttributeGroupInterface","properties":{"attribute_group_id":{"type":"string","description":"Id"},"attribute_group_name":{"type":"string","description":"Name"},"attribute_set_id":{"type":"integer","description":"Attribute set id"},"extension_attributes":{"$ref":"#/definitions/eav-data-attribute-group-extension-interface"}}},"eav-data-attribute-group-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Eav\\Api\\Data\\AttributeGroupInterface","properties":{"attribute_group_code":{"type":"string"},"sort_order":{"type":"string"}}},"catalog-data-tier-price-interface":{"type":"object","description":"Tier price interface.","properties":{"price":{"type":"number","description":"Tier price."},"price_type":{"type":"string","description":"Tier price type."},"website_id":{"type":"integer","description":"Website id."},"sku":{"type":"string","description":"SKU."},"customer_group":{"type":"string","description":"Customer group."},"quantity":{"type":"number","description":"Quantity."},"extension_attributes":{"$ref":"#/definitions/catalog-data-tier-price-extension-interface"}},"required":["price","price_type","website_id","sku","customer_group","quantity"]},"catalog-data-tier-price-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\TierPriceInterface"},"catalog-data-price-update-result-interface":{"type":"object","description":"Interface returned in case of incorrect price passed to efficient price API.","properties":{"message":{"type":"string","description":"Error message, that contains description of error occurred during price update."},"parameters":{"type":"array","description":"Parameters, that could be displayed in error message placeholders.","items":{"type":"string"}},"extension_attributes":{"$ref":"#/definitions/catalog-data-price-update-result-extension-interface"}},"required":["message","parameters"]},"catalog-data-price-update-result-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\PriceUpdateResultInterface"},"catalog-data-base-price-interface":{"type":"object","description":"Price interface.","properties":{"price":{"type":"number","description":"Price."},"store_id":{"type":"integer","description":"Store id."},"sku":{"type":"string","description":"SKU."},"extension_attributes":{"$ref":"#/definitions/catalog-data-base-price-extension-interface"}},"required":["price","store_id","sku"]},"catalog-data-base-price-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\BasePriceInterface"},"catalog-data-cost-interface":{"type":"object","description":"Cost interface.","properties":{"cost":{"type":"number","description":"Cost value."},"store_id":{"type":"integer","description":"Store id."},"sku":{"type":"string","description":"SKU."},"extension_attributes":{"$ref":"#/definitions/catalog-data-cost-extension-interface"}},"required":["cost","store_id","sku"]},"catalog-data-cost-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\CostInterface"},"catalog-data-special-price-interface":{"type":"object","description":"Product Special Price Interface is used to encapsulate data that can be processed by efficient price API.","properties":{"price":{"type":"number","description":"Product special price value."},"store_id":{"type":"integer","description":"ID of store, that contains special price value."},"sku":{"type":"string","description":"SKU of product, that contains special price value."},"price_from":{"type":"string","description":"Start date for special price in Y-m-d H:i:s format."},"price_to":{"type":"string","description":"End date for special price in Y-m-d H:i:s format."},"extension_attributes":{"$ref":"#/definitions/catalog-data-special-price-extension-interface"}},"required":["price","store_id","sku","price_from","price_to"]},"catalog-data-special-price-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\SpecialPriceInterface"},"catalog-data-category-interface":{"type":"object","description":"","properties":{"id":{"type":"integer"},"parent_id":{"type":"integer","description":"Parent category ID"},"name":{"type":"string","description":"Category name"},"is_active":{"type":"boolean","description":"Whether category is active"},"position":{"type":"integer","description":"Category position"},"level":{"type":"integer","description":"Category level"},"children":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"},"path":{"type":"string"},"available_sort_by":{"type":"array","items":{"type":"string"}},"include_in_menu":{"type":"boolean"},"extension_attributes":{"$ref":"#/definitions/catalog-data-category-extension-interface"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["name"]},"catalog-data-category-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\CategoryInterface"},"catalog-data-category-tree-interface":{"type":"object","description":"","properties":{"id":{"type":"integer"},"parent_id":{"type":"integer","description":"Parent category ID"},"name":{"type":"string","description":"Category name"},"is_active":{"type":"boolean","description":"Whether category is active"},"position":{"type":"integer","description":"Category position"},"level":{"type":"integer","description":"Category level"},"product_count":{"type":"integer","description":"Product count"},"children_data":{"type":"array","items":{"$ref":"#/definitions/catalog-data-category-tree-interface"}}},"required":["parent_id","name","is_active","position","level","product_count","children_data"]},"catalog-data-category-search-results-interface":{"type":"object","description":"","properties":{"items":{"type":"array","description":"Categories","items":{"$ref":"#/definitions/catalog-data-category-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"catalog-data-product-custom-option-type-interface":{"type":"object","description":"","properties":{"label":{"type":"string","description":"Option type label"},"code":{"type":"string","description":"Option type code"},"group":{"type":"string","description":"Option type group"},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-custom-option-type-extension-interface"}},"required":["label","code","group"]},"catalog-data-product-custom-option-type-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductCustomOptionTypeInterface"},"catalog-data-product-link-type-interface":{"type":"object","description":"","properties":{"code":{"type":"integer","description":"Link type code"},"name":{"type":"string","description":"Link type name"},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-link-type-extension-interface"}},"required":["code","name"]},"catalog-data-product-link-type-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductLinkTypeInterface"},"catalog-data-product-link-attribute-interface":{"type":"object","description":"","properties":{"code":{"type":"string","description":"Attribute code"},"type":{"type":"string","description":"Attribute type"},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-link-attribute-extension-interface"}},"required":["code","type"]},"catalog-data-product-link-attribute-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductLinkAttributeInterface"},"catalog-data-category-product-link-interface":{"type":"object","description":"","properties":{"sku":{"type":"string"},"position":{"type":"integer"},"category_id":{"type":"string","description":"Category id"},"extension_attributes":{"$ref":"#/definitions/catalog-data-category-product-link-extension-interface"}},"required":["category_id"]},"catalog-data-category-product-link-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\CategoryProductLinkInterface"},"catalog-data-product-website-link-interface":{"type":"object","description":"","properties":{"sku":{"type":"string"},"website_id":{"type":"integer","description":"Website ids"}},"required":["sku","website_id"]},"catalog-data-product-render-search-results-interface":{"type":"object","description":"Dto that holds render information about products","properties":{"items":{"type":"array","description":"List of products rendered information","items":{"$ref":"#/definitions/catalog-data-product-render-interface"}}},"required":["items"]},"catalog-data-product-render-interface":{"type":"object","description":"Represents Data Object which holds enough information to render product This information is put into part as Add To Cart or Add to Compare Data or Price Data","properties":{"add_to_cart_button":{"$ref":"#/definitions/catalog-data-product-render-button-interface"},"add_to_compare_button":{"$ref":"#/definitions/catalog-data-product-render-button-interface"},"price_info":{"$ref":"#/definitions/catalog-data-product-render-price-info-interface"},"images":{"type":"array","description":"Enough information, that needed to render image on front","items":{"$ref":"#/definitions/catalog-data-product-render-image-interface"}},"url":{"type":"string","description":"Product url"},"id":{"type":"integer","description":"Product identifier"},"name":{"type":"string","description":"Product name"},"type":{"type":"string","description":"Product type. Such as bundle, grouped, simple, etc..."},"is_salable":{"type":"string","description":"Information about product saleability (In Stock)"},"store_id":{"type":"integer","description":"Information about current store id or requested store id"},"currency_code":{"type":"string","description":"Current or desired currency code to product"},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-render-extension-interface"}},"required":["add_to_cart_button","add_to_compare_button","price_info","images","url","id","name","type","is_salable","store_id","currency_code","extension_attributes"]},"catalog-data-product-render-button-interface":{"type":"object","description":"Button interface. This interface represents all manner of product buttons: add to cart, add to compare, etc... The buttons describes by this interface should have interaction with backend","properties":{"post_data":{"type":"string","description":"Post data"},"url":{"type":"string","description":"Url, needed to add product to cart"},"required_options":{"type":"boolean","description":"Flag whether a product has options or not"},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-render-button-extension-interface"}},"required":["post_data","url","required_options"]},"catalog-data-product-render-button-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductRender\\ButtonInterface"},"catalog-data-product-render-price-info-interface":{"type":"object","description":"Price interface.","properties":{"final_price":{"type":"number","description":"Final price"},"max_price":{"type":"number","description":"Max price of a product"},"max_regular_price":{"type":"number","description":"Max regular price"},"minimal_regular_price":{"type":"number","description":"Minimal regular price"},"special_price":{"type":"number","description":"Special price"},"minimal_price":{"type":"number"},"regular_price":{"type":"number","description":"Regular price"},"formatted_prices":{"$ref":"#/definitions/catalog-data-product-render-formatted-price-info-interface"},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-render-price-info-extension-interface"}},"required":["final_price","max_price","max_regular_price","minimal_regular_price","special_price","minimal_price","regular_price","formatted_prices"]},"catalog-data-product-render-formatted-price-info-interface":{"type":"object","description":"Formatted Price interface. Aggregate formatted html with price representations. E.g.: <span class=\"price\">$9.00</span> Consider currency, rounding and html","properties":{"final_price":{"type":"string","description":"Html with final price"},"max_price":{"type":"string","description":"Max price of a product"},"minimal_price":{"type":"string","description":"The minimal price of the product or variation"},"max_regular_price":{"type":"string","description":"Max regular price"},"minimal_regular_price":{"type":"string","description":"Minimal regular price"},"special_price":{"type":"string","description":"Special price"},"regular_price":{"type":"string","description":"Price - is price of product without discounts and special price with taxes and fixed product tax"},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-render-formatted-price-info-extension-interface"}},"required":["final_price","max_price","minimal_price","max_regular_price","minimal_regular_price","special_price","regular_price"]},"catalog-data-product-render-formatted-price-info-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductRender\\FormattedPriceInfoInterface"},"catalog-data-product-render-price-info-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductRender\\PriceInfoInterface","properties":{"msrp":{"$ref":"#/definitions/msrp-data-product-render-msrp-price-info-interface"},"tax_adjustments":{"$ref":"#/definitions/catalog-data-product-render-price-info-interface"},"weee_attributes":{"type":"array","items":{"$ref":"#/definitions/weee-data-product-render-weee-adjustment-attribute-interface"}},"weee_adjustment":{"type":"string"}}},"msrp-data-product-render-msrp-price-info-interface":{"type":"object","description":"Price interface.","properties":{"msrp_price":{"type":"string"},"is_applicable":{"type":"string"},"is_shown_price_on_gesture":{"type":"string"},"msrp_message":{"type":"string"},"explanation_message":{"type":"string"},"extension_attributes":{"$ref":"#/definitions/msrp-data-product-render-msrp-price-info-extension-interface"}},"required":["msrp_price","is_applicable","is_shown_price_on_gesture","msrp_message","explanation_message"]},"msrp-data-product-render-msrp-price-info-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Msrp\\Api\\Data\\ProductRender\\MsrpPriceInfoInterface"},"weee-data-product-render-weee-adjustment-attribute-interface":{"type":"object","description":"List of all weee attributes, their amounts, etc.., that product has","properties":{"amount":{"type":"string","description":"Weee attribute amount"},"tax_amount":{"type":"string","description":"Tax which is calculated to fixed product tax attribute"},"tax_amount_incl_tax":{"type":"string","description":"Tax amount of weee attribute"},"amount_excl_tax":{"type":"string","description":"Product amount exclude tax"},"attribute_code":{"type":"string","description":"Weee attribute code"},"extension_attributes":{"$ref":"#/definitions/weee-data-product-render-weee-adjustment-attribute-extension-interface"}},"required":["amount","tax_amount","tax_amount_incl_tax","amount_excl_tax","attribute_code","extension_attributes"]},"weee-data-product-render-weee-adjustment-attribute-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Weee\\Api\\Data\\ProductRender\\WeeeAdjustmentAttributeInterface"},"catalog-data-product-render-image-interface":{"type":"object","description":"Product Render image interface. Represents physical characteristics of image, that can be used in product listing or product view","properties":{"url":{"type":"string","description":"Image url"},"code":{"type":"string","description":"Image code"},"height":{"type":"number","description":"Image height"},"width":{"type":"number","description":"Image width in px"},"label":{"type":"string","description":"Image label"},"resized_width":{"type":"number","description":"Resize width"},"resized_height":{"type":"number","description":"Resize height"},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-render-image-extension-interface"}},"required":["url","code","height","width","label","resized_width","resized_height"]},"catalog-data-product-render-image-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductRender\\ImageInterface"},"catalog-data-product-render-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductRenderInterface","properties":{"wishlist_button":{"$ref":"#/definitions/catalog-data-product-render-button-interface"},"review_html":{"type":"string"}}},"catalog-inventory-data-stock-status-collection-interface":{"type":"object","description":"Stock Status collection interface","properties":{"items":{"type":"array","description":"Items","items":{"$ref":"#/definitions/catalog-inventory-data-stock-status-interface"}},"search_criteria":{"$ref":"#/definitions/catalog-inventory-stock-status-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"catalog-inventory-data-stock-status-interface":{"type":"object","description":"Interface StockStatusInterface","properties":{"product_id":{"type":"integer"},"stock_id":{"type":"integer"},"qty":{"type":"integer"},"stock_status":{"type":"integer"},"stock_item":{"$ref":"#/definitions/catalog-inventory-data-stock-item-interface"},"extension_attributes":{"$ref":"#/definitions/catalog-inventory-data-stock-status-extension-interface"}},"required":["product_id","stock_id","qty","stock_status","stock_item"]},"catalog-inventory-data-stock-status-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\CatalogInventory\\Api\\Data\\StockStatusInterface"},"catalog-inventory-stock-status-criteria-interface":{"type":"object","description":"Interface StockStatusCriteriaInterface","properties":{"mapper_interface_name":{"type":"string","description":"Associated Mapper Interface name"},"criteria_list":{"type":"array","description":"Criteria objects added to current Composite Criteria","items":{"$ref":"#/definitions/framework-criteria-interface"}},"filters":{"type":"array","description":"List of filters","items":{"type":"string"}},"orders":{"type":"array","description":"Ordering criteria","items":{"type":"string"}},"limit":{"type":"array","description":"Limit","items":{"type":"string"}}},"required":["mapper_interface_name","criteria_list","filters","orders","limit"]},"framework-criteria-interface":{"type":"object","description":"Interface CriteriaInterface","properties":{"mapper_interface_name":{"type":"string","description":"Associated Mapper Interface name"},"criteria_list":{"type":"array","description":"Criteria objects added to current Composite Criteria","items":{"$ref":"#/definitions/framework-criteria-interface"}},"filters":{"type":"array","description":"List of filters","items":{"type":"string"}},"orders":{"type":"array","description":"Ordering criteria","items":{"type":"string"}},"limit":{"type":"array","description":"Limit","items":{"type":"string"}}},"required":["mapper_interface_name","criteria_list","filters","orders","limit"]},"bundle-data-option-type-interface":{"type":"object","description":"Interface OptionTypeInterface","properties":{"label":{"type":"string","description":"Type label"},"code":{"type":"string","description":"Type code"},"extension_attributes":{"$ref":"#/definitions/bundle-data-option-type-extension-interface"}},"required":["label","code"]},"bundle-data-option-type-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Bundle\\Api\\Data\\OptionTypeInterface"},"quote-data-cart-interface":{"type":"object","description":"Interface CartInterface","properties":{"id":{"type":"integer","description":"Cart/quote ID."},"created_at":{"type":"string","description":"Cart creation date and time. Otherwise, null."},"updated_at":{"type":"string","description":"Cart last update date and time. Otherwise, null."},"converted_at":{"type":"string","description":"Cart conversion date and time. Otherwise, null."},"is_active":{"type":"boolean","description":"Active status flag value. Otherwise, null."},"is_virtual":{"type":"boolean","description":"Virtual flag value. Otherwise, null."},"items":{"type":"array","description":"Array of items. Otherwise, null.","items":{"$ref":"#/definitions/quote-data-cart-item-interface"}},"items_count":{"type":"integer","description":"Number of different items or products in the cart. Otherwise, null."},"items_qty":{"type":"number","description":"Total quantity of all cart items. Otherwise, null."},"customer":{"$ref":"#/definitions/customer-data-customer-interface"},"billing_address":{"$ref":"#/definitions/quote-data-address-interface"},"reserved_order_id":{"type":"integer","description":"Reserved order ID. Otherwise, null."},"orig_order_id":{"type":"integer","description":"Original order ID. Otherwise, null."},"currency":{"$ref":"#/definitions/quote-data-currency-interface"},"customer_is_guest":{"type":"boolean","description":"For guest customers, false for logged in customers"},"customer_note":{"type":"string","description":"Notice text"},"customer_note_notify":{"type":"boolean","description":"Customer notification flag"},"customer_tax_class_id":{"type":"integer","description":"Customer tax class ID."},"store_id":{"type":"integer","description":"Store identifier"},"extension_attributes":{"$ref":"#/definitions/quote-data-cart-extension-interface"}},"required":["id","customer","store_id"]},"quote-data-cart-item-interface":{"type":"object","description":"Interface CartItemInterface","properties":{"item_id":{"type":"integer","description":"Item ID. Otherwise, null."},"sku":{"type":"string","description":"Product SKU. Otherwise, null."},"qty":{"type":"number","description":"Product quantity."},"name":{"type":"string","description":"Product name. Otherwise, null."},"price":{"type":"number","description":"Product price. Otherwise, null."},"product_type":{"type":"string","description":"Product type. Otherwise, null."},"quote_id":{"type":"string","description":"Quote id."},"product_option":{"$ref":"#/definitions/quote-data-product-option-interface"},"extension_attributes":{"$ref":"#/definitions/quote-data-cart-item-extension-interface"}},"required":["qty","quote_id"]},"quote-data-product-option-interface":{"type":"object","description":"Product option interface","properties":{"extension_attributes":{"$ref":"#/definitions/quote-data-product-option-extension-interface"}}},"quote-data-product-option-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Quote\\Api\\Data\\ProductOptionInterface","properties":{"custom_options":{"type":"array","items":{"$ref":"#/definitions/catalog-data-custom-option-interface"}},"bundle_options":{"type":"array","items":{"$ref":"#/definitions/bundle-data-bundle-option-interface"}},"downloadable_option":{"$ref":"#/definitions/downloadable-data-downloadable-option-interface"},"giftcard_item_option":{"$ref":"#/definitions/gift-card-data-gift-card-option-interface"},"configurable_item_options":{"type":"array","items":{"$ref":"#/definitions/configurable-product-data-configurable-item-option-value-interface"}}}},"catalog-data-custom-option-interface":{"type":"object","description":"Interface CustomOptionInterface","properties":{"option_id":{"type":"string","description":"Option id"},"option_value":{"type":"string","description":"Option value"},"extension_attributes":{"$ref":"#/definitions/catalog-data-custom-option-extension-interface"}},"required":["option_id","option_value"]},"catalog-data-custom-option-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\CustomOptionInterface","properties":{"file_info":{"$ref":"#/definitions/framework-data-image-content-interface"}}},"bundle-data-bundle-option-interface":{"type":"object","description":"Interface BundleOptionInterface","properties":{"option_id":{"type":"integer","description":"Bundle option id."},"option_qty":{"type":"integer","description":"Bundle option quantity."},"option_selections":{"type":"array","description":"Bundle option selection ids.","items":{"type":"integer"}},"extension_attributes":{"$ref":"#/definitions/bundle-data-bundle-option-extension-interface"}},"required":["option_id","option_qty","option_selections"]},"bundle-data-bundle-option-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Bundle\\Api\\Data\\BundleOptionInterface"},"downloadable-data-downloadable-option-interface":{"type":"object","description":"Downloadable Option","properties":{"downloadable_links":{"type":"array","description":"The list of downloadable links","items":{"type":"integer"}}},"required":["downloadable_links"]},"gift-card-data-gift-card-option-interface":{"type":"object","description":"Interface GiftCardOptionInterface","properties":{"giftcard_amount":{"type":"string","description":"Gift card amount."},"custom_giftcard_amount":{"type":"number","description":"Gift card open amount value."},"giftcard_sender_name":{"type":"string","description":"Gift card sender name."},"giftcard_recipient_name":{"type":"string","description":"Gift card recipient name."},"giftcard_sender_email":{"type":"string","description":"Gift card sender email."},"giftcard_recipient_email":{"type":"string","description":"Gift card recipient email."},"giftcard_message":{"type":"string","description":"Giftcard message."},"extension_attributes":{"$ref":"#/definitions/gift-card-data-gift-card-option-extension-interface"}},"required":["giftcard_amount","giftcard_sender_name","giftcard_recipient_name","giftcard_sender_email","giftcard_recipient_email"]},"gift-card-data-gift-card-option-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\GiftCard\\Api\\Data\\GiftCardOptionInterface"},"configurable-product-data-configurable-item-option-value-interface":{"type":"object","description":"Interface ConfigurableItemOptionValueInterface","properties":{"option_id":{"type":"string","description":"Option SKU"},"option_value":{"type":"integer","description":"Item id"},"extension_attributes":{"$ref":"#/definitions/configurable-product-data-configurable-item-option-value-extension-interface"}},"required":["option_id"]},"configurable-product-data-configurable-item-option-value-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\ConfigurableProduct\\Api\\Data\\ConfigurableItemOptionValueInterface"},"quote-data-cart-item-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Quote\\Api\\Data\\CartItemInterface"},"quote-data-address-interface":{"type":"object","description":"Interface AddressInterface","properties":{"id":{"type":"integer","description":"Id"},"region":{"type":"string","description":"Region name"},"region_id":{"type":"integer","description":"Region id"},"region_code":{"type":"string","description":"Region code"},"country_id":{"type":"string","description":"Country id"},"street":{"type":"array","description":"Street","items":{"type":"string"}},"company":{"type":"string","description":"Company"},"telephone":{"type":"string","description":"Telephone number"},"fax":{"type":"string","description":"Fax number"},"postcode":{"type":"string","description":"Postcode"},"city":{"type":"string","description":"City name"},"firstname":{"type":"string","description":"First name"},"lastname":{"type":"string","description":"Last name"},"middlename":{"type":"string","description":"Middle name"},"prefix":{"type":"string","description":"Prefix"},"suffix":{"type":"string","description":"Suffix"},"vat_id":{"type":"string","description":"Vat id"},"customer_id":{"type":"integer","description":"Customer id"},"email":{"type":"string","description":"Billing/shipping email"},"same_as_billing":{"type":"integer","description":"Same as billing flag"},"customer_address_id":{"type":"integer","description":"Customer address id"},"save_in_address_book":{"type":"integer","description":"Save in address book flag"},"extension_attributes":{"$ref":"#/definitions/quote-data-address-extension-interface"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["region","region_id","region_code","country_id","street","telephone","postcode","city","firstname","lastname","email"]},"quote-data-address-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Quote\\Api\\Data\\AddressInterface","properties":{"gift_registry_id":{"type":"integer"}}},"quote-data-currency-interface":{"type":"object","description":"Interface CurrencyInterface","properties":{"global_currency_code":{"type":"string","description":"Global currency code"},"base_currency_code":{"type":"string","description":"Base currency code"},"store_currency_code":{"type":"string","description":"Store currency code"},"quote_currency_code":{"type":"string","description":"Quote currency code"},"store_to_base_rate":{"type":"number","description":"Store currency to base currency rate"},"store_to_quote_rate":{"type":"number","description":"Store currency to quote currency rate"},"base_to_global_rate":{"type":"number","description":"Base currency to global currency rate"},"base_to_quote_rate":{"type":"number","description":"Base currency to quote currency rate"},"extension_attributes":{"$ref":"#/definitions/quote-data-currency-extension-interface"}}},"quote-data-currency-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Quote\\Api\\Data\\CurrencyInterface"},"quote-data-cart-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Quote\\Api\\Data\\CartInterface","properties":{"shipping_assignments":{"type":"array","items":{"$ref":"#/definitions/quote-data-shipping-assignment-interface"}},"quote_api_test_attribute":{"$ref":"#/definitions/user-data-user-interface"}}},"quote-data-shipping-assignment-interface":{"type":"object","description":"Interface ShippingAssignmentInterface","properties":{"shipping":{"$ref":"#/definitions/quote-data-shipping-interface"},"items":{"type":"array","items":{"$ref":"#/definitions/quote-data-cart-item-interface"}},"extension_attributes":{"$ref":"#/definitions/quote-data-shipping-assignment-extension-interface"}},"required":["shipping","items"]},"quote-data-shipping-interface":{"type":"object","description":"Interface ShippingInterface","properties":{"address":{"$ref":"#/definitions/quote-data-address-interface"},"method":{"type":"string","description":"Shipping method"},"extension_attributes":{"$ref":"#/definitions/quote-data-shipping-extension-interface"}},"required":["address","method"]},"quote-data-shipping-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Quote\\Api\\Data\\ShippingInterface"},"quote-data-shipping-assignment-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Quote\\Api\\Data\\ShippingAssignmentInterface"},"user-data-user-interface":{"type":"object","description":"Admin user interface.","properties":{"id":{"type":"integer","description":"ID."},"first_name":{"type":"string","description":"First name."},"last_name":{"type":"string","description":"Last name."},"email":{"type":"string","description":"Email."},"user_name":{"type":"string","description":"User name."},"password":{"type":"string","description":"Password or password hash."},"created":{"type":"string","description":"User record creation date."},"modified":{"type":"string","description":"User record modification date."},"is_active":{"type":"integer","description":"If user is active."},"interface_locale":{"type":"string","description":"User interface locale."}},"required":["id","first_name","last_name","email","user_name","password","created","modified","is_active","interface_locale"]},"quote-data-cart-search-results-interface":{"type":"object","description":"Interface CartSearchResultsInterface","properties":{"items":{"type":"array","description":"Carts list.","items":{"$ref":"#/definitions/quote-data-cart-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"quote-data-payment-interface":{"type":"object","description":"Interface PaymentInterface","properties":{"po_number":{"type":"string","description":"Purchase order number"},"method":{"type":"string","description":"Payment method code"},"additional_data":{"type":"array","description":"Payment additional details","items":{"type":"string"}},"extension_attributes":{"$ref":"#/definitions/quote-data-payment-extension-interface"}},"required":["method"]},"quote-data-payment-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Quote\\Api\\Data\\PaymentInterface","properties":{"agreement_ids":{"type":"array","items":{"type":"string"}}}},"quote-data-shipping-method-interface":{"type":"object","description":"Interface ShippingMethodInterface","properties":{"carrier_code":{"type":"string","description":"Shipping carrier code."},"method_code":{"type":"string","description":"Shipping method code."},"carrier_title":{"type":"string","description":"Shipping carrier title. Otherwise, null."},"method_title":{"type":"string","description":"Shipping method title. Otherwise, null."},"amount":{"type":"number","description":"Shipping amount in store currency."},"base_amount":{"type":"number","description":"Shipping amount in base currency."},"available":{"type":"boolean","description":"The value of the availability flag for the current shipping method."},"extension_attributes":{"$ref":"#/definitions/quote-data-shipping-method-extension-interface"},"error_message":{"type":"string","description":"Shipping Error message."},"price_excl_tax":{"type":"number","description":"Shipping price excl tax."},"price_incl_tax":{"type":"number","description":"Shipping price incl tax."}},"required":["carrier_code","method_code","amount","base_amount","available","error_message","price_excl_tax","price_incl_tax"]},"quote-data-shipping-method-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Quote\\Api\\Data\\ShippingMethodInterface"},"quote-data-payment-method-interface":{"type":"object","description":"Interface PaymentMethodInterface","properties":{"code":{"type":"string","description":"Payment method code"},"title":{"type":"string","description":"Payment method title"}},"required":["code","title"]},"quote-data-totals-interface":{"type":"object","description":"Interface TotalsInterface","properties":{"grand_total":{"type":"number","description":"Grand total in quote currency"},"base_grand_total":{"type":"number","description":"Grand total in base currency"},"subtotal":{"type":"number","description":"Subtotal in quote currency"},"base_subtotal":{"type":"number","description":"Subtotal in base currency"},"discount_amount":{"type":"number","description":"Discount amount in quote currency"},"base_discount_amount":{"type":"number","description":"Discount amount in base currency"},"subtotal_with_discount":{"type":"number","description":"Subtotal in quote currency with applied discount"},"base_subtotal_with_discount":{"type":"number","description":"Subtotal in base currency with applied discount"},"shipping_amount":{"type":"number","description":"Shipping amount in quote currency"},"base_shipping_amount":{"type":"number","description":"Shipping amount in base currency"},"shipping_discount_amount":{"type":"number","description":"Shipping discount amount in quote currency"},"base_shipping_discount_amount":{"type":"number","description":"Shipping discount amount in base currency"},"tax_amount":{"type":"number","description":"Tax amount in quote currency"},"base_tax_amount":{"type":"number","description":"Tax amount in base currency"},"weee_tax_applied_amount":{"type":"number","description":"Item weee tax applied amount in quote currency."},"shipping_tax_amount":{"type":"number","description":"Shipping tax amount in quote currency"},"base_shipping_tax_amount":{"type":"number","description":"Shipping tax amount in base currency"},"subtotal_incl_tax":{"type":"number","description":"Subtotal including tax in quote currency"},"base_subtotal_incl_tax":{"type":"number","description":"Subtotal including tax in base currency"},"shipping_incl_tax":{"type":"number","description":"Shipping including tax in quote currency"},"base_shipping_incl_tax":{"type":"number","description":"Shipping including tax in base currency"},"base_currency_code":{"type":"string","description":"Base currency code"},"quote_currency_code":{"type":"string","description":"Quote currency code"},"coupon_code":{"type":"string","description":"Applied coupon code"},"items_qty":{"type":"integer","description":"Items qty"},"items":{"type":"array","description":"Totals by items","items":{"$ref":"#/definitions/quote-data-totals-item-interface"}},"total_segments":{"type":"array","description":"Dynamically calculated totals","items":{"$ref":"#/definitions/quote-data-total-segment-interface"}},"extension_attributes":{"$ref":"#/definitions/quote-data-totals-extension-interface"}},"required":["weee_tax_applied_amount","total_segments"]},"quote-data-totals-item-interface":{"type":"object","description":"Interface TotalsItemInterface","properties":{"item_id":{"type":"integer","description":"Item id"},"price":{"type":"number","description":"Item price in quote currency."},"base_price":{"type":"number","description":"Item price in base currency."},"qty":{"type":"number","description":"Item quantity."},"row_total":{"type":"number","description":"Row total in quote currency."},"base_row_total":{"type":"number","description":"Row total in base currency."},"row_total_with_discount":{"type":"number","description":"Row total with discount in quote currency. Otherwise, null."},"tax_amount":{"type":"number","description":"Tax amount in quote currency. Otherwise, null."},"base_tax_amount":{"type":"number","description":"Tax amount in base currency. Otherwise, null."},"tax_percent":{"type":"number","description":"Tax percent. Otherwise, null."},"discount_amount":{"type":"number","description":"Discount amount in quote currency. Otherwise, null."},"base_discount_amount":{"type":"number","description":"Discount amount in base currency. Otherwise, null."},"discount_percent":{"type":"number","description":"Discount percent. Otherwise, null."},"price_incl_tax":{"type":"number","description":"Price including tax in quote currency. Otherwise, null."},"base_price_incl_tax":{"type":"number","description":"Price including tax in base currency. Otherwise, null."},"row_total_incl_tax":{"type":"number","description":"Row total including tax in quote currency. Otherwise, null."},"base_row_total_incl_tax":{"type":"number","description":"Row total including tax in base currency. Otherwise, null."},"options":{"type":"string","description":"Item price in quote currency."},"weee_tax_applied_amount":{"type":"number","description":"Item weee tax applied amount in quote currency."},"weee_tax_applied":{"type":"string","description":"Item weee tax applied in quote currency."},"extension_attributes":{"$ref":"#/definitions/quote-data-totals-item-extension-interface"},"name":{"type":"string","description":"Product name. Otherwise, null."}},"required":["item_id","price","base_price","qty","row_total","base_row_total","options","weee_tax_applied_amount","weee_tax_applied"]},"quote-data-totals-item-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Quote\\Api\\Data\\TotalsItemInterface"},"quote-data-total-segment-interface":{"type":"object","description":"Interface TotalsInterface","properties":{"code":{"type":"string","description":"Code"},"title":{"type":"string","description":"Total title"},"value":{"type":"number","description":"Total value"},"area":{"type":"string","description":"Display area code."},"extension_attributes":{"$ref":"#/definitions/quote-data-total-segment-extension-interface"}},"required":["code","value"]},"quote-data-total-segment-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Quote\\Api\\Data\\TotalSegmentInterface","properties":{"gift_cards":{"type":"string"},"tax_grandtotal_details":{"type":"array","items":{"$ref":"#/definitions/tax-data-grand-total-details-interface"}},"gw_order_id":{"type":"string"},"gw_item_ids":{"type":"array","items":{"type":"string"}},"gw_allow_gift_receipt":{"type":"string"},"gw_add_card":{"type":"string"},"gw_price":{"type":"string"},"gw_base_price":{"type":"string"},"gw_items_price":{"type":"string"},"gw_items_base_price":{"type":"string"},"gw_card_price":{"type":"string"},"gw_card_base_price":{"type":"string"},"gw_base_tax_amount":{"type":"string"},"gw_tax_amount":{"type":"string"},"gw_items_base_tax_amount":{"type":"string"},"gw_items_tax_amount":{"type":"string"},"gw_card_base_tax_amount":{"type":"string"},"gw_card_tax_amount":{"type":"string"},"gw_price_incl_tax":{"type":"string"},"gw_base_price_incl_tax":{"type":"string"},"gw_card_price_incl_tax":{"type":"string"},"gw_card_base_price_incl_tax":{"type":"string"},"gw_items_price_incl_tax":{"type":"string"},"gw_items_base_price_incl_tax":{"type":"string"}}},"tax-data-grand-total-details-interface":{"type":"object","description":"Interface GrandTotalDetailsInterface","properties":{"amount":{"type":"number","description":"Tax amount value"},"rates":{"type":"array","description":"Tax rates info","items":{"$ref":"#/definitions/tax-data-grand-total-rates-interface"}},"group_id":{"type":"integer","description":"Group identifier"}},"required":["amount","rates","group_id"]},"tax-data-grand-total-rates-interface":{"type":"object","description":"Interface GrandTotalRatesInterface","properties":{"percent":{"type":"string","description":"Tax percentage value"},"title":{"type":"string","description":"Rate title"}},"required":["percent","title"]},"quote-data-totals-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Quote\\Api\\Data\\TotalsInterface","properties":{"coupon_label":{"type":"string"},"base_customer_balance_amount":{"type":"number"},"customer_balance_amount":{"type":"number"},"reward_points_balance":{"type":"number"},"reward_currency_amount":{"type":"number"},"base_reward_currency_amount":{"type":"number"}}},"quote-data-totals-additional-data-interface":{"type":"object","description":"Additional data for totals collection.","properties":{"extension_attributes":{"$ref":"#/definitions/quote-data-totals-additional-data-extension-interface"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}}},"quote-data-totals-additional-data-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Quote\\Api\\Data\\TotalsAdditionalDataInterface","properties":{"gift_messages":{"type":"array","items":{"$ref":"#/definitions/gift-message-data-message-interface"}}}},"gift-message-data-message-interface":{"type":"object","description":"Interface MessageInterface","properties":{"gift_message_id":{"type":"integer","description":"Gift message ID. Otherwise, null."},"customer_id":{"type":"integer","description":"Customer ID. Otherwise, null."},"sender":{"type":"string","description":"Sender name."},"recipient":{"type":"string","description":"Recipient name."},"message":{"type":"string","description":"Message text."},"extension_attributes":{"$ref":"#/definitions/gift-message-data-message-extension-interface"}},"required":["sender","recipient","message"]},"gift-message-data-message-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\GiftMessage\\Api\\Data\\MessageInterface","properties":{"entity_id":{"type":"string"},"entity_type":{"type":"string"},"wrapping_id":{"type":"integer"},"wrapping_allow_gift_receipt":{"type":"boolean"},"wrapping_add_printed_card":{"type":"boolean"}}},"framework-search-search-result-interface":{"type":"object","description":"Interface SearchResultInterface","properties":{"items":{"type":"array","items":{"$ref":"#/definitions/framework-search-document-interface"}},"aggregations":{"$ref":"#/definitions/framework-search-aggregation-interface"},"search_criteria":{"$ref":"#/definitions/framework-search-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","aggregations","search_criteria","total_count"]},"framework-search-document-interface":{"type":"object","description":"Interface \\Magento\\Framework\\Api\\Search\\DocumentInterface","properties":{"id":{"type":"integer"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["id"]},"framework-search-aggregation-interface":{"type":"object","description":"Faceted data","properties":{"buckets":{"type":"array","description":"All Document fields","items":{"$ref":"#/definitions/framework-search-bucket-interface"}},"bucket_names":{"type":"array","description":"Document field names","items":{"type":"string"}}},"required":["buckets","bucket_names"]},"framework-search-bucket-interface":{"type":"object","description":"Facet Bucket","properties":{"name":{"type":"string","description":"Field name"},"values":{"type":"array","description":"Field values","items":{"$ref":"#/definitions/framework-search-aggregation-value-interface"}}},"required":["name","values"]},"framework-search-aggregation-value-interface":{"type":"object","description":"Interface \\Magento\\Framework\\Api\\Search\\AggregationValueInterface","properties":{"value":{"type":"string","description":"Aggregation"},"metrics":{"type":"array","description":"Metrics","items":{"type":"string"}}},"required":["value","metrics"]},"framework-search-search-criteria-interface":{"type":"object","description":"Interface SearchCriteriaInterface","properties":{"request_name":{"type":"string"},"filter_groups":{"type":"array","description":"A list of filter groups.","items":{"$ref":"#/definitions/framework-search-filter-group"}},"sort_orders":{"type":"array","description":"Sort order.","items":{"$ref":"#/definitions/framework-sort-order"}},"page_size":{"type":"integer","description":"Page size."},"current_page":{"type":"integer","description":"Current page."}},"required":["request_name","filter_groups"]},"sales-data-order-interface":{"type":"object","description":"Order interface. An order is a document that a web store issues to a customer. Magento generates a sales order that lists the product items, billing and shipping addresses, and shipping and payment methods. A corresponding external document, known as a purchase order, is emailed to the customer.","properties":{"adjustment_negative":{"type":"number","description":"Negative adjustment value."},"adjustment_positive":{"type":"number","description":"Positive adjustment value."},"applied_rule_ids":{"type":"string","description":"Applied rule IDs."},"base_adjustment_negative":{"type":"number","description":"Base negative adjustment value."},"base_adjustment_positive":{"type":"number","description":"Base positive adjustment value."},"base_currency_code":{"type":"string","description":"Base currency code."},"base_discount_amount":{"type":"number","description":"Base discount amount."},"base_discount_canceled":{"type":"number","description":"Base discount canceled."},"base_discount_invoiced":{"type":"number","description":"Base discount invoiced."},"base_discount_refunded":{"type":"number","description":"Base discount refunded."},"base_grand_total":{"type":"number","description":"Base grand total."},"base_discount_tax_compensation_amount":{"type":"number","description":"Base discount tax compensation amount."},"base_discount_tax_compensation_invoiced":{"type":"number","description":"Base discount tax compensation invoiced."},"base_discount_tax_compensation_refunded":{"type":"number","description":"Base discount tax compensation refunded."},"base_shipping_amount":{"type":"number","description":"Base shipping amount."},"base_shipping_canceled":{"type":"number","description":"Base shipping canceled."},"base_shipping_discount_amount":{"type":"number","description":"Base shipping discount amount."},"base_shipping_discount_tax_compensation_amnt":{"type":"number","description":"Base shipping discount tax compensation amount."},"base_shipping_incl_tax":{"type":"number","description":"Base shipping including tax."},"base_shipping_invoiced":{"type":"number","description":"Base shipping invoiced."},"base_shipping_refunded":{"type":"number","description":"Base shipping refunded."},"base_shipping_tax_amount":{"type":"number","description":"Base shipping tax amount."},"base_shipping_tax_refunded":{"type":"number","description":"Base shipping tax refunded."},"base_subtotal":{"type":"number","description":"Base subtotal."},"base_subtotal_canceled":{"type":"number","description":"Base subtotal canceled."},"base_subtotal_incl_tax":{"type":"number","description":"Base subtotal including tax."},"base_subtotal_invoiced":{"type":"number","description":"Base subtotal invoiced."},"base_subtotal_refunded":{"type":"number","description":"Base subtotal refunded."},"base_tax_amount":{"type":"number","description":"Base tax amount."},"base_tax_canceled":{"type":"number","description":"Base tax canceled."},"base_tax_invoiced":{"type":"number","description":"Base tax invoiced."},"base_tax_refunded":{"type":"number","description":"Base tax refunded."},"base_total_canceled":{"type":"number","description":"Base total canceled."},"base_total_due":{"type":"number","description":"Base total due."},"base_total_invoiced":{"type":"number","description":"Base total invoiced."},"base_total_invoiced_cost":{"type":"number","description":"Base total invoiced cost."},"base_total_offline_refunded":{"type":"number","description":"Base total offline refunded."},"base_total_online_refunded":{"type":"number","description":"Base total online refunded."},"base_total_paid":{"type":"number","description":"Base total paid."},"base_total_qty_ordered":{"type":"number","description":"Base total quantity ordered."},"base_total_refunded":{"type":"number","description":"Base total refunded."},"base_to_global_rate":{"type":"number","description":"Base-to-global rate."},"base_to_order_rate":{"type":"number","description":"Base-to-order rate."},"billing_address_id":{"type":"integer","description":"Billing address ID."},"can_ship_partially":{"type":"integer","description":"Can-ship-partially flag value."},"can_ship_partially_item":{"type":"integer","description":"Can-ship-partially-item flag value."},"coupon_code":{"type":"string","description":"Coupon code."},"created_at":{"type":"string","description":"Created-at timestamp."},"customer_dob":{"type":"string","description":"Customer date-of-birth (DOB)."},"customer_email":{"type":"string","description":"Customer email address."},"customer_firstname":{"type":"string","description":"Customer first name."},"customer_gender":{"type":"integer","description":"Customer gender."},"customer_group_id":{"type":"integer","description":"Customer group ID."},"customer_id":{"type":"integer","description":"Customer ID."},"customer_is_guest":{"type":"integer","description":"Customer-is-guest flag value."},"customer_lastname":{"type":"string","description":"Customer last name."},"customer_middlename":{"type":"string","description":"Customer middle name."},"customer_note":{"type":"string","description":"Customer note."},"customer_note_notify":{"type":"integer","description":"Customer-note-notify flag value."},"customer_prefix":{"type":"string","description":"Customer prefix."},"customer_suffix":{"type":"string","description":"Customer suffix."},"customer_taxvat":{"type":"string","description":"Customer value-added tax (VAT)."},"discount_amount":{"type":"number","description":"Discount amount."},"discount_canceled":{"type":"number","description":"Discount canceled."},"discount_description":{"type":"string","description":"Discount description."},"discount_invoiced":{"type":"number","description":"Discount invoiced."},"discount_refunded":{"type":"number","description":"Discount refunded amount."},"edit_increment":{"type":"integer","description":"Edit increment value."},"email_sent":{"type":"integer","description":"Email-sent flag value."},"entity_id":{"type":"integer","description":"Order ID."},"ext_customer_id":{"type":"string","description":"External customer ID."},"ext_order_id":{"type":"string","description":"External order ID."},"forced_shipment_with_invoice":{"type":"integer","description":"Forced-shipment-with-invoice flag value."},"global_currency_code":{"type":"string","description":"Global currency code."},"grand_total":{"type":"number","description":"Grand total."},"discount_tax_compensation_amount":{"type":"number","description":"Discount tax compensation amount."},"discount_tax_compensation_invoiced":{"type":"number","description":"Discount tax compensation invoiced amount."},"discount_tax_compensation_refunded":{"type":"number","description":"Discount tax compensation refunded amount."},"hold_before_state":{"type":"string","description":"Hold before state."},"hold_before_status":{"type":"string","description":"Hold before status."},"increment_id":{"type":"string","description":"Increment ID."},"is_virtual":{"type":"integer","description":"Is-virtual flag value."},"order_currency_code":{"type":"string","description":"Order currency code."},"original_increment_id":{"type":"string","description":"Original increment ID."},"payment_authorization_amount":{"type":"number","description":"Payment authorization amount."},"payment_auth_expiration":{"type":"integer","description":"Payment authorization expiration date."},"protect_code":{"type":"string","description":"Protect code."},"quote_address_id":{"type":"integer","description":"Quote address ID."},"quote_id":{"type":"integer","description":"Quote ID."},"relation_child_id":{"type":"string","description":"Relation child ID."},"relation_child_real_id":{"type":"string","description":"Relation child real ID."},"relation_parent_id":{"type":"string","description":"Relation parent ID."},"relation_parent_real_id":{"type":"string","description":"Relation parent real ID."},"remote_ip":{"type":"string","description":"Remote IP address."},"shipping_amount":{"type":"number","description":"Shipping amount."},"shipping_canceled":{"type":"number","description":"Shipping canceled amount."},"shipping_description":{"type":"string","description":"Shipping description."},"shipping_discount_amount":{"type":"number","description":"Shipping discount amount."},"shipping_discount_tax_compensation_amount":{"type":"number","description":"Shipping discount tax compensation amount."},"shipping_incl_tax":{"type":"number","description":"Shipping including tax amount."},"shipping_invoiced":{"type":"number","description":"Shipping invoiced amount."},"shipping_refunded":{"type":"number","description":"Shipping refunded amount."},"shipping_tax_amount":{"type":"number","description":"Shipping tax amount."},"shipping_tax_refunded":{"type":"number","description":"Shipping tax refunded amount."},"state":{"type":"string","description":"State."},"status":{"type":"string","description":"Status."},"store_currency_code":{"type":"string","description":"Store currency code."},"store_id":{"type":"integer","description":"Store ID."},"store_name":{"type":"string","description":"Store name."},"store_to_base_rate":{"type":"number","description":"Store-to-base rate."},"store_to_order_rate":{"type":"number","description":"Store-to-order rate."},"subtotal":{"type":"number","description":"Subtotal."},"subtotal_canceled":{"type":"number","description":"Subtotal canceled amount."},"subtotal_incl_tax":{"type":"number","description":"Subtotal including tax amount."},"subtotal_invoiced":{"type":"number","description":"Subtotal invoiced amount."},"subtotal_refunded":{"type":"number","description":"Subtotal refunded amount."},"tax_amount":{"type":"number","description":"Tax amount."},"tax_canceled":{"type":"number","description":"Tax canceled amount."},"tax_invoiced":{"type":"number","description":"Tax invoiced amount."},"tax_refunded":{"type":"number","description":"Tax refunded amount."},"total_canceled":{"type":"number","description":"Total canceled."},"total_due":{"type":"number","description":"Total due."},"total_invoiced":{"type":"number","description":"Total invoiced amount."},"total_item_count":{"type":"integer","description":"Total item count."},"total_offline_refunded":{"type":"number","description":"Total offline refunded amount."},"total_online_refunded":{"type":"number","description":"Total online refunded amount."},"total_paid":{"type":"number","description":"Total paid."},"total_qty_ordered":{"type":"number","description":"Total quantity ordered."},"total_refunded":{"type":"number","description":"Total amount refunded."},"updated_at":{"type":"string","description":"Updated-at timestamp."},"weight":{"type":"number","description":"Weight."},"x_forwarded_for":{"type":"string","description":"X-Forwarded-For field value."},"items":{"type":"array","description":"Array of items.","items":{"$ref":"#/definitions/sales-data-order-item-interface"}},"billing_address":{"$ref":"#/definitions/sales-data-order-address-interface"},"payment":{"$ref":"#/definitions/sales-data-order-payment-interface"},"status_histories":{"type":"array","description":"Array of status histories.","items":{"$ref":"#/definitions/sales-data-order-status-history-interface"}},"extension_attributes":{"$ref":"#/definitions/sales-data-order-extension-interface"}},"required":["base_grand_total","customer_email","grand_total","items"]},"sales-data-order-item-interface":{"type":"object","description":"Order item interface. An order is a document that a web store issues to a customer. Magento generates a sales order that lists the product items, billing and shipping addresses, and shipping and payment methods. A corresponding external document, known as a purchase order, is emailed to the customer.","properties":{"additional_data":{"type":"string","description":"Additional data."},"amount_refunded":{"type":"number","description":"Amount refunded."},"applied_rule_ids":{"type":"string","description":"Applied rule IDs."},"base_amount_refunded":{"type":"number","description":"Base amount refunded."},"base_cost":{"type":"number","description":"Base cost."},"base_discount_amount":{"type":"number","description":"Base discount amount."},"base_discount_invoiced":{"type":"number","description":"Base discount invoiced."},"base_discount_refunded":{"type":"number","description":"Base discount refunded."},"base_discount_tax_compensation_amount":{"type":"number","description":"Base discount tax compensation amount."},"base_discount_tax_compensation_invoiced":{"type":"number","description":"Base discount tax compensation invoiced."},"base_discount_tax_compensation_refunded":{"type":"number","description":"Base discount tax compensation refunded."},"base_original_price":{"type":"number","description":"Base original price."},"base_price":{"type":"number","description":"Base price."},"base_price_incl_tax":{"type":"number","description":"Base price including tax."},"base_row_invoiced":{"type":"number","description":"Base row invoiced."},"base_row_total":{"type":"number","description":"Base row total."},"base_row_total_incl_tax":{"type":"number","description":"Base row total including tax."},"base_tax_amount":{"type":"number","description":"Base tax amount."},"base_tax_before_discount":{"type":"number","description":"Base tax before discount."},"base_tax_invoiced":{"type":"number","description":"Base tax invoiced."},"base_tax_refunded":{"type":"number","description":"Base tax refunded."},"base_weee_tax_applied_amount":{"type":"number","description":"Base WEEE tax applied amount."},"base_weee_tax_applied_row_amnt":{"type":"number","description":"Base WEEE tax applied row amount."},"base_weee_tax_disposition":{"type":"number","description":"Base WEEE tax disposition."},"base_weee_tax_row_disposition":{"type":"number","description":"Base WEEE tax row disposition."},"created_at":{"type":"string","description":"Created-at timestamp."},"description":{"type":"string","description":"Description."},"discount_amount":{"type":"number","description":"Discount amount."},"discount_invoiced":{"type":"number","description":"Discount invoiced."},"discount_percent":{"type":"number","description":"Discount percent."},"discount_refunded":{"type":"number","description":"Discount refunded."},"event_id":{"type":"integer","description":"Event ID."},"ext_order_item_id":{"type":"string","description":"External order item ID."},"free_shipping":{"type":"integer","description":"Free-shipping flag value."},"gw_base_price":{"type":"number","description":"GW base price."},"gw_base_price_invoiced":{"type":"number","description":"GW base price invoiced."},"gw_base_price_refunded":{"type":"number","description":"GW base price refunded."},"gw_base_tax_amount":{"type":"number","description":"GW base tax amount."},"gw_base_tax_amount_invoiced":{"type":"number","description":"GW base tax amount invoiced."},"gw_base_tax_amount_refunded":{"type":"number","description":"GW base tax amount refunded."},"gw_id":{"type":"integer","description":"GW ID."},"gw_price":{"type":"number","description":"GW price."},"gw_price_invoiced":{"type":"number","description":"GW price invoiced."},"gw_price_refunded":{"type":"number","description":"GW price refunded."},"gw_tax_amount":{"type":"number","description":"GW tax amount."},"gw_tax_amount_invoiced":{"type":"number","description":"GW tax amount invoiced."},"gw_tax_amount_refunded":{"type":"number","description":"GW tax amount refunded."},"discount_tax_compensation_amount":{"type":"number","description":"Discount tax compensation amount."},"discount_tax_compensation_canceled":{"type":"number","description":"Discount tax compensation canceled."},"discount_tax_compensation_invoiced":{"type":"number","description":"Discount tax compensation invoiced."},"discount_tax_compensation_refunded":{"type":"number","description":"Discount tax compensation refunded."},"is_qty_decimal":{"type":"integer","description":"Is-quantity-decimal flag value."},"is_virtual":{"type":"integer","description":"Is-virtual flag value."},"item_id":{"type":"integer","description":"Item ID."},"locked_do_invoice":{"type":"integer","description":"Locked DO invoice flag value."},"locked_do_ship":{"type":"integer","description":"Locked DO ship flag value."},"name":{"type":"string","description":"Name."},"no_discount":{"type":"integer","description":"No-discount flag value."},"order_id":{"type":"integer","description":"Order ID."},"original_price":{"type":"number","description":"Original price."},"parent_item_id":{"type":"integer","description":"Parent item ID."},"price":{"type":"number","description":"Price."},"price_incl_tax":{"type":"number","description":"Price including tax."},"product_id":{"type":"integer","description":"Product ID."},"product_type":{"type":"string","description":"Product type."},"qty_backordered":{"type":"number","description":"Quantity backordered."},"qty_canceled":{"type":"number","description":"Quantity canceled."},"qty_invoiced":{"type":"number","description":"Quantity invoiced."},"qty_ordered":{"type":"number","description":"Quantity ordered."},"qty_refunded":{"type":"number","description":"Quantity refunded."},"qty_returned":{"type":"number","description":"Quantity returned."},"qty_shipped":{"type":"number","description":"Quantity shipped."},"quote_item_id":{"type":"integer","description":"Quote item ID."},"row_invoiced":{"type":"number","description":"Row invoiced."},"row_total":{"type":"number","description":"Row total."},"row_total_incl_tax":{"type":"number","description":"Row total including tax."},"row_weight":{"type":"number","description":"Row weight."},"sku":{"type":"string","description":"SKU."},"store_id":{"type":"integer","description":"Store ID."},"tax_amount":{"type":"number","description":"Tax amount."},"tax_before_discount":{"type":"number","description":"Tax before discount."},"tax_canceled":{"type":"number","description":"Tax canceled."},"tax_invoiced":{"type":"number","description":"Tax invoiced."},"tax_percent":{"type":"number","description":"Tax percent."},"tax_refunded":{"type":"number","description":"Tax refunded."},"updated_at":{"type":"string","description":"Updated-at timestamp."},"weee_tax_applied":{"type":"string","description":"WEEE tax applied."},"weee_tax_applied_amount":{"type":"number","description":"WEEE tax applied amount."},"weee_tax_applied_row_amount":{"type":"number","description":"WEEE tax applied row amount."},"weee_tax_disposition":{"type":"number","description":"WEEE tax disposition."},"weee_tax_row_disposition":{"type":"number","description":"WEEE tax row disposition."},"weight":{"type":"number","description":"Weight."},"parent_item":{"$ref":"#/definitions/sales-data-order-item-interface"},"product_option":{"$ref":"#/definitions/catalog-data-product-option-interface"},"extension_attributes":{"$ref":"#/definitions/sales-data-order-item-extension-interface"}},"required":["sku"]},"catalog-data-product-option-interface":{"type":"object","description":"Product option interface","properties":{"extension_attributes":{"$ref":"#/definitions/catalog-data-product-option-extension-interface"}}},"catalog-data-product-option-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductOptionInterface","properties":{"custom_options":{"type":"array","items":{"$ref":"#/definitions/catalog-data-custom-option-interface"}},"bundle_options":{"type":"array","items":{"$ref":"#/definitions/bundle-data-bundle-option-interface"}},"downloadable_option":{"$ref":"#/definitions/downloadable-data-downloadable-option-interface"},"giftcard_item_option":{"$ref":"#/definitions/gift-card-data-gift-card-option-interface"},"configurable_item_options":{"type":"array","items":{"$ref":"#/definitions/configurable-product-data-configurable-item-option-value-interface"}}}},"sales-data-order-item-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\OrderItemInterface","properties":{"gift_message":{"$ref":"#/definitions/gift-message-data-message-interface"},"gw_id":{"type":"string"},"gw_base_price":{"type":"string"},"gw_price":{"type":"string"},"gw_base_tax_amount":{"type":"string"},"gw_tax_amount":{"type":"string"},"gw_base_price_invoiced":{"type":"string"},"gw_price_invoiced":{"type":"string"},"gw_base_tax_amount_invoiced":{"type":"string"},"gw_tax_amount_invoiced":{"type":"string"},"gw_base_price_refunded":{"type":"string"},"gw_price_refunded":{"type":"string"},"gw_base_tax_amount_refunded":{"type":"string"},"gw_tax_amount_refunded":{"type":"string"}}},"sales-data-order-address-interface":{"type":"object","description":"Order address interface. An order is a document that a web store issues to a customer. Magento generates a sales order that lists the product items, billing and shipping addresses, and shipping and payment methods. A corresponding external document, known as a purchase order, is emailed to the customer.","properties":{"address_type":{"type":"string","description":"Address type."},"city":{"type":"string","description":"City."},"company":{"type":"string","description":"Company."},"country_id":{"type":"string","description":"Country ID."},"customer_address_id":{"type":"integer","description":"Country address ID."},"customer_id":{"type":"integer","description":"Customer ID."},"email":{"type":"string","description":"Email address."},"entity_id":{"type":"integer","description":"Order address ID."},"fax":{"type":"string","description":"Fax number."},"firstname":{"type":"string","description":"First name."},"lastname":{"type":"string","description":"Last name."},"middlename":{"type":"string","description":"Middle name."},"parent_id":{"type":"integer","description":"Parent ID."},"postcode":{"type":"string","description":"Postal code."},"prefix":{"type":"string","description":"Prefix."},"region":{"type":"string","description":"Region."},"region_code":{"type":"string","description":"Region code."},"region_id":{"type":"integer","description":"Region ID."},"street":{"type":"array","description":"Array of any street values. Otherwise, null.","items":{"type":"string"}},"suffix":{"type":"string","description":"Suffix."},"telephone":{"type":"string","description":"Telephone number."},"vat_id":{"type":"string","description":"VAT ID."},"vat_is_valid":{"type":"integer","description":"VAT-is-valid flag value."},"vat_request_date":{"type":"string","description":"VAT request date."},"vat_request_id":{"type":"string","description":"VAT request ID."},"vat_request_success":{"type":"integer","description":"VAT-request-success flag value."},"extension_attributes":{"$ref":"#/definitions/sales-data-order-address-extension-interface"}},"required":["address_type","city","country_id","firstname","lastname","postcode","telephone"]},"sales-data-order-address-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\OrderAddressInterface"},"sales-data-order-payment-interface":{"type":"object","description":"Order payment interface. An order is a document that a web store issues to a customer. Magento generates a sales order that lists the product items, billing and shipping addresses, and shipping and payment methods. A corresponding external document, known as a purchase order, is emailed to the customer.","properties":{"account_status":{"type":"string","description":"Account status."},"additional_data":{"type":"string","description":"Additional data."},"additional_information":{"type":"array","description":"Array of additional information.","items":{"type":"string"}},"address_status":{"type":"string","description":"Address status."},"amount_authorized":{"type":"number","description":"Amount authorized."},"amount_canceled":{"type":"number","description":"Amount canceled."},"amount_ordered":{"type":"number","description":"Amount ordered."},"amount_paid":{"type":"number","description":"Amount paid."},"amount_refunded":{"type":"number","description":"Amount refunded."},"anet_trans_method":{"type":"string","description":"Anet transaction method."},"base_amount_authorized":{"type":"number","description":"Base amount authorized."},"base_amount_canceled":{"type":"number","description":"Base amount canceled."},"base_amount_ordered":{"type":"number","description":"Base amount ordered."},"base_amount_paid":{"type":"number","description":"Base amount paid."},"base_amount_paid_online":{"type":"number","description":"Base amount paid online."},"base_amount_refunded":{"type":"number","description":"Base amount refunded."},"base_amount_refunded_online":{"type":"number","description":"Base amount refunded online."},"base_shipping_amount":{"type":"number","description":"Base shipping amount."},"base_shipping_captured":{"type":"number","description":"Base shipping captured amount."},"base_shipping_refunded":{"type":"number","description":"Base shipping refunded amount."},"cc_approval":{"type":"string","description":"Credit card approval."},"cc_avs_status":{"type":"string","description":"Credit card avs status."},"cc_cid_status":{"type":"string","description":"Credit card CID status."},"cc_debug_request_body":{"type":"string","description":"Credit card debug request body."},"cc_debug_response_body":{"type":"string","description":"Credit card debug response body."},"cc_debug_response_serialized":{"type":"string","description":"Credit card debug response serialized."},"cc_exp_month":{"type":"string","description":"Credit card expiration month."},"cc_exp_year":{"type":"string","description":"Credit card expiration year."},"cc_last4":{"type":"string","description":"Last four digits of the credit card."},"cc_number_enc":{"type":"string","description":"Encrypted credit card number."},"cc_owner":{"type":"string","description":"Credit card number."},"cc_secure_verify":{"type":"string","description":"Credit card secure verify."},"cc_ss_issue":{"type":"string","description":"Credit card SS issue."},"cc_ss_start_month":{"type":"string","description":"Credit card SS start month."},"cc_ss_start_year":{"type":"string","description":"Credit card SS start year."},"cc_status":{"type":"string","description":"Credit card status."},"cc_status_description":{"type":"string","description":"Credit card status description."},"cc_trans_id":{"type":"string","description":"Credit card transaction ID."},"cc_type":{"type":"string","description":"Credit card type."},"echeck_account_name":{"type":"string","description":"eCheck account name."},"echeck_account_type":{"type":"string","description":"eCheck account type."},"echeck_bank_name":{"type":"string","description":"eCheck bank name."},"echeck_routing_number":{"type":"string","description":"eCheck routing number."},"echeck_type":{"type":"string","description":"eCheck type."},"entity_id":{"type":"integer","description":"Entity ID."},"last_trans_id":{"type":"string","description":"Last transaction ID."},"method":{"type":"string","description":"Method."},"parent_id":{"type":"integer","description":"Parent ID."},"po_number":{"type":"string","description":"PO number."},"protection_eligibility":{"type":"string","description":"Protection eligibility."},"quote_payment_id":{"type":"integer","description":"Quote payment ID."},"shipping_amount":{"type":"number","description":"Shipping amount."},"shipping_captured":{"type":"number","description":"Shipping captured."},"shipping_refunded":{"type":"number","description":"Shipping refunded."},"extension_attributes":{"$ref":"#/definitions/sales-data-order-payment-extension-interface"}},"required":["account_status","additional_information","cc_last4","method"]},"sales-data-order-payment-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\OrderPaymentInterface","properties":{"vault_payment_token":{"$ref":"#/definitions/vault-data-payment-token-interface"}}},"vault-data-payment-token-interface":{"type":"object","description":"Gateway vault payment token interface.","properties":{"entity_id":{"type":"integer","description":"Entity ID."},"customer_id":{"type":"integer","description":"Customer ID."},"public_hash":{"type":"string","description":"Public hash"},"payment_method_code":{"type":"string","description":"Payment method code"},"type":{"type":"string","description":"Type"},"created_at":{"type":"string","description":"Token creation timestamp"},"expires_at":{"type":"string","description":"Token expiration timestamp"},"gateway_token":{"type":"string","description":"Gateway token ID"},"token_details":{"type":"string","description":"Token details"},"is_active":{"type":"boolean","description":"Is active."},"is_visible":{"type":"boolean","description":"Is visible."}},"required":["public_hash","payment_method_code","type","gateway_token","token_details","is_active","is_visible"]},"sales-data-order-status-history-interface":{"type":"object","description":"Order status history interface. An order is a document that a web store issues to a customer. Magento generates a sales order that lists the product items, billing and shipping addresses, and shipping and payment methods. A corresponding external document, known as a purchase order, is emailed to the customer.","properties":{"comment":{"type":"string","description":"Comment."},"created_at":{"type":"string","description":"Created-at timestamp."},"entity_id":{"type":"integer","description":"Order status history ID."},"entity_name":{"type":"string","description":"Entity name."},"is_customer_notified":{"type":"integer","description":"Is-customer-notified flag value."},"is_visible_on_front":{"type":"integer","description":"Is-visible-on-storefront flag value."},"parent_id":{"type":"integer","description":"Parent ID."},"status":{"type":"string","description":"Status."},"extension_attributes":{"$ref":"#/definitions/sales-data-order-status-history-extension-interface"}},"required":["comment","is_customer_notified","is_visible_on_front","parent_id"]},"sales-data-order-status-history-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\OrderStatusHistoryInterface"},"sales-data-order-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\OrderInterface","properties":{"shipping_assignments":{"type":"array","items":{"$ref":"#/definitions/sales-data-shipping-assignment-interface"}},"base_customer_balance_amount":{"type":"number"},"customer_balance_amount":{"type":"number"},"base_customer_balance_invoiced":{"type":"number"},"customer_balance_invoiced":{"type":"number"},"base_customer_balance_refunded":{"type":"number"},"customer_balance_refunded":{"type":"number"},"base_customer_balance_total_refunded":{"type":"number"},"customer_balance_total_refunded":{"type":"number"},"gift_cards":{"type":"array","items":{"$ref":"#/definitions/gift-card-account-data-gift-card-interface"}},"base_gift_cards_amount":{"type":"number"},"gift_cards_amount":{"type":"number"},"base_gift_cards_invoiced":{"type":"number"},"gift_cards_invoiced":{"type":"number"},"base_gift_cards_refunded":{"type":"number"},"gift_cards_refunded":{"type":"number"},"applied_taxes":{"type":"array","items":{"$ref":"#/definitions/tax-data-order-tax-details-applied-tax-interface"}},"item_applied_taxes":{"type":"array","items":{"$ref":"#/definitions/tax-data-order-tax-details-item-interface"}},"converting_from_quote":{"type":"boolean"},"gift_message":{"$ref":"#/definitions/gift-message-data-message-interface"},"gw_id":{"type":"string"},"gw_allow_gift_receipt":{"type":"string"},"gw_add_card":{"type":"string"},"gw_base_price":{"type":"string"},"gw_price":{"type":"string"},"gw_items_base_price":{"type":"string"},"gw_items_price":{"type":"string"},"gw_card_base_price":{"type":"string"},"gw_card_price":{"type":"string"},"gw_base_tax_amount":{"type":"string"},"gw_tax_amount":{"type":"string"},"gw_items_base_tax_amount":{"type":"string"},"gw_items_tax_amount":{"type":"string"},"gw_card_base_tax_amount":{"type":"string"},"gw_card_tax_amount":{"type":"string"},"gw_base_price_incl_tax":{"type":"string"},"gw_price_incl_tax":{"type":"string"},"gw_items_base_price_incl_tax":{"type":"string"},"gw_items_price_incl_tax":{"type":"string"},"gw_card_base_price_incl_tax":{"type":"string"},"gw_card_price_incl_tax":{"type":"string"},"gw_base_price_invoiced":{"type":"string"},"gw_price_invoiced":{"type":"string"},"gw_items_base_price_invoiced":{"type":"string"},"gw_items_price_invoiced":{"type":"string"},"gw_card_base_price_invoiced":{"type":"string"},"gw_card_price_invoiced":{"type":"string"},"gw_base_tax_amount_invoiced":{"type":"string"},"gw_tax_amount_invoiced":{"type":"string"},"gw_items_base_tax_invoiced":{"type":"string"},"gw_items_tax_invoiced":{"type":"string"},"gw_card_base_tax_invoiced":{"type":"string"},"gw_card_tax_invoiced":{"type":"string"},"gw_base_price_refunded":{"type":"string"},"gw_price_refunded":{"type":"string"},"gw_items_base_price_refunded":{"type":"string"},"gw_items_price_refunded":{"type":"string"},"gw_card_base_price_refunded":{"type":"string"},"gw_card_price_refunded":{"type":"string"},"gw_base_tax_amount_refunded":{"type":"string"},"gw_tax_amount_refunded":{"type":"string"},"gw_items_base_tax_refunded":{"type":"string"},"gw_items_tax_refunded":{"type":"string"},"gw_card_base_tax_refunded":{"type":"string"},"gw_card_tax_refunded":{"type":"string"}}},"sales-data-shipping-assignment-interface":{"type":"object","description":"Interface ShippingAssignmentInterface","properties":{"shipping":{"$ref":"#/definitions/sales-data-shipping-interface"},"items":{"type":"array","description":"Order items of shipping assignment","items":{"$ref":"#/definitions/sales-data-order-item-interface"}},"stock_id":{"type":"integer","description":"Stock id"},"extension_attributes":{"$ref":"#/definitions/sales-data-shipping-assignment-extension-interface"}},"required":["shipping","items"]},"sales-data-shipping-interface":{"type":"object","description":"Interface ShippingInterface","properties":{"address":{"$ref":"#/definitions/sales-data-order-address-interface"},"method":{"type":"string","description":"Shipping method"},"total":{"$ref":"#/definitions/sales-data-total-interface"},"extension_attributes":{"$ref":"#/definitions/sales-data-shipping-extension-interface"}}},"sales-data-total-interface":{"type":"object","description":"Interface TotalInterface","properties":{"base_shipping_amount":{"type":"number","description":"Base shipping amount."},"base_shipping_canceled":{"type":"number","description":"Base shipping canceled."},"base_shipping_discount_amount":{"type":"number","description":"Base shipping discount amount."},"base_shipping_discount_tax_compensation_amnt":{"type":"number","description":"Base shipping discount tax compensation amount."},"base_shipping_incl_tax":{"type":"number","description":"Base shipping including tax."},"base_shipping_invoiced":{"type":"number","description":"Base shipping invoiced."},"base_shipping_refunded":{"type":"number","description":"Base shipping refunded."},"base_shipping_tax_amount":{"type":"number","description":"Base shipping tax amount."},"base_shipping_tax_refunded":{"type":"number","description":"Base shipping tax refunded."},"shipping_amount":{"type":"number","description":"Shipping amount."},"shipping_canceled":{"type":"number","description":"Shipping canceled amount."},"shipping_discount_amount":{"type":"number","description":"Shipping discount amount."},"shipping_discount_tax_compensation_amount":{"type":"number","description":"Shipping discount tax compensation amount."},"shipping_incl_tax":{"type":"number","description":"Shipping including tax amount."},"shipping_invoiced":{"type":"number","description":"Shipping invoiced amount."},"shipping_refunded":{"type":"number","description":"Shipping refunded amount."},"shipping_tax_amount":{"type":"number","description":"Shipping tax amount."},"shipping_tax_refunded":{"type":"number","description":"Shipping tax refunded amount."},"extension_attributes":{"$ref":"#/definitions/sales-data-total-extension-interface"}}},"sales-data-total-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\TotalInterface"},"sales-data-shipping-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\ShippingInterface"},"sales-data-shipping-assignment-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\ShippingAssignmentInterface"},"gift-card-account-data-gift-card-interface":{"type":"object","description":"Gift Card data","properties":{"id":{"type":"integer","description":"Id"},"code":{"type":"string","description":"Code"},"amount":{"type":"number","description":"Amount"},"base_amount":{"type":"number","description":"Base Amount"}},"required":["id","code","amount","base_amount"]},"tax-data-order-tax-details-applied-tax-interface":{"type":"object","description":"Interface OrderTaxDetailsAppliedTaxInterface","properties":{"code":{"type":"string","description":"Code"},"title":{"type":"string","description":"Title"},"percent":{"type":"number","description":"Tax Percent"},"amount":{"type":"number","description":"Tax amount"},"base_amount":{"type":"number","description":"Tax amount in base currency"},"extension_attributes":{"$ref":"#/definitions/tax-data-order-tax-details-applied-tax-extension-interface"}},"required":["amount","base_amount"]},"tax-data-order-tax-details-applied-tax-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Tax\\Api\\Data\\OrderTaxDetailsAppliedTaxInterface","properties":{"rates":{"type":"array","items":{"$ref":"#/definitions/tax-data-applied-tax-rate-interface"}}}},"tax-data-applied-tax-rate-interface":{"type":"object","description":"Applied tax rate interface.","properties":{"code":{"type":"string","description":"Code"},"title":{"type":"string","description":"Title"},"percent":{"type":"number","description":"Tax Percent"},"extension_attributes":{"$ref":"#/definitions/tax-data-applied-tax-rate-extension-interface"}}},"tax-data-applied-tax-rate-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Tax\\Api\\Data\\AppliedTaxRateInterface"},"tax-data-order-tax-details-item-interface":{"type":"object","description":"Interface OrderTaxDetailsItemInterface","properties":{"type":{"type":"string","description":"Type (shipping, product, weee, gift wrapping, etc)"},"item_id":{"type":"integer","description":"Item id if this item is a product"},"associated_item_id":{"type":"integer","description":"Associated item id if this item is associated with another item, null otherwise"},"applied_taxes":{"type":"array","description":"Applied taxes","items":{"$ref":"#/definitions/tax-data-order-tax-details-applied-tax-interface"}},"extension_attributes":{"$ref":"#/definitions/tax-data-order-tax-details-item-extension-interface"}}},"tax-data-order-tax-details-item-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Tax\\Api\\Data\\OrderTaxDetailsItemInterface"},"sales-data-order-search-result-interface":{"type":"object","description":"Order search result interface. An order is a document that a web store issues to a customer. Magento generates a sales order that lists the product items, billing and shipping addresses, and shipping and payment methods. A corresponding external document, known as a purchase order, is emailed to the customer.","properties":{"items":{"type":"array","description":"Array of collection items.","items":{"$ref":"#/definitions/sales-data-order-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"sales-data-order-status-history-search-result-interface":{"type":"object","description":"Order status history search result interface. An order is a document that a web store issues to a customer. Magento generates a sales order that lists the product items, billing and shipping addresses, and shipping and payment methods. A corresponding external document, known as a purchase order, is emailed to the customer.","properties":{"items":{"type":"array","description":"Array of collection items.","items":{"$ref":"#/definitions/sales-data-order-status-history-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"sales-data-order-item-search-result-interface":{"type":"object","description":"Order item search result interface. An order is a document that a web store issues to a customer. Magento generates a sales order that lists the product items, billing and shipping addresses, and shipping and payment methods. A corresponding external document, known as a purchase order, is emailed to the customer.","properties":{"items":{"type":"array","description":"Array of collection items.","items":{"$ref":"#/definitions/sales-data-order-item-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"sales-data-invoice-interface":{"type":"object","description":"Invoice interface. An invoice is a record of the receipt of payment for an order.","properties":{"base_currency_code":{"type":"string","description":"Base currency code."},"base_discount_amount":{"type":"number","description":"Base discount amount."},"base_grand_total":{"type":"number","description":"Base grand total."},"base_discount_tax_compensation_amount":{"type":"number","description":"Base discount tax compensation amount."},"base_shipping_amount":{"type":"number","description":"Base shipping amount."},"base_shipping_discount_tax_compensation_amnt":{"type":"number","description":"Base shipping discount tax compensation amount."},"base_shipping_incl_tax":{"type":"number","description":"Base shipping including tax."},"base_shipping_tax_amount":{"type":"number","description":"Base shipping tax amount."},"base_subtotal":{"type":"number","description":"Base subtotal."},"base_subtotal_incl_tax":{"type":"number","description":"Base subtotal including tax."},"base_tax_amount":{"type":"number","description":"Base tax amount."},"base_total_refunded":{"type":"number","description":"Base total refunded."},"base_to_global_rate":{"type":"number","description":"Base-to-global rate."},"base_to_order_rate":{"type":"number","description":"Base-to-order rate."},"billing_address_id":{"type":"integer","description":"Billing address ID."},"can_void_flag":{"type":"integer","description":"Can void flag value."},"created_at":{"type":"string","description":"Created-at timestamp."},"discount_amount":{"type":"number","description":"Discount amount."},"discount_description":{"type":"string","description":"Discount description."},"email_sent":{"type":"integer","description":"Email-sent flag value."},"entity_id":{"type":"integer","description":"Invoice ID."},"global_currency_code":{"type":"string","description":"Global currency code."},"grand_total":{"type":"number","description":"Grand total."},"discount_tax_compensation_amount":{"type":"number","description":"Discount tax compensation amount."},"increment_id":{"type":"string","description":"Increment ID."},"is_used_for_refund":{"type":"integer","description":"Is-used-for-refund flag value."},"order_currency_code":{"type":"string","description":"Order currency code."},"order_id":{"type":"integer","description":"Order ID."},"shipping_address_id":{"type":"integer","description":"Shipping address ID."},"shipping_amount":{"type":"number","description":"Shipping amount."},"shipping_discount_tax_compensation_amount":{"type":"number","description":"Shipping discount tax compensation amount."},"shipping_incl_tax":{"type":"number","description":"Shipping including tax."},"shipping_tax_amount":{"type":"number","description":"Shipping tax amount."},"state":{"type":"integer","description":"State."},"store_currency_code":{"type":"string","description":"Store currency code."},"store_id":{"type":"integer","description":"Store ID."},"store_to_base_rate":{"type":"number","description":"Store-to-base rate."},"store_to_order_rate":{"type":"number","description":"Store-to-order rate."},"subtotal":{"type":"number","description":"Subtotal."},"subtotal_incl_tax":{"type":"number","description":"Subtotal including tax."},"tax_amount":{"type":"number","description":"Tax amount."},"total_qty":{"type":"number","description":"Total quantity."},"transaction_id":{"type":"string","description":"Transaction ID."},"updated_at":{"type":"string","description":"Updated-at timestamp."},"items":{"type":"array","description":"Array of invoice items.","items":{"$ref":"#/definitions/sales-data-invoice-item-interface"}},"comments":{"type":"array","description":"Array of any invoice comments. Otherwise, null.","items":{"$ref":"#/definitions/sales-data-invoice-comment-interface"}},"extension_attributes":{"$ref":"#/definitions/sales-data-invoice-extension-interface"}},"required":["order_id","total_qty","items"]},"sales-data-invoice-item-interface":{"type":"object","description":"Invoice item interface. An invoice is a record of the receipt of payment for an order. An invoice item is a purchased item in an invoice.","properties":{"additional_data":{"type":"string","description":"Additional data."},"base_cost":{"type":"number","description":"Base cost."},"base_discount_amount":{"type":"number","description":"Base discount amount."},"base_discount_tax_compensation_amount":{"type":"number","description":"Base discount tax compensation amount."},"base_price":{"type":"number","description":"Base price."},"base_price_incl_tax":{"type":"number","description":"Base price including tax."},"base_row_total":{"type":"number","description":"Base row total."},"base_row_total_incl_tax":{"type":"number","description":"Base row total including tax."},"base_tax_amount":{"type":"number","description":"Base tax amount."},"description":{"type":"string","description":"Description."},"discount_amount":{"type":"number","description":"Discount amount."},"entity_id":{"type":"integer","description":"Invoice item ID."},"discount_tax_compensation_amount":{"type":"number","description":"Discount tax compensation amount."},"name":{"type":"string","description":"Name."},"parent_id":{"type":"integer","description":"Parent ID."},"price":{"type":"number","description":"Price."},"price_incl_tax":{"type":"number","description":"Price including tax."},"product_id":{"type":"integer","description":"Product ID."},"row_total":{"type":"number","description":"Row total."},"row_total_incl_tax":{"type":"number","description":"Row total including tax."},"sku":{"type":"string","description":"SKU."},"tax_amount":{"type":"number","description":"Tax amount."},"extension_attributes":{"$ref":"#/definitions/sales-data-invoice-item-extension-interface"},"order_item_id":{"type":"integer","description":"Order item ID."},"qty":{"type":"number","description":"Quantity."}},"required":["sku","order_item_id","qty"]},"sales-data-invoice-item-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\InvoiceItemInterface"},"sales-data-invoice-comment-interface":{"type":"object","description":"Invoice comment interface. An invoice is a record of the receipt of payment for an order. An invoice can include comments that detail the invoice history.","properties":{"is_customer_notified":{"type":"integer","description":"Is-customer-notified flag value."},"parent_id":{"type":"integer","description":"Parent ID."},"extension_attributes":{"$ref":"#/definitions/sales-data-invoice-comment-extension-interface"},"comment":{"type":"string","description":"Comment."},"is_visible_on_front":{"type":"integer","description":"Is-visible-on-storefront flag value."},"created_at":{"type":"string","description":"Created-at timestamp."},"entity_id":{"type":"integer","description":"Invoice ID."}},"required":["is_customer_notified","parent_id","comment","is_visible_on_front"]},"sales-data-invoice-comment-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\InvoiceCommentInterface"},"sales-data-invoice-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\InvoiceInterface","properties":{"base_customer_balance_amount":{"type":"number"},"customer_balance_amount":{"type":"number"},"base_gift_cards_amount":{"type":"number"},"gift_cards_amount":{"type":"number"},"gw_base_price":{"type":"string"},"gw_price":{"type":"string"},"gw_items_base_price":{"type":"string"},"gw_items_price":{"type":"string"},"gw_card_base_price":{"type":"string"},"gw_card_price":{"type":"string"},"gw_base_tax_amount":{"type":"string"},"gw_tax_amount":{"type":"string"},"gw_items_base_tax_amount":{"type":"string"},"gw_items_tax_amount":{"type":"string"},"gw_card_base_tax_amount":{"type":"string"},"gw_card_tax_amount":{"type":"string"},"invoice_api_test_attribute":{"$ref":"#/definitions/user-data-user-interface"}}},"sales-data-invoice-search-result-interface":{"type":"object","description":"Invoice search result interface. An invoice is a record of the receipt of payment for an order.","properties":{"items":{"type":"array","description":"Array of collection items.","items":{"$ref":"#/definitions/sales-data-invoice-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"sales-data-invoice-comment-search-result-interface":{"type":"object","description":"Invoice comment search result interface. An invoice is a record of the receipt of payment for an order. An invoice can include comments that detail the invoice history.","properties":{"items":{"type":"array","description":"Array of collection items.","items":{"$ref":"#/definitions/sales-data-invoice-comment-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"sales-data-creditmemo-item-creation-interface":{"type":"object","description":"Interface CreditmemoItemCreationInterface","properties":{"extension_attributes":{"$ref":"#/definitions/sales-data-creditmemo-item-creation-extension-interface"},"order_item_id":{"type":"integer","description":"Order item ID."},"qty":{"type":"number","description":"Quantity."}},"required":["order_item_id","qty"]},"sales-data-creditmemo-item-creation-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\CreditmemoItemCreationInterface"},"sales-data-creditmemo-comment-creation-interface":{"type":"object","description":"Interface CreditmemoCommentCreationInterface","properties":{"extension_attributes":{"$ref":"#/definitions/sales-data-creditmemo-comment-creation-extension-interface"},"comment":{"type":"string","description":"Comment."},"is_visible_on_front":{"type":"integer","description":"Is-visible-on-storefront flag value."}},"required":["comment","is_visible_on_front"]},"sales-data-creditmemo-comment-creation-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\CreditmemoCommentCreationInterface"},"sales-data-creditmemo-creation-arguments-interface":{"type":"object","description":"Interface CreditmemoCreationArgumentsInterface","properties":{"shipping_amount":{"type":"number","description":"Credit memo shipping amount."},"adjustment_positive":{"type":"number","description":"Credit memo positive adjustment."},"adjustment_negative":{"type":"number","description":"Credit memo negative adjustment."},"extension_attributes":{"$ref":"#/definitions/sales-data-creditmemo-creation-arguments-extension-interface"}}},"sales-data-creditmemo-creation-arguments-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\CreditmemoCreationArgumentsInterface","properties":{"return_to_stock_items":{"type":"array","items":{"type":"integer"}}}},"sales-data-creditmemo-comment-search-result-interface":{"type":"object","description":"Credit memo comment search result interface. After a customer places and pays for an order and an invoice has been issued, the merchant can create a credit memo to refund all or part of the amount paid for any returned or undelivered items. The memo restores funds to the customer account so that the customer can make future purchases. A credit memo usually includes comments that detail why the credit memo amount was credited to the customer.","properties":{"items":{"type":"array","description":"Array of collection items.","items":{"$ref":"#/definitions/sales-data-creditmemo-comment-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"sales-data-creditmemo-comment-interface":{"type":"object","description":"Credit memo comment interface. After a customer places and pays for an order and an invoice has been issued, the merchant can create a credit memo to refund all or part of the amount paid for any returned or undelivered items. The memo restores funds to the customer account so that the customer can make future purchases. A credit memo usually includes comments that detail why the credit memo amount was credited to the customer.","properties":{"comment":{"type":"string","description":"Comment."},"created_at":{"type":"string","description":"Created-at timestamp."},"entity_id":{"type":"integer","description":"Credit memo ID."},"is_customer_notified":{"type":"integer","description":"Is-customer-notified flag value."},"is_visible_on_front":{"type":"integer","description":"Is-visible-on-storefront flag value."},"parent_id":{"type":"integer","description":"Parent ID."},"extension_attributes":{"$ref":"#/definitions/sales-data-creditmemo-comment-extension-interface"}},"required":["comment","is_customer_notified","is_visible_on_front","parent_id"]},"sales-data-creditmemo-comment-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\CreditmemoCommentInterface"},"sales-data-creditmemo-interface":{"type":"object","description":"Credit memo interface. After a customer places and pays for an order and an invoice has been issued, the merchant can create a credit memo to refund all or part of the amount paid for any returned or undelivered items. The memo restores funds to the customer account so that the customer can make future purchases.","properties":{"adjustment":{"type":"number","description":"Credit memo adjustment."},"adjustment_negative":{"type":"number","description":"Credit memo negative adjustment."},"adjustment_positive":{"type":"number","description":"Credit memo positive adjustment."},"base_adjustment":{"type":"number","description":"Credit memo base adjustment."},"base_adjustment_negative":{"type":"number","description":"Credit memo negative base adjustment."},"base_adjustment_positive":{"type":"number","description":"Credit memo positive base adjustment."},"base_currency_code":{"type":"string","description":"Credit memo base currency code."},"base_discount_amount":{"type":"number","description":"Credit memo base discount amount."},"base_grand_total":{"type":"number","description":"Credit memo base grand total."},"base_discount_tax_compensation_amount":{"type":"number","description":"Credit memo base discount tax compensation amount."},"base_shipping_amount":{"type":"number","description":"Credit memo base shipping amount."},"base_shipping_discount_tax_compensation_amnt":{"type":"number","description":"Credit memo base shipping discount tax compensation amount."},"base_shipping_incl_tax":{"type":"number","description":"Credit memo base shipping including tax."},"base_shipping_tax_amount":{"type":"number","description":"Credit memo base shipping tax amount."},"base_subtotal":{"type":"number","description":"Credit memo base subtotal."},"base_subtotal_incl_tax":{"type":"number","description":"Credit memo base subtotal including tax."},"base_tax_amount":{"type":"number","description":"Credit memo base tax amount."},"base_to_global_rate":{"type":"number","description":"Credit memo base-to-global rate."},"base_to_order_rate":{"type":"number","description":"Credit memo base-to-order rate."},"billing_address_id":{"type":"integer","description":"Credit memo billing address ID."},"created_at":{"type":"string","description":"Credit memo created-at timestamp."},"creditmemo_status":{"type":"integer","description":"Credit memo status."},"discount_amount":{"type":"number","description":"Credit memo discount amount."},"discount_description":{"type":"string","description":"Credit memo discount description."},"email_sent":{"type":"integer","description":"Credit memo email sent flag value."},"entity_id":{"type":"integer","description":"Credit memo ID."},"global_currency_code":{"type":"string","description":"Credit memo global currency code."},"grand_total":{"type":"number","description":"Credit memo grand total."},"discount_tax_compensation_amount":{"type":"number","description":"Credit memo discount tax compensation amount."},"increment_id":{"type":"string","description":"Credit memo increment ID."},"invoice_id":{"type":"integer","description":"Credit memo invoice ID."},"order_currency_code":{"type":"string","description":"Credit memo order currency code."},"order_id":{"type":"integer","description":"Credit memo order ID."},"shipping_address_id":{"type":"integer","description":"Credit memo shipping address ID."},"shipping_amount":{"type":"number","description":"Credit memo shipping amount."},"shipping_discount_tax_compensation_amount":{"type":"number","description":"Credit memo shipping discount tax compensation amount."},"shipping_incl_tax":{"type":"number","description":"Credit memo shipping including tax."},"shipping_tax_amount":{"type":"number","description":"Credit memo shipping tax amount."},"state":{"type":"integer","description":"Credit memo state."},"store_currency_code":{"type":"string","description":"Credit memo store currency code."},"store_id":{"type":"integer","description":"Credit memo store ID."},"store_to_base_rate":{"type":"number","description":"Credit memo store-to-base rate."},"store_to_order_rate":{"type":"number","description":"Credit memo store-to-order rate."},"subtotal":{"type":"number","description":"Credit memo subtotal."},"subtotal_incl_tax":{"type":"number","description":"Credit memo subtotal including tax."},"tax_amount":{"type":"number","description":"Credit memo tax amount."},"transaction_id":{"type":"string","description":"Credit memo transaction ID."},"updated_at":{"type":"string","description":"Credit memo updated-at timestamp."},"items":{"type":"array","description":"Array of credit memo items.","items":{"$ref":"#/definitions/sales-data-creditmemo-item-interface"}},"comments":{"type":"array","description":"Array of any credit memo comments. Otherwise, null.","items":{"$ref":"#/definitions/sales-data-creditmemo-comment-interface"}},"extension_attributes":{"$ref":"#/definitions/sales-data-creditmemo-extension-interface"}},"required":["order_id","items"]},"sales-data-creditmemo-item-interface":{"type":"object","description":"Credit memo item interface. After a customer places and pays for an order and an invoice has been issued, the merchant can create a credit memo to refund all or part of the amount paid for any returned or undelivered items. The memo restores funds to the customer account so that the customer can make future purchases. A credit memo item is an invoiced item for which a merchant creates a credit memo.","properties":{"additional_data":{"type":"string","description":"Additional data."},"base_cost":{"type":"number","description":"The base cost for a credit memo item."},"base_discount_amount":{"type":"number","description":"The base discount amount for a credit memo item."},"base_discount_tax_compensation_amount":{"type":"number","description":"The base discount tax compensation amount for a credit memo item."},"base_price":{"type":"number","description":"The base price for a credit memo item."},"base_price_incl_tax":{"type":"number","description":"Base price including tax."},"base_row_total":{"type":"number","description":"Base row total."},"base_row_total_incl_tax":{"type":"number","description":"Base row total including tax."},"base_tax_amount":{"type":"number","description":"Base tax amount."},"base_weee_tax_applied_amount":{"type":"number","description":"Base WEEE tax applied amount."},"base_weee_tax_applied_row_amnt":{"type":"number","description":"Base WEEE tax applied row amount."},"base_weee_tax_disposition":{"type":"number","description":"Base WEEE tax disposition."},"base_weee_tax_row_disposition":{"type":"number","description":"Base WEEE tax row disposition."},"description":{"type":"string","description":"Description."},"discount_amount":{"type":"number","description":"Discount amount."},"entity_id":{"type":"integer","description":"Credit memo item ID."},"discount_tax_compensation_amount":{"type":"number","description":"Discount tax compensation amount."},"name":{"type":"string","description":"Name."},"order_item_id":{"type":"integer","description":"Order item ID."},"parent_id":{"type":"integer","description":"Parent ID."},"price":{"type":"number","description":"Price."},"price_incl_tax":{"type":"number","description":"Price including tax."},"product_id":{"type":"integer","description":"Product ID."},"qty":{"type":"number","description":"Quantity."},"row_total":{"type":"number","description":"Row total."},"row_total_incl_tax":{"type":"number","description":"Row total including tax."},"sku":{"type":"string","description":"SKU."},"tax_amount":{"type":"number","description":"Tax amount."},"weee_tax_applied":{"type":"string","description":"WEEE tax applied."},"weee_tax_applied_amount":{"type":"number","description":"WEEE tax applied amount."},"weee_tax_applied_row_amount":{"type":"number","description":"WEEE tax applied row amount."},"weee_tax_disposition":{"type":"number","description":"WEEE tax disposition."},"weee_tax_row_disposition":{"type":"number","description":"WEEE tax row disposition."},"extension_attributes":{"$ref":"#/definitions/sales-data-creditmemo-item-extension-interface"}},"required":["base_cost","base_price","entity_id","order_item_id","qty"]},"sales-data-creditmemo-item-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\CreditmemoItemInterface"},"sales-data-creditmemo-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\CreditmemoInterface","properties":{"base_customer_balance_amount":{"type":"number"},"customer_balance_amount":{"type":"number"},"base_gift_cards_amount":{"type":"number"},"gift_cards_amount":{"type":"number"},"gw_base_price":{"type":"string"},"gw_price":{"type":"string"},"gw_items_base_price":{"type":"string"},"gw_items_price":{"type":"string"},"gw_card_base_price":{"type":"string"},"gw_card_price":{"type":"string"},"gw_base_tax_amount":{"type":"string"},"gw_tax_amount":{"type":"string"},"gw_items_base_tax_amount":{"type":"string"},"gw_items_tax_amount":{"type":"string"},"gw_card_base_tax_amount":{"type":"string"},"gw_card_tax_amount":{"type":"string"}}},"sales-data-creditmemo-search-result-interface":{"type":"object","description":"Credit memo search result interface. After a customer places and pays for an order and an invoice has been issued, the merchant can create a credit memo to refund all or part of the amount paid for any returned or undelivered items. The memo restores funds to the customer account so that the customer can make future purchases.","properties":{"items":{"type":"array","description":"Array of collection items.","items":{"$ref":"#/definitions/sales-data-creditmemo-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"sales-data-shipment-interface":{"type":"object","description":"Shipment interface. A shipment is a delivery package that contains products. A shipment document accompanies the shipment. This document lists the products and their quantities in the delivery package.","properties":{"billing_address_id":{"type":"integer","description":"Billing address ID."},"created_at":{"type":"string","description":"Created-at timestamp."},"customer_id":{"type":"integer","description":"Customer ID."},"email_sent":{"type":"integer","description":"Email-sent flag value."},"entity_id":{"type":"integer","description":"Shipment ID."},"increment_id":{"type":"string","description":"Increment ID."},"order_id":{"type":"integer","description":"Order ID."},"packages":{"type":"array","description":"Array of packages, if any. Otherwise, null.","items":{"$ref":"#/definitions/sales-data-shipment-package-interface"}},"shipment_status":{"type":"integer","description":"Shipment status."},"shipping_address_id":{"type":"integer","description":"Shipping address ID."},"shipping_label":{"type":"string","description":"Shipping label."},"store_id":{"type":"integer","description":"Store ID."},"total_qty":{"type":"number","description":"Total quantity."},"total_weight":{"type":"number","description":"Total weight."},"updated_at":{"type":"string","description":"Updated-at timestamp."},"items":{"type":"array","description":"Array of items.","items":{"$ref":"#/definitions/sales-data-shipment-item-interface"}},"tracks":{"type":"array","description":"Array of tracks.","items":{"$ref":"#/definitions/sales-data-shipment-track-interface"}},"comments":{"type":"array","description":"Array of comments.","items":{"$ref":"#/definitions/sales-data-shipment-comment-interface"}},"extension_attributes":{"$ref":"#/definitions/sales-data-shipment-extension-interface"}},"required":["order_id","items","tracks","comments"]},"sales-data-shipment-package-interface":{"type":"object","description":"Shipment package interface. A shipment is a delivery package that contains products. A shipment document accompanies the shipment. This document lists the products and their quantities in the delivery package.","properties":{"extension_attributes":{"$ref":"#/definitions/sales-data-shipment-package-extension-interface"}}},"sales-data-shipment-package-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\ShipmentPackageInterface"},"sales-data-shipment-item-interface":{"type":"object","description":"Shipment item interface. A shipment is a delivery package that contains products. A shipment document accompanies the shipment. This document lists the products and their quantities in the delivery package. A product is an item in a shipment.","properties":{"additional_data":{"type":"string","description":"Additional data."},"description":{"type":"string","description":"Description."},"entity_id":{"type":"integer","description":"Shipment item ID."},"name":{"type":"string","description":"Name."},"parent_id":{"type":"integer","description":"Parent ID."},"price":{"type":"number","description":"Price."},"product_id":{"type":"integer","description":"Product ID."},"row_total":{"type":"number","description":"Row total."},"sku":{"type":"string","description":"SKU."},"weight":{"type":"number","description":"Weight."},"extension_attributes":{"$ref":"#/definitions/sales-data-shipment-item-extension-interface"},"order_item_id":{"type":"integer","description":"Order item ID."},"qty":{"type":"number","description":"Quantity."}},"required":["order_item_id","qty"]},"sales-data-shipment-item-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\ShipmentItemInterface"},"sales-data-shipment-track-interface":{"type":"object","description":"Shipment track interface. A shipment is a delivery package that contains products. A shipment document accompanies the shipment. This document lists the products and their quantities in the delivery package. Merchants and customers can track shipments.","properties":{"order_id":{"type":"integer","description":"The order_id for the shipment package."},"created_at":{"type":"string","description":"Created-at timestamp."},"entity_id":{"type":"integer","description":"Shipment package ID."},"parent_id":{"type":"integer","description":"Parent ID."},"updated_at":{"type":"string","description":"Updated-at timestamp."},"weight":{"type":"number","description":"Weight."},"qty":{"type":"number","description":"Quantity."},"description":{"type":"string","description":"Description."},"extension_attributes":{"$ref":"#/definitions/sales-data-shipment-track-extension-interface"},"track_number":{"type":"string","description":"Track number."},"title":{"type":"string","description":"Title."},"carrier_code":{"type":"string","description":"Carrier code."}},"required":["order_id","parent_id","weight","qty","description","track_number","title","carrier_code"]},"sales-data-shipment-track-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\ShipmentTrackInterface"},"sales-data-shipment-comment-interface":{"type":"object","description":"Shipment comment interface. A shipment is a delivery package that contains products. A shipment document accompanies the shipment. This document lists the products and their quantities in the delivery package. A shipment document can contain comments.","properties":{"is_customer_notified":{"type":"integer","description":"Is-customer-notified flag value."},"parent_id":{"type":"integer","description":"Parent ID."},"extension_attributes":{"$ref":"#/definitions/sales-data-shipment-comment-extension-interface"},"comment":{"type":"string","description":"Comment."},"is_visible_on_front":{"type":"integer","description":"Is-visible-on-storefront flag value."},"created_at":{"type":"string","description":"Created-at timestamp."},"entity_id":{"type":"integer","description":"Invoice ID."}},"required":["is_customer_notified","parent_id","comment","is_visible_on_front"]},"sales-data-shipment-comment-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\ShipmentCommentInterface"},"sales-data-shipment-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\ShipmentInterface"},"sales-data-shipment-search-result-interface":{"type":"object","description":"Shipment search result interface. A shipment is a delivery package that contains products. A shipment document accompanies the shipment. This document lists the products and their quantities in the delivery package.","properties":{"items":{"type":"array","description":"Array of collection items.","items":{"$ref":"#/definitions/sales-data-shipment-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"sales-data-shipment-comment-search-result-interface":{"type":"object","description":"Shipment comment search result interface. A shipment is a delivery package that contains products. A shipment document accompanies the shipment. This document lists the products and their quantities in the delivery package. A shipment document can contain comments.","properties":{"items":{"type":"array","description":"Array of collection items.","items":{"$ref":"#/definitions/sales-data-shipment-comment-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"sales-data-shipment-item-creation-interface":{"type":"object","description":"Input argument for shipment item creation Interface ShipmentItemCreationInterface","properties":{"extension_attributes":{"$ref":"#/definitions/sales-data-shipment-item-creation-extension-interface"},"order_item_id":{"type":"integer","description":"Order item ID."},"qty":{"type":"number","description":"Quantity."}},"required":["order_item_id","qty"]},"sales-data-shipment-item-creation-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\ShipmentItemCreationInterface"},"sales-data-shipment-comment-creation-interface":{"type":"object","description":"Interface ShipmentCommentCreationInterface","properties":{"extension_attributes":{"$ref":"#/definitions/sales-data-shipment-comment-creation-extension-interface"},"comment":{"type":"string","description":"Comment."},"is_visible_on_front":{"type":"integer","description":"Is-visible-on-storefront flag value."}},"required":["comment","is_visible_on_front"]},"sales-data-shipment-comment-creation-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\ShipmentCommentCreationInterface"},"sales-data-shipment-track-creation-interface":{"type":"object","description":"Shipment Track Creation interface.","properties":{"extension_attributes":{"$ref":"#/definitions/sales-data-shipment-track-creation-extension-interface"},"track_number":{"type":"string","description":"Track number."},"title":{"type":"string","description":"Title."},"carrier_code":{"type":"string","description":"Carrier code."}},"required":["track_number","title","carrier_code"]},"sales-data-shipment-track-creation-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\ShipmentTrackCreationInterface"},"sales-data-shipment-package-creation-interface":{"type":"object","description":"Shipment package interface. A shipment is a delivery package that contains products. A shipment document accompanies the shipment. This document lists the products and their quantities in the delivery package.","properties":{"extension_attributes":{"$ref":"#/definitions/sales-data-shipment-package-creation-extension-interface"}}},"sales-data-shipment-package-creation-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\ShipmentPackageCreationInterface"},"sales-data-shipment-creation-arguments-interface":{"type":"object","description":"Interface for creation arguments for Shipment.","properties":{"extension_attributes":{"$ref":"#/definitions/sales-data-shipment-creation-arguments-extension-interface"}}},"sales-data-shipment-creation-arguments-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\ShipmentCreationArgumentsInterface"},"sales-data-transaction-interface":{"type":"object","description":"Transaction interface. A transaction is an interaction between a merchant and a customer such as a purchase, a credit, a refund, and so on.","properties":{"transaction_id":{"type":"integer","description":"Transaction ID."},"parent_id":{"type":"integer","description":"The parent ID for the transaction. Otherwise, null."},"order_id":{"type":"integer","description":"Order ID."},"payment_id":{"type":"integer","description":"Payment ID."},"txn_id":{"type":"string","description":"Transaction business ID."},"parent_txn_id":{"type":"string","description":"Parent transaction business ID."},"txn_type":{"type":"string","description":"Transaction type."},"is_closed":{"type":"integer","description":"Is-closed flag value."},"additional_information":{"type":"array","description":"Array of additional information. Otherwise, null.","items":{"type":"string"}},"created_at":{"type":"string","description":"Created-at timestamp."},"child_transactions":{"type":"array","description":"Array of child transactions.","items":{"$ref":"#/definitions/sales-data-transaction-interface"}},"extension_attributes":{"$ref":"#/definitions/sales-data-transaction-extension-interface"}},"required":["transaction_id","order_id","payment_id","txn_id","parent_txn_id","txn_type","is_closed","created_at","child_transactions"]},"sales-data-transaction-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\TransactionInterface"},"sales-data-transaction-search-result-interface":{"type":"object","description":"Transaction search result interface. A transaction is an interaction between a merchant and a customer such as a purchase, a credit, a refund, and so on.","properties":{"items":{"type":"array","description":"Array of collection items.","items":{"$ref":"#/definitions/sales-data-transaction-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"sales-data-invoice-item-creation-interface":{"type":"object","description":"Input argument for invoice creation Interface InvoiceItemCreationInterface","properties":{"extension_attributes":{"$ref":"#/definitions/sales-data-invoice-item-creation-extension-interface"},"order_item_id":{"type":"integer","description":"Order item ID."},"qty":{"type":"number","description":"Quantity."}},"required":["order_item_id","qty"]},"sales-data-invoice-item-creation-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\InvoiceItemCreationInterface"},"sales-data-invoice-comment-creation-interface":{"type":"object","description":"Interface InvoiceCommentCreationInterface","properties":{"extension_attributes":{"$ref":"#/definitions/sales-data-invoice-comment-creation-extension-interface"},"comment":{"type":"string","description":"Comment."},"is_visible_on_front":{"type":"integer","description":"Is-visible-on-storefront flag value."}},"required":["comment","is_visible_on_front"]},"sales-data-invoice-comment-creation-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\InvoiceCommentCreationInterface"},"sales-data-invoice-creation-arguments-interface":{"type":"object","description":"Interface for creation arguments for Invoice.","properties":{"extension_attributes":{"$ref":"#/definitions/sales-data-invoice-creation-arguments-extension-interface"}}},"sales-data-invoice-creation-arguments-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\InvoiceCreationArgumentsInterface"},"checkout-data-shipping-information-interface":{"type":"object","description":"Interface ShippingInformationInterface","properties":{"shipping_address":{"$ref":"#/definitions/quote-data-address-interface"},"billing_address":{"$ref":"#/definitions/quote-data-address-interface"},"shipping_method_code":{"type":"string","description":"Shipping method code"},"shipping_carrier_code":{"type":"string","description":"Carrier code"},"extension_attributes":{"$ref":"#/definitions/checkout-data-shipping-information-extension-interface"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["shipping_address","shipping_method_code","shipping_carrier_code"]},"checkout-data-shipping-information-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Checkout\\Api\\Data\\ShippingInformationInterface"},"checkout-data-payment-details-interface":{"type":"object","description":"Interface PaymentDetailsInterface","properties":{"payment_methods":{"type":"array","items":{"$ref":"#/definitions/quote-data-payment-method-interface"}},"totals":{"$ref":"#/definitions/quote-data-totals-interface"},"extension_attributes":{"$ref":"#/definitions/checkout-data-payment-details-extension-interface"}},"required":["payment_methods","totals"]},"checkout-data-payment-details-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Checkout\\Api\\Data\\PaymentDetailsInterface"},"checkout-data-totals-information-interface":{"type":"object","description":"Interface TotalsInformationInterface","properties":{"address":{"$ref":"#/definitions/quote-data-address-interface"},"shipping_method_code":{"type":"string","description":"Shipping method code"},"shipping_carrier_code":{"type":"string","description":"Carrier code"},"extension_attributes":{"$ref":"#/definitions/checkout-data-totals-information-extension-interface"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["address"]},"checkout-data-totals-information-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Checkout\\Api\\Data\\TotalsInformationInterface"},"checkout-agreements-data-agreement-interface":{"type":"object","description":"Interface AgreementInterface","properties":{"agreement_id":{"type":"integer","description":"Agreement ID."},"name":{"type":"string","description":"Agreement name."},"content":{"type":"string","description":"Agreement content."},"content_height":{"type":"string","description":"Agreement content height. Otherwise, null."},"checkbox_text":{"type":"string","description":"Agreement checkbox text."},"is_active":{"type":"boolean","description":"Agreement status."},"is_html":{"type":"boolean","description":"* true - HTML. * false - plain text."},"mode":{"type":"integer","description":"The agreement applied mode."},"extension_attributes":{"$ref":"#/definitions/checkout-agreements-data-agreement-extension-interface"}},"required":["agreement_id","name","content","checkbox_text","is_active","is_html","mode"]},"checkout-agreements-data-agreement-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\CheckoutAgreements\\Api\\Data\\AgreementInterface"},"gift-card-account-data-gift-card-account-interface":{"type":"object","description":"Gift Card Account data","properties":{"gift_cards":{"type":"array","description":"Cards codes","items":{"type":"string"}},"gift_cards_amount":{"type":"number","description":"Cards amount in quote currency"},"base_gift_cards_amount":{"type":"number","description":"Cards amount in base currency"},"gift_cards_amount_used":{"type":"number","description":"Cards amount used in quote currency"},"base_gift_cards_amount_used":{"type":"number","description":"Cards amount used in base currency"},"extension_attributes":{"$ref":"#/definitions/gift-card-account-data-gift-card-account-extension-interface"}},"required":["gift_cards","gift_cards_amount","base_gift_cards_amount","gift_cards_amount_used","base_gift_cards_amount_used"]},"gift-card-account-data-gift-card-account-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\GiftCardAccount\\Api\\Data\\GiftCardAccountInterface"},"tax-data-tax-rate-interface":{"type":"object","description":"Tax rate interface.","properties":{"id":{"type":"integer","description":"Id"},"tax_country_id":{"type":"string","description":"Country id"},"tax_region_id":{"type":"integer","description":"Region id"},"region_name":{"type":"string","description":"Region name"},"tax_postcode":{"type":"string","description":"Postcode"},"zip_is_range":{"type":"integer","description":"Zip is range"},"zip_from":{"type":"integer","description":"Zip range from"},"zip_to":{"type":"integer","description":"Zip range to"},"rate":{"type":"number","description":"Tax rate in percentage"},"code":{"type":"string","description":"Tax rate code"},"titles":{"type":"array","description":"Tax rate titles","items":{"$ref":"#/definitions/tax-data-tax-rate-title-interface"}},"extension_attributes":{"$ref":"#/definitions/tax-data-tax-rate-extension-interface"}},"required":["tax_country_id","rate","code"]},"tax-data-tax-rate-title-interface":{"type":"object","description":"Tax rate title interface.","properties":{"store_id":{"type":"string","description":"Store id"},"value":{"type":"string","description":"Title value"},"extension_attributes":{"$ref":"#/definitions/tax-data-tax-rate-title-extension-interface"}},"required":["store_id","value"]},"tax-data-tax-rate-title-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Tax\\Api\\Data\\TaxRateTitleInterface"},"tax-data-tax-rate-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Tax\\Api\\Data\\TaxRateInterface"},"tax-data-tax-rate-search-results-interface":{"type":"object","description":"Interface for tax rate search results.","properties":{"items":{"type":"array","description":"Items","items":{"$ref":"#/definitions/tax-data-tax-rate-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"tax-data-tax-rule-interface":{"type":"object","description":"Tax rule interface.","properties":{"id":{"type":"integer","description":"Id"},"code":{"type":"string","description":"Tax rule code"},"priority":{"type":"integer","description":"Priority"},"position":{"type":"integer","description":"Sort order."},"customer_tax_class_ids":{"type":"array","description":"Customer tax class id","items":{"type":"integer"}},"product_tax_class_ids":{"type":"array","description":"Product tax class id","items":{"type":"integer"}},"tax_rate_ids":{"type":"array","description":"Tax rate ids","items":{"type":"integer"}},"calculate_subtotal":{"type":"boolean","description":"Calculate subtotal."},"extension_attributes":{"$ref":"#/definitions/tax-data-tax-rule-extension-interface"}},"required":["code","priority","position","customer_tax_class_ids","product_tax_class_ids","tax_rate_ids"]},"tax-data-tax-rule-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Tax\\Api\\Data\\TaxRuleInterface"},"tax-data-tax-rule-search-results-interface":{"type":"object","description":"Interface for tax rule search results.","properties":{"items":{"type":"array","description":"Items","items":{"$ref":"#/definitions/tax-data-tax-rule-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"tax-data-tax-class-interface":{"type":"object","description":"Tax class interface.","properties":{"class_id":{"type":"integer","description":"Tax class ID."},"class_name":{"type":"string","description":"Tax class name."},"class_type":{"type":"string","description":"Tax class type."},"extension_attributes":{"$ref":"#/definitions/tax-data-tax-class-extension-interface"}},"required":["class_name","class_type"]},"tax-data-tax-class-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Tax\\Api\\Data\\TaxClassInterface"},"tax-data-tax-class-search-results-interface":{"type":"object","description":"Interface for tax class search results.","properties":{"items":{"type":"array","description":"Items","items":{"$ref":"#/definitions/tax-data-tax-class-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"gift-wrapping-data-wrapping-interface":{"type":"object","description":"Interface WrappingInterface","properties":{"wrapping_id":{"type":"integer"},"design":{"type":"string"},"status":{"type":"integer"},"base_price":{"type":"number"},"image_name":{"type":"string"},"image_base64_content":{"type":"string"},"base_currency_code":{"type":"string"},"website_ids":{"type":"array","items":{"type":"integer"}},"image_url":{"type":"string","description":"Wrapping image URL."},"extension_attributes":{"$ref":"#/definitions/gift-wrapping-data-wrapping-extension-interface"}},"required":["design","status","base_price"]},"gift-wrapping-data-wrapping-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\GiftWrapping\\Api\\Data\\WrappingInterface"},"gift-wrapping-data-wrapping-search-results-interface":{"type":"object","description":"Interface WrappingSearchResultsInterface","properties":{"items":{"type":"array","description":"Items","items":{"$ref":"#/definitions/gift-wrapping-data-wrapping-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"sales-rule-data-rule-interface":{"type":"object","description":"Interface RuleInterface","properties":{"rule_id":{"type":"integer","description":"Rule id"},"name":{"type":"string","description":"Rule name"},"store_labels":{"type":"array","description":"Display label","items":{"$ref":"#/definitions/sales-rule-data-rule-label-interface"}},"description":{"type":"string","description":"Description"},"website_ids":{"type":"array","description":"A list of websites the rule applies to","items":{"type":"integer"}},"customer_group_ids":{"type":"array","description":"Ids of customer groups that the rule applies to","items":{"type":"integer"}},"from_date":{"type":"string","description":"The start date when the coupon is active"},"to_date":{"type":"string","description":"The end date when the coupon is active"},"uses_per_customer":{"type":"integer","description":"Number of uses per customer"},"is_active":{"type":"boolean","description":"The coupon is active"},"condition":{"$ref":"#/definitions/sales-rule-data-condition-interface"},"action_condition":{"$ref":"#/definitions/sales-rule-data-condition-interface"},"stop_rules_processing":{"type":"boolean","description":"To stop rule processing"},"is_advanced":{"type":"boolean","description":"Is this field needed"},"product_ids":{"type":"array","description":"Product ids","items":{"type":"integer"}},"sort_order":{"type":"integer","description":"Sort order"},"simple_action":{"type":"string","description":"Simple action of the rule"},"discount_amount":{"type":"number","description":"Discount amount"},"discount_qty":{"type":"number","description":"Maximum qty discount is applied"},"discount_step":{"type":"integer","description":"Discount step"},"apply_to_shipping":{"type":"boolean","description":"The rule applies to shipping"},"times_used":{"type":"integer","description":"How many times the rule has been used"},"is_rss":{"type":"boolean","description":"Whether the rule is in RSS"},"coupon_type":{"type":"string","description":"Coupon type"},"use_auto_generation":{"type":"boolean","description":"To auto generate coupon"},"uses_per_coupon":{"type":"integer","description":"Limit of uses per coupon"},"simple_free_shipping":{"type":"string","description":"To grant free shipping"},"extension_attributes":{"$ref":"#/definitions/sales-rule-data-rule-extension-interface"}},"required":["website_ids","customer_group_ids","uses_per_customer","is_active","stop_rules_processing","is_advanced","sort_order","discount_amount","discount_step","apply_to_shipping","times_used","is_rss","coupon_type","use_auto_generation","uses_per_coupon"]},"sales-rule-data-rule-label-interface":{"type":"object","description":"Interface RuleLabelInterface","properties":{"store_id":{"type":"integer","description":"StoreId"},"store_label":{"type":"string","description":"The label for the store"},"extension_attributes":{"$ref":"#/definitions/sales-rule-data-rule-label-extension-interface"}},"required":["store_id","store_label"]},"sales-rule-data-rule-label-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\SalesRule\\Api\\Data\\RuleLabelInterface"},"sales-rule-data-condition-interface":{"type":"object","description":"Interface ConditionInterface","properties":{"condition_type":{"type":"string","description":"Condition type"},"conditions":{"type":"array","description":"List of conditions","items":{"$ref":"#/definitions/sales-rule-data-condition-interface"}},"aggregator_type":{"type":"string","description":"The aggregator type"},"operator":{"type":"string","description":"The operator of the condition"},"attribute_name":{"type":"string","description":"The attribute name of the condition"},"value":{"type":"string","description":"The value of the condition"},"extension_attributes":{"$ref":"#/definitions/sales-rule-data-condition-extension-interface"}},"required":["condition_type","operator","value"]},"sales-rule-data-condition-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\SalesRule\\Api\\Data\\ConditionInterface"},"sales-rule-data-rule-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\SalesRule\\Api\\Data\\RuleInterface","properties":{"reward_points_delta":{"type":"integer"}}},"sales-rule-data-rule-search-result-interface":{"type":"object","description":"","properties":{"items":{"type":"array","description":"Rules.","items":{"$ref":"#/definitions/sales-rule-data-rule-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"sales-rule-data-coupon-interface":{"type":"object","description":"Interface CouponInterface","properties":{"coupon_id":{"type":"integer","description":"Coupon id"},"rule_id":{"type":"integer","description":"The id of the rule associated with the coupon"},"code":{"type":"string","description":"Coupon code"},"usage_limit":{"type":"integer","description":"Usage limit"},"usage_per_customer":{"type":"integer","description":"Usage limit per customer"},"times_used":{"type":"integer","description":"The number of times the coupon has been used"},"expiration_date":{"type":"string","description":"Expiration date"},"is_primary":{"type":"boolean","description":"The coupon is primary coupon for the rule that it's associated with"},"created_at":{"type":"string","description":"When the coupon is created"},"type":{"type":"integer","description":"Of coupon"},"extension_attributes":{"$ref":"#/definitions/sales-rule-data-coupon-extension-interface"}},"required":["rule_id","times_used","is_primary"]},"sales-rule-data-coupon-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\SalesRule\\Api\\Data\\CouponInterface"},"sales-rule-data-coupon-search-result-interface":{"type":"object","description":"","properties":{"items":{"type":"array","description":"Rules.","items":{"$ref":"#/definitions/sales-rule-data-coupon-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"sales-rule-data-coupon-generation-spec-interface":{"type":"object","description":"CouponGenerationSpecInterface","properties":{"rule_id":{"type":"integer","description":"The id of the rule associated with the coupon"},"format":{"type":"string","description":"Format of generated coupon code"},"quantity":{"type":"integer","description":"Of coupons to generate"},"length":{"type":"integer","description":"Length of coupon code"},"prefix":{"type":"string","description":"The prefix"},"suffix":{"type":"string","description":"The suffix"},"delimiter_at_every":{"type":"integer","description":"The spacing where the delimiter should exist"},"delimiter":{"type":"string","description":"The delimiter"},"extension_attributes":{"$ref":"#/definitions/sales-rule-data-coupon-generation-spec-extension-interface"}},"required":["rule_id","format","quantity","length"]},"sales-rule-data-coupon-generation-spec-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\SalesRule\\Api\\Data\\CouponGenerationSpecInterface"},"sales-rule-data-coupon-mass-delete-result-interface":{"type":"object","description":"Coupon mass delete results interface.","properties":{"failed_items":{"type":"array","description":"List of failed items.","items":{"type":"string"}},"missing_items":{"type":"array","description":"List of missing items.","items":{"type":"string"}}},"required":["failed_items","missing_items"]},"rma-data-track-interface":{"type":"object","description":"Interface TrackInterface","properties":{"entity_id":{"type":"integer","description":"Entity id"},"rma_entity_id":{"type":"integer","description":"Rma entity id"},"track_number":{"type":"string","description":"Track number"},"carrier_title":{"type":"string","description":"Carrier title"},"carrier_code":{"type":"string","description":"Carrier code"},"extension_attributes":{"$ref":"#/definitions/rma-data-track-extension-interface"}},"required":["entity_id","rma_entity_id","track_number","carrier_title","carrier_code"]},"rma-data-track-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Rma\\Api\\Data\\TrackInterface"},"rma-data-track-search-result-interface":{"type":"object","description":"Interface TrackSearchResultInterface","properties":{"items":{"type":"array","description":"Rma list","items":{"$ref":"#/definitions/rma-data-track-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"rma-data-rma-interface":{"type":"object","description":"Interface RmaInterface","properties":{"increment_id":{"type":"string","description":"Entity_id"},"entity_id":{"type":"integer","description":"Entity_id"},"order_id":{"type":"integer","description":"Order_id"},"order_increment_id":{"type":"string","description":"Order_increment_id"},"store_id":{"type":"integer","description":"Store_id"},"customer_id":{"type":"integer","description":"Customer_id"},"date_requested":{"type":"string","description":"Date_requested"},"customer_custom_email":{"type":"string","description":"Customer_custom_email"},"items":{"type":"array","description":"Items","items":{"$ref":"#/definitions/rma-data-item-interface"}},"status":{"type":"string","description":"Status"},"comments":{"type":"array","description":"Comments list","items":{"$ref":"#/definitions/rma-data-comment-interface"}},"tracks":{"type":"array","description":"Tracks list","items":{"$ref":"#/definitions/rma-data-track-interface"}},"extension_attributes":{"$ref":"#/definitions/rma-data-rma-extension-interface"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["increment_id","entity_id","order_id","order_increment_id","store_id","customer_id","date_requested","customer_custom_email","items","status","comments","tracks"]},"rma-data-item-interface":{"type":"object","description":"Interface CategoryInterface","properties":{"entity_id":{"type":"integer","description":"Id"},"rma_entity_id":{"type":"integer","description":"RMA id"},"order_item_id":{"type":"integer","description":"Order_item_id"},"qty_requested":{"type":"integer","description":"Qty_requested"},"qty_authorized":{"type":"integer","description":"Qty_authorized"},"qty_approved":{"type":"integer","description":"Qty_approved"},"qty_returned":{"type":"integer","description":"Qty_returned"},"reason":{"type":"string","description":"Reason"},"condition":{"type":"string","description":"Condition"},"resolution":{"type":"string","description":"Resolution"},"status":{"type":"string","description":"Status"},"extension_attributes":{"$ref":"#/definitions/rma-data-item-extension-interface"}},"required":["entity_id","rma_entity_id","order_item_id","qty_requested","qty_authorized","qty_approved","qty_returned","reason","condition","resolution","status"]},"rma-data-item-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Rma\\Api\\Data\\ItemInterface"},"rma-data-comment-interface":{"type":"object","description":"Interface CommentInterface","properties":{"comment":{"type":"string","description":"Comment"},"rma_entity_id":{"type":"integer","description":"Rma Id"},"created_at":{"type":"string","description":"Created_at"},"entity_id":{"type":"integer","description":"Entity_id"},"customer_notified":{"type":"boolean","description":"Is_customer_notified"},"visible_on_front":{"type":"boolean","description":"Is_visible_on_front"},"status":{"type":"string","description":"Status"},"admin":{"type":"boolean","description":"Is_admin"},"extension_attributes":{"$ref":"#/definitions/rma-data-comment-extension-interface"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["comment","rma_entity_id","created_at","entity_id","customer_notified","visible_on_front","status","admin"]},"rma-data-comment-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Rma\\Api\\Data\\CommentInterface"},"rma-data-rma-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Rma\\Api\\Data\\RmaInterface"},"rma-data-comment-search-result-interface":{"type":"object","description":"Interface CommentSearchResultInterface","properties":{"items":{"type":"array","description":"Rma Status History list","items":{"$ref":"#/definitions/rma-data-comment-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"rma-data-rma-search-result-interface":{"type":"object","description":"Interface RmaSearchResultInterface","properties":{"items":{"type":"array","description":"Rma list","items":{"$ref":"#/definitions/rma-data-rma-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"framework-metadata-object-interface":{"type":"object","description":"Provides metadata about an attribute.","properties":{"attribute_code":{"type":"string","description":"Code of the attribute."}},"required":["attribute_code"]},"test-module1-v1-entity-item":{"type":"object","description":"","properties":{"item_id":{"type":"integer"},"name":{"type":"string"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["item_id","name"]},"test-module1-v2-entity-item":{"type":"object","description":"","properties":{"id":{"type":"integer"},"name":{"type":"string"},"price":{"type":"string"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["id","name","price"]},"test-module2-v1-entity-item":{"type":"object","description":"","properties":{"id":{"type":"integer"},"name":{"type":"string"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["id","name"]},"test-module3-v1-entity-parameter":{"type":"object","description":"","properties":{"name":{"type":"string","description":"$name"},"value":{"type":"string","description":"$value"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["name","value"]},"test-module3-v1-entity-wrapped-error-parameter":{"type":"object","description":"","properties":{"field_name":{"type":"string","description":"$name"},"value":{"type":"string","description":"$value"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["field_name","value"]},"test-module4-v1-entity-data-object-response":{"type":"object","description":"","properties":{"entity_id":{"type":"integer"},"name":{"type":"string"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["entity_id","name"]},"test-module4-v1-entity-data-object-request":{"type":"object","description":"","properties":{"name":{"type":"string"},"entity_id":{"type":"integer"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["name"]},"test-module4-v1-entity-nested-data-object-request":{"type":"object","description":"","properties":{"details":{"$ref":"#/definitions/test-module4-v1-entity-data-object-request"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["details"]},"test-module4-v1-entity-extensible-request-interface":{"type":"object","description":"","properties":{"name":{"type":"string"},"entity_id":{"type":"integer"}},"required":["name"]},"test-module5-v1-entity-all-soap-and-rest":{"type":"object","description":"Some Data Object short description. Data Object long multi line description.","properties":{"entity_id":{"type":"integer","description":"Item ID"},"name":{"type":"string","description":"Item name"},"enabled":{"type":"boolean","description":"If entity is enabled"},"orders":{"type":"boolean","description":"If current entity has a property defined"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["entity_id","enabled","orders"]},"test-module5-v2-entity-all-soap-and-rest":{"type":"object","description":"Some Data Object short description. Data Object long multi line description.","properties":{"price":{"type":"integer"}},"required":["price"]},"test-module-ms-cdata-item-interface":{"type":"object","description":"","properties":{"item_id":{"type":"integer"},"name":{"type":"string"}},"required":["item_id","name"]}}} \ No newline at end of file diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/definition.mustache b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/definition.mustache deleted file mode 100644 index e61212219..000000000 --- a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/definition.mustache +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../DataGenerator/etc/dataOperation.xsd"> - <operation name="{{ operationName }}" dataType="{{ operationDataType }}" type="{{ operationType }}"> - {{> field2 }} - {{> array1 }} - </operation> -</config> \ No newline at end of file diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/operation.mustache b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/operation.mustache deleted file mode 100644 index 5114f233a..000000000 --- a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/operation.mustache +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../DataGenerator/etc/dataOperation.xsd"> - <operation name="{{ operationName }}" dataType="{{ operationDataType }}" type="{{ operationType }}" auth="{{ auth }}" url="{{ operationUrl }}" method="{{ method }}"> - <contentType>application/json</contentType> - {{> field }} - {{> param }} - {{> array }} - </operation> -</config> \ No newline at end of file diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/array1.mustache b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/array1.mustache deleted file mode 100644 index 3669c78d0..000000000 --- a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/array1.mustache +++ /dev/null @@ -1,12 +0,0 @@ -{{! -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -}} -{{# arrays1 }} -<array key="{{ arrayKey }}"> - {{> value }} - {{> arrays2 }} -</array> -{{/ arrays1 }} diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/array2.mustache b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/array2.mustache deleted file mode 100644 index 072b430fb..000000000 --- a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/array2.mustache +++ /dev/null @@ -1,12 +0,0 @@ -{{! -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -}} -{{# arrays2 }} -<array key="{{ arrayKey }}"> - {{> value }} - {{> arrays3 }} -</array> -{{/ arrays2 }} diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/array3.mustache b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/array3.mustache deleted file mode 100644 index 401dbbcbd..000000000 --- a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/array3.mustache +++ /dev/null @@ -1,12 +0,0 @@ -{{! -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -}} -{{! No array is nested more than 2 level in Magento2 swagger spec. }} -{{# arrays3 }} -<array key="{{ arrayKey }}"> - {{> value }} -</array> -{{/ arrays3 }} diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/field.mustache b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/field.mustache deleted file mode 100644 index 29a822d05..000000000 --- a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/field.mustache +++ /dev/null @@ -1,9 +0,0 @@ -{{! -/** - * Copyright ? Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -}} -{{# fields }} -<field key="{{ fieldName }}" required="{{ isRequired }}">{{ fieldType }}</field> -{{/ fields }} diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/field2.mustache b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/field2.mustache deleted file mode 100644 index bf4f6c2a5..000000000 --- a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/field2.mustache +++ /dev/null @@ -1,9 +0,0 @@ -{{! -/** - * Copyright ? Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -}} -{{# fields }} -<field key="{{ fieldName }}">{{ fieldType }}</field> -{{/ fields }} diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/param.mustache b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/param.mustache deleted file mode 100644 index be5f4a3ef..000000000 --- a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/param.mustache +++ /dev/null @@ -1,9 +0,0 @@ -{{! -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -}} -{{# params }} -<param key="{{ paramName }}">{{ paramType }}</param> -{{/ params }} \ No newline at end of file diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/value.mustache b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/value.mustache deleted file mode 100644 index def0c03ff..000000000 --- a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/value.mustache +++ /dev/null @@ -1,9 +0,0 @@ -{{! -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -}} -{{# values }} -<value>{{ value }}</value> -{{/ values }} From 260107450725c8af5a520598604a9650661ff87b Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Wed, 11 Mar 2020 16:19:48 -0500 Subject: [PATCH 277/888] MQE-2018: Remove dead code: GenerateDocsCommand --- .../ActionGroupAnnotationExtractorTest.php | 43 ------ .../Util/DocGeneratorTest.php | 127 ---------------- docs/commands/mftf.md | 34 ----- .../Console/CommandList.php | 1 - .../Console/GenerateDocsCommand.php | 86 ----------- .../Util/ActionGroupAnnotationExtractor.php | 50 ------- .../Util/DocGenerator.php | 137 ------------------ 7 files changed, 478 deletions(-) delete mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/Util/DocGeneratorTest.php delete mode 100644 src/Magento/FunctionalTestingFramework/Console/GenerateDocsCommand.php delete mode 100644 src/Magento/FunctionalTestingFramework/Util/DocGenerator.php diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionGroupAnnotationExtractorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionGroupAnnotationExtractorTest.php index af39298b1..392c870d9 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionGroupAnnotationExtractorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionGroupAnnotationExtractorTest.php @@ -44,49 +44,6 @@ public function testActionGroupExtractAnnotations() $this->assertEquals("someDescription", $returnedAnnotations['description']); } - /** - * Annotation extractor should throw warning when required annotations are missing - * - * @throws \Exception - */ - public function testActionGroupMissingAnnotations() - { - // Action Group Data, missing description - $testAnnotations = []; - // Perform Test - $extractor = new ActionGroupAnnotationExtractor(); - AspectMock::double($extractor, ['isCommandDefined' => true]); - $extractor->extractAnnotations($testAnnotations, "fileName"); - - // Asserts - TestLoggingUtil::getInstance()->validateMockLogStatement( - 'warning', - 'DEPRECATION: Action Group File fileName is missing required annotations.', - [ - 'actionGroup' => 'fileName', - 'missingAnnotations' => "description" - ] - ); - } - - /** - * Annotation extractor should not throw warning when required - * annotations are missing if command is not generate:docs - * - * @throws \Exception - */ - public function testActionGroupMissingAnnotationsNoWarning() - { - // Action Group Data, missing description - $testAnnotations = []; - // Perform Test - $extractor = new ActionGroupAnnotationExtractor(); - $extractor->extractAnnotations($testAnnotations, "fileName"); - - // Asserts - TestLoggingUtil::getInstance()->validateMockLogEmpty(); - } - /** * After class functionality * @return void diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/DocGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/DocGeneratorTest.php deleted file mode 100644 index 0fb73e53f..000000000 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/DocGeneratorTest.php +++ /dev/null @@ -1,127 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Tests\unit\Magento\FunctionalTestFramework\Test\Handlers; - -use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; -use Magento\FunctionalTestingFramework\Util\DocGenerator; -use tests\unit\Util\ActionGroupObjectBuilder; - -class DocGeneratorTest extends MagentoTestCase -{ - const DOC_FILENAME = "documentation"; - - /** - * Basic test to check creation of documentation - * - * @throws \Exception - */ - public function testBasicCreateDocumentation() - { - $annotations = [ - "description" => "someDescription" - ]; - $actionGroupUnderTest = (new ActionGroupObjectBuilder()) - ->withAnnotations($annotations) - ->withFilename("filename") - ->build(); - $docGenerator = new DocGenerator(); - $docGenerator->createDocumentation( - [$actionGroupUnderTest->getName() => $actionGroupUnderTest], - DOCS_OUTPUT_DIR, - true - ); - - $docFile = DOCS_OUTPUT_DIR . DIRECTORY_SEPARATOR . self::DOC_FILENAME . ".md"; - - $this->assertTrue(file_exists($docFile)); - - $this->assertFileEquals( - RESOURCE_DIR . DIRECTORY_SEPARATOR . "basicDocumentation.txt", - $docFile - ); - } - - /** - * Test to check creation of documentation when overwriting previous - * - * @throws \Exception - */ - public function testCreateDocumentationWithOverwrite() - { - $annotations = [ - "description" => "someDescription" - ]; - $actionGroupUnderTest = (new ActionGroupObjectBuilder()) - ->withAnnotations($annotations) - ->withFilename("filename") - ->build(); - $docGenerator = new DocGenerator(); - $docGenerator->createDocumentation( - [$actionGroupUnderTest->getName() => $actionGroupUnderTest], - DOCS_OUTPUT_DIR, - true - ); - - $annotations = [ - "description" => "alteredDescription" - ]; - $actionGroupUnderTest = (new ActionGroupObjectBuilder()) - ->withAnnotations($annotations) - ->withFilename("filename") - ->build(); - $docGenerator = new DocGenerator(); - $docGenerator->createDocumentation( - [$actionGroupUnderTest->getName() => $actionGroupUnderTest], - DOCS_OUTPUT_DIR, - true - ); - - $docFile = DOCS_OUTPUT_DIR . DIRECTORY_SEPARATOR . self::DOC_FILENAME . ".md"; - - $this->assertTrue(file_exists($docFile)); - - $this->assertFileEquals( - RESOURCE_DIR . DIRECTORY_SEPARATOR . "alteredDocumentation.txt", - $docFile - ); - } - - /** - * Test for existing documentation without clean - * - * @throws \Exception - */ - public function testCreateDocumentationNotCleanException() - { - $annotations = [ - "description" => "someDescription" - ]; - $actionGroupUnderTest = (new ActionGroupObjectBuilder()) - ->withAnnotations($annotations) - ->withFilename("filename") - ->build(); - $docGenerator = new DocGenerator(); - $docGenerator->createDocumentation( - [$actionGroupUnderTest->getName() => $actionGroupUnderTest], - DOCS_OUTPUT_DIR, - true - ); - - $docFile = DOCS_OUTPUT_DIR . DIRECTORY_SEPARATOR . self::DOC_FILENAME . ".md"; - - $this->expectException(TestFrameworkException::class); - $this->expectExceptionMessage("$docFile already exists, please add --clean if you want to overwrite it."); - - $docGenerator = new DocGenerator(); - $docGenerator->createDocumentation( - [$actionGroupUnderTest->getName() => $actionGroupUnderTest], - DOCS_OUTPUT_DIR, - false - ); - } -} diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 9b16e23a4..7a4852efb 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -89,14 +89,6 @@ vendor/bin/mftf run:failed This command cleans up the previously generated tests; generates and runs the tests listed in `dev/tests/acceptance/tests/_output/failed`. For more details about `failed`, refer to [Reporting][]. -### Generate documentation for action groups - -```bash -vendor/bin/mftf generate:docs -``` - -This command generates documentation for action groups. - ## Reference ### `build:project` @@ -270,32 +262,6 @@ vendor/bin/mftf generate:urn-catalog [--force] [<path to the directory with misc vendor/bin/mftf generate:urn-catalog .idea/ ``` -### `generate:docs` - -#### Description - -Generates documentation that lists all action groups available in the codebase. -The default path is `<projectRoot>/dev/tests/docs/documentation.md`. - -#### Usage - -```bash -vendor/bin/mftf generate:docs [--clean] [--output=/path/to/alternate/dir] -``` - -#### Options - -| Option | Description | -| ------------- | --------------------------------------------------------------------- | -| `-c, --clean` | Overwrites previously existing documentation | -| `-o, --output` | Changes the default output directory to a user specified directory | - -#### Example - -```bash -vendor/bin/mftf generate:docs --clean -``` - ### `reset` #### Description diff --git a/src/Magento/FunctionalTestingFramework/Console/CommandList.php b/src/Magento/FunctionalTestingFramework/Console/CommandList.php index bf9cbd58e..f77c2c576 100644 --- a/src/Magento/FunctionalTestingFramework/Console/CommandList.php +++ b/src/Magento/FunctionalTestingFramework/Console/CommandList.php @@ -31,7 +31,6 @@ public function __construct(array $commands = []) $this->commands = [ 'build:project' => new BuildProjectCommand(), 'doctor' => new DoctorCommand(), - 'generate:docs' => new GenerateDocsCommand(), 'generate:suite' => new GenerateSuiteCommand(), 'generate:tests' => new GenerateTestsCommand(), 'generate:urn-catalog' => new GenerateDevUrnCommand(), diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateDocsCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateDocsCommand.php deleted file mode 100644 index ce920e39d..000000000 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateDocsCommand.php +++ /dev/null @@ -1,86 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types = 1); - -namespace Magento\FunctionalTestingFramework\Console; - -use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; -use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; -use Magento\FunctionalTestingFramework\Test\Handlers\ActionGroupObjectHandler; -use Magento\FunctionalTestingFramework\Util\DocGenerator; -use PhpParser\Comment\Doc; -use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\Console\Output\OutputInterface; - -class GenerateDocsCommand extends Command -{ - /** - * Configures the current command. - * - * @return void - */ - protected function configure() - { - $this->setName('generate:docs') - ->setDescription('This command generates documentation for created MFTF files.') - ->addOption( - "output", - 'o', - InputOption::VALUE_REQUIRED, - 'Output Directory' - )->addOption( - "clean", - 'c', - InputOption::VALUE_NONE, - 'Clean Output Directory' - )->addOption( - "force", - 'f', - InputOption::VALUE_NONE, - 'Force Document Generation For All Action Groups' - ); - } - - /** - * Executes the current command. - * - * @param InputInterface $input - * @param OutputInterface $output - * @return void - * @throws TestFrameworkException - * @throws \Magento\FunctionalTestingFramework\Exceptions\TestReferenceException - * @throws \Magento\FunctionalTestingFramework\Exceptions\XmlException - */ - protected function execute(InputInterface $input, OutputInterface $output) - { - defined('COMMAND') || define('COMMAND', 'generate:docs'); - $config = $input->getOption('output'); - $clean = $input->getOption('clean'); - $force = $input->getOption('force'); - - MftfApplicationConfig::create( - $force, - MftfApplicationConfig::GENERATION_PHASE, - false, - MftfApplicationConfig::LEVEL_DEFAULT, - true - ); - - $allActionGroups = ActionGroupObjectHandler::getInstance()->getAllObjects(); - $docGenerator = new DocGenerator(); - $docGenerator->createDocumentation($allActionGroups, $config, $clean); - - $output->writeln("Generate Docs Command Run"); - - if (empty($config)) { - $output->writeln("Output to ". DocGenerator::DEFAULT_OUTPUT_DIR); - } else { - $output->writeln("Output to ". $config); - } - } -} diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/ActionGroupAnnotationExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/ActionGroupAnnotationExtractor.php index 9d3a9877e..65f0f41b0 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/ActionGroupAnnotationExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/ActionGroupAnnotationExtractor.php @@ -13,11 +13,6 @@ */ class ActionGroupAnnotationExtractor extends AnnotationExtractor { - const ACTION_GROUP_REQUIRED_ANNOTATIONS = [ - "description" - ]; - const GENERATE_DOCS_COMMAND = 'generate:docs'; - /** * This method trims away irrelevant tags and returns annotations used in the array passed. The annotations * can be found in both Tests and their child element tests. @@ -35,52 +30,7 @@ public function extractAnnotations($testAnnotations, $filename) foreach ($annotations as $annotationKey => $annotationData) { $annotationObjects[$annotationKey] = $annotationData[parent::ANNOTATION_VALUE]; } - // TODO: Remove this when all action groups have annotations - if ($this->isCommandDefined()) { - $this->validateMissingAnnotations($annotationObjects, $filename); - } return $annotationObjects; } - - /** - * Validates given annotations against list of required annotations. - * - * @param array $annotationObjects - * @return void - * @throws \Exception - */ - private function validateMissingAnnotations($annotationObjects, $filename) - { - $missingAnnotations = []; - - foreach (self::ACTION_GROUP_REQUIRED_ANNOTATIONS as $REQUIRED_ANNOTATION) { - if (!array_key_exists($REQUIRED_ANNOTATION, $annotationObjects)) { - $missingAnnotations[] = $REQUIRED_ANNOTATION; - } - } - - if (!empty($missingAnnotations)) { - $message = "Action Group File {$filename} is missing required annotations."; - LoggingUtil::getInstance()->getLogger(ActionObject::class)->deprecation( - $message, - ["actionGroup" => $filename, "missingAnnotations" => implode(", ", $missingAnnotations)], - true - ); - } - } - - /** - * Checks if command is defined as generate:docs - * - * @return boolean - */ - private function isCommandDefined() - { - if (defined('COMMAND') and COMMAND == self::GENERATE_DOCS_COMMAND) { - return true; - } else { - return false; - } - } } diff --git a/src/Magento/FunctionalTestingFramework/Util/DocGenerator.php b/src/Magento/FunctionalTestingFramework/Util/DocGenerator.php deleted file mode 100644 index 7a28f8969..000000000 --- a/src/Magento/FunctionalTestingFramework/Util/DocGenerator.php +++ /dev/null @@ -1,137 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\FunctionalTestingFramework\Util; - -use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; -use Magento\FunctionalTestingFramework\Test\Handlers\ActionGroupObjectHandler; -use Magento\FunctionalTestingFramework\Test\Objects\ActionGroupObject; -use Magento\FunctionalTestingFramework\Test\Objects\TestObject; -use Magento\FunctionalTestingFramework\Test\Util\ActionGroupAnnotationExtractor; -use Magento\FunctionalTestingFramework\Test\Util\ActionGroupObjectExtractor; - -/** - * Class TestGenerator - */ -class DocGenerator -{ - const DEFAULT_OUTPUT_DIR = - PROJECT_ROOT . - DIRECTORY_SEPARATOR . - "dev" . - DIRECTORY_SEPARATOR . - "tests" . - DIRECTORY_SEPARATOR . - "docs"; - const DOC_NAME = "documentation.md"; - # This is the only place FILENAMES is defined as this string - const FILENAMES = "filenames"; - - /** - * DocGenerator constructor. - * - */ - public function __construct() - { - } - - /** - * This creates html documentation for objects passed in - * - * @param ActionGroupObject[]|TestObject[] $annotatedObjects - * @param string $outputDir - * @return void - * @throws TestFrameworkException - */ - public function createDocumentation($annotatedObjects, $outputDir, $clean) - { - if (empty($outputDir)) { - $fullPath = self::DEFAULT_OUTPUT_DIR . DIRECTORY_SEPARATOR; - } else { - $fullPath = $outputDir . DIRECTORY_SEPARATOR; - } - $filePath = $fullPath . self::DOC_NAME; - - if (!file_exists($fullPath)) { - mkdir($fullPath, 0755, true); - } - if (file_exists($filePath) and !$clean) { - throw new TestFrameworkException( - "$filePath already exists, please add --clean if you want to overwrite it." - ); - } - $pageGroups = []; - - foreach ($annotatedObjects as $name => $object) { - $annotations = $object->getAnnotations(); - $filenames = explode(',', $object->getFilename()); - $arguments = $object->getArguments(); - - $info = [ - actionGroupObject::ACTION_GROUP_DESCRIPTION => $annotations[actionGroupObject::ACTION_GROUP_DESCRIPTION] - ?? 'NO_DESCRIPTION_SPECIFIED', - self::FILENAMES => $filenames, - ActionGroupObjectExtractor::ACTION_GROUP_ARGUMENTS => $arguments - ]; - - $pageGroups = array_merge_recursive( - $pageGroups, - [$annotations[ActionGroupObject::ACTION_GROUP_PAGE] ?? 'NO_PAGE_SPECIFIED' => [$name => $info]] - ); - } - - ksort($pageGroups); - foreach ($pageGroups as $page => $groups) { - ksort($groups); - $pageGroups[$page] = $groups; - } - - $markdown = $this->transformToMarkdown($pageGroups); - - file_put_contents($filePath, $markdown); - } - - /** - * This creates html documentation for objects passed in - * - * @param array $annotationList - * @return string - */ - private function transformToMarkdown($annotationList) - { - $markdown = "#Action Group Information" . PHP_EOL; - $markdown .= "This documentation contains a list of all Action Groups." . - PHP_EOL . - PHP_EOL; - - $markdown .= "---" . PHP_EOL; - foreach ($annotationList as $group => $objects) { - foreach ($objects as $name => $annotations) { - $markdown .= "###$name" . PHP_EOL; - $markdown .= "**Description**:" . PHP_EOL; - $markdown .= "- " . $annotations[actionGroupObject::ACTION_GROUP_DESCRIPTION] . PHP_EOL . PHP_EOL; - if (!empty($annotations[ActionGroupObjectExtractor::ACTION_GROUP_ARGUMENTS])) { - $markdown .= "**Action Group Arguments**:" . PHP_EOL . PHP_EOL; - $markdown .= "| Name | Type |" . PHP_EOL; - $markdown .= "| ---- | ---- |" . PHP_EOL; - foreach ($annotations[ActionGroupObjectExtractor::ACTION_GROUP_ARGUMENTS] as $argument) { - $argumentName = $argument->getName(); - $argumentType = $argument->getDataType(); - $markdown .= "| $argumentName | $argumentType |" . PHP_EOL; - } - $markdown .= PHP_EOL; - } - $markdown .= "**Located In**:" . PHP_EOL; - foreach ($annotations[self::FILENAMES] as $filename) { - $relativeFilename = str_replace(MAGENTO_BP . DIRECTORY_SEPARATOR, "", $filename); - $markdown .= PHP_EOL . "- $relativeFilename"; - } - $markdown .= PHP_EOL . "***" . PHP_EOL; - } - } - return $markdown; - } -} From 0a2179528bd9a1b5237e5c0015cf430c86e03b19 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Thu, 12 Mar 2020 08:54:28 -0500 Subject: [PATCH 278/888] MQE-683: [Deprecation] Only use more nested assertion syntax - Merge fixes --- .../Upgrade/UpdateAssertionSchema.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php index 6e834b8de..4c3cc52b8 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php @@ -7,6 +7,7 @@ namespace Magento\FunctionalTestingFramework\Upgrade; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Finder\Finder; @@ -21,9 +22,10 @@ class UpdateAssertionSchema implements UpgradeInterface * WILL NOT CATCH cases where style is a mix of old and new * * @param InputInterface $input + * @param OutputInterface $output * @return string */ - public function execute(InputInterface $input) + public function execute(InputInterface $input, OutputInterface $output) { $testsPath = $input->getArgument('path'); $finder = new Finder(); From 9357cf75c37620def3ccecfe8548733b86c291bb Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Thu, 12 Mar 2020 09:04:07 -0500 Subject: [PATCH 279/888] MQE-683: [Deprecation] Only use more nested assertion syntax - static check fix --- .../Upgrade/UpdateAssertionSchema.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php index 4c3cc52b8..09eafa483 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php @@ -21,7 +21,7 @@ class UpdateAssertionSchema implements UpgradeInterface * Upgrades all test xml files, changing as many <assert> actions to be nested as possible * WILL NOT CATCH cases where style is a mix of old and new * - * @param InputInterface $input + * @param InputInterface $input * @param OutputInterface $output * @return string */ From 23e95a94ac2cdaf98441563e2a53a2405ac653ab Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 12 Mar 2020 09:22:44 -0500 Subject: [PATCH 280/888] MQE-2026: ModuleResolver handle test module that depends on more than one Magento modules --- .../Util/ModuleResolverTest.php | 147 ++++++++++++++++-- .../Util/ModuleResolver.php | 22 +-- 2 files changed, 149 insertions(+), 20 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php index ad0b1769d..5244e6995 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php @@ -57,7 +57,6 @@ public function testGetModulePathsAlreadySet() */ public function testGetModulePathsAggregate() { - $this->mockForceGenerate(false); $this->setMockResolverClass( false, @@ -89,6 +88,50 @@ public function testGetModulePathsAggregate() ); } + /** + * Validate aggregateTestModulePaths() when module path part of DEV_TESTS + * + * @throws \Exception + */ + public function testAggregateTestModulePathsDevTests() + { + $origin = TESTS_MODULE_PATH; + $modulePath = ModuleResolver::DEV_TESTS . DIRECTORY_SEPARATOR . "Magento"; + putenv("TESTS_MODULE_PATH=$modulePath"); + + $this->mockForceGenerate(false); + $mockResolver = $this->setMockResolverClass( + true, + [], + null, + null, + [], + [], + [], + null, + null, + [], + [], + null, + function ($arg) { + return $arg; + }, + function ($arg) { + return $arg; + } + ); + $resolver = ModuleResolver::getInstance(); + $this->setMockResolverProperties($resolver, null, null); + $this->assertEquals( + [], + $resolver->getModulesPath() + ); + + $mockResolver->verifyNeverInvoked('globRelevantPaths', [$modulePath, '']); + + putenv("TESTS_MODULE_PATH=$origin"); + } + /** * Validate correct path locations are fed into globRelevantPaths * @throws \Exception @@ -409,6 +452,81 @@ public function testMergeFlipAndFilterModulePathsNoForceGenerate() ); } + /** + * Validate mergeModulePaths() and flipAndSortModulePathsArray() + * + * @throws \Exception + */ + public function testMergeFlipNoSortModulePathsNoForceGenerate() + { + $this->mockForceGenerate(false); + $this->setMockResolverClass( + false, + null, + null, + null, + null, + null, + null, + null, + null, + [ + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR + . 'Magento' . DIRECTORY_SEPARATOR . 'ModuleA' => + [ + 'Magento_ModuleA' + ], + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR + . 'Magento' . DIRECTORY_SEPARATOR . 'ModuleBC' => + [ + 'Magento_ModuleB', + 'Magento_ModuleC', + ], + ], + [ + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR + . 'Magento' . DIRECTORY_SEPARATOR . 'ModuleCD' => + [ + 'Magento_ModuleC', + 'Magento_ModuleD' + ], + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR + . 'Magento' . DIRECTORY_SEPARATOR . 'ModuleE' => + [ + 'Magento_ModuleE' + ], + ], + [ + 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'example' => ['Magento_Example'], + 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'sample' => ['Magento_Sample'], + ] + ); + + $resolver = ModuleResolver::getInstance(); + $this->setMockResolverProperties( + $resolver, + null, + [ + 0 => 'Magento_ModuleB', + 1 => 'Magento_ModuleC', + 2 => 'Magento_ModuleE', + 3 => 'Magento_Example', + 4 => 'Magento_Otherexample' + ] + ); + + $this->assertEquals( + [ + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'Magento' . DIRECTORY_SEPARATOR + . 'ModuleE', + 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'example', + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'Magento' . DIRECTORY_SEPARATOR + . 'ModuleBC' + ], + $resolver->getModulesPath() + ); + } + /** * Validate mergeModulePaths() and flipAndSortModulePathsArray() * @@ -428,23 +546,27 @@ public function testMergeFlipAndSortModulePathsForceGenerate() null, null, [ - 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathA' => + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR + . 'Magento' . DIRECTORY_SEPARATOR . 'ModuleA' => [ 'Magento_ModuleA' ], - 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathB' => + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR + . 'Magento' . DIRECTORY_SEPARATOR . 'ModuleBC' => [ 'Magento_ModuleB', 'Magento_ModuleC', ], ], [ - 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathA' => + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR + . 'Magento' . DIRECTORY_SEPARATOR . 'ModuleCD' => [ 'Magento_ModuleC', 'Magento_ModuleD' ], - 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathB' => + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR + . 'Magento' . DIRECTORY_SEPARATOR . 'ModuleD' => [ 'Magento_ModuleD' ], @@ -467,14 +589,19 @@ public function testMergeFlipAndSortModulePathsForceGenerate() 4 => 'Magento_Otherexample' ] ); + $this->assertEquals( [ 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'example', - 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathA', - 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathB', - 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathA', - 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathB', - 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'sample' + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'Magento' . DIRECTORY_SEPARATOR + . 'ModuleA', + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'Magento' . DIRECTORY_SEPARATOR + . 'ModuleD', + 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'sample', + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'Magento' . DIRECTORY_SEPARATOR + . 'ModuleBC', + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'Magento' . DIRECTORY_SEPARATOR + . 'ModuleCD' ], $resolver->getModulesPath() ); diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index d7f06306a..b24e77d9c 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -320,14 +320,16 @@ private function aggregateTestModulePaths() $modulePath = defined('TESTS_MODULE_PATH') ? TESTS_MODULE_PATH : TESTS_BP; $modulePath = FilePathFormatter::format($modulePath, false); + // If $modulePath is DEV_TESTS path, we don't need to search by pattern + if (strpos($modulePath, self::DEV_TESTS) === false) { + $codePathsToPattern[$modulePath] = ''; + } + $vendorCodePath = DIRECTORY_SEPARATOR . self::VENDOR; - $appCodePath = DIRECTORY_SEPARATOR . self::APP_CODE; + $codePathsToPattern[$magentoBaseCodePath . $vendorCodePath] = self::TEST_MFTF_PATTERN; - $codePathsToPattern = [ - $modulePath => '', - $magentoBaseCodePath . $vendorCodePath => self::TEST_MFTF_PATTERN, - $magentoBaseCodePath . $appCodePath => self::TEST_MFTF_PATTERN - ]; + $appCodePath = DIRECTORY_SEPARATOR . self::APP_CODE; + $codePathsToPattern[$magentoBaseCodePath . $appCodePath] = self::TEST_MFTF_PATTERN; foreach ($codePathsToPattern as $codePath => $pattern) { $allModulePaths = array_merge_recursive($allModulePaths, $this->globRelevantPaths($codePath, $pattern)); @@ -538,10 +540,10 @@ private function flipAndSortModulePathsArray($objectArray, $sort, $inFlippedArra foreach ($objectArray as $path => $modules) { if (is_array($modules) && count($modules) > 1) { // The "one path => many module names" case is designed to be strictly used when it's - // impossible to write tests in dedicated modules. Due to performance consideration and there - // is no real usage of this currently, we will use the first module name for the path. - // TODO: consider saving all module names if this information is needed in the future. - $module = $modules[0]; + // impossible to write tests in dedicated modules. + // For now we will set module name based on path. + // TODO: Consider saving all module names if this information is needed in the future. + $module = $this->findVendorAndModuleNameFromPath($path); } elseif (is_array($modules)) { if (strpos($modules[0], '_') === false) { $module = $this->findVendorNameFromPath($path) . '_' . $modules[0]; From 12d98e7298683bd593fc3f944bf34c4729e455ba Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Thu, 12 Mar 2020 11:27:28 -0500 Subject: [PATCH 281/888] MQE-683: [Deprecation] Only use more nested assertion syntax - Fixed Ugprade script to use new format --- .../Upgrade/UpdateAssertionSchema.php | 51 +++++++++++-------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php index 09eafa483..95f7c9750 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php @@ -6,6 +6,7 @@ namespace Magento\FunctionalTestingFramework\Upgrade; +use Magento\FunctionalTestingFramework\Util\Script\ScriptUtil; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Filesystem\Filesystem; @@ -27,33 +28,39 @@ class UpdateAssertionSchema implements UpgradeInterface */ public function execute(InputInterface $input, OutputInterface $output) { - $testsPath = $input->getArgument('path'); - $finder = new Finder(); - $finder->files()->in($testsPath)->name("*.xml"); + $testPaths[] = $input->getArgument('path'); + if (empty($testPaths[0])) { + $testPaths = ScriptUtil::getAllModulePaths(); + } - $fileSystem = new Filesystem(); $testsUpdated = 0; - foreach ($finder->files() as $file) { - $contents = $file->getContents(); - // Isolate <assert ... /> but never <assert> ... </assert>, stops after finding first /> - preg_match_all('/<assert.*\/>/', $contents, $potentialAssertions); - $newAssertions = []; - $index = 0; - if (empty($potentialAssertions[0])) { - continue; - } - foreach ($potentialAssertions[0] as $potentialAssertion) { - $newAssertions[$index] = $this->convertOldAssertionToNew($potentialAssertion); - $index++; - } - foreach ($newAssertions as $currentIndex => $replacements) { - $contents = str_replace($potentialAssertions[0][$currentIndex], $replacements, $contents); + foreach ($testPaths as $testsPath) { + $finder = new Finder(); + $finder->files()->in($testsPath)->name("*.xml"); + + $fileSystem = new Filesystem(); + foreach ($finder->files() as $file) { + $contents = $file->getContents(); + // Isolate <assert ... /> but never <assert> ... </assert>, stops after finding first /> + preg_match_all('/<assert.*\/>/', $contents, $potentialAssertions); + $newAssertions = []; + $index = 0; + if (empty($potentialAssertions[0])) { + continue; + } + foreach ($potentialAssertions[0] as $potentialAssertion) { + $newAssertions[$index] = $this->convertOldAssertionToNew($potentialAssertion); + $index++; + } + foreach ($newAssertions as $currentIndex => $replacements) { + $contents = str_replace($potentialAssertions[0][$currentIndex], $replacements, $contents); + } + $fileSystem->dumpFile($file->getRealPath(), $contents); + $testsUpdated++; } - $fileSystem->dumpFile($file->getRealPath(), $contents); - $testsUpdated++; } - return ("Assertion Syntax updated in {$testsUpdated} file(s).\n"); + return ("Assertion Syntax updated in {$testsUpdated} file(s)."); } /** From 84303c9acbcffc84c27cfad67cd291f3f0c89008 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Corr=C3=AAa=20Gomes?= <rafaelstz@users.noreply.github.com> Date: Thu, 12 Mar 2020 15:05:09 -0400 Subject: [PATCH 282/888] Adding the Selenium server download in the example --- docs/getting-started.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 4cf13d7a7..4d27675e5 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -212,11 +212,11 @@ To run tests, you need a running Selenium server and [`mftf`][] commands. #### Run the Selenium server {#selenium-server} -Run the Selenium server in terminal. -For example, the following commands run the Selenium server for Google Chrome: +Run the Selenium server in the terminal. +For example, the following commands download and run the Selenium server for Google Chrome: ```bash -cd <path_to_directory_with_selenium_server_and_webdriver>/ +curl -O http://selenium-release.storage.googleapis.com/3.14/selenium-server-standalone-3.14.0.jar ``` ```bash From 65fa3ccabdf516f44e98487f12445ae7acdc140a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Corr=C3=AAa=20Gomes?= <rafaelstz@users.noreply.github.com> Date: Thu, 12 Mar 2020 15:24:53 -0400 Subject: [PATCH 283/888] Getting started > Removing code snippet I removed an unnecessary code snippet which doesn't make sense where it's. --- docs/getting-started.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 4cf13d7a7..6a0b7a154 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -229,10 +229,6 @@ java -Dwebdriver.chrome.driver=chromedriver -jar selenium-server-standalone-3.14 vendor/bin/mftf generate:tests ``` -```bash -cd dev/tests/acceptance -``` - ```bash vendor/bin/codecept run functional -c dev/tests/acceptance/codeception.yml ``` From 7c7bad00070225d18508dcfd139d061cfb949e0e Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 12 Mar 2020 14:30:57 -0500 Subject: [PATCH 284/888] MQE-1963: Update XSD Schema to verify that file has only single entity --- docs/guides/git-vs-composer-install.md | 3 +++ docs/introduction.md | 8 +++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/guides/git-vs-composer-install.md b/docs/guides/git-vs-composer-install.md index 3a45e3a68..fd9006cc1 100644 --- a/docs/guides/git-vs-composer-install.md +++ b/docs/guides/git-vs-composer-install.md @@ -55,6 +55,8 @@ The file structure under both paths is the same: │   └── ... ├── Section │   └── ... +├── Suite +│   └── ... └── Test └── ... ``` @@ -65,6 +67,7 @@ With either type of installation, all tests and test data are read and merged by 1. `<magento_root>/app/code/<vendor_name>/<module_name>/Test/Mftf/` 1. `<magento_root>/vendor/<vendor_name>/<module_name>/Test/Mftf/` +1. `<magento_root>/dev/tests/acceptance/tests/functional/<vendor_name>/<module_name>/` ## Conclusion diff --git a/docs/introduction.md b/docs/introduction.md index d68f67cf2..02354e150 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -104,14 +104,14 @@ codeception.dist.yml // Codeception configuration (generated while ru ## MFTF tests -The MFTF supports two different locations for storing the tests and test artifacts: - +The MFTF supports three different locations for storing the tests and test artifacts: - `<magento_root>/app/code/<vendor_name>/<module_name>/Test/Mftf/` is the directory to create new tests. - `<magento_root>/vendor/<vendor_name>/<module_name>/Test/Mftf/` is the directory with the out of the box tests (fetched by the Composer). +- `<magento_root>/dev/tests/acceptance/tests/functional/<vendor_name>/<module_name>/` is the directory to create new tests that depends on more than one Magento modules. All tests and test data from these locations are merged in the order indicated in the above list. -The file structure under the both path cases is the same: +The directories immediately follow above three paths use the same format and further sub-directories under each category are supported. ```tree <Path> @@ -125,6 +125,8 @@ The file structure under the both path cases is the same: │   └── ... ├── Section │   └── ... +├── Suite +│   └── ... └── Test └── ... ``` From 34e1ad8963554936bfa9dfb2afc3639c96bdd631 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Thu, 12 Mar 2020 14:43:04 -0500 Subject: [PATCH 285/888] MQE-2028: DevDoc & MFTF Notice for MFTF 3.0.0 specific upgrade - CR Fixes --- CHANGELOG.md | 5 ++++- docs/introduction.md | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b581c8ff..0968ac3f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,13 @@ Magento Functional Testing Framework Changelog ----- ### Upgrade Instructions * Run `bin/mftf reset --hard` to remove old generated configurations. +* Run `bin/mftf build:project` to generate new configurations. * Run `bin/mftf upgrade:tests`. [See command page for details](./docs/commands/mftf.md#upgradetests). * After running the above command, you will need to manually update some tests: * Remove all occurrences of `<executeInSelenium>` and `<performOn>` -* Lastly, try to generate and all tests. Tests should all be generating as a result of the upgrades. + * Remove all occurrences of `<module file=""/>` from any `<suite>`s + * Ensure all `<assert*>` actions in your tests do not have invalid schema +* Lastly, try to generate all tests. Tests should all be generated as a result of the upgrades. If not, the most likely issue will be changed XML schema. You will need to check error messaging and search your codebase for the attributes listed. 2.6.3 diff --git a/docs/introduction.md b/docs/introduction.md index 02354e150..904a0b0c7 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -2,7 +2,7 @@ <div class="bs-callout bs-callout-info" markdown="1"> These are the docs for the latest MFTF release. -To find older documentation, please refer to the `docs` folder inside you desired release in Github. +To find older documentation, please refer to the [docs folder] of your desired release in Github. </div> [Find your MFTF version][] of the MFTF. @@ -141,3 +141,4 @@ Follow the [MFTF project] and [contribute on Github]. [MFTF project]: https://github.com/magento/magento2-functional-testing-framework [Find your MFTF version]: #find-your-mftf-version [MFTF Test Migration]: https://github.com/magento/magento-functional-tests-migration +[docs folder]: https://github.com/magento/magento2-functional-testing-framework/tree/master/docs From f1110423436e54f16a56d36c2fac7abe154fffdd Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 12 Mar 2020 15:05:37 -0500 Subject: [PATCH 286/888] MQE-1963: Update XSD Schema to verify that file has only single entity --- docs/commands/mftf.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 0e55e97c1..20f0ae706 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -509,6 +509,10 @@ vendor/bin/mftf static-checks testDependencies actionGroupArguments When the path argument is specified, this command applies all the major version MFTF upgrade scripts to the test components in the given path (test.xml, data.xml, etc). Otherwise, it will apply all the major version MFTF upgrade scripts to all installed test components. +**Note**: + +The upgrade scripts are meant to be used for Test Modules under source code control. However, if you have old version of test modules under `vendor`, those test modules will get upgraded. + #### Usage ```bash From f559e75e425314ed36ab9e481922e13507b302bb Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Thu, 12 Mar 2020 15:09:15 -0500 Subject: [PATCH 287/888] MQE-1581: Remove NONE debug level for next MFTF major release Overriding pipeline code for debug level = none --- .../Config/MftfApplicationConfig.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php b/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php index ab06b5612..5181e8dc9 100644 --- a/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php +++ b/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php @@ -100,6 +100,12 @@ private function __construct( $this->phase = $phase; $this->verboseEnabled = $verboseEnabled; + + //TODO: overriding pipeline config, to be removed for MFTF 3.0.0 + if (strtolower($debugLevel) === 'none') { + $debugLevel = self::LEVEL_DEFAULT; + } + if (isset($debugLevel) && !in_array(strtolower($debugLevel), self::MFTF_DEBUG_LEVEL)) { throw new TestFrameworkException("{$debugLevel} is not a debug level. Use 'DEFAULT' or 'DEVELOPER'"); } From 8df17bf4f390cc3f0daf9ae308fbfebab0f34b4f Mon Sep 17 00:00:00 2001 From: Lukasz Bajsarowicz <lukasz.bajsarowicz@gmail.com> Date: Wed, 11 Mar 2020 01:00:41 +0100 Subject: [PATCH 288/888] DevDocs: Update Best Practices --- docs/best-practices.md | 42 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/docs/best-practices.md b/docs/best-practices.md index 0b95b1c41..5a62e7347 100644 --- a/docs/best-practices.md +++ b/docs/best-practices.md @@ -2,11 +2,46 @@ Check out our best practices below to ensure you are getting the absolute most out of the Magento Functional Testing Framework. +## Focus on reusability + +### Use existing Tests and resources + +Magento offers more than **3000** acceptance tests, **2500** [Action group]s, **750** Page declarations with more than **1500** Section definitions. +It is very probable that behaviour you want to test already exists as other Test or Action Group. +Instead of writing everything by yourself - try to use `extends` attribute to refer to existing element and customize it. + +**Resources you can reuse** + +* Tests (reusable with `<test extends="...">` argument) +* Action Group (reusable with including `<actionGroup ref="...">`, or extending `<actionGroup extends="...">`) +* Pages (reusable with reference `{{PageDefinition.url}}`) +* Sections (reusable with reference `{{SectionDefinition.elementDefinition}}`) +* Data Entities (reusable with reference `<createData entity="...">"` or extending `<entity extends="...">`) + +<div class="bs-callout bs-callout-warning" markdown="1"> + +Avoid using resources that are marked as **Deprecated**. Usually there's a replacement provided for deprecated resource. + +</div> + +### Extract repetitive Actions + +Instead of writing a few of Tests that perform mostly the same actions, you should thing about [Action group] that is a container for repetitive Actions. +If each run needs different data, use `<arguments>` to inject necessary information. + +We recommend to keep Action Groups having single responsibility, for example `AdminLoginActionGroup`, which expected outcome is being logged in as Administrator when [Action group] is executed. + +## Contribute + +Althought Magento Core team and Contributors join their forces to cover most of the features with tests, it's impossible to have this done that quick. +If you've covered Magento Core feature with Functional Tests - you are more than welcome to contribute. + +You can also help with [MFTF Test Migration] to get the experience and valuable feedback from other community members and maintainers. + ## Action group -1. [Action group] names should be sufficiently descriptive to inform a test writer of what the action group does and when it should be used. - Add additional explanation in annotations if needed. -2. Provide default values for the arguments that apply to your most common case scenarios. +1. [Action group] names should be sufficiently descriptive to inform a test writer of what the action group does and when it should be used. Add additional explanation in annotations if needed. +1. Provide default values for the arguments that apply to your most common case scenarios. ## `actionGroups` vs `extends` @@ -175,3 +210,4 @@ Since the configurable product module could be disabled, this approach is more r [merging]: merging.html [parameterized selectors]: section/parameterized-selectors.html [sections]: section.html +[MFTF Test Migration]: https://github.com/magento/magento-functional-tests-migration From 716ebd5a3cbfb2882f5237accb50f3f81f92f89a Mon Sep 17 00:00:00 2001 From: Lukasz Bajsarowicz <lukasz.bajsarowicz@gmail.com> Date: Tue, 10 Mar 2020 23:57:54 +0100 Subject: [PATCH 289/888] Add missing information about Backend Domain support. --- docs/configuration.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/configuration.md b/docs/configuration.md index 9466f2bcc..89ade5e9b 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -32,6 +32,16 @@ Example: MAGENTO_BACKEND_NAME=admin_12346 ``` +### MAGENTO_BACKEND_BASE_URL + +(Optional) If you are running Admin Panel on separate domain, you may need to specify this value: + +Example: + +```conf +MAGENTO_BACKEND_BASE_URL=https://admin.magento2.test +``` + ### MAGENTO_ADMIN_USERNAME The username that tests can use to access the Magento Admin page From 984cc2702cafe717ab1994c494160e4a57be659a Mon Sep 17 00:00:00 2001 From: Lukasz Bajsarowicz <lukasz.bajsarowicz@gmail.com> Date: Tue, 10 Mar 2020 23:46:16 +0100 Subject: [PATCH 290/888] DevDocs: Update documentation regarding Versioning --- docs/versioning.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/versioning.md b/docs/versioning.md index ecb8438c5..15b98f743 100644 --- a/docs/versioning.md +++ b/docs/versioning.md @@ -12,7 +12,6 @@ If a modification to MFTF forces tests to be changed, this is a backward incompa To find the version of MFTF that you are using, run the Magento CLI command: ```bash -cd <magento_root>/ vendor/bin/mftf --version ``` @@ -61,8 +60,10 @@ You must reset the patch and minor version to 0 when you change the major versio This table lists the version of the MFTF that was released with a particular version of Magento. |Magento version| MFTF version| -|---|---| +|--- |--- | +| 2.3.4 | 2.5.3 | +| 2.3.3 | 2.4.5 | | 2.3.2 | 2.3.14 | | 2.3.1 | 2.3.13 | -| 2.3.0 | 2.3.9 | +| 2.3.0 | 2.3.9 | | 2.2.8 | 2.3.13 | From 84d207464547cc0de9cd0794a183884d3fee790f Mon Sep 17 00:00:00 2001 From: Lukasz Bajsarowicz <lukasz.bajsarowicz@gmail.com> Date: Tue, 10 Mar 2020 23:05:59 +0100 Subject: [PATCH 291/888] DevDocs: Update documentation regarding Update process --- docs/update.md | 81 ++++++++++++++++---------------------------------- 1 file changed, 25 insertions(+), 56 deletions(-) diff --git a/docs/update.md b/docs/update.md index 129742346..5ede6a27d 100644 --- a/docs/update.md +++ b/docs/update.md @@ -1,79 +1,48 @@ # Update the Magento Functional Testing Framework <div class="bs-callout bs-callout-info" markdown="1"> -[Find your version][] of the MFTF. -The latest Magento 2.3 release supports MFTF 2.3.13. -The latest Magento 2.2 release supports MFTF 2.3.8. -</div> - -Magento tests and the framework are stored in different repositories. - -Magento tests are stored in the same repository as the Magento code base. -When you pull changes in the Magento code, you're potentially pulling corresponding tests as well. - -The MFTF is installed separately as a dependency using Composer. -When pulling the latest Magento code, update the corresponding Composer dependencies in the `magento2` root directory. -This ensures that the MFTF is up to date. +Both Magento `2.2` and `2.3` supports MFTF `2.5.3` ([Find your version][] of the MFTF). -## Update the MFTF from 2.3.x - -To update the MFTF to the latest patch: - -1. Verify that the Magento [WYSIWYG settings][] and [Security settings][] are set appropriately. -1. Check details about backward incompatible changes in the [Changelog][] and update your new or customized tests. -1. Get the latest framework version using Composer: - - ```bash - composer update - ``` - -1. Generate the updated tests: - - ```bash - vendor/bin/mftf generate:tests - ``` - -## Update the MFTF from 2.2 +</div> -To update the MFTF from the previous minor version: -1. When you update Magento, verify that the Magento [WYSIWYG settings][] and [Security settings][] are set appropriately. -1. Starting at the `magento2/` root directory remove the `vendor/` directory: +**Tests and the Framework itself are stored in different repositories.** - ```bash - rm -rf vendor/ - ``` +* Tests are stored in Module's directory. +* The MFTF is installed separately (usually as a Composer dependency) -1. Get the latest framework version from the Composer dependencies: +While pulling the latest Magento codebase, you are going to get Tests and it's dependencies (eg. Action Groups). - ```bash - composer install - ``` +To understand types of update - please follow the [Versioning][] page. -1. Run the `upgrade:tests` using the new command line tool: +## Patch version update - ```bash - vendor/bin/mftf upgrade:tests app - ``` +Takes place when **third** digit of version number changes. -1. If you are using Phpstorm, update the urn catalog: +1. Make sure that [Security settings][] are set appropriately. +1. Get latest Framework version with `composer update magento/magento2-functional-testing-framework --with-dependencies` +1. Generate updated tests with `vendor/bin/mftf generate:tests` - ```bash - vendor/bin/mftf generate:urn-catalog .idea/ - ``` +## Minor version update -1. Update your own tests, including data, metadata, and so on, if they contain tags that are unsupported in the newer version. +Takes place when **second** digit of version number changes. - Check details about backward incompatible changes and review new MFTF release documentation in the [Changelog][]. +1. Check details about backward incompatible changes in the [Changelog][] and update your new or customized tests. +1. Perform all the actions provided for [Patch Version Update][] +1. When updating from versions below `2.5.0`, verify [WYSIWYG settings][] +1. You may need to run the `upgrade:tests` using `vendor/bin/mftf upgrade:tests app` -1. Generate newly pulled tests: +## Always after update - ```bash - vendor/bin/mftf generate:tests - ``` +1. It's good to regenerate your IDE Schema Definition catalog with `vendor/bin/mftf generate:urn-catalog .idea/` +1. Update your own tests, including data, metadata and other resoruces. Validate if they contain tags that are unsupported in the newer version. +1. As soon as possible - remove the references to resources (ActionGroups, Sections, Tests) marked as deprecated. <!-- Link Definitions --> [Changelog]: https://github.com/magento/magento2-functional-testing-framework/blob/master/CHANGELOG.md [WYSIWYG settings]: getting-started.md#wysiwyg-settings [Security settings]: getting-started.md#security-settings +[Find your version]: introduction.md#find-your-mftf-version +[Versioning]: versioning.md#versioning-policy +[Patch Version Update]: #patch-version-update From c161ab10c0ab9bb7e32782d52e4d2074fce7c80b Mon Sep 17 00:00:00 2001 From: Lukasz Bajsarowicz <lukasz.bajsarowicz@gmail.com> Date: Thu, 12 Mar 2020 22:35:45 +0100 Subject: [PATCH 292/888] Update Introduction for MFTF --- docs/introduction.md | 137 ++++++++++++++++++++----------------------- 1 file changed, 65 insertions(+), 72 deletions(-) diff --git a/docs/introduction.md b/docs/introduction.md index 61c1eaef3..2c22854a1 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -1,62 +1,94 @@ # Introduction to the Magento Functional Testing Framework -[Find your MFTF version][] of the MFTF. +The **Magento Functional Tesitng Framework** (MFTF) is framework to perform end-to-end acceptance testing. Tests are performed in real web browser (eg. Google Chrome) just like the real user of the Magento store. -The Magento Functional Testing Framework (MFTF) aims to replace the [Functional Testing Framework] in future releases. -MFTF improves: +## Goals -- **Traceability** for clear logging and reporting capabilities. -- **Modularity** to run tests based on installed modules and extensions. -- **Customizability** for existing tests. -- **Readability** using clear and declarative XML test steps. -- **Maintainability** based on simple test creation and overall structure. +- Facilitate functional testing and minimize the effort it takes to perform regression testing. +- Enable extension developers to provide the Functional Tests to offered extensions. +- Having common standard of Quality Assurrance between Magento, Extension Developers and System Intergrators. -Because MFTF tests are written in XML, you no longer need to learn PHP to write tests. +**MFTF also focuses on** -<div class="bs-callout bs-callout-info" markdown="1"> -We are actively developing functional tests. -Refer to `<magento_root>/app/code/<vendor_name>/<module_name>/Test/Mftf/` for examples. -Check out the [MFTF Test Migration][] repo. -</div> +- **Traceability** for clear logging and reporting capabilities. +- **Modularity** to run tests based on installed modules and extensions. +- **Customizability** for existing tests. +- **Readability** using clear and declarative XML test steps. +- **Maintainability** based on simple test creation and overall structure. ## Audience -This MFTF guide is intended for Magento developers and software engineers, such as QA specialists, PHP developers, and system integrators. +- **Contributors**: Tests build their confidence about the results of changes introduced to the platform. +- **Extension Developers**: Can adjust expected behaviour according to their customizations. +- **System Integrators**: MFTF coverage provided out-of-the-box with Magento is solid base for Acceptance / Regression Tests. -## Goals +## MFTF tests + +The MFTF supports two different locations for storing the tests and test artifacts: + +- `<magento_root>/app/code/<vendor_name>/<module_name>/Test/Mftf/` is the location of local, customized tests. +- `<magento_root>/vendor/<vendor_name>/<module_name>/Test/Mftf/` is location of tests provided by Magento and vendors. + +If you installed Magento with Composer, please refer to `vendor/magento/<module_dir>/Test/Mftf/` for examples. + +### Directory Structure -The purpose of MFTF is to: +The file structure under both of the both path cases is the same: -- Facilitate functional testing and minimize the effort it takes to perform regression testing. -- Make it easier to support the extension and customization of tests via XML merging. +```tree +Test +└── Mftf + ├── ActionGroup + │   └── ... + ├── Data + │   └── ... + ├── Metadata + │   └── ... + ├── Page + │   └── ... + ├── Section + │   └── ... + └── Test + └── ... +``` -## Scope -MFTF will enable you to: +<div class="bs-callout bs-callout-info" markdown="1"> -- Test user interactions with web applications in testing. -- Write functional tests located in `<magento_root>/app/code/<vendor_name>/<module_name>/Test/Mftf/`. -- Cover basic functionality using out-of-the-box tests. You can test extended functionality using custom tests. -- Automate regression testing. +We are actively developing functional tests. Check out the [MFTF Test Migration][] repository. + +</div> ## Use cases -As a Magento developer, test changes, such as extended search functionality, a new form attribute, or new product tags. +* **Contributor** changes the core behaviour, fixing the annoing bug. + He wants to have automated "supervisor" which is going to verify his work continuously across the stages of bug fixing. Finally, when fix is done - Functional Test is also proof of work done. -As a software engineer, perform regression testing before release to ensure that Magento works as expected with new functionality. +* **Extension Developer** offers extension that changes core behaviour. + He can easily write new tests to make sure that after enabling the feature, Magento behaves properly. Everything with just extending existing tests. As a result he don't need to write coverage from scratch. + +* **Integration Agency** maintains Client's e-commerce. + They are able to customize tests delivered with Magento core to follow customizations implemented to Magento. After each upgrade they can just run the MFTF tests to know that no regression was introduced. + + +## MFTF output + +- Generated PHP Codeception tests +- Codeception results and console logs +- Screenshots and HTML failure report +- Allure formatted XML results +- Allure report dashboard of results ## Find your MFTF version There are two options to find out your MFTF version: -- using the MFTF CLI -- using the Composer CLI +- using the MFTF CLI +- using the Composer CLI -### MFTF CLI +All the Command Line commands needs to be executed from `<magento_root>` -```bash -cd <magento_root>/ -``` +### MFTF CLI ```bash vendor/bin/mftf --version @@ -64,10 +96,6 @@ vendor/bin/mftf --version ### Composer CLI -```bash -cd <magento_root>/ -``` - ```bash composer show magento/magento2-functional-testing-framework ``` @@ -89,41 +117,6 @@ utils // The test-running utilities. codeception.dist.yml // Codeception configuration (generated while running 'bin/mftf build:project') ``` -## MFTF output - -- Generated PHP Codeception tests -- Codeception results and console logs -- Screenshots and HTML failure report -- Allure formatted XML results -- Allure report dashboard of results - -## MFTF tests - -The MFTF supports two different locations for storing the tests and test artifacts: - -- `<magento_root>/app/code/<vendor_name>/<module_name>/Test/Mftf/` is the directory to create new tests. -- `<magento_root>/vendor/<vendor_name>/<module_name>/Test/Mftf/` is the directory with the out of the box tests (fetched by the Composer). - -All tests and test data from these locations are merged in the order indicated in the above list. - -The file structure under the both path cases is the same: - -```tree -<Path> -├── ActionGroup -│   └── ... -├── Data -│   └── ... -├── Metadata -│   └── ... -├── Page -│   └── ... -├── Section -│   └── ... -└── Test - └── ... -``` - ## MFTF on Github Follow the [MFTF project] and [contribute on Github]. From 73b49e876c77ed7560949d4e7678ec9dc489b394 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Fri, 13 Mar 2020 08:40:25 -0500 Subject: [PATCH 293/888] MQE-1963: Update XSD Schema to verify that file has only single entity - CR Fixes --- CHANGELOG.md | 6 +++--- docs/commands/mftf.md | 2 +- docs/introduction.md | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0968ac3f7..1d1ae20a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,12 +6,12 @@ Magento Functional Testing Framework Changelog * Run `bin/mftf reset --hard` to remove old generated configurations. * Run `bin/mftf build:project` to generate new configurations. * Run `bin/mftf upgrade:tests`. [See command page for details](./docs/commands/mftf.md#upgradetests). -* After running the above command, you will need to manually update some tests: +* After running the above command, some tests may need manually updates: * Remove all occurrences of `<executeInSelenium>` and `<performOn>` * Remove all occurrences of `<module file=""/>` from any `<suite>`s - * Ensure all `<assert*>` actions in your tests do not have invalid schema + * Ensure all `<assert*>` actions in your tests have a valid schema. * Lastly, try to generate all tests. Tests should all be generated as a result of the upgrades. - If not, the most likely issue will be changed XML schema. You will need to check error messaging and search your codebase for the attributes listed. + * If not, the most likely issue will be a changed XML schema. Check error messaging and search your codebase for the attributes listed. 2.6.3 ----- diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 8e39e187a..6d2dedfd1 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -479,7 +479,7 @@ Otherwise, it will apply all the major version MFTF upgrade scripts to all insta **Note**: -The upgrade scripts are meant to be used for Test Modules under source code control. However, if you have old version of test modules under `vendor`, those test modules will get upgraded. +The upgrade scripts are meant to be used for Test Modules under source code control. If you have old versions of test modules under vendor, those test modules will get upgraded #### Usage diff --git a/docs/introduction.md b/docs/introduction.md index 904a0b0c7..b68cca819 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -107,11 +107,11 @@ codeception.dist.yml // Codeception configuration (generated while ru The MFTF supports three different locations for storing the tests and test artifacts: - `<magento_root>/app/code/<vendor_name>/<module_name>/Test/Mftf/` is the directory to create new tests. - `<magento_root>/vendor/<vendor_name>/<module_name>/Test/Mftf/` is the directory with the out of the box tests (fetched by the Composer). -- `<magento_root>/dev/tests/acceptance/tests/functional/<vendor_name>/<module_name>/` is the directory to create new tests that depends on more than one Magento modules. +- `<magento_root>/dev/tests/acceptance/tests/functional/<vendor_name>/<module_name>/` is used to store tests that depend on multiple modules. All tests and test data from these locations are merged in the order indicated in the above list. -The directories immediately follow above three paths use the same format and further sub-directories under each category are supported. +Directories immediately following the above paths will use the same format, and sub-directories under each category are supported. ```tree <Path> From f8bccbf9ac7556e28d095e499262bce08595f12a Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Fri, 13 Mar 2020 08:45:41 -0500 Subject: [PATCH 294/888] MQE-683: [Deprecation] Only use more nested assertion syntax - Docs Fix --- docs/test/assertions.md | 124 ++-------------------------------------- 1 file changed, 4 insertions(+), 120 deletions(-) diff --git a/docs/test/assertions.md b/docs/test/assertions.md index 17a3d194a..dfe4c3d4b 100644 --- a/docs/test/assertions.md +++ b/docs/test/assertions.md @@ -53,14 +53,13 @@ The following example shows a common test that gets text from a page and asserts Example: ```xml -<assertElementContainsAttribute selector=".admin__menu-overlay" attribute="style" expectedValue="color: #333;" stepKey="assertElementContainsAttribute"/> +<assertElementContainsAttribute stepKey="assertElementContainsAttribute"> + <expectedResult selector=".admin__menu-overlay" attribute="style" type="string">color: #333;</expectedResult> +</assertElementContainsAttribute> ``` Attribute|Type|Use|Description ---|---|---|--- -`selector`|string|required| -`expectedValue`|string|optional| A value of the expected result. -`attribute`|string|required| `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. `after`|string|optional| `stepKey` of the preceding action. @@ -92,12 +91,7 @@ It must be in typical array format like `[1,2,3,4,5]` or `[alpha, brontosaurus, See [assertArrayHasKey docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertArrayHasKey) Attribute|Type|Use|Description ----|---|---|--- -`expected`|string|required| A value of the expected result. -`expectedType`|string|optional| A type of the expected result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. -`message`|string|optional|Text of informational message about a cause of failure. +---|---|---|---`message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. `after`|string|optional| `stepKey` of the preceding action. @@ -108,10 +102,6 @@ See [assertArrayNotHasKey docs on codeception.com](http://codeception.com/docs/m Attribute|Type|Use|Description ---|---|---|--- -`expected`|string|required| A value of the expected result. -`expectedType`|string|optional| A type of the expected result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. @@ -123,10 +113,6 @@ See [assertArraySubset docs on codeception.com](http://codeception.com/docs/modu Attribute|Type|Use|Description ---|---|---|--- -`expected`|string|required| A value of the expected result. -`expectedType`|string|optional| A type of the expected result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `strict`|boolean|optional| `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. @@ -139,10 +125,6 @@ See [assertContains docs on codeception.com](http://codeception.com/docs/modules Attribute|Type|Use|Description ---|---|---|--- -`expected`|string|required| A value of the expected result. -`expectedType`|string|optional| A type of the expected result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. @@ -154,10 +136,6 @@ See [assertCount docs on codeception.com](http://codeception.com/docs/modules/As Attribute|Type|Use|Description ---|---|---|--- -`expected`|string|required| A value of the expected result. -`expectedType`|string|optional| A type of the expected result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. @@ -169,8 +147,6 @@ See [assertEmpty docs on codeception.com](http://codeception.com/docs/modules/As Attribute|Type|Use|Description ---|---|---|--- -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. @@ -182,10 +158,6 @@ See [assertEquals docs on codeception.com](http://codeception.com/docs/modules/A Attribute|Type|Use|Description ---|---|---|--- -`expected`|string|required| A value of the expected result. -`expectedType`|string|optional| A type of the expected result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `delta`|string|optional| `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. @@ -198,8 +170,6 @@ See [assertFalse docs on codeception.com](http://codeception.com/docs/modules/As Attribute|Type|Use|Description ---|---|---|--- -`actual`|string|required| Actual value. -`actualType`|assertEnum|optional| Type of actual value. `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. @@ -211,8 +181,6 @@ See [assertFileExists docs on codeception.com](http://codeception.com/docs/modul Attribute|Type|Use|Description ---|---|---|--- -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. @@ -224,8 +192,6 @@ See [assertFileNotExists docs on codeception.com](http://codeception.com/docs/mo Attribute|Type|Use|Description ---|---|---|--- -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. @@ -237,10 +203,6 @@ See [assertGreaterOrEquals docs on codeception.com](http://codeception.com/docs/ Attribute|Type|Use|Description ---|---|---|--- -`expected`|string|required| A value of the expected result. -`expectedType`|string|optional| A type of the expected result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. @@ -252,10 +214,6 @@ See [assertGreaterThan docs on codeception.com](http://codeception.com/docs/modu Attribute|Type|Use|Description ---|---|---|--- -`expected`|string|required| A value of the expected result. -`expectedType`|string|optional| A type of the expected result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. @@ -267,10 +225,6 @@ See [assertGreaterThanOrEqual docs on codeception.com](http://codeception.com/do Attribute|Type|Use|Description ---|---|---|--- -`expected`|string|required| A value of the expected result. -`expectedType`|string|optional| A type of the expected result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. @@ -282,10 +236,6 @@ See [assertInstanceOf docs on codeception.com](http://codeception.com/docs/modul Attribute|Type|Use|Description ---|---|---|--- -`expected`|string|required| A value of the expected result. -`expectedType`|string|optional| A type of the expected result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. @@ -297,10 +247,6 @@ See [assertInternalType docs on codeception.com](http://codeception.com/docs/mod Attribute|Type|Use|Description ---|---|---|--- -`expected`|string|required| A value of the expected result. -`expectedType`|string|optional| A type of the expected result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. @@ -312,8 +258,6 @@ See [assertIsEmpty docs on codeception.com](http://codeception.com/docs/modules/ Attribute|Type|Use|Description ---|---|---|--- -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. @@ -325,10 +269,6 @@ See [assertLessOrEquals docs on codeception.com](http://codeception.com/docs/mod Attribute|Type|Use|Description ---|---|---|--- -`expected`|string|required| A value of the expected result. -`expectedType`|string|optional| A type of the expected result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. @@ -340,10 +280,6 @@ See [assertLessThan docs on codeception.com](http://codeception.com/docs/modules Attribute|Type|Use|Description ---|---|---|--- -`expected`|string|required| A value of the expected result. -`expectedType`|string|optional| A type of the expected result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. @@ -355,10 +291,6 @@ See [assertLessThanOrEqual docs on codeception.com](http://codeception.com/docs/ Attribute|Type|Use|Description ---|---|---|--- -`expected`|string|required| A value of the expected result. -`expectedType`|string|optional| A type of the expected result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. @@ -370,10 +302,6 @@ See [assertNotContains docs on codeception.com](http://codeception.com/docs/modu Attribute|Type|Use|Description ---|---|---|--- -`expected`|string|required| A value of the expected result. -`expectedType`|string|optional| A type of the expected result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. @@ -385,8 +313,6 @@ See [assertNotEmpty docs on codeception.com](http://codeception.com/docs/modules Attribute|Type|Use|Description ---|---|---|--- -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. @@ -398,10 +324,6 @@ See [assertNotEquals docs on codeception.com](http://codeception.com/docs/module Attribute|Type|Use|Description ---|---|---|--- -`expected`|string|required| A value of the expected result. -`expectedType`|string|optional| A type of the expected result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `delta`|string|optional| `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. @@ -414,10 +336,6 @@ See [assertNotInstanceOf docs on codeception.com](http://codeception.com/docs/mo Attribute|Type|Use|Description ---|---|---|--- -`expected`|string|required| A value of the expected result. -`expectedType`|string|optional| A type of the expected result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. @@ -429,8 +347,6 @@ See [assertNotNull docs on codeception.com](http://codeception.com/docs/modules/ Attribute|Type|Use|Description ---|---|---|--- -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. @@ -442,10 +358,6 @@ See [assertNotRegExp docs on codeception.com](http://codeception.com/docs/module Attribute|Type|Use|Description ---|---|---|--- -`expected`|string|required| A value of the expected result. -`expectedType`|string|optional| A type of the expected result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. @@ -457,10 +369,6 @@ See [assertNotSame docs on codeception.com](http://codeception.com/docs/modules/ Attribute|Type|Use|Description ---|---|---|--- -`expected`|string|required| A value of the expected result. -`expectedType`|string|optional| A type of the expected result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. @@ -472,8 +380,6 @@ See [assertNull docs on codeception.com](http://codeception.com/docs/modules/Ass Attribute|Type|Use|Description ---|---|---|--- -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. @@ -485,10 +391,6 @@ See [assertRegExp docs on codeception.com](http://codeception.com/docs/modules/A Attribute|Type|Use|Description ---|---|---|--- -`expected`|string|required| A value of the expected result. -`expectedType`|string|optional| A type of the expected result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. @@ -500,10 +402,6 @@ See [assertSame docs on codeception.com](http://codeception.com/docs/modules/Ass Attribute|Type|Use|Description ---|---|---|--- -`expected`|string|required| A value of the expected result. -`expectedType`|string|optional| A type of the expected result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. @@ -515,10 +413,6 @@ See [assertStringStartsNotWith docs on codeception.com](http://codeception.com/d Attribute|Type|Use|Description ---|---|---|--- -`expected`|string|required| A value of the expected result. -`expectedType`|string|optional| A type of the expected result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. @@ -530,10 +424,6 @@ See [assertStringStartsWith docs on codeception.com](http://codeception.com/docs Attribute|Type|Use|Description ---|---|---|--- -`expected`|string|required| A value of the expected result. -`expectedType`|string|optional| A type of the expected result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. @@ -545,8 +435,6 @@ See [assertTrue docs on codeception.com](http://codeception.com/docs/modules/Ass Attribute|Type|Use|Description ---|---|---|--- -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. @@ -558,10 +446,6 @@ See [expectException docs on codeception.com](http://codeception.com/docs/module Attribute|Type|Use|Description ---|---|---|--- -`expected`|string|required| A value of the expected result. -`expectedType`|string|optional| A type of the expected result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. -`actual`|string|required| A value of the actual result. -`actualType`|string|optional| A type of the actual result. Possible values: `const` (default), `int`, `float`, `bool`, `string`, `variable`, `array`. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. `after`|string|optional| `stepKey` of the preceding action. From 11955b0539b145b14c32e7e0e821550938be6113 Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Fri, 13 Mar 2020 10:20:58 -0500 Subject: [PATCH 295/888] Editorial pass --- docs/best-practices.md | 46 +++++++++++++++++----------------- docs/configuration.md | 2 +- docs/introduction.md | 56 ++++++++++++++++++++---------------------- docs/update.md | 21 ++++++---------- 4 files changed, 58 insertions(+), 67 deletions(-) diff --git a/docs/best-practices.md b/docs/best-practices.md index 5a62e7347..c9068a90b 100644 --- a/docs/best-practices.md +++ b/docs/best-practices.md @@ -7,36 +7,36 @@ Check out our best practices below to ensure you are getting the absolute most o ### Use existing Tests and resources Magento offers more than **3000** acceptance tests, **2500** [Action group]s, **750** Page declarations with more than **1500** Section definitions. -It is very probable that behaviour you want to test already exists as other Test or Action Group. -Instead of writing everything by yourself - try to use `extends` attribute to refer to existing element and customize it. +It is very probable that behaviour you want to test already exists as a Test or Action Group. +Instead of writing everything by yourself - use `extends` attribute to refer to existing element and customize it. -**Resources you can reuse** +**Reusable Resources** -* Tests (reusable with `<test extends="...">` argument) -* Action Group (reusable with including `<actionGroup ref="...">`, or extending `<actionGroup extends="...">`) -* Pages (reusable with reference `{{PageDefinition.url}}`) -* Sections (reusable with reference `{{SectionDefinition.elementDefinition}}`) -* Data Entities (reusable with reference `<createData entity="...">"` or extending `<entity extends="...">`) +* Tests (reusable with `<test extends="...">` argument) +* Action Group (reusable with including `<actionGroup ref="...">`, or extending `<actionGroup extends="...">`) +* Pages (reusable with reference `{{PageDefinition.url}}`) +* Sections (reusable with reference `{{SectionDefinition.elementDefinition}}`) +* Data Entities (reusable with reference `<createData entity="...">"` or extending `<entity extends="...">`) <div class="bs-callout bs-callout-warning" markdown="1"> -Avoid using resources that are marked as **Deprecated**. Usually there's a replacement provided for deprecated resource. +Avoid using resources that are marked as **Deprecated**. Usually there is a replacement provided for a deprecated resource. </div> ### Extract repetitive Actions -Instead of writing a few of Tests that perform mostly the same actions, you should thing about [Action group] that is a container for repetitive Actions. +Instead of writing a few of Tests that perform mostly the same actions, you should thing about [Action group] that is a container for repetitive Actions. If each run needs different data, use `<arguments>` to inject necessary information. We recommend to keep Action Groups having single responsibility, for example `AdminLoginActionGroup`, which expected outcome is being logged in as Administrator when [Action group] is executed. ## Contribute -Althought Magento Core team and Contributors join their forces to cover most of the features with tests, it's impossible to have this done that quick. +Althought the Magento Core team and Contributors join forces to cover most of the features with tests, it is impossible to have this done quickly. If you've covered Magento Core feature with Functional Tests - you are more than welcome to contribute. -You can also help with [MFTF Test Migration] to get the experience and valuable feedback from other community members and maintainers. +You can also help with MFTF Test Migration to get the experience and valuable feedback from other community members and maintainers. ## Action group @@ -129,20 +129,20 @@ Use the _Foo.camelCase_ naming convention, which is similar to _Classes_ and _cl Use an upper case first letter for: -- File names. Example: _StorefrontCreateCustomerTest.xml_ -- Test name attributes. Example: `<test name="TestAllTheThingsTest">` -- Data entity names. Example: `<entity name="OutOfStockProduct">` -- Page name. Example: `<page name="AdminLoginPage">` -- Section name. Example: `<section name="AdminCategorySidebarActionSection">` -- Action group name. Example: `<actionGroup name="LoginToAdminActionGroup">` +* File names. Example: _StorefrontCreateCustomerTest.xml_ +* Test name attributes. Example: `<test name="TestAllTheThingsTest">` +* Data entity names. Example: `<entity name="OutOfStockProduct">` +* Page name. Example: `<page name="AdminLoginPage">` +* Section name. Example: `<section name="AdminCategorySidebarActionSection">` +* Action group name. Example: `<actionGroup name="LoginToAdminActionGroup">` #### Lower case Use a lower case first letter for: -- Data keys. Example: `<data key="firstName">` -- Element names. Examples: `<element name="confirmDeleteButton"/>` -- Step keys. For example: `<click selector="..." stepKey="clickLogin"/>` +* Data keys. Example: `<data key="firstName">` +* Element names. Examples: `<element name="confirmDeleteButton"/>` +* Step keys. For example: `<click selector="..." stepKey="clickLogin"/>` ## Page object @@ -180,9 +180,9 @@ Define these three elements and reference them by name in the tests. 1. Keep your tests short and granular for target testing, easier reviews, and easier merge conflict resolution. It also helps you to identify the cause of test failure. 1. Use comments to keep tests readable and maintainable: - - Keep the inline `<!-- XML comments -->` and [`<comment>`] tags up to date. + * Keep the inline `<!-- XML comments -->` and [`<comment>`] tags up to date. It helps to inform the reader of what you are testing and to yield a more descriptive Allure report. - - Explain in comments unclear or tricky test steps. + * Explain in comments unclear or tricky test steps. 1. Refer to [sections] instead of writing selectors. ## Test step merging order diff --git a/docs/configuration.md b/docs/configuration.md index 89ade5e9b..a7b81c7c9 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -34,7 +34,7 @@ MAGENTO_BACKEND_NAME=admin_12346 ### MAGENTO_BACKEND_BASE_URL -(Optional) If you are running Admin Panel on separate domain, you may need to specify this value: +(Optional) If you are running the Admin Panel on separate a domain, specify this value: Example: diff --git a/docs/introduction.md b/docs/introduction.md index 2c22854a1..53b763d8c 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -1,26 +1,26 @@ # Introduction to the Magento Functional Testing Framework -The **Magento Functional Tesitng Framework** (MFTF) is framework to perform end-to-end acceptance testing. Tests are performed in real web browser (eg. Google Chrome) just like the real user of the Magento store. +The Magento Functional Tesitng Framework (MFTF) is a framework used to perform automated end-to-end functional testing. ## Goals -- Facilitate functional testing and minimize the effort it takes to perform regression testing. -- Enable extension developers to provide the Functional Tests to offered extensions. -- Having common standard of Quality Assurrance between Magento, Extension Developers and System Intergrators. +- To facilitate functional testing and minimize the effort it takes to perform regression testing. +- Enable extension developers to provide the Functional Tests to offered extensions. +- Ensuring a common standard of quality between Magento, Extension Developers and System Intergrators. -**MFTF also focuses on** +MFTF also focuses on -- **Traceability** for clear logging and reporting capabilities. -- **Modularity** to run tests based on installed modules and extensions. -- **Customizability** for existing tests. -- **Readability** using clear and declarative XML test steps. -- **Maintainability** based on simple test creation and overall structure. +- **Traceability** for clear logging and reporting capabilities. +- **Modularity** to run tests based on installed modules and extensions. +- **Customizability** for existing tests. +- **Readability** using clear and declarative XML test steps. +- **Maintainability** based on simple test creation and overall structure. ## Audience -- **Contributors**: Tests build their confidence about the results of changes introduced to the platform. -- **Extension Developers**: Can adjust expected behaviour according to their customizations. -- **System Integrators**: MFTF coverage provided out-of-the-box with Magento is solid base for Acceptance / Regression Tests. +- **Contributors**: Tests build confidence about the results of changes introduced to the platform. +- **Extension Developers**: Can adjust expected behaviour according to their customizations. +- **System Integrators**: MFTF coverage provided out-of-the-box with Magento is solid base for Acceptance / Regression Tests. ## MFTF tests @@ -52,7 +52,6 @@ Test └── ... ``` - <div class="bs-callout bs-callout-info" markdown="1"> We are actively developing functional tests. Check out the [MFTF Test Migration][] repository. @@ -61,30 +60,27 @@ We are actively developing functional tests. Check out the [MFTF Test Migration] ## Use cases -* **Contributor** changes the core behaviour, fixing the annoing bug. - He wants to have automated "supervisor" which is going to verify his work continuously across the stages of bug fixing. Finally, when fix is done - Functional Test is also proof of work done. - -* **Extension Developer** offers extension that changes core behaviour. - He can easily write new tests to make sure that after enabling the feature, Magento behaves properly. Everything with just extending existing tests. As a result he don't need to write coverage from scratch. - -* **Integration Agency** maintains Client's e-commerce. - They are able to customize tests delivered with Magento core to follow customizations implemented to Magento. After each upgrade they can just run the MFTF tests to know that no regression was introduced. - +- Contributor: changes the core behaviour, fixing the annoing bug. + He wants to have automated "supervisor" which is going to verify his work continuously across the stages of bug fixing. Finally, when fix is done - Functional Test is also proof of work done. +- Extension Developer: offers extension that changes core behaviour. + He can easily write new tests to make sure that after enabling the feature, Magento behaves properly. Everything with just extending existing tests. As a result he don't need to write coverage from scratch. +- Integration Agency: maintains Client's e-commerce. + They are able to customize tests delivered with Magento core to follow customizations implemented to Magento. After each upgrade they can just run the MFTF tests to know that no regression was introduced. ## MFTF output -- Generated PHP Codeception tests -- Codeception results and console logs -- Screenshots and HTML failure report -- Allure formatted XML results -- Allure report dashboard of results +- Generated PHP Codeception tests +- Codeception results and console logs +- Screenshots and HTML failure report +- Allure formatted XML results +- Allure report dashboard of results ## Find your MFTF version There are two options to find out your MFTF version: -- using the MFTF CLI -- using the Composer CLI +- using the MFTF CLI +- using the Composer CLI All the Command Line commands needs to be executed from `<magento_root>` diff --git a/docs/update.md b/docs/update.md index 5ede6a27d..ebd096158 100644 --- a/docs/update.md +++ b/docs/update.md @@ -1,20 +1,15 @@ # Update the Magento Functional Testing Framework <div class="bs-callout bs-callout-info" markdown="1"> - Both Magento `2.2` and `2.3` supports MFTF `2.5.3` ([Find your version][] of the MFTF). - </div> +Tests and the Framework itself are stored in different repositories. -**Tests and the Framework itself are stored in different repositories.** - -* Tests are stored in Module's directory. -* The MFTF is installed separately (usually as a Composer dependency) - -While pulling the latest Magento codebase, you are going to get Tests and it's dependencies (eg. Action Groups). +* Tests are stored in Module's directory. +* MFTF is installed separately (usually as a Composer dependency) -To understand types of update - please follow the [Versioning][] page. +To understand different types of update - please follow the [Versioning][] page. ## Patch version update @@ -33,11 +28,11 @@ Takes place when **second** digit of version number changes. 1. When updating from versions below `2.5.0`, verify [WYSIWYG settings][] 1. You may need to run the `upgrade:tests` using `vendor/bin/mftf upgrade:tests app` -## Always after update +## After updating -1. It's good to regenerate your IDE Schema Definition catalog with `vendor/bin/mftf generate:urn-catalog .idea/` -1. Update your own tests, including data, metadata and other resoruces. Validate if they contain tags that are unsupported in the newer version. -1. As soon as possible - remove the references to resources (ActionGroups, Sections, Tests) marked as deprecated. +1. It is a good idea to regenerate your IDE Schema Definition catalog with `vendor/bin/mftf generate:urn-catalog .idea/` +1. Update your tests, including data, metadata and other resoruces. Check if they contain tags that are unsupported in the newer version. +1. Remove the references to resources (ActionGroups, Sections, Tests) marked as deprecated. <!-- Link Definitions --> [Changelog]: https://github.com/magento/magento2-functional-testing-framework/blob/master/CHANGELOG.md From 5fa28d262631c970496f5d6a520dba49c1d712bb Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Fri, 13 Mar 2020 11:30:41 -0500 Subject: [PATCH 296/888] MQE-2019: Remove dead code: Magento Readiness --- .../Resources/ActionGroupSkipReadiness.txt | 35 -- .../ActionGroupSkipReadiness.xml | 13 - .../Extension/PageReadinessExtension.php | 240 ------------ .../ReadinessMetrics/AbstractMetricCheck.php | 364 ------------------ .../ReadinessMetrics/DocumentReadyState.php | 43 --- .../ReadinessMetrics/JQueryAjaxRequests.php | 58 --- .../ReadinessMetrics/MagentoLoadingMasks.php | 54 --- .../PrototypeAjaxRequests.php | 58 --- .../ReadinessMetrics/RequireJsDefinitions.php | 60 --- .../Module/MagentoWebDriver.php | 12 - .../Test/Util/ActionMergeUtil.php | 37 -- .../Test/etc/mergedTestSchema.xsd | 7 - .../Util/TestGenerator.php | 3 - 13 files changed, 984 deletions(-) delete mode 100644 dev/tests/verification/Resources/ActionGroupSkipReadiness.txt delete mode 100644 dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupSkipReadiness.xml delete mode 100644 src/Magento/FunctionalTestingFramework/Extension/PageReadinessExtension.php delete mode 100644 src/Magento/FunctionalTestingFramework/Extension/ReadinessMetrics/AbstractMetricCheck.php delete mode 100644 src/Magento/FunctionalTestingFramework/Extension/ReadinessMetrics/DocumentReadyState.php delete mode 100644 src/Magento/FunctionalTestingFramework/Extension/ReadinessMetrics/JQueryAjaxRequests.php delete mode 100644 src/Magento/FunctionalTestingFramework/Extension/ReadinessMetrics/MagentoLoadingMasks.php delete mode 100644 src/Magento/FunctionalTestingFramework/Extension/ReadinessMetrics/PrototypeAjaxRequests.php delete mode 100644 src/Magento/FunctionalTestingFramework/Extension/ReadinessMetrics/RequireJsDefinitions.php diff --git a/dev/tests/verification/Resources/ActionGroupSkipReadiness.txt b/dev/tests/verification/Resources/ActionGroupSkipReadiness.txt deleted file mode 100644 index 891054638..000000000 --- a/dev/tests/verification/Resources/ActionGroupSkipReadiness.txt +++ /dev/null @@ -1,35 +0,0 @@ -<?php -namespace Magento\AcceptanceTest\_default\Backend; - -use Magento\FunctionalTestingFramework\AcceptanceTester; -use \Codeception\Util\Locator; -use Yandex\Allure\Adapter\Annotation\Features; -use Yandex\Allure\Adapter\Annotation\Stories; -use Yandex\Allure\Adapter\Annotation\Title; -use Yandex\Allure\Adapter\Annotation\Description; -use Yandex\Allure\Adapter\Annotation\Parameter; -use Yandex\Allure\Adapter\Annotation\Severity; -use Yandex\Allure\Adapter\Model\SeverityLevel; -use Yandex\Allure\Adapter\Annotation\TestCaseId; - -/** - * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest/ActionGroupSkipReadiness.xml<br>") - */ -class ActionGroupSkipReadinessCest -{ - /** - * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") - * @param AcceptanceTester $I - * @return void - * @throws \Exception - */ - public function ActionGroupSkipReadiness(AcceptanceTester $I) - { - $I->comment("Entering Action Group actionGroupWithSkipReadinessActions (skipReadinessActionGroup)"); - $I->skipReadinessCheck(true); - $I->comment("ActionGroupSkipReadiness"); - $I->skipReadinessCheck(false); - $I->comment("Exiting Action Group actionGroupWithSkipReadinessActions (skipReadinessActionGroup)"); - } -} diff --git a/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupSkipReadiness.xml b/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupSkipReadiness.xml deleted file mode 100644 index 776a6f10f..000000000 --- a/dev/tests/verification/TestModule/Test/ActionGroupTest/ActionGroupSkipReadiness.xml +++ /dev/null @@ -1,13 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> - <test name="ActionGroupSkipReadiness"> - <actionGroup ref="actionGroupWithSkipReadinessActions" stepKey="skipReadinessActionGroup"/> - </test> -</tests> diff --git a/src/Magento/FunctionalTestingFramework/Extension/PageReadinessExtension.php b/src/Magento/FunctionalTestingFramework/Extension/PageReadinessExtension.php deleted file mode 100644 index 2dfcbec1a..000000000 --- a/src/Magento/FunctionalTestingFramework/Extension/PageReadinessExtension.php +++ /dev/null @@ -1,240 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\FunctionalTestingFramework\Extension; - -use Codeception\Event\StepEvent; -use Codeception\Event\TestEvent; -use Codeception\Step; -use Facebook\WebDriver\Exception\UnexpectedAlertOpenException; -use Magento\FunctionalTestingFramework\Extension\ReadinessMetrics\AbstractMetricCheck; -use Facebook\WebDriver\Exception\TimeOutException; -use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; -use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; -use Monolog\Logger; - -/** - * Class PageReadinessExtension - */ -class PageReadinessExtension extends BaseExtension -{ - /** - * List of action types that should bypass metric checks - * shouldSkipCheck() also checks for the 'Comment' step type, which doesn't follow the $step->getAction() pattern - * - * @var array - */ - private $ignoredActions = [ - 'saveScreenshot', - 'skipReadinessCheck', - 'wait' - ]; - - /** - * @var Logger - */ - private $logger; - - /** - * Logger verbosity - * - * @var boolean - */ - private $verbose; - - /** - * Array of readiness metrics, initialized during beforeTest event - * - * @var AbstractMetricCheck[] - */ - private $readinessMetrics; - - /** - * The name of the active test - * - * @var string - */ - private $testName; - - /** - * Initialize local vars - * - * @return void - * @throws \Exception - */ - public function _initialize() - { - $this->logger = LoggingUtil::getInstance()->getLogger(get_class($this)); - $this->verbose = MftfApplicationConfig::getConfig()->verboseEnabled(); - parent::_initialize(); - } - - /** - * Initialize the readiness metrics for the test - * - * @param TestEvent $e - * @return void - * @throws \Exception - */ - public function beforeTest(TestEvent $e) - { - parent::beforeTest($e); - if (isset($this->config['resetFailureThreshold'])) { - $failThreshold = intval($this->config['resetFailureThreshold']); - } else { - $failThreshold = 3; - } - - $this->testName = $e->getTest()->getMetadata()->getName(); - - $this->getDriver()->_setConfig(['skipReadiness' => false]); - - $metrics = []; - foreach ($this->config['readinessMetrics'] as $metricClass) { - $metrics[] = new $metricClass($this, $failThreshold); - } - - $this->readinessMetrics = $metrics; - } - - /** - * Waits for busy page flags to disappear before executing a step - * - * @param StepEvent $e - * @return void - * @throws \Exception - */ - public function beforeStep(StepEvent $e) - { - $step = $e->getStep(); - $manualSkip = $this->getDriver()->_getConfig()['skipReadiness']; - if ($this->shouldSkipCheck($step, $manualSkip)) { - return; - } - - $this->resetMetricTracker($step); - - $metrics = $this->readinessMetrics; - - $this->waitForReadiness($metrics); - - /** @var AbstractMetricCheck $metric */ - foreach ($metrics as $metric) { - $metric->finalizeForStep($step); - } - } - - /** - * Check if page has changed, if so reset metric tracking - * - * @param Step $step - * @return void - */ - private function resetMetricTracker($step) - { - if ($this->pageChanged($step)) { - $this->logDebug( - 'Page URI changed; resetting readiness metric failure tracking', - [ - 'step' => $step->__toString(), - 'newUri' => $this->getUri() - ] - ); - /** @var AbstractMetricCheck $metric */ - foreach ($this->readinessMetrics as $metric) { - $metric->resetTracker(); - } - } - } - - /** - * Wait for page readiness. - * @param array $metrics - * @return void - * @throws \Codeception\Exception\ModuleRequireException - * @throws \Facebook\WebDriver\Exception\NoSuchElementException - */ - private function waitForReadiness($metrics) - { - // todo: Implement step parameter to override global timeout configuration - if (isset($this->config['timeout'])) { - $timeout = intval($this->config['timeout']); - } else { - $timeout = $this->getDriver()->_getConfig()['pageload_timeout']; - } - - try { - $this->getDriver()->webDriver->wait($timeout)->until( - function () use ($metrics) { - $passing = true; - - /** @var AbstractMetricCheck $metric */ - foreach ($metrics as $metric) { - try { - if (!$metric->runCheck()) { - $passing = false; - } - } catch (UnexpectedAlertOpenException $exception) { - } - } - return $passing; - } - ); - } catch (TimeoutException $exception) { - } - } - - /** - * Gets the name of the active test - * - * @return string - */ - public function getTestName() - { - return $this->testName; - } - - /** - * Should the given step bypass the readiness checks - * todo: Implement step parameter to bypass specific metrics (or all) instead of basing on action type - * - * @param Step $step - * @param boolean $manualSkip - * @return boolean - */ - private function shouldSkipCheck($step, $manualSkip) - { - if ($step instanceof Step\Comment || in_array($step->getAction(), $this->ignoredActions) || $manualSkip) { - return true; - } - return false; - } - - /** - * If verbose, log the given message to logger->debug including test context information - * - * @param string $message - * @param array $context - * @return void - * @SuppressWarnings(PHPMD) - */ - private function logDebug($message, $context = []) - { - if ($this->verbose) { - $logContext = [ - 'test' => $this->testName, - 'uri' => $this->getUri() - ]; - foreach ($this->readinessMetrics as $metric) { - $logContext[$metric->getName()] = $metric->getStoredValue(); - $logContext[$metric->getName() . '.failCount'] = $metric->getFailureCount(); - } - $context = array_merge($logContext, $context); - //TODO REMOVE THIS LINE, UNCOMMENT LOGGER - //$this->logger->info($message, $context); - } - } -} diff --git a/src/Magento/FunctionalTestingFramework/Extension/ReadinessMetrics/AbstractMetricCheck.php b/src/Magento/FunctionalTestingFramework/Extension/ReadinessMetrics/AbstractMetricCheck.php deleted file mode 100644 index 8b611283d..000000000 --- a/src/Magento/FunctionalTestingFramework/Extension/ReadinessMetrics/AbstractMetricCheck.php +++ /dev/null @@ -1,364 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\FunctionalTestingFramework\Extension\ReadinessMetrics; - -use Codeception\Exception\ModuleRequireException; -use Codeception\Module\WebDriver; -use Codeception\Step; -use Facebook\WebDriver\Exception\UnexpectedAlertOpenException; -use Magento\FunctionalTestingFramework\Extension\PageReadinessExtension; -use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; -use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; -use Monolog\Logger; - -/** - * Class AbstractMetricCheck - */ -abstract class AbstractMetricCheck -{ - /** - * Extension being used to verify this metric passes before test metrics - * - * @var PageReadinessExtension - */ - protected $extension; - - /** - * Current state of the value the metric tracks - * - * @var mixed; - */ - protected $currentValue; - - /** - * Most recent saved state of the value the metric tracks - * Updated when the metric passes or is finalized - * - * @var mixed; - */ - protected $storedValue; - - /** - * Current count of sequential identical failures - * - * @var integer; - */ - protected $failCount; - - /** - * Number of sequential identical failures before force-resetting the metric - * - * @var integer - */ - protected $resetFailureThreshold; - - /** - * @var Logger - */ - protected $logger; - - /** - * @var boolean - */ - protected $verbose; - - /** - * Constructor, called from the beforeTest event - * - * @param PageReadinessExtension $extension - * @param integer $resetFailureThreshold - * @throws \Exception - */ - public function __construct($extension, $resetFailureThreshold) - { - $this->extension = $extension; - $this->logger = LoggingUtil::getInstance()->getLogger(get_class($this)); - $this->verbose = MftfApplicationConfig::getConfig()->verboseEnabled(); - - // If the clearFailureOnPage() method is overridden, use the configured failure threshold - // If not, the default clearFailureOnPage() method does nothing so don't worry about resetting failures - $reflector = new \ReflectionMethod($this, 'clearFailureOnPage'); - if ($reflector->getDeclaringClass()->getName() === get_class($this)) { - $this->resetFailureThreshold = $resetFailureThreshold; - } else { - $this->resetFailureThreshold = -1; - } - - $this->resetTracker(); - } - - /** - * Does the given value pass the readiness metric - * - * @param mixed $value - * @return boolean - */ - abstract protected function doesMetricPass($value); - - /** - * Retrieve the active value for the metric to check from the page - * - * @return mixed - * @throws UnexpectedAlertOpenException - */ - abstract protected function fetchValueFromPage(); - - /** - * Override this method to reset the actual state of the page to make the metric pass - * This method is called when too many identical failures were encountered in a row - * - * @return void - */ - protected function clearFailureOnPage() - { - return; - } - - /** - * Get the base class name of the metric implementation - * - * @return string - */ - public function getName() - { - $clazz = get_class($this); - $namespaceBreak = strrpos($clazz, '\\'); - if ($namespaceBreak !== false) { - $clazz = substr($clazz, $namespaceBreak + 1); - } - return $clazz; - } - - /** - * Fetches a new value for the metric and checks if it passes, clearing the failure tracking if so - * - * Even on a success, the readiness check will continue to be run until all metrics pass at the same time in order - * to catch cases where a slow request of one metric can trigger calls for other metrics that were previously - * thought ready - * - * @return boolean - * @throws UnexpectedAlertOpenException - */ - public function runCheck() - { - if ($this->doesMetricPass($this->getCurrentValue(true))) { - $this->setTracker($this->getCurrentValue(), 0); - return true; - } - - return false; - } - - /** - * Update the state of the metric including tracked failure state and checking if a failing value is stuck and - * needs to be reset so future checks can be accurate - * - * Called when the readiness check is finished (either all metrics pass or the check has timed out) - * - * @param Step $step - * @return void - */ - public function finalizeForStep($step) - { - try { - $currentValue = $this->getCurrentValue(); - } catch (UnexpectedAlertOpenException $exception) { - $this->debugLog( - 'An alert is open, bypassing javascript-based metric check', - ['step' => $step->__toString()] - ); - return; - } - - if ($this->doesMetricPass($currentValue)) { - $this->setTracker($currentValue, 0); - } else { - // If failure happened on the same value as before, increment the fail count, otherwise set at 1 - if (!isset($this->storedValue) || $currentValue !== $this->getStoredValue()) { - $failCount = 1; - } else { - $failCount = $this->getFailureCount() + 1; - } - $this->setTracker($currentValue, $failCount); - - $this->errorLog('Failed readiness check', ['step' => $step->__toString()]); - - if ($this->resetFailureThreshold >= 0 && $failCount >= $this->resetFailureThreshold) { - $this->debugLog( - 'Too many failures, assuming metric is stuck and resetting state', - ['step' => $step->__toString()] - ); - $this->resetMetric(); - } - } - } - - /** - * Helper function to retrieve the driver being used to run the test - * - * @return WebDriver - * @throws ModuleRequireException - */ - protected function getDriver() - { - return $this->extension->getDriver(); - } - - /** - * Helper function to execute javascript code, see WebDriver::executeJs for more information - * - * @param string $script - * @param array $arguments - * @return mixed - * @throws ModuleRequireException - */ - protected function executeJs($script, $arguments = []) - { - return $this->extension->getDriver()->executeJS($script, $arguments); - } - - /** - * Gets the current state of the given variable - * Fetches an updated value if not known or $refresh is true - * - * @param boolean $refresh - * @return mixed - * @throws UnexpectedAlertOpenException - */ - private function getCurrentValue($refresh = false) - { - if ($refresh) { - unset($this->currentValue); - } - if (!isset($this->currentValue)) { - $this->currentValue = $this->fetchValueFromPage(); - } - return $this->currentValue; - } - - /** - * Returns the value of the given variable for the previous check - * - * @return mixed - */ - public function getStoredValue() - { - return $this->storedValue ?? null; - } - - /** - * The current count of sequential identical failures - * Used to detect potentially stuck metrics - * - * @return integer - */ - public function getFailureCount() - { - return $this->failCount; - } - - /** - * Update the state of the page to pass the metric and clear the saved failure state - * Called when a failure is found to be stuck - * - * @return void - */ - private function resetMetric() - { - $this->clearFailureOnPage(); - $this->resetTracker(); - } - - /** - * Tracks the most recent value and the number of identical failures in a row - * - * @param mixed $value - * @param integer $failCount - * @return void - */ - public function setTracker($value, $failCount) - { - unset($this->currentValue); - $this->storedValue = $value; - $this->failCount = $failCount; - } - - /** - * Resets the tracked metric values on a new page or stuck failure - * - * @return void - */ - public function resetTracker() - { - unset($this->currentValue); - unset($this->storedValue); - $this->failCount = 0; - } - - /** - * Log the given message to logger->error including context information - * - * @param string $message - * @param array $context - * @return void - * @SuppressWarnings(PHPMD) - */ - protected function errorLog($message, $context = []) - { - $context = array_merge($this->getLogContext(), $context); - //TODO REMOVE THIS LINE, UNCOMMENT LOGGER - //$this->logger->error($message, $context); - } - - /** - * Log the given message to logger->info including context information - * - * @param string $message - * @param array $context - * @return void - * @SuppressWarnings(PHPMD) - */ - protected function infoLog($message, $context = []) - { - $context = array_merge($this->getLogContext(), $context); - //TODO REMOVE THIS LINE, UNCOMMENT LOGGER - //$this->logger->info($message, $context); - } - - /** - * If verbose, log the given message to logger->debug including context information - * - * @param string $message - * @param array $context - * @return void - * @SuppressWarnings(PHPMD) - */ - protected function debugLog($message, $context = []) - { - if ($this->verbose) { - $context = array_merge($this->getLogContext(), $context); - //TODO REMOVE THIS LINE, UNCOMMENT LOGGER - //$this->logger->debug($message, $context); - } - } - - /** - * Base context information to include in all log messages: test name, current URI, metric state - * Reports most recent stored value, not current value, so call setTracker() first to update - * - * @return array - */ - private function getLogContext() - { - return [ - 'test' => $this->extension->getTestName(), - 'uri' => $this->extension->getUri(), - $this->getName() => $this->getStoredValue(), - $this->getName() . '.failCount' => $this->getFailureCount() - ]; - } -} diff --git a/src/Magento/FunctionalTestingFramework/Extension/ReadinessMetrics/DocumentReadyState.php b/src/Magento/FunctionalTestingFramework/Extension/ReadinessMetrics/DocumentReadyState.php deleted file mode 100644 index 26cf91aa7..000000000 --- a/src/Magento/FunctionalTestingFramework/Extension/ReadinessMetrics/DocumentReadyState.php +++ /dev/null @@ -1,43 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\FunctionalTestingFramework\Extension\ReadinessMetrics; - -/** - * Class DocumentReadyState - */ - -use Facebook\WebDriver\Exception\UnexpectedAlertOpenException; - -/** - * Class DocumentReadyState - * - * Looks for document.readyState == 'complete' before passing the readiness check - */ -class DocumentReadyState extends AbstractMetricCheck -{ - /** - * Metric passes when document.readyState == 'complete' - * - * @param string $value - * @return boolean - */ - protected function doesMetricPass($value) - { - return $value === 'complete'; - } - - /** - * Retrieve document.readyState - * - * @return string - * @throws UnexpectedAlertOpenException - */ - protected function fetchValueFromPage() - { - return $this->executeJS('return document.readyState;'); - } -} diff --git a/src/Magento/FunctionalTestingFramework/Extension/ReadinessMetrics/JQueryAjaxRequests.php b/src/Magento/FunctionalTestingFramework/Extension/ReadinessMetrics/JQueryAjaxRequests.php deleted file mode 100644 index c005923d3..000000000 --- a/src/Magento/FunctionalTestingFramework/Extension/ReadinessMetrics/JQueryAjaxRequests.php +++ /dev/null @@ -1,58 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\FunctionalTestingFramework\Extension\ReadinessMetrics; - -use Facebook\WebDriver\Exception\UnexpectedAlertOpenException; - -/** - * Class JQueryAjaxRequests - * - * Looks for all active jQuery ajax requests to finish before passing the readiness check - */ -class JQueryAjaxRequests extends AbstractMetricCheck -{ - /** - * Metric passes once there are no remaining active requests - * - * @param integer $value - * @return boolean - */ - protected function doesMetricPass($value) - { - return $value == 0; - } - - /** - * Grabs the number of active jQuery ajax requests if available - * - * @return integer - * @throws UnexpectedAlertOpenException - */ - protected function fetchValueFromPage() - { - return intval( - $this->executeJS( - 'if (!!window.jQuery) { - return window.jQuery.active; - } - return 0;' - ) - ); - } - - /** - * Active request count can get stuck above zero if an exception is thrown during a callback, causing the - * ajax handler method to fail before decrementing the request count - * - * @return void - * @throws UnexpectedAlertOpenException - */ - protected function clearFailureOnPage() - { - $this->executeJS('if (!!window.jQuery) { window.jQuery.active = 0; };'); - } -} diff --git a/src/Magento/FunctionalTestingFramework/Extension/ReadinessMetrics/MagentoLoadingMasks.php b/src/Magento/FunctionalTestingFramework/Extension/ReadinessMetrics/MagentoLoadingMasks.php deleted file mode 100644 index 4f15524ba..000000000 --- a/src/Magento/FunctionalTestingFramework/Extension/ReadinessMetrics/MagentoLoadingMasks.php +++ /dev/null @@ -1,54 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\FunctionalTestingFramework\Extension\ReadinessMetrics; - -use Facebook\WebDriver\Exception\NoSuchElementException; -use Facebook\WebDriver\Exception\StaleElementReferenceException; -use Magento\FunctionalTestingFramework\Module\MagentoWebDriver; -use WebDriverBy; - -/** - * Class MagentoLoadingMasks - * - * Looks for all loading masks to disappear before passing the readiness check - */ -class MagentoLoadingMasks extends AbstractMetricCheck -{ - /** - * Metric passes once all loading masks are absent or invisible - * - * @param string|null $value - * @return boolean - */ - protected function doesMetricPass($value) - { - return $value === null; - } - - /** - * Get the locator and ID for the first active loading mask or null if there are none visible - * - * @return string|null - */ - protected function fetchValueFromPage() - { - foreach (MagentoWebDriver::$loadingMasksLocators as $maskLocator) { - $driverLocator = WebDriverBy::xpath($maskLocator); - $maskElements = $this->getDriver()->webDriver->findElements($driverLocator); - foreach ($maskElements as $element) { - try { - if ($element->isDisplayed()) { - return "$maskLocator : " . $element ->getID(); - } - } catch (NoSuchElementException $e) { - } catch (StaleElementReferenceException $e) { - } - } - } - return null; - } -} diff --git a/src/Magento/FunctionalTestingFramework/Extension/ReadinessMetrics/PrototypeAjaxRequests.php b/src/Magento/FunctionalTestingFramework/Extension/ReadinessMetrics/PrototypeAjaxRequests.php deleted file mode 100644 index 2fc8f70cb..000000000 --- a/src/Magento/FunctionalTestingFramework/Extension/ReadinessMetrics/PrototypeAjaxRequests.php +++ /dev/null @@ -1,58 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\FunctionalTestingFramework\Extension\ReadinessMetrics; - -use Facebook\WebDriver\Exception\UnexpectedAlertOpenException; - -/** - * Class PrototypeAjaxRequests - * - * Looks for all active prototype ajax requests to finish before passing the readiness check - */ -class PrototypeAjaxRequests extends AbstractMetricCheck -{ - /** - * Metric passes once there are no remaining active requests - * - * @param integer $value - * @return boolean - */ - protected function doesMetricPass($value) - { - return $value == 0; - } - - /** - * Grabs the number of active prototype ajax requests if available - * - * @return integer - * @throws UnexpectedAlertOpenException - */ - protected function fetchValueFromPage() - { - return intval( - $this->executeJS( - 'if (!!window.Prototype) { - return window.Ajax.activeRequestCount; - } - return 0;' - ) - ); - } - - /** - * Active request count can get stuck above zero if an exception is thrown during a callback, causing the - * ajax handler method to fail before decrementing the request count - * - * @return void - * @throws UnexpectedAlertOpenException - */ - protected function clearFailureOnPage() - { - $this->executeJS('if (!!window.Prototype) { window.Ajax.activeRequestCount = 0; };'); - } -} diff --git a/src/Magento/FunctionalTestingFramework/Extension/ReadinessMetrics/RequireJsDefinitions.php b/src/Magento/FunctionalTestingFramework/Extension/ReadinessMetrics/RequireJsDefinitions.php deleted file mode 100644 index 6df470123..000000000 --- a/src/Magento/FunctionalTestingFramework/Extension/ReadinessMetrics/RequireJsDefinitions.php +++ /dev/null @@ -1,60 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\FunctionalTestingFramework\Extension\ReadinessMetrics; - -use Facebook\WebDriver\Exception\UnexpectedAlertOpenException; - -/** - * Class RequireJsDefinitions - * - * Looks for all active require.js module definitions to complete before passing the readiness check - */ -class RequireJsDefinitions extends AbstractMetricCheck -{ - /** - * Metric passes once there are no enabled modules waiting in the registry queue - * - * @param string|null $value - * @return boolean - */ - protected function doesMetricPass($value) - { - return $value === null; - } - - /** - * Retrieve the name of the first enabled module still waiting in the require.js registry queue - * - * @return string|null - * @throws UnexpectedAlertOpenException - */ - protected function fetchValueFromPage() - { - $script = - 'if (!window.requirejs) { - return null; - } - var contexts = window.requirejs.s.contexts; - for (var label in contexts) { - if (contexts.hasOwnProperty(label)) { - var registry = contexts[label].registry; - for (var module in registry) { - if (registry.hasOwnProperty(module) && registry[module].enabled) { - return module; - } - } - } - } - return null;'; - - $moduleInProgress = $this->executeJS($script); - if ($moduleInProgress === 'null') { - $moduleInProgress = null; - } - return $moduleInProgress; - } -} diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 26c66acd1..b02675163 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -860,18 +860,6 @@ public function amOnPage($page) $this->waitForPageLoad(); } - /** - * Turn Readiness check on or off - * - * @param boolean $check - * @return void - * @throws \Exception - */ - public function skipReadinessCheck($check) - { - $this->config['skipReadiness'] = $check; - } - /** * Clean Javascript errors in internal array * diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/ActionMergeUtil.php b/src/Magento/FunctionalTestingFramework/Test/Util/ActionMergeUtil.php index 159822db1..28a7d405d 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/ActionMergeUtil.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/ActionMergeUtil.php @@ -23,9 +23,6 @@ class ActionMergeUtil const WAIT_ATTR = 'timeout'; const WAIT_ACTION_NAME = 'waitForPageLoad'; const WAIT_ACTION_SUFFIX = 'WaitForPageLoad'; - const SKIP_READINESS_ACTION_NAME = 'skipReadinessCheck'; - const SKIP_READINESS_OFF_SUFFIX = 'SkipReadinessOff'; - const SKIP_READINESS_ON_SUFFIX = 'SkipReadinessOn'; const DEFAULT_SKIP_ON_ORDER = 'before'; const DEFAULT_SKIP_OFF_ORDER = 'after'; const DEFAULT_WAIT_ORDER = 'after'; @@ -86,7 +83,6 @@ public function resolveActionSteps($parsedSteps, $skipActionGroupResolution = fa { $this->mergeActions($parsedSteps); $this->insertWaits(); - $this->insertReadinessSkips(); if ($skipActionGroupResolution) { return $this->orderedSteps; @@ -233,39 +229,6 @@ private function insertWaits() } } - /** - * Runs through the prepared orderedSteps and calls insertWait if a step requires a wait after it. - * - * @return void - */ - private function insertReadinessSkips() - { - foreach ($this->orderedSteps as $step) { - if (array_key_exists("skipReadiness", $step->getCustomActionAttributes())) { - if ($step->getCustomActionAttributes()['skipReadiness'] == "true") { - $skipReadinessOn = new ActionObject( - $step->getStepKey() . self::SKIP_READINESS_ON_SUFFIX, - self::SKIP_READINESS_ACTION_NAME, - ['state' => "true"], - $step->getStepKey(), - self::DEFAULT_SKIP_ON_ORDER - ); - - $skipReadinessOff = new ActionObject( - $step->getStepKey() . self::SKIP_READINESS_OFF_SUFFIX, - self::SKIP_READINESS_ACTION_NAME, - ['state' => "false"], - $step->getStepKey(), - self::DEFAULT_SKIP_OFF_ORDER - ); - - $this->insertStep($skipReadinessOn); - $this->insertStep($skipReadinessOff); - } - } - } - } - /** * This method takes the steps from the parser and splits steps which need merge from steps that are ordered. * diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/mergedTestSchema.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/mergedTestSchema.xsd index 6ded366bb..6690ef8dd 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/mergedTestSchema.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/mergedTestSchema.xsd @@ -136,13 +136,6 @@ </xs:documentation> </xs:annotation> </xs:attribute> - <xs:attribute type="xs:boolean" name="skipReadiness" use="prohibited"> - <xs:annotation> - <xs:documentation> - Flag for skipping readiness check. - </xs:documentation> - </xs:annotation> - </xs:attribute> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> </xs:schema> diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 275c01c8f..e0543463d 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1334,9 +1334,6 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $testSteps .= $dateGenerateCode; break; - case "skipReadinessCheck": - $testSteps .= $this->wrapFunctionCall($actor, $actionObject, $customActionAttributes['state']); - break; case "comment": $input = $input === null ? strtr($value, ['$' => '\$', '{' => '\{', '}' => '\}']) : $input; // Combining userInput from native XML comment and <comment/> action to fall-through 'default' case From 1f59783cd619dbb9e2c0a4a47f6d3b75bab15d11 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Sun, 15 Mar 2020 23:15:19 -0500 Subject: [PATCH 297/888] MQE-1964: MFTF Helper - Implementation --- composer.json | 2 +- .../DeprecatedCommentActionGroup.xml | 9 + .../MFTF/DevDocs/Helper/CustomHelper.php | 13 ++ .../DevDocs/Test/DeprecatedDevDocsTest.xml | 4 +- .../tests/MFTF/DevDocs/Test/DevDocsTest.xml | 5 + etc/config/functional.suite.dist.yml | 2 - etc/di.xml | 8 +- .../Helper/Acceptance.php | 42 ---- .../Helper/AdminUrlList.php | 189 ------------------ .../Helper/Code/ClassReader.php | 51 +++++ .../Helper/EntityRESTApiHelper.php | 112 ----------- .../Helper/Helper.php | 10 + .../Helper/HelperContainer.php | 30 +++ .../Helper/MagentoFakerData.php | 122 ----------- .../Helper/views/TestInjectMethod.mustache | 19 ++ .../Test/Objects/ActionGroupObject.php | 1 - .../Test/Objects/ActionObject.php | 50 +++++ .../Test/Util/ActionObjectExtractor.php | 34 ++++ .../Test/etc/Actions/customActions.xsd | 20 ++ .../Util/TestGenerator.php | 71 ++++++- 20 files changed, 322 insertions(+), 472 deletions(-) create mode 100644 dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php delete mode 100644 src/Magento/FunctionalTestingFramework/Helper/Acceptance.php delete mode 100644 src/Magento/FunctionalTestingFramework/Helper/AdminUrlList.php create mode 100644 src/Magento/FunctionalTestingFramework/Helper/Code/ClassReader.php delete mode 100644 src/Magento/FunctionalTestingFramework/Helper/EntityRESTApiHelper.php create mode 100644 src/Magento/FunctionalTestingFramework/Helper/Helper.php create mode 100644 src/Magento/FunctionalTestingFramework/Helper/HelperContainer.php delete mode 100644 src/Magento/FunctionalTestingFramework/Helper/MagentoFakerData.php create mode 100644 src/Magento/FunctionalTestingFramework/Helper/views/TestInjectMethod.mustache diff --git a/composer.json b/composer.json index 23b0848d5..74743f674 100755 --- a/composer.json +++ b/composer.json @@ -53,7 +53,7 @@ "files": ["src/Magento/FunctionalTestingFramework/_bootstrap.php"], "psr-4": { "Magento\\FunctionalTestingFramework\\": "src/Magento/FunctionalTestingFramework", - "MFTF\\": "dev/tests/functional/MFTF" + "MFTF\\": "dev/tests/functional/tests/MFTF" } }, "autoload-dev": { diff --git a/dev/tests/functional/tests/MFTF/DevDocs/ActionGroup/DeprecatedCommentActionGroup.xml b/dev/tests/functional/tests/MFTF/DevDocs/ActionGroup/DeprecatedCommentActionGroup.xml index 6c27627d5..c9622bf7b 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/ActionGroup/DeprecatedCommentActionGroup.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/ActionGroup/DeprecatedCommentActionGroup.xml @@ -8,6 +8,15 @@ <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="DeprecatedCommentActionGroup" deprecated="This Action Group is outdated and will be deleted next release."> + <arguments> + <argument name="test" type="string" /> + </arguments> <comment userInput="Action group to demonstrate deprecation notices." stepKey="comment" /> + <helper class="\MFTF\DevDocs\Helper\CustomHelper" method="goTo" stepKey="custobhhmHelper"> + <argument name="test">{{contentSection.pageIntro}}</argument> + <argument name="module">['{{test}}', 'Bla']</argument> + <argument name="url">{{test}}</argument> + </helper> + </actionGroup> </actionGroups> diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php b/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php new file mode 100644 index 000000000..cc716d11b --- /dev/null +++ b/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php @@ -0,0 +1,13 @@ +<?php + +namespace MFTF\DevDocs\Helper; + +use Magento\FunctionalTestingFramework\Helper\Helper; + +class CustomHelper extends Helper +{ + public function goTo(string $url, $test, array $module = [], $superBla = null, $bla = 'blaValue', array $arraysomething = []) + { + print("this is it: " . $url . PHP_EOL); + } +} diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Test/DeprecatedDevDocsTest.xml b/dev/tests/functional/tests/MFTF/DevDocs/Test/DeprecatedDevDocsTest.xml index 5944a964c..a3f41a943 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Test/DeprecatedDevDocsTest.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/Test/DeprecatedDevDocsTest.xml @@ -22,6 +22,8 @@ <!-- Open MFTF DevDocs Page --> <amOnPage stepKey="openMFTFDevDocPage" url="{{DeprecatedMFTFDocPage.url}}" /> <see stepKey="verifyPageIntroText" selector="{{DeprecatedContentSection.pageIntro}}" userInput="{{DeprecatedMessageData.message}}" /> - <actionGroup ref="DeprecatedCommentActionGroup" stepKey="commentActionGroup" /> + <actionGroup ref="DeprecatedCommentActionGroup" stepKey="commentActionGroup"> + <argument name="test" value="{{DeprecatedContentSection.pageIntro}}" /> + </actionGroup> </test> </tests> diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml b/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml index 592294889..72c06d33c 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml @@ -22,5 +22,10 @@ <!-- Open MFTF DevDocs Page --> <amOnPage stepKey="openMFTFDevDocPage" url="{{MFTFDocPage.url}}" /> <see stepKey="verifyPageIntroText" selector="{{contentSection.pageIntro}}" userInput="{{MessageData.message}}" /> + <helper class="\MFTF\DevDocs\Helper\CustomHelper" method="goTo" stepKey="customHelper"> + <argument name="test">{{contentSection.pageIntro}}</argument> + <argument name="module">['Test', 'Bla']</argument> + <argument name="url">{{MFTFDocPage.url}}</argument> + </helper> </test> </tests> diff --git a/etc/config/functional.suite.dist.yml b/etc/config/functional.suite.dist.yml index 10fe1212d..ffbb60990 100644 --- a/etc/config/functional.suite.dist.yml +++ b/etc/config/functional.suite.dist.yml @@ -12,8 +12,6 @@ namespace: Magento\FunctionalTestingFramework modules: enabled: - \Magento\FunctionalTestingFramework\Module\MagentoWebDriver - - \Magento\FunctionalTestingFramework\Helper\Acceptance - - \Magento\FunctionalTestingFramework\Helper\MagentoFakerData - \Magento\FunctionalTestingFramework\Module\MagentoSequence - \Magento\FunctionalTestingFramework\Module\MagentoAssert - \Magento\FunctionalTestingFramework\Module\MagentoActionProxies diff --git a/etc/di.xml b/etc/di.xml index 8d06383a5..1dd91896a 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -8,7 +8,7 @@ <!-- Entity value gets replaced in Dom.php before reading $xml --> <!DOCTYPE config [ - <!ENTITY commonTestActions "acceptPopup|actionGroup|amOnPage|amOnUrl|amOnSubdomain|appendField|assertArrayIsSorted|assertArraySubset|assertElementContainsAttribute|attachFile|cancelPopup|checkOption|clearField|click|clickWithLeftButton|clickWithRightButton|closeAdminNotification|closeTab|comment|conditionalClick|createData|deleteData|updateData|getData|dontSee|dontSeeJsError|dontSeeCheckboxIsChecked|dontSeeCookie|dontSeeCurrentUrlEquals|dontSeeCurrentUrlMatches|dontSeeElement|dontSeeElementInDOM|dontSeeInCurrentUrl|dontSeeInField|dontSeeInFormFields|dontSeeInPageSource|dontSeeInSource|dontSeeInTitle|dontSeeLink|dontSeeOptionIsSelected|doubleClick|dragAndDrop|entity|executeJS|fillField|formatMoney|generateDate|grabAttributeFrom|grabCookie|grabFromCurrentUrl|grabMultiple|grabPageSource|grabTextFrom|grabValueFrom|loadSessionSnapshot|loginAsAdmin|magentoCLI|magentoCron|makeScreenshot|maximizeWindow|moveBack|moveForward|moveMouseOver|mSetLocale|mResetLocale|openNewTab|pauseExecution|parseFloat|pressKey|reloadPage|resetCookie|submitForm|resizeWindow|saveSessionSnapshot|scrollTo|scrollToTopOfPage|searchAndMultiSelectOption|see|seeCheckboxIsChecked|seeCookie|seeCurrentUrlEquals|seeCurrentUrlMatches|seeElement|seeElementInDOM|seeInCurrentUrl|seeInField|seeInFormFields|seeInPageSource|seeInPopup|seeInSource|seeInTitle|seeLink|seeNumberOfElements|seeOptionIsSelected|selectOption|setCookie|submitForm|switchToIFrame|switchToNextTab|switchToPreviousTab|switchToWindow|typeInPopup|uncheckOption|unselectOption|wait|waitForAjaxLoad|waitForElement|waitForElementChange|waitForElementNotVisible|waitForElementVisible|waitForPwaElementNotVisible|waitForPwaElementVisible|waitForJS|waitForLoadingMaskToDisappear|waitForPageLoad|waitForText|assertArrayHasKey|assertArrayNotHasKey|assertArraySubset|assertContains|assertCount|assertEmpty|assertEquals|assertFalse|assertFileExists|assertFileNotExists|assertGreaterOrEquals|assertGreaterThan|assertGreaterThanOrEqual|assertInstanceOf|assertInternalType|assertIsEmpty|assertLessOrEquals|assertLessThan|assertLessThanOrEqual|assertNotContains|assertNotEmpty|assertNotEquals|assertNotInstanceOf|assertNotNull|assertNotRegExp|assertNotSame|assertNull|assertRegExp|assertSame|assertStringStartsNotWith|assertStringStartsWith|assertTrue|expectException|fail|dontSeeFullUrlEquals|dontSee|dontSeeFullUrlMatches|dontSeeInFullUrl|seeFullUrlEquals|seeFullUrlMatches|seeInFullUrl|grabFromFullUrl"> + <!ENTITY commonTestActions "acceptPopup|actionGroup|amOnPage|amOnUrl|amOnSubdomain|appendField|assertArrayIsSorted|assertArraySubset|assertElementContainsAttribute|attachFile|cancelPopup|checkOption|clearField|click|clickWithLeftButton|clickWithRightButton|closeAdminNotification|closeTab|comment|conditionalClick|createData|deleteData|updateData|getData|dontSee|dontSeeJsError|dontSeeCheckboxIsChecked|dontSeeCookie|dontSeeCurrentUrlEquals|dontSeeCurrentUrlMatches|dontSeeElement|dontSeeElementInDOM|dontSeeInCurrentUrl|dontSeeInField|dontSeeInFormFields|dontSeeInPageSource|dontSeeInSource|dontSeeInTitle|dontSeeLink|dontSeeOptionIsSelected|doubleClick|dragAndDrop|entity|executeJS|fillField|formatMoney|generateDate|grabAttributeFrom|grabCookie|grabFromCurrentUrl|grabMultiple|grabPageSource|grabTextFrom|grabValueFrom|loadSessionSnapshot|loginAsAdmin|magentoCLI|magentoCron|makeScreenshot|maximizeWindow|moveBack|moveForward|moveMouseOver|mSetLocale|mResetLocale|openNewTab|pauseExecution|parseFloat|pressKey|reloadPage|resetCookie|submitForm|resizeWindow|saveSessionSnapshot|scrollTo|scrollToTopOfPage|searchAndMultiSelectOption|see|seeCheckboxIsChecked|seeCookie|seeCurrentUrlEquals|seeCurrentUrlMatches|seeElement|seeElementInDOM|seeInCurrentUrl|seeInField|seeInFormFields|seeInPageSource|seeInPopup|seeInSource|seeInTitle|seeLink|seeNumberOfElements|seeOptionIsSelected|selectOption|setCookie|submitForm|switchToIFrame|switchToNextTab|switchToPreviousTab|switchToWindow|typeInPopup|uncheckOption|unselectOption|wait|waitForAjaxLoad|waitForElement|waitForElementChange|waitForElementNotVisible|waitForElementVisible|waitForPwaElementNotVisible|waitForPwaElementVisible|waitForJS|waitForLoadingMaskToDisappear|waitForPageLoad|waitForText|assertArrayHasKey|assertArrayNotHasKey|assertArraySubset|assertContains|assertCount|assertEmpty|assertEquals|assertFalse|assertFileExists|assertFileNotExists|assertGreaterOrEquals|assertGreaterThan|assertGreaterThanOrEqual|assertInstanceOf|assertInternalType|assertIsEmpty|assertLessOrEquals|assertLessThan|assertLessThanOrEqual|assertNotContains|assertNotEmpty|assertNotEquals|assertNotInstanceOf|assertNotNull|assertNotRegExp|assertNotSame|assertNull|assertRegExp|assertSame|assertStringStartsNotWith|assertStringStartsWith|assertTrue|expectException|fail|dontSeeFullUrlEquals|dontSee|dontSeeFullUrlMatches|dontSeeInFullUrl|seeFullUrlEquals|seeFullUrlMatches|seeInFullUrl|grabFromFullUrl|helper"> ]> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../src/Magento/FunctionalTestingFramework/ObjectManager/etc/config.xsd"> @@ -222,6 +222,8 @@ <item name="/tests/test/(createData|updateData|getData)/requiredEntity" xsi:type="string">createDataKey</item> <item name="/tests/test/(createData|updateData|getData)/field" xsi:type="string">key</item> <item name="/tests/test/(actionGroup|&commonTestActions;)" xsi:type="string">stepKey</item> + <item name="/tests/test/helper/argument" xsi:type="string">name</item> + <item name="/tests/test/(before|after)/helper/argument" xsi:type="string">name</item> <item name="/tests/test/(before|after)/(actionGroup|&commonTestActions;)" xsi:type="string">stepKey</item> <item name="/tests/test/remove" xsi:type="string">keyForRemoval</item> <item name="/tests/test/(before|after)/remove" xsi:type="string">keyForRemoval</item> @@ -239,6 +241,8 @@ <argument name="assocArrayAttributes" xsi:type="array"> <item name="/tests/test/(actionGroup|&commonTestActions;)" xsi:type="string">stepKey</item> <item name="/tests/test/(before|after)/(actionGroup|&commonTestActions;)" xsi:type="string">stepKey</item> + <item name="/tests/test/helper/argument" xsi:type="string">name</item> + <item name="/tests/test/(before|after)/helper/argument" xsi:type="string">name</item> <item name="/tests/test/remove" xsi:type="string">keyForRemoval</item> <item name="/tests/test/(before|after)/remove" xsi:type="string">keyForRemoval</item> <item name="/tests/test" xsi:type="string">name</item> @@ -299,6 +303,7 @@ <argument name="idAttributes" xsi:type="array"> <item name="/actionGroups/actionGroup" xsi:type="string">name</item> <item name="/actionGroups/actionGroup/arguments/argument" xsi:type="string">name</item> + <item name="/actionGroups/actionGroup/helper/argument" xsi:type="string">name</item> <item name="/actionGroups/actionGroup/(&commonTestActions;)" xsi:type="string">stepKey</item> <item name="/actionGroups/actionGroup/(createData|updateData|getData)/requiredEntity" xsi:type="string">createDataKey</item> <item name="/actionGroups/actionGroup/(createData|updateData|getData)/field" xsi:type="string">key</item> @@ -316,6 +321,7 @@ <item name="/actionGroups/actionGroup/remove" xsi:type="string">keyForRemoval</item> <item name="/actionGroups/actionGroup" xsi:type="string">name</item> <item name="/actionGroups/actionGroup/arguments/argument" xsi:type="string">name</item> + <item name="/actionGroups/actionGroup/helper/argument" xsi:type="string">name</item> <item name="/actionGroups/actionGroup/(createData|updateData|getData)/requiredEntity" xsi:type="string">createDataKey</item> <item name="/actionGroups/actionGroup/(createData|updateData|getData)/field" xsi:type="string">key</item> </argument> diff --git a/src/Magento/FunctionalTestingFramework/Helper/Acceptance.php b/src/Magento/FunctionalTestingFramework/Helper/Acceptance.php deleted file mode 100644 index fafe167af..000000000 --- a/src/Magento/FunctionalTestingFramework/Helper/Acceptance.php +++ /dev/null @@ -1,42 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\FunctionalTestingFramework\Helper; - -use Magento\FunctionalTestingFramework\Module\MagentoWebDriver; -use Codeception\Module; - -/** - * Class Acceptance - * - * Define global actions - * All public methods declared in helper class will be available in $I - */ -class Acceptance extends Module -{ - /** - * Reconfig WebDriver. - * - * @param string $config - * @param string $value - * @return void - */ - public function changeConfiguration($config, $value) - { - $this->getModule(MagentoWebDriver::class)->_reconfigure([$config => $value]); - } - - /** - * Get WebDriver configuration. - * - * @param string $config - * @return string - */ - public function getConfiguration($config) - { - return $this->getModule(MagentoWebDriver::class)->_getConfig($config); - } -} diff --git a/src/Magento/FunctionalTestingFramework/Helper/AdminUrlList.php b/src/Magento/FunctionalTestingFramework/Helper/AdminUrlList.php deleted file mode 100644 index ca96033dc..000000000 --- a/src/Magento/FunctionalTestingFramework/Helper/AdminUrlList.php +++ /dev/null @@ -1,189 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\FunctionalTestingFramework\Helper; - -/** - * Class AdminUrlList - * @SuppressWarnings(PHPMD) - */ -// @codingStandardsIgnoreFile -class AdminUrlList -{ - public static $adminLoginPage = '/admin/admin/'; - public static $adminLogoutPage = '/admin/admin/auth/logout/'; - public static $adminForgotYourPasswordPage = '/admin/admin/auth/forgotpassword/'; - - public static $adminDashboardPage = '/admin/admin/dashboard/'; - - public static $adminOrdersGrid = '/admin/sales/order/'; - public static $adminOrderByIdPage = '/admin/sales/order/view/order_id/'; - public static $adminAddOrderPage = '/admin/sales/order_create/index/'; - public static $adminAddOrderForCustomerIdPage = '/admin/sales/order_create/index/customer_id/'; - public static $adminInvoicesGrid = '/admin/sales/invoice/'; - public static $adminAddInvoiceForOrderIdPage = '/admin/sales/order_invoice/new/order_id/'; - public static $adminShipmentsGrid = '/admin/sales/shipment/'; - public static $adminShipmentForIdPage = '/admin/sales/shipment/view/shipment_id/'; - public static $adminCreditMemosGrid = '/admin/sales/creditmemo/'; - public static $adminCreditMemoForIdPage = '/admin/sales/creditmemo/view/creditmemo_id/'; - public static $adminBillingAgreementsGrid = '/admin/paypal/billing_agreement/'; - // TODO: Determine the correct address for Billing Agreements for Billing Agreement ID page URL. - public static $adminTransactionsGrid = '/admin/sales/transactions/'; - // TODO: Determine the correct address for Transactions for Transaction ID page URL. - - public static $adminCatalogGrid = '/admin/catalog/product/'; - public static $adminProductForIdPage = '/admin/catalog/product/edit/id/'; - public static $adminAddSimpleProductPage = '/admin/catalog/product/new/set/4/type/simple/'; - public static $adminAddConfigurableProductPage = '/admin/catalog/product/new/set/4/type/configurable/'; - public static $adminAddGroupedProductPage = '/admin/catalog/product/new/set/4/type/grouped/'; - public static $adminAddVirtualProductPage = '/admin/catalog/product/new/set/4/type/virtual/'; - public static $adminAddBundleProductPage = '/admin/catalog/product/new/set/4/type/bundle/'; - public static $adminAddDownloadableProductPage = '/admin/catalog/product/new/set/4/type/downloadable/'; - - public static $adminCategoriesPage = '/admin/catalog/category/'; - public static $adminCategoryForIdPage = '/admin/catalog/category/edit/id/'; - public static $adminAddRootCategoryPage = '/admin/catalog/category/add/store/0/parent/1'; - public static $adminAddSubCategoryPage = '/admin/catalog/category/add/store/0/parent/2'; - - public static $adminAllCustomersGrid = '/admin/customer/index/'; - public static $adminCustomersNowOnlineGrid = '/admin/customer/online/'; - public static $adminCustomerForCustomerIdPage = '/admin/customer/index/edit/id/'; - public static $adminAddCustomerPage = '/admin/customer/index/new/'; - - public static $adminCatalogPriceRuleGrid = '/admin/catalog_rule/promo_catalog/'; - public static $adminCatalogPriceRuleForIdPage = '/admin/catalog_rule/promo_catalog/edit/id/'; - public static $adminAddCatalogPriceRulePage = '/admin/catalog_rule/promo_catalog/new/'; - public static $adminCartPriceRulesGrid = '/admin/sales_rule/promo_quote/'; - public static $adminCartPriceRuleForIdPage = '/admin/sales_rule/promo_quote/edit/id/'; - public static $adminAddCartPriceRulePage = '/admin/sales_rule/promo_quote/new/'; - public static $adminEmailTemplatesGrid = '/admin/admin/email_template/'; - public static $adminEmailTemplateForIdPage = '/admin/admin/email_template/edit/id/'; - public static $adminAddEmailTemplatePage = '/admin/admin/email_template/new/'; - public static $adminNewsletterTemplateGrid = '/admin/newsletter/template/'; - public static $adminNewsletterTemplateForIdPage = '/admin/newsletter/template/edit/id/'; - public static $adminAddNewsletterTemplatePage = '/admin/newsletter/template/new/'; - public static $adminNewsletterQueueGrid = '/admin/newsletter/queue/'; - // TODO: Determine if there is a Details page for the Newsletter Queue. - public static $adminNewsletterSubscribersGrid = '/admin/newsletter/subscriber/'; - public static $adminURLRewritesGrid = '/admin/admin/url_rewrite/index/'; - public static $adminURLRewriteForIdPage = '/admin/admin/url_rewrite/edit/id/'; - public static $adminAddURLRewritePage = '/admin/admin/url_rewrite/edit/id'; // If you don't list an ID it drops you on the Add page. - public static $adminSearchTermsGrid = '/admin/search/term/index/'; - public static $adminSearchTermForIdPage = '/admin/search/term/edit/id/'; - public static $adminAddSearchTermPage = '/admin/search/term/new/'; - public static $adminSearchSynonymsGrid = '/admin/search/synonyms/index/'; - public static $adminSearchSynonymGroupForIdPage = '/admin/search/synonyms/edit/group_id/'; - public static $adminAddSearchSynonymGroupPage = '/admin/search/synonyms/new/'; - public static $adminSiteMapGrid = '/admin/admin/sitemap/'; - public static $adminSiteMapForIdPage = '/admin/admin/sitemap/edit/sitemap_id/'; - public static $adminAddSiteMapPage = '/admin/admin/sitemap/new/'; - public static $adminReviewsGrid = '/admin/review/product/index/'; - public static $adminReviewByIdPage = '/admin/review/product/edit/id/'; - public static $adminAddReviewPage = '/admin/review/product/new/'; - - public static $adminPagesGrid = '/admin/cms/page/'; - public static $adminPageForIdPage = '/admin/cms/page/edit/page_id/'; - public static $adminAddPagePage = '/admin/cms/page/new/'; - public static $adminBlocksGrid = '/admin/cms/block/'; - public static $adminBlockForIdPage = '/admin/cms/block/edit/block_id/'; - public static $adminAddBlockPage = '/admin/cms/block/new/'; - public static $adminWidgetsGrid = '/admin/admin/widget_instance/'; - // TODO: Determine how the Edit Widget URLs are generated. - public static $adminAddWidgetPage = '/admin/admin/widget_instance/new/'; - public static $adminDesignConfigurationGrid = '/admin/theme/design_config/'; - // TODO: Determine how the Design Configuration URLs are generated. - public static $adminThemesGrid = '/admin/admin/system_design_theme/'; - public static $adminThemeByIdPage = '/admin/admin/system_design_theme/edit/id/'; - public static $adminStoreContentScheduleGrid = '/admin/admin/system_design/'; - public static $adminStoreContentScheduleForIdPage = '/admin/admin/system_design/edit/id/'; - public static $adminAddStoreDesignChangePage = '/admin/admin/system_design/new/'; - - public static $adminProductsInCartGrid = '/admin/reports/report_shopcart/product/'; - public static $adminSearchTermsReportGrid = '/admin/search/term/report/'; - public static $adminAbandonedCartsGrid = '/admin/reports/report_shopcart/abandoned/'; - public static $adminNewsletterProblemsReportGrid = '/admin/newsletter/problem/'; - public static $adminCustomerReviewsReportGrid = '/admin/reports/report_review/customer/'; - public static $adminProductReviewsReportGrid = '/admin/reports/report_review/product/'; - public static $adminProductReviewsForProductIdPage = '/admin/review/product/index/productId/'; - public static $adminOrdersReportGrid = '/admin/reports/report_sales/sales/'; - public static $adminTaxReportGrid = '/admin/reports/report_sales/tax/'; - public static $adminInvoiceReportGrid = '/admin/reports/report_sales/invoiced/'; - public static $adminShippingReportGrid = '/admin/reports/report_sales/shipping/'; - public static $adminRefundsReportGrid = '/admin/reports/report_sales/refunded/'; - public static $adminCouponsReportGrid = '/admin/reports/report_sales/coupons/'; - public static $adminPayPalSettlementReportsGrid = '/admin/paypal/paypal_reports/'; - public static $adminBraintreeSettlementReportGrid = '/admin/braintree/report/'; - public static $adminOrderTotalReportGrid = '/admin/reports/report_customer/totals/'; - public static $adminOrderCountReportGrid = '/admin/reports/report_customer/orders/'; - public static $adminNewAccountsReportGrid = '/admin/reports/report_customer/accounts/'; - public static $adminProductViewsReportGrid = '/admin/reports/report_product/viewed/'; - public static $adminBestsellersReportGrid = '/admin/reports/report_sales/bestsellers/'; - public static $adminLowStockReportGrid = '/admin/reports/report_product/lowstock/'; - public static $adminOrderedProductsReportGrid = '/admin/reports/report_product/sold/'; - public static $adminDownloadsReportGrid = '/admin/reports/report_product/downloads/'; - public static $adminRefreshStatisticsGrid = '/admin/reports/report_statistics/'; - - public static $adminAllStoresGrid = '/admin/admin/system_store/'; - public static $adminCreateStoreViewPage = '/admin/admin/system_store/newStore/'; - public static $adminCreateStorePage = '/admin/admin/system_store/newGroup/'; - public static $adminCreateWebsitePage = '/admin/admin/system_store/newWebsite/'; - public static $adminWebsiteByIdPage = '/admin/admin/system_store/editWebsite/website_id/'; - public static $adminStoreViewByIdPage = '/admin/admin/system_store/editStore/store_id/'; - public static $adminStoreByIdPage = '/admin/admin/system_store/editGroup/group_id/'; - public static $adminConfigurationGrid = '/admin/admin/system_config/'; - public static $adminTermsAndConditionsGrid = '/admin/checkout/agreement/'; - public static $adminTermsAndConditionByIdPage = '/admin/checkout/agreement/edit/id/'; - public static $adminAddNewTermsAndConditionPage = '/admin/checkout/agreement/new/'; - public static $adminOrderStatusGrid = '/admin/sales/order_status/'; - public static $adminAddOrderStatusPage = '/admin/sales/order_status/new/'; - // TODO: Determine how the Order Status URLs are generated. - public static $adminTaxRulesGrid = '/admin/tax/rule/'; - public static $adminTaxRuleByIdPage = '/admin/tax/rule/edit/rule/'; - public static $adminAddTaxRulePage = '/admin/tax/rule/new/'; - public static $adminTaxZonesAndRatesGrid = '/admin/tax/rate/'; - public static $adminTaxZoneAndRateByIdPage = '/admin/tax/rate/edit/rate/'; - public static $adminAddTaxZoneAndRatePage = '/admin/tax/rate/add/'; - public static $adminCurrencyRatesPage = '/admin/admin/system_currency/'; - public static $adminCurrencySymbolsPage = '/admin/admin/system_currencysymbol/'; - public static $adminProductAttributesGrid = '/admin/catalog/product_attribute/'; - public static $adminProductAttributeForIdPage = '/admin/catalog/product_attribute/edit/attribute_id/'; - public static $adminAddProductAttributePage = '/admin/catalog/product_attribute/new/'; - public static $adminAttributeSetsGrid = '/admin/catalog/product_set/'; - public static $adminAttributeSetByIdPage = '/admin/catalog/product_set/edit/id/'; - public static $adminAddAttributeSetPage = '/admin/catalog/product_set/add/'; - public static $adminRatingsGrid = '/admin/review/rating/'; - public static $adminRatingForIdPage = '/admin/review/rating/edit/id/'; - public static $adminAddRatingPage = '/admin/review/rating/new/'; - public static $adminCustomerGroupsGrid = '/admin/customer/group/'; - public static $adminCustomerGroupByIdPage = '/admin/customer/group/edit/id/'; - public static $adminAddCustomerGroupPage = '/admin/customer/group/new/'; - - public static $adminImportPage = '/admin/admin/import/'; - public static $adminExportPage = '/admin/admin/export/'; - public static $adminImportAndExportTaxRatesPage = '/admin/tax/rate/importExport/'; - public static $adminImportHistoryGrid = '/admin/admin/history/'; - public static $adminIntegrationsGrid = '/admin/admin/integration/'; - public static $adminIntegrationByIdPage = '/admin/admin/integration/edit/id/'; - public static $adminAddIntegrationPage = '/admin/admin/integration/new/'; - public static $adminCacheManagementGrid = '/admin/admin/cache/'; - public static $adminBackupsGrid = '/admin/backup/index/'; - public static $adminIndexManagementGrid = '/admin/indexer/indexer/list/'; - public static $adminWebSetupWizardPage = '/setup/'; - public static $adminAllUsersGrid = '/admin/admin/user/'; - public static $adminUserByIdPage = '/admin/admin/user/edit/user_id/'; - public static $adminAddNewUserPage = '/admin/admin/user/new/'; - public static $adminLockedUsersGrid = '/admin/admin/locks/'; - public static $adminUserRolesGrid = '/admin/admin/user_role/'; - public static $adminUserRoleByIdPage = '/admin/admin/user_role/editrole/rid/'; - public static $adminAddUserRolePage = '/admin/admin/user_role/editrole/'; - public static $adminNotificationsGrid = '/admin/admin/notification/'; - public static $adminCustomVariablesGrid = '/admin/admin/system_variable/'; - public static $adminCustomVariableByIdPage = '/admin/admin/system_variable/edit/variable_id/'; - public static $adminAddCustomVariablePage = '/admin/admin/system_variable/new/'; - public static $adminEncryptionKeyPage = '/admin/admin/crypt_key/'; - - public static $adminFindPartnersAndExtensions = '/admin/marketplace/index/'; -} \ No newline at end of file diff --git a/src/Magento/FunctionalTestingFramework/Helper/Code/ClassReader.php b/src/Magento/FunctionalTestingFramework/Helper/Code/ClassReader.php new file mode 100644 index 000000000..146a3d6a9 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Helper/Code/ClassReader.php @@ -0,0 +1,51 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\FunctionalTestingFramework\Helper\Code; + +/** + * Class ClassReader + * + * @internal + */ +class ClassReader +{ + /** + * Read class method signature + * + * @param string $className + * @param string $method + * @return array|null + * @throws \ReflectionException + */ + public function getParameters($className, $method) + { + $class = new \ReflectionClass($className); + $result = null; + $method = $class->getMethod($method); + if ($method) { + $result = []; + /** @var $parameter \ReflectionParameter */ + foreach ($method->getParameters() as $parameter) { + try { + $result[$parameter->getName()] = [ + 'type' => $parameter->getType() === null ? null : $parameter->getType()->getName(), + 'variableName' => $parameter->getName(), + 'isOptional' => $parameter->isOptional(), + 'optionalValue' => $parameter->isOptional() ? + $parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : null : + null + ]; + } catch (\ReflectionException $e) { + $message = $e->getMessage(); + throw new \ReflectionException($message, 0, $e); + } + } + } + + return $result; + } +} diff --git a/src/Magento/FunctionalTestingFramework/Helper/EntityRESTApiHelper.php b/src/Magento/FunctionalTestingFramework/Helper/EntityRESTApiHelper.php deleted file mode 100644 index 521ddc9ee..000000000 --- a/src/Magento/FunctionalTestingFramework/Helper/EntityRESTApiHelper.php +++ /dev/null @@ -1,112 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\FunctionalTestingFramework\Helper; - -use GuzzleHttp\Client; - -/** - * Class EntityRESTApiHelper - * @package Magento\FunctionalTestingFramework\Helper - */ -class EntityRESTApiHelper -{ - /** - * Integration admin token uri. - */ - const INTEGRATION_ADMIN_TOKEN_URI = '/rest/V1/integration/admin/token'; - - /** - * Application json header. - */ - const APPLICATION_JSON_HEADER = ['Content-Type' => 'application/json']; - - /** - * Rest API client. - * - * @var Client - */ - private $guzzle_client; - - /** - * EntityRESTApiHelper constructor. - * @param string $host - * @param string $port - */ - public function __construct($host, $port) - { - $this->guzzle_client = new Client([ - 'base_uri' => "http://{$host}:{$port}", - 'timeout' => 5.0, - ]); - } - - /** - * Submit Auth API Request. - * - * @param string $apiMethod - * @param string $requestURI - * @param string $jsonBody - * @param array $headers - * @return \Psr\Http\Message\ResponseInterface - */ - public function submitAuthAPIRequest($apiMethod, $requestURI, $jsonBody, $headers) - { - $allHeaders = $headers; - $authTokenVal = $this->getAuthToken(); - $authToken = ['Authorization' => 'Bearer ' . $authTokenVal]; - $allHeaders = array_merge($allHeaders, $authToken); - - return $this->submitAPIRequest($apiMethod, $requestURI, $jsonBody, $allHeaders); - } - - /** - * Function that sends a REST call to the integration endpoint for an authorization token. - * - * @return string - */ - private function getAuthToken() - { - $jsonArray = json_encode(['username' => 'admin', 'password' => 'admin123']); - - $response = $this->submitAPIRequest( - 'POST', - self::INTEGRATION_ADMIN_TOKEN_URI, - $jsonArray, - self::APPLICATION_JSON_HEADER - ); - - if ($response->getStatusCode() != 200) { - throwException($response->getReasonPhrase() .' Could not get admin token from service, please check logs.'); - } - - $authToken = str_replace('"', "", $response->getBody()->getContents()); - return $authToken; - } - - /** - * Function that submits an api request from the guzzle client using the following parameters: - * - * @param string $apiMethod - * @param string $requestURI - * @param string $jsonBody - * @param array $headers - * @return \Psr\Http\Message\ResponseInterface - */ - private function submitAPIRequest($apiMethod, $requestURI, $jsonBody, $headers) - { - $response = $this->guzzle_client->request( - $apiMethod, - $requestURI, - [ - 'headers' => $headers, - 'body' => $jsonBody - ] - ); - - return $response; - } -} diff --git a/src/Magento/FunctionalTestingFramework/Helper/Helper.php b/src/Magento/FunctionalTestingFramework/Helper/Helper.php new file mode 100644 index 000000000..897474dd2 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Helper/Helper.php @@ -0,0 +1,10 @@ +<?php + + +namespace Magento\FunctionalTestingFramework\Helper; + + +class Helper extends \Codeception\Module +{ + // +} \ No newline at end of file diff --git a/src/Magento/FunctionalTestingFramework/Helper/HelperContainer.php b/src/Magento/FunctionalTestingFramework/Helper/HelperContainer.php new file mode 100644 index 000000000..f53937bae --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Helper/HelperContainer.php @@ -0,0 +1,30 @@ +<?php + + +namespace Magento\FunctionalTestingFramework\Helper; + + +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; + +class HelperContainer +{ + private $helpers = []; + + public function __construct(array $helpers = []) + { + $this->helpers = $helpers; + } + + public function get(string $className) + { + if ($this->has($className)) { + return $this->helpers[$className]; + } + throw new TestFrameworkException('Custom helper ' . $className . 'not found.'); + } + + public function has(string $className) + { + return array_key_exists($className, $this->helpers); + } +} diff --git a/src/Magento/FunctionalTestingFramework/Helper/MagentoFakerData.php b/src/Magento/FunctionalTestingFramework/Helper/MagentoFakerData.php deleted file mode 100644 index 9c28a3531..000000000 --- a/src/Magento/FunctionalTestingFramework/Helper/MagentoFakerData.php +++ /dev/null @@ -1,122 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\FunctionalTestingFramework\Helper; - -/** - * Class MagentoFakerData - */ -class MagentoFakerData extends \Codeception\Module -{ - /** - * Get Customer data. - * - * @param array $additional - * @return array - */ - public function getCustomerData(array $additional = []) - { - $faker = \Faker\Factory::create(); - $customerData = [ - 'prefix' => $faker->title, - 'firstname' => $faker->firstName, - 'middlename' => $faker->firstName, - 'lastname' => $faker->lastName, - 'suffix' => \Faker\Provider\en_US\Person::suffix(), - 'email' => $faker->email, - 'dateOfBirth' => $faker->date('m/d/Y', 'now'), - 'gender' => rand(0, 1), - 'group_id' => 1, - 'store_id' => 1, - 'website_id' => 1, - 'taxVatNumber' => \Faker\Provider\at_AT\Payment::vat(), - 'company' => $faker->company, - 'phoneNumber' => $faker->phoneNumber, - 'address' => [ - 'address1' => $faker->streetAddress, - 'address2' => $faker->streetAddress, - 'city' => $faker->city, - 'country' => 'United States', - 'state' => \Faker\Provider\en_US\Address::state(), - 'zipCode' => $faker->postcode - ] - ]; - return array_merge($customerData, $additional); - } - - /** - * Get category data. - * - * @return array - */ - public function getCategoryData() - { - $faker = \Faker\Factory::create(); - - return [ - 'enableCategory' => $faker->boolean(), - 'includeInMenu' => $faker->boolean(), - 'categoryName' => $faker->md5, - 'categoryImage' => '', - 'description' => $faker->sentence(10, true), - 'addCMSBlock' => '', - - 'urlKey' => $faker->uuid, - 'metaTitle' => $faker->word, - 'metaKeywords' => $faker->sentence(5, true), - 'metaDescription' => $faker->sentence(10, true), - ]; - } - - /** - * Get simple product data. - * - * @return array - */ - public function getProductData() - { - $faker = \Faker\Factory::create(); - return [ - 'enableProduct' => $faker->boolean(), - 'attributeSet' => '', - 'productName' => $faker->text(20), - 'sku' => \Faker\Provider\DateTime::unixTime('now'), - 'price' => $faker->randomFloat(2, 0, 999), - 'quantity' => $faker->numberBetween(1, 999), - - 'urlKey' => $faker->uuid, - 'metaTitle' => $faker->word, - 'metaKeywords' => $faker->sentence(5, true), - 'metaDescription' => $faker->sentence(10, true) - ]; - } - - /** - * Get Content Page Data. - * - * @return array - */ - public function getContentPage() - { - $faker = \Faker\Factory::create(); - - $pageContent = [ - 'pageTitle' => $faker->sentence(3, true), - 'contentHeading' => $faker->sentence(3, true), - 'contentBody' => $faker->sentence(10, true), - 'urlKey' => $faker->uuid, - 'metaTitle' => $faker->word, - 'metaKeywords' => $faker->sentence(5, true), - 'metaDescription' => $faker->sentence(10, true), - 'from' => $faker->date($format = 'm/d/Y', 'now'), - 'to' => $faker->date($format = 'm/d/Y') - ]; - $pageContent['layoutUpdateXml'] = "<note><to>Tove</to><from>Jani</from><heading>Reminder</heading>"; - $pageContent['layoutUpdateXml'] .= "<body>Don't forget me this weekend!</body></note>"; - - return $pageContent; - } -} diff --git a/src/Magento/FunctionalTestingFramework/Helper/views/TestInjectMethod.mustache b/src/Magento/FunctionalTestingFramework/Helper/views/TestInjectMethod.mustache new file mode 100644 index 000000000..d921120cf --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Helper/views/TestInjectMethod.mustache @@ -0,0 +1,19 @@ + /** + * @var \Magento\FunctionalTestingFramework\Helper\HelperContainer + */ + private $helperContainer; + + /** + * Special method which automatically creates the respective objects. + */ + public function _inject( + {{argumentsWithTypes}} + ) { + $this->helperContainer = new \Magento\FunctionalTestingFramework\Helper\HelperContainer( + [ + {{#arguments}} + '{{type}}' => {{var}}, + {{/arguments}} + ] + ); + } diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php index dc1b158e1..3e1afae31 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php @@ -8,7 +8,6 @@ use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Test\Util\ActionMergeUtil; -use Magento\FunctionalTestingFramework\Test\Util\ObjectExtension; /** * Class ActionGroupObject diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php index 0ae3d336e..8bee7cff8 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php @@ -75,6 +75,7 @@ class ActionObject const DEFAULT_COMMAND_WAIT_TIMEOUT = 60; const ACTION_ATTRIBUTE_USERINPUT = 'userInput'; const ACTION_TYPE_COMMENT = 'comment'; + const ACTION_TYPE_HELPER = 'helper'; const INVISIBLE_STEP_ACTIONS = ['retrieveEntityField', 'getSecret']; /** @@ -282,6 +283,7 @@ public function setTimeout($timeout) public function resolveReferences() { if (empty($this->resolvedCustomAttributes)) { + $this->resolveHelperReferences(); $this->trimAssertionAttributes(); $this->resolveSelectorReferenceAndTimeout(); $this->resolveUrlReference(); @@ -293,6 +295,54 @@ public function resolveReferences() } } + /** + * @throws TestReferenceException + * @throws XmlException + */ + private function resolveHelperReferences() + { + if ($this->getType() !== 'helper') { + return; + } + $isResolved = false; + + try { + foreach ($this->actionAttributes as $attrKey => $attrValue) { + $this->actionAttributes[$attrKey] = $this->findAndReplaceReferences(SectionObjectHandler::getInstance(), $attrValue); + } + $isResolved = true; + } catch (\Exception $e) { + // catching exception to allow other entity type resolution to proceed + } + + try { + foreach ($this->actionAttributes as $attrKey => $attrValue) { + $this->actionAttributes[$attrKey] = $this->findAndReplaceReferences(PageObjectHandler::getInstance(), $attrValue); + } + $isResolved = true; + } catch (\Exception $e) { + // catching exception to allow other entity type resolution to proceed + } + + try { + foreach ($this->actionAttributes as $attrKey => $attrValue) { + $this->actionAttributes[$attrKey] = $this->findAndReplaceReferences(DataObjectHandler::getInstance(), $attrValue); + } + $isResolved = true; + } catch (\Exception $e) { + // catching exception to allow other entity type resolution to proceed + } + + if ($isResolved !== true) { + throw new TestReferenceException( + "Could not resolve entity reference \"{$attrValue}\" " + . "in Action with stepKey \"{$this->getStepKey()}\"", + ["input" => $attrValue, "stepKey" => $this->getStepKey()] + ); + + } + } + /** * Flattens expectedResult/actualResults/array nested elements, if necessary. * e.g. expectedResults[] -> ["expectedType" => "string", "expected" => "value"] diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/ActionObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/ActionObjectExtractor.php index fc874fa24..1f0bbdf77 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/ActionObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/ActionObjectExtractor.php @@ -22,6 +22,7 @@ class ActionObjectExtractor extends BaseObjectExtractor const TEST_ACTION_AFTER = 'after'; const TEST_STEP_MERGE_KEY = 'stepKey'; const ACTION_GROUP_TAG = 'actionGroup'; + const HELPER_TAG = 'helper'; const ACTION_GROUP_REF = 'ref'; const ACTION_GROUP_ARGUMENTS = 'arguments'; const ACTION_GROUP_ARG_VALUE = 'value'; @@ -84,6 +85,7 @@ public function extractActions($testActions, $testName = null) } $actionAttributes = $this->processActionGroupArgs($actionType, $actionAttributes); + $actionAttributes = $this->processHelperArgs($actionType, $actionAttributes); $linkedAction = $this->processLinkedActions($actionName, $actionData); $actions = $this->extractFieldActions($actionData, $actions); $actionAttributes = $this->extractFieldReferences($actionData, $actionAttributes); @@ -167,6 +169,38 @@ private function processActionGroupArgs($actionType, $actionAttributeData) return $actionAttributeArgData; } + /** + * Takes the helper arguments as an array that can be passed to PHP class + * defined in the action group xml. + * + * @param string $actionType + * @param array $actionAttributeData + * @return array + */ + private function processHelperArgs($actionType, $actionAttributeData) + { + $reservedHelperVariableNames = ['class', 'method']; + if ($actionType !== self::HELPER_TAG) { + return $actionAttributeData; + } + + $actionAttributeArgData = []; + foreach ($actionAttributeData as $attributeDataKey => $attributeDataValues) { + if (isset($attributeDataValues['nodeName']) && $attributeDataValues['nodeName'] == 'argument') { + if (isset($attributeDataValues['name']) && in_array($attributeDataValues['name'], $reservedHelperVariableNames)) { + throw new TestFrameworkException( + 'Helper argument names ' . implode(',', $reservedHelperVariableNames) . ' are reserved and can not be used.' + ); + } + $actionAttributeArgData[$attributeDataValues['name']] = $attributeDataValues['value'] ?? null; + continue; + } + $actionAttributeArgData[$attributeDataKey] = $attributeDataValues; + } + + return $actionAttributeArgData; + } + /** * Takes the array representing an action and validates it is a persistence type. If of type persistence, * the function checks for any user specified fields to extract as separate actions to be resolved independently diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd index 8670d9885..fbb21456f 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd @@ -11,6 +11,7 @@ <xs:group name="customTags"> <xs:choice> + <xs:element name="helper" type="helperType" minOccurs="0" maxOccurs="unbounded" /> <xs:element type="magentoCLIType" name="magentoCLI" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="magentoCronType" name="magentoCron" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="closeAdminNotificationType" name="closeAdminNotification" minOccurs="0" maxOccurs="unbounded"/> @@ -29,6 +30,25 @@ <!-- Complex Types --> + <xs:complexType name="helperType"> + <xs:sequence> + <xs:element name="argument" type="argumentType" minOccurs="0" maxOccurs="unbounded" /> + </xs:sequence> + <xs:attribute type="xs:string" name="class" use="required" /> + <xs:attribute type="xs:string" name="method" use="required" /> + <xs:attributeGroup ref="commonActionAttributes"/> + </xs:complexType> + + <xs:complexType name="argumentType" mixed="true"> + <xs:attribute name="name" use="required"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:pattern value="[^cm].*|c(.{0,3}|[^l].*|l[^a].*|la[^s].*|las[^s].*|lass.+)|m(.{0,4}|[^e].*|e[^t].*|et[^h].*|eth[^o].*|etho[^d].*|ethod.+)" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + </xs:complexType> + <xs:complexType name="magentoCLIType"> <xs:annotation> <xs:documentation> diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 275c01c8f..a27aedc75 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -25,6 +25,8 @@ use Magento\FunctionalTestingFramework\Util\Filesystem\DirSetupUtil; use Magento\FunctionalTestingFramework\Test\Util\ActionMergeUtil; use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; +use Mustache_Engine; +use Mustache_Loader_FilesystemLoader; /** * Class TestGenerator @@ -60,6 +62,13 @@ class TestGenerator const ARRAY_WRAP_OPEN = '['; const ARRAY_WRAP_CLOSE = ']'; + /** + * Array with helpers classes and methods. + * + * @var array + */ + private $customHelpers = []; + /** * Actor name for AcceptanceTest * @@ -268,6 +277,7 @@ public function assembleTestPhp($testObject) $cestPhp .= $classAnnotationsPhp; $cestPhp .= sprintf("class %s\n", $className); $cestPhp .= "{\n"; + $cestPhp .= $this->generateInjectMethod(); $cestPhp .= $hookPhp; $cestPhp .= $testsPhp; $cestPhp .= "}\n"; @@ -275,6 +285,28 @@ public function assembleTestPhp($testObject) return $cestPhp; } + private function generateInjectMethod() + { + if (empty($this->customHelpers)) { + return ""; + } + + $mustacheEngine = new Mustache_Engine([ + 'loader' => new Mustache_Loader_FilesystemLoader(dirname(__DIR__) . DIRECTORY_SEPARATOR . "Helper" . DIRECTORY_SEPARATOR . 'views') + ]); + + $argumentsWithType = []; + $arguments = []; + foreach ($this->customHelpers as $customHelperVar => $customHelperType) { + $argumentsWithType[] = $customHelperType . ' ' . $customHelperVar; + $arguments[] = ['type' => $customHelperType, 'var' => $customHelperVar]; + } + $mustacheData['argumentsWithTypes'] = implode(', ' . PHP_EOL, $argumentsWithType); + $mustacheData['arguments'] = $arguments; + + return $mustacheEngine->render('TestInjectMethod', $mustacheData); + } + /** * Load ALL Test objects. Loop over and pass each to the assembleTestPhp function. * @@ -774,6 +806,35 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato } switch ($actionObject->getType()) { + case "helper": + if (!in_array($customActionAttributes['class'], $this->customHelpers)) { + $this->customHelpers['$' . $stepKey] = $customActionAttributes['class']; + } + + $arguments = []; + $classReader = new \Magento\FunctionalTestingFramework\Helper\Code\ClassReader(); + $parameters = $classReader->getParameters( + $customActionAttributes['class'], + $customActionAttributes['method'] + ); + foreach ($parameters as $parameter) { + if (isset($customActionAttributes[$parameter['variableName']])) { + $value = $customActionAttributes[$parameter['variableName']]; + $arguments[] = $this->addUniquenessFunctionCall( + $value, + $parameter['type'] === 'string' || $parameter['type'] === null + ); + } elseif (!$parameter['isOptional']) { + throw new TestFrameworkException( + 'Argument \'' . $parameter['variableName'] . '\' for method ' + . $customActionAttributes['class'] . '::' . $customActionAttributes['method'] + . ' is not found.' + ); + } + } + + $testSteps .= $this->wrapFunctionCall($actor, $actionObject, $arguments); + break; case "createData": $entity = $customActionAttributes['entity']; @@ -1844,7 +1905,15 @@ private function addDollarSign($input) private function wrapFunctionCall($actor, $action, ...$args) { $isFirst = true; - $output = sprintf("\t\t$%s->%s(", $actor, $action->getType()); + $isActionHelper = $action->getType() === 'helper'; + $actionType = $action->getType(); + if ($isActionHelper) { + $actor = "this->helperContainer->get('" . $action->getCustomActionAttributes()['class'] . "')"; + $args = $args[0]; + $actionType = $action->getCustomActionAttributes()['method']; + } + + $output = sprintf("\t\t$%s->%s(", $actor, $actionType); for ($i = 0; $i < count($args); $i++) { if (null === $args[$i]) { continue; From debda269c526d3f5c964fd96a1499725d5ad22ec Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Sun, 15 Mar 2020 23:38:13 -0500 Subject: [PATCH 298/888] MQE-1964: MFTF Helper - Implementation --- .../FunctionalTestingFramework/Util/TestGenerator.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index a27aedc75..713a49fcb 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -832,7 +832,12 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato ); } } - + $testSteps .= sprintf( + "\t\t$%s->comment('[%s] %s()');" . PHP_EOL, + $actor, + $stepKey, + $customActionAttributes['class'] . '::' . $customActionAttributes['method'] + ); $testSteps .= $this->wrapFunctionCall($actor, $actionObject, $arguments); break; case "createData": From 4a710d6ccee5fa4fce982afbbf8d02391cced849 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Sun, 15 Mar 2020 23:46:51 -0500 Subject: [PATCH 299/888] MQE-1964: MFTF Helper - Implementation --- src/Magento/FunctionalTestingFramework/Util/TestGenerator.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 713a49fcb..624e06213 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -817,12 +817,13 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $customActionAttributes['class'], $customActionAttributes['method'] ); + $typesToQuote = ['string', 'float']; foreach ($parameters as $parameter) { if (isset($customActionAttributes[$parameter['variableName']])) { $value = $customActionAttributes[$parameter['variableName']]; $arguments[] = $this->addUniquenessFunctionCall( $value, - $parameter['type'] === 'string' || $parameter['type'] === null + in_array($parameter['type'], $typesToQuote) || $parameter['type'] === null ); } elseif (!$parameter['isOptional']) { throw new TestFrameworkException( From 73a5ad62fbc89890d6e1068a1a2dbf710d6a1b71 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 16 Mar 2020 10:03:45 -0500 Subject: [PATCH 300/888] MQE-1964: MFTF Helper - Implementation - fix static tests --- .../MFTF/DevDocs/Helper/CustomHelper.php | 26 +++++++++++++++-- .../Helper/Helper.php | 11 +++++-- .../Helper/HelperContainer.php | 29 +++++++++++++++++-- .../Test/Objects/ActionObject.php | 20 +++++++++---- .../Test/Util/ActionObjectExtractor.php | 8 +++-- .../Util/TestGenerator.php | 9 +++++- 6 files changed, 88 insertions(+), 15 deletions(-) diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php b/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php index cc716d11b..57bb016d2 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php +++ b/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php @@ -1,4 +1,8 @@ <?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ namespace MFTF\DevDocs\Helper; @@ -6,8 +10,26 @@ class CustomHelper extends Helper { - public function goTo(string $url, $test, array $module = [], $superBla = null, $bla = 'blaValue', array $arraysomething = []) - { + /** + * Custom helper. + * + * @param string $url + * @param float $test + * @param array $module + * @param null $superBla + * @param string $bla + * @param array $arraysomething + * @return void + */ + public function goTo( + string $url, + float $test, + array $module = [], + $superBla = null, + $bla = 'blaValue', + array $arraysomething = [] + ) { print("this is it: " . $url . PHP_EOL); + sleep(4); } } diff --git a/src/Magento/FunctionalTestingFramework/Helper/Helper.php b/src/Magento/FunctionalTestingFramework/Helper/Helper.php index 897474dd2..e47aca32b 100644 --- a/src/Magento/FunctionalTestingFramework/Helper/Helper.php +++ b/src/Magento/FunctionalTestingFramework/Helper/Helper.php @@ -1,10 +1,15 @@ <?php - +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ namespace Magento\FunctionalTestingFramework\Helper; - +/** + * Class Helper to abstract Codeception module class and make possible to add own functionality if needed. + */ class Helper extends \Codeception\Module { // -} \ No newline at end of file +} diff --git a/src/Magento/FunctionalTestingFramework/Helper/HelperContainer.php b/src/Magento/FunctionalTestingFramework/Helper/HelperContainer.php index f53937bae..83a71fbc0 100644 --- a/src/Magento/FunctionalTestingFramework/Helper/HelperContainer.php +++ b/src/Magento/FunctionalTestingFramework/Helper/HelperContainer.php @@ -1,20 +1,39 @@ <?php - +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ namespace Magento\FunctionalTestingFramework\Helper; - use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +/** + * Class HelperContainer + */ class HelperContainer { + /** + * @var Helper[] + */ private $helpers = []; + /** + * HelperContainer constructor. + * @param array $helpers + */ public function __construct(array $helpers = []) { $this->helpers = $helpers; } + /** + * Returns helper object by it's class name. + * + * @param string $className + * @return Helper + * @throws TestFrameworkException + */ public function get(string $className) { if ($this->has($className)) { @@ -23,6 +42,12 @@ public function get(string $className) throw new TestFrameworkException('Custom helper ' . $className . 'not found.'); } + /** + * Verifies that helper object exist. + * + * @param string $className + * @return boolean + */ public function has(string $className) { return array_key_exists($className, $this->helpers); diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php index 8bee7cff8..648471c7a 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php @@ -296,8 +296,10 @@ public function resolveReferences() } /** + * Resolves references for helpers. + * * @throws TestReferenceException - * @throws XmlException + * @return void */ private function resolveHelperReferences() { @@ -308,7 +310,10 @@ private function resolveHelperReferences() try { foreach ($this->actionAttributes as $attrKey => $attrValue) { - $this->actionAttributes[$attrKey] = $this->findAndReplaceReferences(SectionObjectHandler::getInstance(), $attrValue); + $this->actionAttributes[$attrKey] = $this->findAndReplaceReferences( + SectionObjectHandler::getInstance(), + $attrValue + ); } $isResolved = true; } catch (\Exception $e) { @@ -317,7 +322,10 @@ private function resolveHelperReferences() try { foreach ($this->actionAttributes as $attrKey => $attrValue) { - $this->actionAttributes[$attrKey] = $this->findAndReplaceReferences(PageObjectHandler::getInstance(), $attrValue); + $this->actionAttributes[$attrKey] = $this->findAndReplaceReferences( + PageObjectHandler::getInstance(), + $attrValue + ); } $isResolved = true; } catch (\Exception $e) { @@ -326,7 +334,10 @@ private function resolveHelperReferences() try { foreach ($this->actionAttributes as $attrKey => $attrValue) { - $this->actionAttributes[$attrKey] = $this->findAndReplaceReferences(DataObjectHandler::getInstance(), $attrValue); + $this->actionAttributes[$attrKey] = $this->findAndReplaceReferences( + DataObjectHandler::getInstance(), + $attrValue + ); } $isResolved = true; } catch (\Exception $e) { @@ -339,7 +350,6 @@ private function resolveHelperReferences() . "in Action with stepKey \"{$this->getStepKey()}\"", ["input" => $attrValue, "stepKey" => $this->getStepKey()] ); - } } diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/ActionObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/ActionObjectExtractor.php index 1f0bbdf77..d9b8d32fb 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/ActionObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/ActionObjectExtractor.php @@ -176,6 +176,7 @@ private function processActionGroupArgs($actionType, $actionAttributeData) * @param string $actionType * @param array $actionAttributeData * @return array + * @throws TestFrameworkException */ private function processHelperArgs($actionType, $actionAttributeData) { @@ -187,9 +188,12 @@ private function processHelperArgs($actionType, $actionAttributeData) $actionAttributeArgData = []; foreach ($actionAttributeData as $attributeDataKey => $attributeDataValues) { if (isset($attributeDataValues['nodeName']) && $attributeDataValues['nodeName'] == 'argument') { - if (isset($attributeDataValues['name']) && in_array($attributeDataValues['name'], $reservedHelperVariableNames)) { + if (isset($attributeDataValues['name']) + && in_array($attributeDataValues['name'], $reservedHelperVariableNames)) { + $message = 'Helper argument names ' . implode(',', $reservedHelperVariableNames); + $message .= ' are reserved and can not be used.'; throw new TestFrameworkException( - 'Helper argument names ' . implode(',', $reservedHelperVariableNames) . ' are reserved and can not be used.' + $message ); } $actionAttributeArgData[$attributeDataValues['name']] = $attributeDataValues['value'] ?? null; diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 624e06213..a7053ac1d 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -285,6 +285,11 @@ public function assembleTestPhp($testObject) return $cestPhp; } + /** + * Generates _injectMethod based on $this->customHelpers. + * + * @return string + */ private function generateInjectMethod() { if (empty($this->customHelpers)) { @@ -292,7 +297,9 @@ private function generateInjectMethod() } $mustacheEngine = new Mustache_Engine([ - 'loader' => new Mustache_Loader_FilesystemLoader(dirname(__DIR__) . DIRECTORY_SEPARATOR . "Helper" . DIRECTORY_SEPARATOR . 'views') + 'loader' => new Mustache_Loader_FilesystemLoader( + dirname(__DIR__) . DIRECTORY_SEPARATOR . "Helper" . DIRECTORY_SEPARATOR . 'views' + ) ]); $argumentsWithType = []; From 516c88a2e897ad32abb7545672a22ca3b41febf1 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 16 Mar 2020 12:58:16 -0500 Subject: [PATCH 301/888] MQE-1964: MFTF Helper - Implementation - add travis build for functional test execution --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index fb21686b8..083b87248 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,10 @@ language: php php: - 7.2 - 7.3 +services: + - docker +before_install: + - docker run -d -p 4444:4444 -v /dev/shm:/dev/shm selenium/standalone-chrome:3.141.59-zirconium install: composer install --no-interaction --prefer-source env: matrix: From 345ec25d73c0333cd79b148fa461056557fc7963 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 16 Mar 2020 13:02:06 -0500 Subject: [PATCH 302/888] MQE-1964: MFTF Helper - Implementation - add travis build for functional test execution --- .travis.yml | 1 + bin/functional | 10 ++++++++++ .../tests/MFTF/DevDocs/Helper/CustomHelper.php | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100755 bin/functional diff --git a/.travis.yml b/.travis.yml index 083b87248..fba3b46ae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,7 @@ env: matrix: - VERIFICATION_TOOL=phpunit-checks - VERIFICATION_TOOL=static-checks + - VERIFICATION_TOOL=functional script: - bin/$VERIFICATION_TOOL after_success: diff --git a/bin/functional b/bin/functional new file mode 100755 index 000000000..99377337e --- /dev/null +++ b/bin/functional @@ -0,0 +1,10 @@ +# Copyright © Magento, Inc. All rights reserved. +# See COPYING.txt for license details. + +set -e + +echo "===============================" +echo " EXECUTE DevDocsTest " +echo "===============================" +bin/mftf build:project +bin/mftf run:test DevDocsTest -f diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php b/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php index 57bb016d2..cb98e0a0d 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php +++ b/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php @@ -23,7 +23,7 @@ class CustomHelper extends Helper */ public function goTo( string $url, - float $test, + $test, array $module = [], $superBla = null, $bla = 'blaValue', From 56d8f3caff2661636221b9c35ef34dd0029f0684 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 16 Mar 2020 13:41:40 -0500 Subject: [PATCH 303/888] MQE-1964: MFTF Helper - Implementation - add travis build for functional test execution --- .../tests/MFTF/DevDocs/Helper/CustomHelper.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php b/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php index cb98e0a0d..a99e089ae 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php +++ b/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php @@ -29,7 +29,12 @@ public function goTo( $bla = 'blaValue', array $arraysomething = [] ) { - print("this is it: " . $url . PHP_EOL); - sleep(4); + print('Hello, this is custom helper which gives an ability to write custom solutions without usage of <executeInSelenium /> and <performOn /> actions.'); + print('string $url = ' . $url . PHP_EOL); + print('$test = ' . $test . PHP_EOL); + print('array $module = [' . implode(', ', $module) . ']' . PHP_EOL); + print('$superBla = ' . $superBla . PHP_EOL); + print('$bla = ' . $url . PHP_EOL); + print('array $arraysomething = [' . implode(', ', $arraysomething) . ']' . PHP_EOL); } } From 4458f0ae0bfe468bf53365dc52718d0d480701d6 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 16 Mar 2020 13:47:41 -0500 Subject: [PATCH 304/888] MQE-1964: MFTF Helper - Implementation - add travis build for functional test execution --- .../functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml b/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml index 72c06d33c..2db170161 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml @@ -27,5 +27,11 @@ <argument name="module">['Test', 'Bla']</argument> <argument name="url">{{MFTFDocPage.url}}</argument> </helper> + + <helper class="\MFTF\DevDocs\Helper\CustomHelper" method="goTo" stepKey="custobhhmHelper"> + <argument name="test">{{contentSection.pageIntro}}</argument> + <argument name="module">['{{DeprecatedContentSection.pageIntro}}', 'Bla']</argument> + <argument name="url">{{DeprecatedMFTFDocPage.url}}</argument> + </helper> </test> </tests> From 2d73bdf3e5da14558b2a4979884a1a708120bcbe Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 16 Mar 2020 16:33:32 -0500 Subject: [PATCH 305/888] MQE-1964: MFTF Helper - Implementation - addressed review comments --- composer.lock | 5 ++-- .../DeprecatedCommentActionGroup.xml | 9 ------- .../DevDocs/ActionGroup/HelperActionGroup.xml | 24 +++++++++++++++++++ .../tests/MFTF/DevDocs/Data/HelperData.xml | 14 +++++++++++ .../MFTF/DevDocs/Helper/CustomHelper.php | 14 +++++++---- .../MFTF/DevDocs/Section/ContentSection.xml | 1 + .../DevDocs/Test/DeprecatedDevDocsTest.xml | 4 +--- .../tests/MFTF/DevDocs/Test/DevDocsTest.xml | 16 +++++++++++-- .../Util/TestGenerator.php | 17 ++++++++----- 9 files changed, 78 insertions(+), 26 deletions(-) create mode 100644 dev/tests/functional/tests/MFTF/DevDocs/ActionGroup/HelperActionGroup.xml create mode 100644 dev/tests/functional/tests/MFTF/DevDocs/Data/HelperData.xml diff --git a/composer.lock b/composer.lock index 43be8f65d..8757833cb 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ddf9b7965d3a2369bf0f22f5172d75dc", + "content-hash": "797f6caab6c9a1ae60da15083d03a548", "packages": [ { "name": "allure-framework/allure-codeception", @@ -6872,7 +6872,8 @@ "php": "~7.2.0||~7.3.0", "ext-curl": "*", "ext-json": "*", - "ext-openssl": "*" + "ext-openssl": "*", + "ext-dom": "*" }, "platform-dev": [] } diff --git a/dev/tests/functional/tests/MFTF/DevDocs/ActionGroup/DeprecatedCommentActionGroup.xml b/dev/tests/functional/tests/MFTF/DevDocs/ActionGroup/DeprecatedCommentActionGroup.xml index c9622bf7b..6c27627d5 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/ActionGroup/DeprecatedCommentActionGroup.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/ActionGroup/DeprecatedCommentActionGroup.xml @@ -8,15 +8,6 @@ <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="DeprecatedCommentActionGroup" deprecated="This Action Group is outdated and will be deleted next release."> - <arguments> - <argument name="test" type="string" /> - </arguments> <comment userInput="Action group to demonstrate deprecation notices." stepKey="comment" /> - <helper class="\MFTF\DevDocs\Helper\CustomHelper" method="goTo" stepKey="custobhhmHelper"> - <argument name="test">{{contentSection.pageIntro}}</argument> - <argument name="module">['{{test}}', 'Bla']</argument> - <argument name="url">{{test}}</argument> - </helper> - </actionGroup> </actionGroups> diff --git a/dev/tests/functional/tests/MFTF/DevDocs/ActionGroup/HelperActionGroup.xml b/dev/tests/functional/tests/MFTF/DevDocs/ActionGroup/HelperActionGroup.xml new file mode 100644 index 000000000..4e39a2da1 --- /dev/null +++ b/dev/tests/functional/tests/MFTF/DevDocs/ActionGroup/HelperActionGroup.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="HelperActionGroup"> + <arguments> + <argument name="test" type="string" /> + </arguments> + <comment userInput="Action group to demonstrate helper functionality available from action groups." stepKey="comment" /> + <helper class="\MFTF\DevDocs\Helper\CustomHelper" method="goTo" stepKey="customHelper"> + <argument name="test">{{contentSection.parametrizedSelector(test)}}</argument> + <argument name="module">['{{test}}', 'Bla']</argument> + <argument name="url">{{test}}</argument> + <argument name="bool">true</argument> + <argument name="float">4.400000000234234</argument> + <argument name="int">42</argument> + </helper> + </actionGroup> +</actionGroups> diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Data/HelperData.xml b/dev/tests/functional/tests/MFTF/DevDocs/Data/HelperData.xml new file mode 100644 index 000000000..bc84a5fb2 --- /dev/null +++ b/dev/tests/functional/tests/MFTF/DevDocs/Data/HelperData.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="HelperData"> + <data key="entityField">Some kind of data for testing purposes</data> + </entity> +</entities> diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php b/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php index a99e089ae..4f2725421 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php +++ b/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php @@ -14,27 +14,33 @@ class CustomHelper extends Helper * Custom helper. * * @param string $url - * @param float $test + * @param mixed $test + * @param bool $bool + * @param int $int + * @param float $float * @param array $module * @param null $superBla - * @param string $bla + * @param mixed $bla * @param array $arraysomething * @return void */ public function goTo( string $url, $test, + bool $bool, + int $int, + float $float, array $module = [], $superBla = null, $bla = 'blaValue', - array $arraysomething = [] + array $arraysomething = ['key' => 'value', 'test'] ) { print('Hello, this is custom helper which gives an ability to write custom solutions without usage of <executeInSelenium /> and <performOn /> actions.'); print('string $url = ' . $url . PHP_EOL); print('$test = ' . $test . PHP_EOL); print('array $module = [' . implode(', ', $module) . ']' . PHP_EOL); print('$superBla = ' . $superBla . PHP_EOL); - print('$bla = ' . $url . PHP_EOL); + print('$bla = ' . $bla . PHP_EOL); print('array $arraysomething = [' . implode(', ', $arraysomething) . ']' . PHP_EOL); } } diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Section/ContentSection.xml b/dev/tests/functional/tests/MFTF/DevDocs/Section/ContentSection.xml index c318fac3f..e0a133d51 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Section/ContentSection.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/Section/ContentSection.xml @@ -10,6 +10,7 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="contentSection"> <element name="pageIntro" type="text" selector=".page-intro"/> + <element name="parametrizedSelector" type="text" selector=".page-intro > {{justToProofItWorks}}" parameterized="true"/> <element name="deprecatedPageIntro" type="text" selector=".page-intro-old" deprecated="New element was introduced. Please use 'contentSection.pageIntro'"/> </section> </sections> diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Test/DeprecatedDevDocsTest.xml b/dev/tests/functional/tests/MFTF/DevDocs/Test/DeprecatedDevDocsTest.xml index a3f41a943..6aae104ed 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Test/DeprecatedDevDocsTest.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/Test/DeprecatedDevDocsTest.xml @@ -22,8 +22,6 @@ <!-- Open MFTF DevDocs Page --> <amOnPage stepKey="openMFTFDevDocPage" url="{{DeprecatedMFTFDocPage.url}}" /> <see stepKey="verifyPageIntroText" selector="{{DeprecatedContentSection.pageIntro}}" userInput="{{DeprecatedMessageData.message}}" /> - <actionGroup ref="DeprecatedCommentActionGroup" stepKey="commentActionGroup"> - <argument name="test" value="{{DeprecatedContentSection.pageIntro}}" /> - </actionGroup> + <actionGroup ref="DeprecatedCommentActionGroup" stepKey="commentActionGroup"/> </test> </tests> diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml b/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml index 2db170161..e7c3bed54 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml @@ -26,12 +26,24 @@ <argument name="test">{{contentSection.pageIntro}}</argument> <argument name="module">['Test', 'Bla']</argument> <argument name="url">{{MFTFDocPage.url}}</argument> + <argument name="bool">true</argument> + <argument name="float">1.2</argument> + <argument name="int">123</argument> </helper> - <helper class="\MFTF\DevDocs\Helper\CustomHelper" method="goTo" stepKey="custobhhmHelper"> + <helper class="\MFTF\DevDocs\Helper\CustomHelper" method="goTo" stepKey="customHelperWithArrayParametrized"> <argument name="test">{{contentSection.pageIntro}}</argument> - <argument name="module">['{{DeprecatedContentSection.pageIntro}}', 'Bla']</argument> + <argument name="module">[]</argument> <argument name="url">{{DeprecatedMFTFDocPage.url}}</argument> + <argument name="superBla">1.2</argument> + <argument name="bla" /> + <argument name="bool">false</argument> + <argument name="float">4.223</argument> + <argument name="int">987</argument> </helper> + + <actionGroup ref="HelperActionGroup" stepKey="actionGroupWithCustomHelper"> + <argument name="test" value="{{HelperData.entityField}}" /> + </actionGroup> </test> </tests> diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index a7053ac1d..f724f9714 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -825,21 +825,26 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $customActionAttributes['method'] ); $typesToQuote = ['string', 'float']; + $errors = []; foreach ($parameters as $parameter) { - if (isset($customActionAttributes[$parameter['variableName']])) { + if (array_key_exists($parameter['variableName'], $customActionAttributes)) { $value = $customActionAttributes[$parameter['variableName']]; $arguments[] = $this->addUniquenessFunctionCall( $value, in_array($parameter['type'], $typesToQuote) || $parameter['type'] === null ); - } elseif (!$parameter['isOptional']) { - throw new TestFrameworkException( - 'Argument \'' . $parameter['variableName'] . '\' for method ' + } elseif ($parameter['isOptional']) { + $value = $parameter['optionalValue']; + $arguments[] = str_replace(PHP_EOL, '', var_export($value, true)); + } else { + $errors[] = 'Argument \'' . $parameter['variableName'] . '\' for method ' . $customActionAttributes['class'] . '::' . $customActionAttributes['method'] - . ' is not found.' - ); + . ' is not found.'; } } + if (!empty($errors)) { + throw new TestFrameworkException(implode(PHP_EOL, $errors)); + } $testSteps .= sprintf( "\t\t$%s->comment('[%s] %s()');" . PHP_EOL, $actor, From 43d34b7fd9f1fcf4e6bb793afc9481565f2ba522 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Tue, 17 Mar 2020 11:24:32 -0500 Subject: [PATCH 306/888] MQE-1964: MFTF Helper - Implementation - addressed review comments --- .../functional/tests/MFTF/DevDocs/Helper/CustomHelper.php | 5 ++++- .../FunctionalTestingFramework/Util/TestGenerator.php | 3 +-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php b/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php index 4f2725421..46fba18d9 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php +++ b/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php @@ -35,9 +35,12 @@ public function goTo( $bla = 'blaValue', array $arraysomething = ['key' => 'value', 'test'] ) { - print('Hello, this is custom helper which gives an ability to write custom solutions without usage of <executeInSelenium /> and <performOn /> actions.'); + print('Hello, this is custom helper which provides an ability to write custom solutions.' . PHP_EOL); print('string $url = ' . $url . PHP_EOL); print('$test = ' . $test . PHP_EOL); + print('$bool = ' . $bool . PHP_EOL); + print('$int = ' . $int . PHP_EOL); + print('$float = ' . $float . PHP_EOL); print('array $module = [' . implode(', ', $module) . ']' . PHP_EOL); print('$superBla = ' . $superBla . PHP_EOL); print('$bla = ' . $bla . PHP_EOL); diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 740674086..19319d0d7 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -824,14 +824,13 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $customActionAttributes['class'], $customActionAttributes['method'] ); - $typesToQuote = ['string', 'float']; $errors = []; foreach ($parameters as $parameter) { if (array_key_exists($parameter['variableName'], $customActionAttributes)) { $value = $customActionAttributes[$parameter['variableName']]; $arguments[] = $this->addUniquenessFunctionCall( $value, - in_array($parameter['type'], $typesToQuote) || $parameter['type'] === null + $parameter['type'] === 'string' || $parameter['type'] === null ); } elseif ($parameter['isOptional']) { $value = $parameter['optionalValue']; From 18435a3d1547ad3fa2cce97d6c257fbf9b4f9c49 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Tue, 17 Mar 2020 18:01:25 -0500 Subject: [PATCH 307/888] Update MFTF dependencies --- composer.json | 16 +- composer.lock | 2204 ++++++----------- .../Allure/Event/AddUniqueAttachmentEvent.php | 11 +- 3 files changed, 813 insertions(+), 1418 deletions(-) diff --git a/composer.json b/composer.json index 74743f674..a66ce80bb 100755 --- a/composer.json +++ b/composer.json @@ -11,23 +11,23 @@ "require": { "php": "~7.2.0||~7.3.0", "ext-curl": "*", + "ext-dom": "*", "ext-json": "*", "ext-openssl": "*", - "ext-dom": "*", "allure-framework/allure-codeception": "~1.3.0", "aws/aws-sdk-php": "^3.132", "codeception/codeception": "~2.4.5", - "composer/composer": "^1.4", - "consolidation/robo": "^1.0.0", + "composer/composer": "^1.6", "csharpru/vault-php": "~3.5.3", "csharpru/vault-php-guzzle6-transport": "^2.0", - "flow/jsonpath": ">0.2", - "fzaninotto/faker": "^1.6", "monolog/monolog": "^1.0", "mustache/mustache": "~2.5", - "symfony/process": "^2.8 || ^3.1 || ^4.0", - "vlucas/phpdotenv": "^2.4", - "php-webdriver/webdriver": "^1.8.0" + "php-webdriver/webdriver": "^1.8.0", + "symfony/console": "^4.4", + "symfony/finder": "^4.4", + "symfony/mime": "^5.0", + "symfony/process": "^4.4", + "vlucas/phpdotenv": "^2.4" }, "require-dev": { "squizlabs/php_codesniffer": "~3.2", diff --git a/composer.lock b/composer.lock index 8757833cb..bbab8dbd4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "797f6caab6c9a1ae60da15083d03a548", + "content-hash": "8ad8319a9bd27934c8bdc036729d4fac", "packages": [ { "name": "allure-framework/allure-codeception", @@ -59,23 +59,23 @@ }, { "name": "allure-framework/allure-php-api", - "version": "1.1.6", + "version": "1.1.8", "source": { "type": "git", "url": "https://github.com/allure-framework/allure-php-commons.git", - "reference": "2c62a70d60eca190253a6b80e9aa4c2ebc2e6e7f" + "reference": "5ae2deac1c7e1b992cfa572167370de45bdd346d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/allure-framework/allure-php-commons/zipball/2c62a70d60eca190253a6b80e9aa4c2ebc2e6e7f", - "reference": "2c62a70d60eca190253a6b80e9aa4c2ebc2e6e7f", + "url": "https://api.github.com/repos/allure-framework/allure-php-commons/zipball/5ae2deac1c7e1b992cfa572167370de45bdd346d", + "reference": "5ae2deac1c7e1b992cfa572167370de45bdd346d", "shasum": "" }, "require": { "jms/serializer": "^0.16 || ^1.0", "php": ">=5.4.0", "ramsey/uuid": "^3.0", - "symfony/http-foundation": "^2.0 || ^3.0 || ^4.0" + "symfony/http-foundation": "^2.0 || ^3.0 || ^4.0 || ^5.0" }, "require-dev": { "phpunit/phpunit": "^4.0.0" @@ -108,20 +108,20 @@ "php", "report" ], - "time": "2020-01-09T10:26:09+00:00" + "time": "2020-03-13T10:47:35+00:00" }, { "name": "aws/aws-sdk-php", - "version": "3.133.7", + "version": "3.133.38", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "cd6fb07aed2cc68088251e3c572d111d67d558a3" + "reference": "5ec9442162d83f94918bc17136a2b674a04784e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/cd6fb07aed2cc68088251e3c572d111d67d558a3", - "reference": "cd6fb07aed2cc68088251e3c572d111d67d558a3", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/5ec9442162d83f94918bc17136a2b674a04784e5", + "reference": "5ec9442162d83f94918bc17136a2b674a04784e5", "shasum": "" }, "require": { @@ -192,20 +192,20 @@ "s3", "sdk" ], - "time": "2020-02-04T19:11:15+00:00" + "time": "2020-03-17T18:16:01+00:00" }, { "name": "behat/gherkin", - "version": "v4.6.0", + "version": "v4.6.2", "source": { "type": "git", "url": "https://github.com/Behat/Gherkin.git", - "reference": "ab0a02ea14893860bca00f225f5621d351a3ad07" + "reference": "51ac4500c4dc30cbaaabcd2f25694299df666a31" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Behat/Gherkin/zipball/ab0a02ea14893860bca00f225f5621d351a3ad07", - "reference": "ab0a02ea14893860bca00f225f5621d351a3ad07", + "url": "https://api.github.com/repos/Behat/Gherkin/zipball/51ac4500c4dc30cbaaabcd2f25694299df666a31", + "reference": "51ac4500c4dc30cbaaabcd2f25694299df666a31", "shasum": "" }, "require": { @@ -251,7 +251,7 @@ "gherkin", "parser" ], - "time": "2019-01-16T14:22:17+00:00" + "time": "2020-03-17T14:03:26+00:00" }, { "name": "cache/cache", @@ -439,30 +439,27 @@ }, { "name": "codeception/phpunit-wrapper", - "version": "6.8.0", + "version": "7.0.6", "source": { "type": "git", "url": "https://github.com/Codeception/phpunit-wrapper.git", - "reference": "20e054e9cee8de0523322367bcccde8e6a3db263" + "reference": "e8528cb777cf5a5ccea1cf57a3522b142625d1b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/phpunit-wrapper/zipball/20e054e9cee8de0523322367bcccde8e6a3db263", - "reference": "20e054e9cee8de0523322367bcccde8e6a3db263", + "url": "https://api.github.com/repos/Codeception/phpunit-wrapper/zipball/e8528cb777cf5a5ccea1cf57a3522b142625d1b5", + "reference": "e8528cb777cf5a5ccea1cf57a3522b142625d1b5", "shasum": "" }, "require": { - "phpunit/php-code-coverage": ">=4.0.4 <6.0", - "phpunit/phpunit": ">=6.5.13 <7.0", - "sebastian/comparator": ">=1.2.4 <3.0", - "sebastian/diff": ">=1.4 <4.0" - }, - "replace": { - "codeception/phpunit-wrapper": "*" + "phpunit/php-code-coverage": "^6.0", + "phpunit/phpunit": "^7.0", + "sebastian/comparator": "^2.0", + "sebastian/diff": "^3.0" }, "require-dev": { "codeception/specify": "*", - "vlucas/phpdotenv": "^3.0" + "vlucas/phpdotenv": "^2.4" }, "type": "library", "autoload": { @@ -481,24 +478,24 @@ } ], "description": "PHPUnit classes used by Codeception", - "time": "2020-01-03T08:01:16+00:00" + "time": "2018-03-31T18:49:51+00:00" }, { "name": "codeception/stub", - "version": "2.1.0", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/Codeception/Stub.git", - "reference": "853657f988942f7afb69becf3fd0059f192c705a" + "reference": "f50bc271f392a2836ff80690ce0c058efe1ae03e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/Stub/zipball/853657f988942f7afb69becf3fd0059f192c705a", - "reference": "853657f988942f7afb69becf3fd0059f192c705a", + "url": "https://api.github.com/repos/Codeception/Stub/zipball/f50bc271f392a2836ff80690ce0c058efe1ae03e", + "reference": "f50bc271f392a2836ff80690ce0c058efe1ae03e", "shasum": "" }, "require": { - "codeception/phpunit-wrapper": ">6.0.15 <6.1.0 | ^6.6.1 | ^7.7.1 | ^8.0.3" + "phpunit/phpunit": ">=4.8 <8.0" }, "type": "library", "autoload": { @@ -511,7 +508,7 @@ "MIT" ], "description": "Flexible Stub wrapper for PHPUnit's Mock Builder", - "time": "2019-03-02T15:35:10+00:00" + "time": "2018-07-26T11:55:37+00:00" }, { "name": "composer/ca-bundle", @@ -571,16 +568,16 @@ }, { "name": "composer/composer", - "version": "1.9.3", + "version": "1.10.1", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "1291a16ce3f48bfdeca39d64fca4875098af4d7b" + "reference": "b912a45da3e2b22f5cb5a23e441b697a295ba011" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/1291a16ce3f48bfdeca39d64fca4875098af4d7b", - "reference": "1291a16ce3f48bfdeca39d64fca4875098af4d7b", + "url": "https://api.github.com/repos/composer/composer/zipball/b912a45da3e2b22f5cb5a23e441b697a295ba011", + "reference": "b912a45da3e2b22f5cb5a23e441b697a295ba011", "shasum": "" }, "require": { @@ -593,17 +590,17 @@ "psr/log": "^1.0", "seld/jsonlint": "^1.4", "seld/phar-utils": "^1.0", - "symfony/console": "^2.7 || ^3.0 || ^4.0", - "symfony/filesystem": "^2.7 || ^3.0 || ^4.0", - "symfony/finder": "^2.7 || ^3.0 || ^4.0", - "symfony/process": "^2.7 || ^3.0 || ^4.0" + "symfony/console": "^2.7 || ^3.0 || ^4.0 || ^5.0", + "symfony/filesystem": "^2.7 || ^3.0 || ^4.0 || ^5.0", + "symfony/finder": "^2.7 || ^3.0 || ^4.0 || ^5.0", + "symfony/process": "^2.7 || ^3.0 || ^4.0 || ^5.0" }, "conflict": { "symfony/console": "2.8.38" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7", - "phpunit/phpunit-mock-objects": "^2.3 || ^3.0" + "phpspec/prophecy": "^1.10", + "symfony/phpunit-bridge": "^3.4" }, "suggest": { "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages", @@ -616,7 +613,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.9-dev" + "dev-master": "1.10-dev" } }, "autoload": { @@ -647,7 +644,7 @@ "dependency", "package" ], - "time": "2020-02-04T11:58:49+00:00" + "time": "2020-03-13T19:34:27+00:00" }, { "name": "composer/semver", @@ -712,16 +709,16 @@ }, { "name": "composer/spdx-licenses", - "version": "1.5.2", + "version": "1.5.3", "source": { "type": "git", "url": "https://github.com/composer/spdx-licenses.git", - "reference": "7ac1e6aec371357df067f8a688c3d6974df68fa5" + "reference": "0c3e51e1880ca149682332770e25977c70cf9dae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/7ac1e6aec371357df067f8a688c3d6974df68fa5", - "reference": "7ac1e6aec371357df067f8a688c3d6974df68fa5", + "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/0c3e51e1880ca149682332770e25977c70cf9dae", + "reference": "0c3e51e1880ca149682332770e25977c70cf9dae", "shasum": "" }, "require": { @@ -768,20 +765,20 @@ "spdx", "validator" ], - "time": "2019-07-29T10:31:59+00:00" + "time": "2020-02-14T07:44:31+00:00" }, { "name": "composer/xdebug-handler", - "version": "1.4.0", + "version": "1.4.1", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "cbe23383749496fe0f373345208b79568e4bc248" + "reference": "1ab9842d69e64fb3a01be6b656501032d1b78cb7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/cbe23383749496fe0f373345208b79568e4bc248", - "reference": "cbe23383749496fe0f373345208b79568e4bc248", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/1ab9842d69e64fb3a01be6b656501032d1b78cb7", + "reference": "1ab9842d69e64fb3a01be6b656501032d1b78cb7", "shasum": "" }, "require": { @@ -812,566 +809,7 @@ "Xdebug", "performance" ], - "time": "2019-11-06T16:40:04+00:00" - }, - { - "name": "consolidation/annotated-command", - "version": "2.12.0", - "source": { - "type": "git", - "url": "https://github.com/consolidation/annotated-command.git", - "reference": "512a2e54c98f3af377589de76c43b24652bcb789" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/consolidation/annotated-command/zipball/512a2e54c98f3af377589de76c43b24652bcb789", - "reference": "512a2e54c98f3af377589de76c43b24652bcb789", - "shasum": "" - }, - "require": { - "consolidation/output-formatters": "^3.4", - "php": ">=5.4.5", - "psr/log": "^1", - "symfony/console": "^2.8|^3|^4", - "symfony/event-dispatcher": "^2.5|^3|^4", - "symfony/finder": "^2.5|^3|^4" - }, - "require-dev": { - "g1a/composer-test-scenarios": "^3", - "php-coveralls/php-coveralls": "^1", - "phpunit/phpunit": "^6", - "squizlabs/php_codesniffer": "^2.7" - }, - "type": "library", - "extra": { - "scenarios": { - "symfony4": { - "require": { - "symfony/console": "^4.0" - }, - "config": { - "platform": { - "php": "7.1.3" - } - } - }, - "symfony2": { - "require": { - "symfony/console": "^2.8" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.36" - }, - "remove": [ - "php-coveralls/php-coveralls" - ], - "config": { - "platform": { - "php": "5.4.8" - } - }, - "scenario-options": { - "create-lockfile": "false" - } - }, - "phpunit4": { - "require-dev": { - "phpunit/phpunit": "^4.8.36" - }, - "remove": [ - "php-coveralls/php-coveralls" - ], - "config": { - "platform": { - "php": "5.4.8" - } - } - } - }, - "branch-alias": { - "dev-master": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "Consolidation\\AnnotatedCommand\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Greg Anderson", - "email": "greg.1.anderson@greenknowe.org" - } - ], - "description": "Initialize Symfony Console commands from annotated command class methods.", - "time": "2019-03-08T16:55:03+00:00" - }, - { - "name": "consolidation/config", - "version": "1.2.1", - "source": { - "type": "git", - "url": "https://github.com/consolidation/config.git", - "reference": "cac1279bae7efb5c7fb2ca4c3ba4b8eb741a96c1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/consolidation/config/zipball/cac1279bae7efb5c7fb2ca4c3ba4b8eb741a96c1", - "reference": "cac1279bae7efb5c7fb2ca4c3ba4b8eb741a96c1", - "shasum": "" - }, - "require": { - "dflydev/dot-access-data": "^1.1.0", - "grasmash/expander": "^1", - "php": ">=5.4.0" - }, - "require-dev": { - "g1a/composer-test-scenarios": "^3", - "php-coveralls/php-coveralls": "^1", - "phpunit/phpunit": "^5", - "squizlabs/php_codesniffer": "2.*", - "symfony/console": "^2.5|^3|^4", - "symfony/yaml": "^2.8.11|^3|^4" - }, - "suggest": { - "symfony/yaml": "Required to use Consolidation\\Config\\Loader\\YamlConfigLoader" - }, - "type": "library", - "extra": { - "scenarios": { - "symfony4": { - "require-dev": { - "symfony/console": "^4.0" - }, - "config": { - "platform": { - "php": "7.1.3" - } - } - }, - "symfony2": { - "require-dev": { - "symfony/console": "^2.8", - "symfony/event-dispatcher": "^2.8", - "phpunit/phpunit": "^4.8.36" - }, - "remove": [ - "php-coveralls/php-coveralls" - ], - "config": { - "platform": { - "php": "5.4.8" - } - } - } - }, - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Consolidation\\Config\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Greg Anderson", - "email": "greg.1.anderson@greenknowe.org" - } - ], - "description": "Provide configuration services for a commandline tool.", - "time": "2019-03-03T19:37:04+00:00" - }, - { - "name": "consolidation/log", - "version": "1.1.1", - "source": { - "type": "git", - "url": "https://github.com/consolidation/log.git", - "reference": "b2e887325ee90abc96b0a8b7b474cd9e7c896e3a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/consolidation/log/zipball/b2e887325ee90abc96b0a8b7b474cd9e7c896e3a", - "reference": "b2e887325ee90abc96b0a8b7b474cd9e7c896e3a", - "shasum": "" - }, - "require": { - "php": ">=5.4.5", - "psr/log": "^1.0", - "symfony/console": "^2.8|^3|^4" - }, - "require-dev": { - "g1a/composer-test-scenarios": "^3", - "php-coveralls/php-coveralls": "^1", - "phpunit/phpunit": "^6", - "squizlabs/php_codesniffer": "^2" - }, - "type": "library", - "extra": { - "scenarios": { - "symfony4": { - "require": { - "symfony/console": "^4.0" - }, - "config": { - "platform": { - "php": "7.1.3" - } - } - }, - "symfony2": { - "require": { - "symfony/console": "^2.8" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.36" - }, - "remove": [ - "php-coveralls/php-coveralls" - ], - "config": { - "platform": { - "php": "5.4.8" - } - } - }, - "phpunit4": { - "require-dev": { - "phpunit/phpunit": "^4.8.36" - }, - "remove": [ - "php-coveralls/php-coveralls" - ], - "config": { - "platform": { - "php": "5.4.8" - } - } - } - }, - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Consolidation\\Log\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Greg Anderson", - "email": "greg.1.anderson@greenknowe.org" - } - ], - "description": "Improved Psr-3 / Psr\\Log logger based on Symfony Console components.", - "time": "2019-01-01T17:30:51+00:00" - }, - { - "name": "consolidation/output-formatters", - "version": "3.5.0", - "source": { - "type": "git", - "url": "https://github.com/consolidation/output-formatters.git", - "reference": "99ec998ffb697e0eada5aacf81feebfb13023605" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/consolidation/output-formatters/zipball/99ec998ffb697e0eada5aacf81feebfb13023605", - "reference": "99ec998ffb697e0eada5aacf81feebfb13023605", - "shasum": "" - }, - "require": { - "dflydev/dot-access-data": "^1.1.0", - "php": ">=5.4.0", - "symfony/console": "^2.8|^3|^4", - "symfony/finder": "^2.5|^3|^4" - }, - "require-dev": { - "g1a/composer-test-scenarios": "^3", - "php-coveralls/php-coveralls": "^1", - "phpunit/phpunit": "^5.7.27", - "squizlabs/php_codesniffer": "^2.7", - "symfony/var-dumper": "^2.8|^3|^4", - "victorjonsson/markdowndocs": "^1.3" - }, - "suggest": { - "symfony/var-dumper": "For using the var_dump formatter" - }, - "type": "library", - "extra": { - "scenarios": { - "symfony4": { - "require": { - "symfony/console": "^4.0" - }, - "require-dev": { - "phpunit/phpunit": "^6" - }, - "config": { - "platform": { - "php": "7.1.3" - } - } - }, - "symfony3": { - "require": { - "symfony/console": "^3.4", - "symfony/finder": "^3.4", - "symfony/var-dumper": "^3.4" - }, - "config": { - "platform": { - "php": "5.6.32" - } - } - }, - "symfony2": { - "require": { - "symfony/console": "^2.8" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.36" - }, - "remove": [ - "php-coveralls/php-coveralls" - ], - "config": { - "platform": { - "php": "5.4.8" - } - }, - "scenario-options": { - "create-lockfile": "false" - } - } - }, - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Consolidation\\OutputFormatters\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Greg Anderson", - "email": "greg.1.anderson@greenknowe.org" - } - ], - "description": "Format text by applying transformations provided by plug-in formatters.", - "time": "2019-05-30T23:16:01+00:00" - }, - { - "name": "consolidation/robo", - "version": "1.4.11", - "source": { - "type": "git", - "url": "https://github.com/consolidation/Robo.git", - "reference": "5fa1d901776a628167a325baa9db95d8edf13a80" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/consolidation/Robo/zipball/5fa1d901776a628167a325baa9db95d8edf13a80", - "reference": "5fa1d901776a628167a325baa9db95d8edf13a80", - "shasum": "" - }, - "require": { - "consolidation/annotated-command": "^2.11.0", - "consolidation/config": "^1.2", - "consolidation/log": "~1", - "consolidation/output-formatters": "^3.1.13", - "consolidation/self-update": "^1", - "grasmash/yaml-expander": "^1.3", - "league/container": "^2.2", - "php": ">=5.5.0", - "symfony/console": "^2.8|^3|^4", - "symfony/event-dispatcher": "^2.5|^3|^4", - "symfony/filesystem": "^2.5|^3|^4", - "symfony/finder": "^2.5|^3|^4", - "symfony/process": "^2.5|^3|^4" - }, - "replace": { - "codegyre/robo": "< 1.0" - }, - "require-dev": { - "codeception/aspect-mock": "^1|^2.1.1", - "codeception/base": "^2.3.7", - "codeception/verify": "^0.3.2", - "g1a/composer-test-scenarios": "^3", - "goaop/framework": "~2.1.2", - "goaop/parser-reflection": "^1.1.0", - "natxet/cssmin": "3.0.4", - "nikic/php-parser": "^3.1.5", - "patchwork/jsqueeze": "~2", - "pear/archive_tar": "^1.4.4", - "php-coveralls/php-coveralls": "^1", - "phpunit/php-code-coverage": "~2|~4", - "sebastian/comparator": "^1.2.4", - "squizlabs/php_codesniffer": "^2.8" - }, - "suggest": { - "henrikbjorn/lurker": "For monitoring filesystem changes in taskWatch", - "natxet/CssMin": "For minifying CSS files in taskMinify", - "patchwork/jsqueeze": "For minifying JS files in taskMinify", - "pear/archive_tar": "Allows tar archives to be created and extracted in taskPack and taskExtract, respectively." - }, - "bin": [ - "robo" - ], - "type": "library", - "extra": { - "scenarios": { - "symfony4": { - "require": { - "symfony/console": "^4" - }, - "config": { - "platform": { - "php": "7.1.3" - } - } - }, - "symfony2": { - "require": { - "symfony/console": "^2.8" - }, - "remove": [ - "goaop/framework" - ], - "config": { - "platform": { - "php": "5.5.9" - } - }, - "scenario-options": { - "create-lockfile": "false" - } - } - }, - "branch-alias": { - "dev-master": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "Robo\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Davert", - "email": "davert.php@resend.cc" - } - ], - "description": "Modern task runner", - "time": "2019-10-29T15:50:02+00:00" - }, - { - "name": "consolidation/self-update", - "version": "1.1.5", - "source": { - "type": "git", - "url": "https://github.com/consolidation/self-update.git", - "reference": "a1c273b14ce334789825a09d06d4c87c0a02ad54" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/consolidation/self-update/zipball/a1c273b14ce334789825a09d06d4c87c0a02ad54", - "reference": "a1c273b14ce334789825a09d06d4c87c0a02ad54", - "shasum": "" - }, - "require": { - "php": ">=5.5.0", - "symfony/console": "^2.8|^3|^4", - "symfony/filesystem": "^2.5|^3|^4" - }, - "bin": [ - "scripts/release" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "SelfUpdate\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Greg Anderson", - "email": "greg.1.anderson@greenknowe.org" - }, - { - "name": "Alexander Menk", - "email": "menk@mestrona.net" - } - ], - "description": "Provides a self:update command for Symfony Console applications.", - "time": "2018-10-28T01:52:03+00:00" - }, - { - "name": "container-interop/container-interop", - "version": "1.2.0", - "source": { - "type": "git", - "url": "https://github.com/container-interop/container-interop.git", - "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/container-interop/container-interop/zipball/79cbf1341c22ec75643d841642dd5d6acd83bdb8", - "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8", - "shasum": "" - }, - "require": { - "psr/container": "^1.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Interop\\Container\\": "src/Interop/Container/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", - "homepage": "https://github.com/container-interop/container-interop", - "abandoned": "psr/container", - "time": "2017-02-14T19:40:03+00:00" + "time": "2020-03-01T12:26:26+00:00" }, { "name": "csharpru/vault-php", @@ -1459,91 +897,32 @@ "description": "Guzzle6 transport for Vault PHP client", "time": "2019-03-10T06:17:37+00:00" }, - { - "name": "dflydev/dot-access-data", - "version": "v1.1.0", - "source": { - "type": "git", - "url": "https://github.com/dflydev/dflydev-dot-access-data.git", - "reference": "3fbd874921ab2c041e899d044585a2ab9795df8a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/3fbd874921ab2c041e899d044585a2ab9795df8a", - "reference": "3fbd874921ab2c041e899d044585a2ab9795df8a", - "shasum": "" - }, - "require": { - "php": ">=5.3.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "psr-0": { - "Dflydev\\DotAccessData": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Dragonfly Development Inc.", - "email": "info@dflydev.com", - "homepage": "http://dflydev.com" - }, - { - "name": "Beau Simensen", - "email": "beau@dflydev.com", - "homepage": "http://beausimensen.com" - }, - { - "name": "Carlos Frutos", - "email": "carlos@kiwing.it", - "homepage": "https://github.com/cfrutos" - } - ], - "description": "Given a deep data structure, access data by dot notation.", - "homepage": "https://github.com/dflydev/dflydev-dot-access-data", - "keywords": [ - "access", - "data", - "dot", - "notation" - ], - "time": "2017-01-20T21:14:22+00:00" - }, { "name": "doctrine/annotations", - "version": "v1.4.0", + "version": "v1.8.0", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "54cacc9b81758b14e3ce750f205a393d52339e97" + "reference": "904dca4eb10715b92569fbcd79e201d5c349b6bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/54cacc9b81758b14e3ce750f205a393d52339e97", - "reference": "54cacc9b81758b14e3ce750f205a393d52339e97", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/904dca4eb10715b92569fbcd79e201d5c349b6bc", + "reference": "904dca4eb10715b92569fbcd79e201d5c349b6bc", "shasum": "" }, "require": { "doctrine/lexer": "1.*", - "php": "^5.6 || ^7.0" + "php": "^7.1" }, "require-dev": { "doctrine/cache": "1.*", - "phpunit/phpunit": "^5.7" + "phpunit/phpunit": "^7.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4.x-dev" + "dev-master": "1.7.x-dev" } }, "autoload": { @@ -1556,6 +935,10 @@ "MIT" ], "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -1564,10 +947,6 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -1584,7 +963,7 @@ "docblock", "parser" ], - "time": "2017-02-24T16:22:25+00:00" + "time": "2019-10-01T18:55:10+00:00" }, { "name": "doctrine/cache", @@ -1725,32 +1104,34 @@ }, { "name": "doctrine/instantiator", - "version": "1.0.5", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + "reference": "ae466f726242e637cebdd526a7d991b9433bacf1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/ae466f726242e637cebdd526a7d991b9433bacf1", + "reference": "ae466f726242e637cebdd526a7d991b9433bacf1", "shasum": "" }, "require": { - "php": ">=5.3,<8.0-DEV" + "php": "^7.1" }, "require-dev": { - "athletic/athletic": "~0.1.8", + "doctrine/coding-standard": "^6.0", "ext-pdo": "*", "ext-phar": "*", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~2.0" + "phpbench/phpbench": "^0.13", + "phpstan/phpstan-phpunit": "^0.11", + "phpstan/phpstan-shim": "^0.11", + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { @@ -1770,37 +1151,39 @@ } ], "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://github.com/doctrine/instantiator", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", "keywords": [ "constructor", "instantiate" ], - "time": "2015-06-14T21:17:01+00:00" + "time": "2019-10-21T16:45:58+00:00" }, { "name": "doctrine/lexer", - "version": "1.0.2", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/doctrine/lexer.git", - "reference": "1febd6c3ef84253d7c815bed85fc622ad207a9f8" + "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/1febd6c3ef84253d7c815bed85fc622ad207a9f8", - "reference": "1febd6c3ef84253d7c815bed85fc622ad207a9f8", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6", + "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6", "shasum": "" }, "require": { - "php": ">=5.3.2" + "php": "^7.2" }, "require-dev": { - "phpunit/phpunit": "^4.5" + "doctrine/coding-standard": "^6.0", + "phpstan/phpstan": "^0.11.8", + "phpunit/phpunit": "^8.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { @@ -1813,14 +1196,14 @@ "MIT" ], "authors": [ - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, { "name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com" }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, { "name": "Johannes Schmitt", "email": "schmittjoh@gmail.com" @@ -1835,193 +1218,7 @@ "parser", "php" ], - "time": "2019-06-08T11:03:04+00:00" - }, - { - "name": "flow/jsonpath", - "version": "0.5.0", - "source": { - "type": "git", - "url": "https://github.com/FlowCommunications/JSONPath.git", - "reference": "b9738858c75d008c1211612b973e9510f8b7f8ea" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/FlowCommunications/JSONPath/zipball/b9738858c75d008c1211612b973e9510f8b7f8ea", - "reference": "b9738858c75d008c1211612b973e9510f8b7f8ea", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "peekmo/jsonpath": "dev-master", - "phpunit/phpunit": "^7.0" - }, - "type": "library", - "autoload": { - "psr-0": { - "Flow\\JSONPath": "src/", - "Flow\\JSONPath\\Test": "tests/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Stephen Frank", - "email": "stephen@flowsa.com" - } - ], - "description": "JSONPath implementation for parsing, searching and flattening arrays", - "time": "2019-07-15T17:23:22+00:00" - }, - { - "name": "fzaninotto/faker", - "version": "v1.9.1", - "source": { - "type": "git", - "url": "https://github.com/fzaninotto/Faker.git", - "reference": "fc10d778e4b84d5bd315dad194661e091d307c6f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/fc10d778e4b84d5bd315dad194661e091d307c6f", - "reference": "fc10d778e4b84d5bd315dad194661e091d307c6f", - "shasum": "" - }, - "require": { - "php": "^5.3.3 || ^7.0" - }, - "require-dev": { - "ext-intl": "*", - "phpunit/phpunit": "^4.8.35 || ^5.7", - "squizlabs/php_codesniffer": "^2.9.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.9-dev" - } - }, - "autoload": { - "psr-4": { - "Faker\\": "src/Faker/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "François Zaninotto" - } - ], - "description": "Faker is a PHP library that generates fake data for you.", - "keywords": [ - "data", - "faker", - "fixtures" - ], - "time": "2019-12-12T13:22:17+00:00" - }, - { - "name": "grasmash/expander", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/grasmash/expander.git", - "reference": "95d6037344a4be1dd5f8e0b0b2571a28c397578f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/grasmash/expander/zipball/95d6037344a4be1dd5f8e0b0b2571a28c397578f", - "reference": "95d6037344a4be1dd5f8e0b0b2571a28c397578f", - "shasum": "" - }, - "require": { - "dflydev/dot-access-data": "^1.1.0", - "php": ">=5.4" - }, - "require-dev": { - "greg-1-anderson/composer-test-scenarios": "^1", - "phpunit/phpunit": "^4|^5.5.4", - "satooshi/php-coveralls": "^1.0.2|dev-master", - "squizlabs/php_codesniffer": "^2.7" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Grasmash\\Expander\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Matthew Grasmick" - } - ], - "description": "Expands internal property references in PHP arrays file.", - "time": "2017-12-21T22:14:55+00:00" - }, - { - "name": "grasmash/yaml-expander", - "version": "1.4.0", - "source": { - "type": "git", - "url": "https://github.com/grasmash/yaml-expander.git", - "reference": "3f0f6001ae707a24f4d9733958d77d92bf9693b1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/grasmash/yaml-expander/zipball/3f0f6001ae707a24f4d9733958d77d92bf9693b1", - "reference": "3f0f6001ae707a24f4d9733958d77d92bf9693b1", - "shasum": "" - }, - "require": { - "dflydev/dot-access-data": "^1.1.0", - "php": ">=5.4", - "symfony/yaml": "^2.8.11|^3|^4" - }, - "require-dev": { - "greg-1-anderson/composer-test-scenarios": "^1", - "phpunit/phpunit": "^4.8|^5.5.4", - "satooshi/php-coveralls": "^1.0.2|dev-master", - "squizlabs/php_codesniffer": "^2.7" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Grasmash\\YamlExpander\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Matthew Grasmick" - } - ], - "description": "Expands internal property references in a yaml file.", - "time": "2017-12-16T16:06:03+00:00" + "time": "2019-10-30T14:39:59+00:00" }, { "name": "guzzlehttp/guzzle", @@ -2304,16 +1501,16 @@ }, { "name": "jms/serializer", - "version": "1.14.0", + "version": "1.14.1", "source": { "type": "git", "url": "https://github.com/schmittjoh/serializer.git", - "reference": "ee96d57024af9a7716d56fcbe3aa94b3d030f3ca" + "reference": "ba908d278fff27ec01fb4349f372634ffcd697c0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/ee96d57024af9a7716d56fcbe3aa94b3d030f3ca", - "reference": "ee96d57024af9a7716d56fcbe3aa94b3d030f3ca", + "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/ba908d278fff27ec01fb4349f372634ffcd697c0", + "reference": "ba908d278fff27ec01fb4349f372634ffcd697c0", "shasum": "" }, "require": { @@ -2366,13 +1563,13 @@ "MIT" ], "authors": [ - { - "name": "Asmir Mustafic", - "email": "goetas@gmail.com" - }, { "name": "Johannes M. Schmitt", "email": "schmittjoh@gmail.com" + }, + { + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" } ], "description": "Library for (de-)serializing data of any complexity; supports XML, JSON, and YAML.", @@ -2384,7 +1581,7 @@ "serialization", "xml" ], - "time": "2019-04-17T08:12:16+00:00" + "time": "2020-02-22T20:59:37+00:00" }, { "name": "justinrainbow/json-schema", @@ -2452,83 +1649,18 @@ ], "time": "2019-09-25T14:49:45+00:00" }, - { - "name": "league/container", - "version": "2.4.1", - "source": { - "type": "git", - "url": "https://github.com/thephpleague/container.git", - "reference": "43f35abd03a12977a60ffd7095efd6a7808488c0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thephpleague/container/zipball/43f35abd03a12977a60ffd7095efd6a7808488c0", - "reference": "43f35abd03a12977a60ffd7095efd6a7808488c0", - "shasum": "" - }, - "require": { - "container-interop/container-interop": "^1.2", - "php": "^5.4.0 || ^7.0" - }, - "provide": { - "container-interop/container-interop-implementation": "^1.2", - "psr/container-implementation": "^1.0" - }, - "replace": { - "orno/di": "~2.0" - }, - "require-dev": { - "phpunit/phpunit": "4.*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-2.x": "2.x-dev", - "dev-1.x": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "League\\Container\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Phil Bennett", - "email": "philipobenito@gmail.com", - "homepage": "http://www.philipobenito.com", - "role": "Developer" - } - ], - "description": "A fast and intuitive dependency injection container.", - "homepage": "https://github.com/thephpleague/container", - "keywords": [ - "container", - "dependency", - "di", - "injection", - "league", - "provider", - "service" - ], - "time": "2017-05-10T09:20:27+00:00" - }, { "name": "league/flysystem", - "version": "1.0.63", + "version": "1.0.66", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "8132daec326565036bc8e8d1876f77ec183a7bd6" + "reference": "021569195e15f8209b1c4bebb78bd66aa4f08c21" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/8132daec326565036bc8e8d1876f77ec183a7bd6", - "reference": "8132daec326565036bc8e8d1876f77ec183a7bd6", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/021569195e15f8209b1c4bebb78bd66aa4f08c21", + "reference": "021569195e15f8209b1c4bebb78bd66aa4f08c21", "shasum": "" }, "require": { @@ -2540,7 +1672,7 @@ }, "require-dev": { "phpspec/phpspec": "^3.4", - "phpunit/phpunit": "^5.7.10" + "phpunit/phpunit": "^5.7.26" }, "suggest": { "ext-fileinfo": "Required for MimeType", @@ -2599,7 +1731,7 @@ "sftp", "storage" ], - "time": "2020-01-04T16:30:31+00:00" + "time": "2020-03-17T18:58:12+00:00" }, { "name": "monolog/monolog", @@ -2784,25 +1916,28 @@ }, { "name": "myclabs/deep-copy", - "version": "1.7.0", + "version": "1.9.5", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e" + "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", - "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/b2c28789e80a97badd14145fda39b545d83ca3ef", + "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "php": "^7.1" + }, + "replace": { + "myclabs/deep-copy": "self.version" }, "require-dev": { "doctrine/collections": "^1.0", "doctrine/common": "^2.6", - "phpunit/phpunit": "^4.1" + "phpunit/phpunit": "^7.1" }, "type": "library", "autoload": { @@ -2825,7 +1960,7 @@ "object", "object graph" ], - "time": "2017-10-19T19:58:43+00:00" + "time": "2020-01-17T21:11:47+00:00" }, { "name": "paragonie/random_compat", @@ -2976,16 +2111,16 @@ }, { "name": "php-webdriver/webdriver", - "version": "1.8.0", + "version": "1.8.2", "source": { "type": "git", "url": "https://github.com/php-webdriver/php-webdriver.git", - "reference": "3e33ee3b8a688d719c55acdd7c6788e3006e1d3e" + "reference": "3308a70be084d6d7fd1ee5787b4c2e6eb4b70aab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/3e33ee3b8a688d719c55acdd7c6788e3006e1d3e", - "reference": "3e33ee3b8a688d719c55acdd7c6788e3006e1d3e", + "url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/3308a70be084d6d7fd1ee5787b4c2e6eb4b70aab", + "reference": "3308a70be084d6d7fd1ee5787b4c2e6eb4b70aab", "shasum": "" }, "require": { @@ -3017,12 +2152,12 @@ } }, "autoload": { - "files": [ - "lib/Exception/TimeoutException.php" - ], "psr-4": { "Facebook\\WebDriver\\": "lib/" - } + }, + "files": [ + "lib/Exception/TimeoutException.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3037,7 +2172,7 @@ "selenium", "webdriver" ], - "time": "2020-02-10T15:04:25+00:00" + "time": "2020-03-04T14:40:12+00:00" }, { "name": "phpcollection/phpcollection", @@ -3089,35 +2224,33 @@ }, { "name": "phpdocumentor/reflection-common", - "version": "1.0.1", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" + "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", - "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a", + "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a", "shasum": "" }, "require": { - "php": ">=5.5" + "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "^4.6" + "phpunit/phpunit": "~6" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src" - ] + "phpDocumentor\\Reflection\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -3139,45 +2272,42 @@ "reflection", "static analysis" ], - "time": "2017-09-11T18:02:19+00:00" + "time": "2018-08-07T13:53:10+00:00" }, { "name": "phpdocumentor/reflection-docblock", - "version": "4.3.4", + "version": "5.1.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c" + "reference": "cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/da3fd972d6bafd628114f7e7e036f45944b62e9c", - "reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e", + "reference": "cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e", "shasum": "" }, "require": { - "php": "^7.0", - "phpdocumentor/reflection-common": "^1.0.0 || ^2.0.0", - "phpdocumentor/type-resolver": "~0.4 || ^1.0.0", - "webmozart/assert": "^1.0" + "ext-filter": "^7.1", + "php": "^7.2", + "phpdocumentor/reflection-common": "^2.0", + "phpdocumentor/type-resolver": "^1.0", + "webmozart/assert": "^1" }, "require-dev": { - "doctrine/instantiator": "^1.0.5", - "mockery/mockery": "^1.0", - "phpdocumentor/type-resolver": "0.4.*", - "phpunit/phpunit": "^6.4" + "doctrine/instantiator": "^1", + "mockery/mockery": "^1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.x-dev" + "dev-master": "5.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] + "phpDocumentor\\Reflection\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -3188,37 +2318,41 @@ { "name": "Mike van Riel", "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "account@ijaap.nl" } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2019-12-28T18:55:12+00:00" + "time": "2020-02-22T12:28:44+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "0.5.1", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "cf842904952e64e703800d094cdf34e715a8a3ae" + "reference": "7462d5f123dfc080dfdf26897032a6513644fc95" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/cf842904952e64e703800d094cdf34e715a8a3ae", - "reference": "cf842904952e64e703800d094cdf34e715a8a3ae", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/7462d5f123dfc080dfdf26897032a6513644fc95", + "reference": "7462d5f123dfc080dfdf26897032a6513644fc95", "shasum": "" }, "require": { - "php": "^7.0", - "phpdocumentor/reflection-common": "^1.0" + "php": "^7.2", + "phpdocumentor/reflection-common": "^2.0" }, "require-dev": { - "mockery/mockery": "^1.0", - "phpunit/phpunit": "^6.4" + "ext-tokenizer": "^7.2", + "mockery/mockery": "~1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.x-dev" } }, "autoload": { @@ -3236,7 +2370,8 @@ "email": "me@mikevanriel.com" } ], - "time": "2017-12-30T13:23:38+00:00" + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "time": "2020-02-18T18:59:58+00:00" }, { "name": "phpoption/phpoption", @@ -3295,16 +2430,16 @@ }, { "name": "phpspec/prophecy", - "version": "v1.10.2", + "version": "v1.10.3", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "b4400efc9d206e83138e2bb97ed7f5b14b831cd9" + "reference": "451c3cd1418cf640de218914901e51b064abb093" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/b4400efc9d206e83138e2bb97ed7f5b14b831cd9", - "reference": "b4400efc9d206e83138e2bb97ed7f5b14b831cd9", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/451c3cd1418cf640de218914901e51b064abb093", + "reference": "451c3cd1418cf640de218914901e51b064abb093", "shasum": "" }, "require": { @@ -3354,44 +2489,44 @@ "spy", "stub" ], - "time": "2020-01-20T15:57:02+00:00" + "time": "2020-03-05T15:02:03+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "5.3.2", + "version": "6.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "c89677919c5dd6d3b3852f230a663118762218ac" + "reference": "4cab20a326d14de7575a8e235c70d879b569a57a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c89677919c5dd6d3b3852f230a663118762218ac", - "reference": "c89677919c5dd6d3b3852f230a663118762218ac", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/4cab20a326d14de7575a8e235c70d879b569a57a", + "reference": "4cab20a326d14de7575a8e235c70d879b569a57a", "shasum": "" }, "require": { "ext-dom": "*", "ext-xmlwriter": "*", - "php": "^7.0", + "php": "^7.1", "phpunit/php-file-iterator": "^1.4.2", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^2.0.1", + "phpunit/php-token-stream": "^3.0", "sebastian/code-unit-reverse-lookup": "^1.0.1", - "sebastian/environment": "^3.0", + "sebastian/environment": "^3.1", "sebastian/version": "^2.0.1", "theseer/tokenizer": "^1.1" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^7.0" }, "suggest": { - "ext-xdebug": "^2.5.5" + "ext-xdebug": "^2.6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.3.x-dev" + "dev-master": "6.0-dev" } }, "autoload": { @@ -3417,7 +2552,7 @@ "testing", "xunit" ], - "time": "2018-04-06T15:36:58+00:00" + "time": "2018-05-28T11:49:20+00:00" }, { "name": "phpunit/php-file-iterator", @@ -3509,28 +2644,28 @@ }, { "name": "phpunit/php-timer", - "version": "1.0.9", + "version": "2.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" + "reference": "1038454804406b0b5f5f520358e78c1c2f71501e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/1038454804406b0b5f5f520358e78c1c2f71501e", + "reference": "1038454804406b0b5f5f520358e78c1c2f71501e", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "2.1-dev" } }, "autoload": { @@ -3545,7 +2680,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -3554,33 +2689,33 @@ "keywords": [ "timer" ], - "time": "2017-02-26T11:10:40+00:00" + "time": "2019-06-07T04:22:29+00:00" }, { "name": "phpunit/php-token-stream", - "version": "2.0.2", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "791198a2c6254db10131eecfe8c06670700904db" + "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db", - "reference": "791198a2c6254db10131eecfe8c06670700904db", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/995192df77f63a59e47f025390d2d1fdf8f425ff", + "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff", "shasum": "" }, "require": { "ext-tokenizer": "*", - "php": "^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^6.2.4" + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "3.1-dev" } }, "autoload": { @@ -3603,20 +2738,20 @@ "keywords": [ "tokenizer" ], - "time": "2017-11-27T05:48:46+00:00" + "time": "2019-09-17T06:23:10+00:00" }, { "name": "phpunit/phpunit", - "version": "6.5.14", + "version": "7.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "bac23fe7ff13dbdb461481f706f0e9fe746334b7" + "reference": "536f4d853c12d8189963435088e8ff7c0daeab2e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/bac23fe7ff13dbdb461481f706f0e9fe746334b7", - "reference": "bac23fe7ff13dbdb461481f706f0e9fe746334b7", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/536f4d853c12d8189963435088e8ff7c0daeab2e", + "reference": "536f4d853c12d8189963435088e8ff7c0daeab2e", "shasum": "" }, "require": { @@ -3628,15 +2763,15 @@ "myclabs/deep-copy": "^1.6.1", "phar-io/manifest": "^1.0.1", "phar-io/version": "^1.0", - "php": "^7.0", + "php": "^7.1", "phpspec/prophecy": "^1.7", - "phpunit/php-code-coverage": "^5.3", + "phpunit/php-code-coverage": "^6.0.1", "phpunit/php-file-iterator": "^1.4.3", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-timer": "^1.0.9", - "phpunit/phpunit-mock-objects": "^5.0.9", + "phpunit/php-timer": "^2.0", + "phpunit/phpunit-mock-objects": "^6.0", "sebastian/comparator": "^2.1", - "sebastian/diff": "^2.0", + "sebastian/diff": "^3.0", "sebastian/environment": "^3.1", "sebastian/exporter": "^3.1", "sebastian/global-state": "^2.0", @@ -3644,16 +2779,12 @@ "sebastian/resource-operations": "^1.0", "sebastian/version": "^2.0.1" }, - "conflict": { - "phpdocumentor/reflection-docblock": "3.0.2", - "phpunit/dbunit": "<3.0" - }, "require-dev": { "ext-pdo": "*" }, "suggest": { "ext-xdebug": "*", - "phpunit/php-invoker": "^1.1" + "phpunit/php-invoker": "^2.0" }, "bin": [ "phpunit" @@ -3661,7 +2792,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "6.5.x-dev" + "dev-master": "7.0-dev" } }, "autoload": { @@ -3687,33 +2818,30 @@ "testing", "xunit" ], - "time": "2019-02-01T05:22:47+00:00" + "time": "2018-03-26T07:36:48+00:00" }, { "name": "phpunit/phpunit-mock-objects", - "version": "5.0.10", + "version": "6.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f" + "reference": "f9756fd4f43f014cb2dca98deeaaa8ce5500a36e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/cd1cf05c553ecfec36b170070573e540b67d3f1f", - "reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/f9756fd4f43f014cb2dca98deeaaa8ce5500a36e", + "reference": "f9756fd4f43f014cb2dca98deeaaa8ce5500a36e", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.5", - "php": "^7.0", + "php": "^7.1", "phpunit/php-text-template": "^1.2.1", "sebastian/exporter": "^3.1" }, - "conflict": { - "phpunit/phpunit": "<6.0" - }, "require-dev": { - "phpunit/phpunit": "^6.5.11" + "phpunit/phpunit": "^7.0" }, "suggest": { "ext-soap": "*" @@ -3721,7 +2849,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0.x-dev" + "dev-master": "6.1-dev" } }, "autoload": { @@ -3747,7 +2875,7 @@ "xunit" ], "abandoned": true, - "time": "2018-08-09T05:50:03+00:00" + "time": "2018-05-29T13:54:20+00:00" }, { "name": "psr/cache", @@ -4031,16 +3159,16 @@ }, { "name": "ramsey/uuid", - "version": "3.9.2", + "version": "3.9.3", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "7779489a47d443f845271badbdcedfe4df8e06fb" + "reference": "7e1633a6964b48589b142d60542f9ed31bd37a92" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/7779489a47d443f845271badbdcedfe4df8e06fb", - "reference": "7779489a47d443f845271badbdcedfe4df8e06fb", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/7e1633a6964b48589b142d60542f9ed31bd37a92", + "reference": "7e1633a6964b48589b142d60542f9ed31bd37a92", "shasum": "" }, "require": { @@ -4114,7 +3242,7 @@ "identifier", "uuid" ], - "time": "2019-12-17T08:18:51+00:00" + "time": "2020-02-21T04:36:14+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -4227,28 +3355,29 @@ }, { "name": "sebastian/diff", - "version": "2.0.1", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd" + "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", - "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/720fcc7e9b5cf384ea68d9d930d480907a0c1a29", + "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29", "shasum": "" }, "require": { - "php": "^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^6.2" + "phpunit/phpunit": "^7.5 || ^8.0", + "symfony/process": "^2 || ^3.3 || ^4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -4273,9 +3402,12 @@ "description": "Diff implementation", "homepage": "https://github.com/sebastianbergmann/diff", "keywords": [ - "diff" + "diff", + "udiff", + "unidiff", + "unified diff" ], - "time": "2017-08-03T08:09:46+00:00" + "time": "2019-02-04T06:01:07+00:00" }, { "name": "sebastian/environment", @@ -4726,16 +3858,16 @@ }, { "name": "seld/phar-utils", - "version": "1.0.2", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/Seldaek/phar-utils.git", - "reference": "84715761c35808076b00908a20317a3a8a67d17e" + "reference": "8800503d56b9867d43d9c303b9cbcc26016e82f0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/84715761c35808076b00908a20317a3a8a67d17e", - "reference": "84715761c35808076b00908a20317a3a8a67d17e", + "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/8800503d56b9867d43d9c303b9cbcc26016e82f0", + "reference": "8800503d56b9867d43d9c303b9cbcc26016e82f0", "shasum": "" }, "require": { @@ -4764,44 +3896,236 @@ ], "description": "PHAR file format utilities, for when PHP phars you up", "keywords": [ - "phra" + "phar" ], - "time": "2020-01-13T10:41:09+00:00" + "time": "2020-02-14T15:25:33+00:00" }, { "name": "symfony/browser-kit", - "version": "v3.4.37", + "version": "v4.4.5", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "ede0c5fa204586e3fa51053fbea9cea8a5a3ee8b" + "reference": "090ce406505149d6852a7c03b0346dec3b8cf612" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/090ce406505149d6852a7c03b0346dec3b8cf612", + "reference": "090ce406505149d6852a7c03b0346dec3b8cf612", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/dom-crawler": "^3.4|^4.0|^5.0" + }, + "require-dev": { + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/http-client": "^4.3|^5.0", + "symfony/mime": "^4.3|^5.0", + "symfony/process": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\BrowserKit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony BrowserKit Component", + "homepage": "https://symfony.com", + "time": "2020-02-23T10:00:59+00:00" + }, + { + "name": "symfony/console", + "version": "v4.4.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "4fa15ae7be74e53f6ec8c83ed403b97e23b665e9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/4fa15ae7be74e53f6ec8c83ed403b97e23b665e9", + "reference": "4fa15ae7be74e53f6ec8c83ed403b97e23b665e9", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.8", + "symfony/service-contracts": "^1.1|^2" + }, + "conflict": { + "symfony/dependency-injection": "<3.4", + "symfony/event-dispatcher": "<4.3|>=5", + "symfony/lock": "<4.4", + "symfony/process": "<3.3" + }, + "provide": { + "psr/log-implementation": "1.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/event-dispatcher": "^4.3", + "symfony/lock": "^4.4|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/var-dumper": "^4.3|^5.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Console Component", + "homepage": "https://symfony.com", + "time": "2020-02-24T13:10:00+00:00" + }, + { + "name": "symfony/css-selector", + "version": "v4.4.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "d0a6dd288fa8848dcc3d1f58b94de6a7cc5d2d22" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/d0a6dd288fa8848dcc3d1f58b94de6a7cc5d2d22", + "reference": "d0a6dd288fa8848dcc3d1f58b94de6a7cc5d2d22", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony CssSelector Component", + "homepage": "https://symfony.com", + "time": "2020-02-04T09:01:01+00:00" + }, + { + "name": "symfony/dom-crawler", + "version": "v4.4.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "11dcf08f12f29981bf770f097a5d64d65bce5929" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/ede0c5fa204586e3fa51053fbea9cea8a5a3ee8b", - "reference": "ede0c5fa204586e3fa51053fbea9cea8a5a3ee8b", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/11dcf08f12f29981bf770f097a5d64d65bce5929", + "reference": "11dcf08f12f29981bf770f097a5d64d65bce5929", "shasum": "" }, - "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/dom-crawler": "~2.8|~3.0|~4.0" + "require": { + "php": "^7.1.3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "masterminds/html5": "<2.6" }, "require-dev": { - "symfony/css-selector": "~2.8|~3.0|~4.0", - "symfony/process": "~2.8|~3.0|~4.0" + "masterminds/html5": "^2.6", + "symfony/css-selector": "^3.4|^4.0|^5.0" }, "suggest": { - "symfony/process": "" + "symfony/css-selector": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.4-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\BrowserKit\\": "" + "Symfony\\Component\\DomCrawler\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -4821,59 +4145,57 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony BrowserKit Component", + "description": "Symfony DomCrawler Component", "homepage": "https://symfony.com", - "time": "2020-01-01T11:03:25+00:00" + "time": "2020-02-29T10:05:28+00:00" }, { - "name": "symfony/console", - "version": "v3.4.37", + "name": "symfony/event-dispatcher", + "version": "v4.4.5", "source": { "type": "git", - "url": "https://github.com/symfony/console.git", - "reference": "7c5bdd346f9d90a2d22d4e1fe61e02dc19b98f12" + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "4ad8e149799d3128621a3a1f70e92b9897a8930d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/7c5bdd346f9d90a2d22d4e1fe61e02dc19b98f12", - "reference": "7c5bdd346f9d90a2d22d4e1fe61e02dc19b98f12", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/4ad8e149799d3128621a3a1f70e92b9897a8930d", + "reference": "4ad8e149799d3128621a3a1f70e92b9897a8930d", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/debug": "~2.8|~3.0|~4.0", - "symfony/polyfill-mbstring": "~1.0" + "php": "^7.1.3", + "symfony/event-dispatcher-contracts": "^1.1" }, "conflict": { - "symfony/dependency-injection": "<3.4", - "symfony/process": "<3.3" + "symfony/dependency-injection": "<3.4" }, "provide": { - "psr/log-implementation": "1.0" + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "1.1" }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "~3.3|~4.0", - "symfony/dependency-injection": "~3.4|~4.0", - "symfony/event-dispatcher": "~2.8|~3.0|~4.0", - "symfony/lock": "~3.4|~4.0", - "symfony/process": "~3.3|~4.0" + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/stopwatch": "^3.4|^4.0|^5.0" }, "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/lock": "", - "symfony/process": "" + "symfony/dependency-injection": "", + "symfony/http-kernel": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.4-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\Console\\": "" + "Symfony\\Component\\EventDispatcher\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -4893,40 +4215,41 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Console Component", + "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2020-01-10T07:52:48+00:00" + "time": "2020-02-04T09:32:40+00:00" }, { - "name": "symfony/css-selector", - "version": "v3.4.37", + "name": "symfony/event-dispatcher-contracts", + "version": "v1.1.7", "source": { "type": "git", - "url": "https://github.com/symfony/css-selector.git", - "reference": "e1b3e1a0621d6e48ee46092b4c7d8280f746b3c5" + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "c43ab685673fb6c8d84220c77897b1d6cdbe1d18" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/e1b3e1a0621d6e48ee46092b4c7d8280f746b3c5", - "reference": "e1b3e1a0621d6e48ee46092b4c7d8280f746b3c5", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/c43ab685673fb6c8d84220c77897b1d6cdbe1d18", + "reference": "c43ab685673fb6c8d84220c77897b1d6cdbe1d18", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" + "php": "^7.1.3" + }, + "suggest": { + "psr/event-dispatcher": "", + "symfony/event-dispatcher-implementation": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "1.1-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\CssSelector\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Symfony\\Contracts\\EventDispatcher\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4934,55 +4257,53 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Jean-François Simon", - "email": "jeanfrancois.simon@sensiolabs.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony CssSelector Component", + "description": "Generic abstractions related to dispatching event", "homepage": "https://symfony.com", - "time": "2020-01-01T11:03:25+00:00" + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-09-17T09:54:03+00:00" }, { - "name": "symfony/debug", - "version": "v3.4.37", + "name": "symfony/filesystem", + "version": "v5.0.5", "source": { "type": "git", - "url": "https://github.com/symfony/debug.git", - "reference": "70dd18e93bb8bdf3c4db7fde832619fef9828cf8" + "url": "https://github.com/symfony/filesystem.git", + "reference": "3afadc0f57cd74f86379d073e694b0f2cda2a88c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/70dd18e93bb8bdf3c4db7fde832619fef9828cf8", - "reference": "70dd18e93bb8bdf3c4db7fde832619fef9828cf8", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/3afadc0f57cd74f86379d073e694b0f2cda2a88c", + "reference": "3afadc0f57cd74f86379d073e694b0f2cda2a88c", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "psr/log": "~1.0" - }, - "conflict": { - "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" - }, - "require-dev": { - "symfony/http-kernel": "~2.8|~3.0|~4.0" + "php": "^7.2.5", + "symfony/polyfill-ctype": "~1.8" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "5.0-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\Debug\\": "" + "Symfony\\Component\\Filesystem\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -5002,44 +4323,36 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Debug Component", + "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2020-01-08T16:36:15+00:00" + "time": "2020-01-21T08:40:24+00:00" }, { - "name": "symfony/dom-crawler", - "version": "v3.4.37", + "name": "symfony/finder", + "version": "v4.4.5", "source": { "type": "git", - "url": "https://github.com/symfony/dom-crawler.git", - "reference": "c6fcc96c530ef18dcb4e605e3e9a97c483a160e6" + "url": "https://github.com/symfony/finder.git", + "reference": "ea69c129aed9fdeca781d4b77eb20b62cf5d5357" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/c6fcc96c530ef18dcb4e605e3e9a97c483a160e6", - "reference": "c6fcc96c530ef18dcb4e605e3e9a97c483a160e6", + "url": "https://api.github.com/repos/symfony/finder/zipball/ea69c129aed9fdeca781d4b77eb20b62cf5d5357", + "reference": "ea69c129aed9fdeca781d4b77eb20b62cf5d5357", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.0" - }, - "require-dev": { - "symfony/css-selector": "~2.8|~3.0|~4.0" - }, - "suggest": { - "symfony/css-selector": "" + "php": "^7.1.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.4-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\DomCrawler\\": "" + "Symfony\\Component\\Finder\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -5059,50 +4372,42 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony DomCrawler Component", + "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2020-01-01T11:03:25+00:00" + "time": "2020-02-14T07:42:58+00:00" }, { - "name": "symfony/event-dispatcher", - "version": "v3.4.37", + "name": "symfony/http-foundation", + "version": "v5.0.5", "source": { "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "79ede8f2836e5ec910ebb325bde40f987244baa8" + "url": "https://github.com/symfony/http-foundation.git", + "reference": "6f9c2ba72f4295d7ce6cf9f79dbb18036291d335" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/79ede8f2836e5ec910ebb325bde40f987244baa8", - "reference": "79ede8f2836e5ec910ebb325bde40f987244baa8", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/6f9c2ba72f4295d7ce6cf9f79dbb18036291d335", + "reference": "6f9c2ba72f4295d7ce6cf9f79dbb18036291d335", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" - }, - "conflict": { - "symfony/dependency-injection": "<3.3" + "php": "^7.2.5", + "symfony/mime": "^4.4|^5.0", + "symfony/polyfill-mbstring": "~1.1" }, "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~2.8|~3.0|~4.0", - "symfony/dependency-injection": "~3.3|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/stopwatch": "~2.8|~3.0|~4.0" - }, - "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" + "predis/predis": "~1.0", + "symfony/expression-language": "^4.4|^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "5.0-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\EventDispatcher\\": "" + "Symfony\\Component\\HttpFoundation\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -5122,37 +4427,45 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony EventDispatcher Component", + "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2020-01-04T12:05:51+00:00" + "time": "2020-02-14T07:43:07+00:00" }, { - "name": "symfony/filesystem", - "version": "v3.4.37", + "name": "symfony/mime", + "version": "v5.0.5", "source": { "type": "git", - "url": "https://github.com/symfony/filesystem.git", - "reference": "0a0d3b4bda11aa3a0464531c40e681e184e75628" + "url": "https://github.com/symfony/mime.git", + "reference": "9b3e5b5e58c56bbd76628c952d2b78556d305f3c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/0a0d3b4bda11aa3a0464531c40e681e184e75628", - "reference": "0a0d3b4bda11aa3a0464531c40e681e184e75628", + "url": "https://api.github.com/repos/symfony/mime/zipball/9b3e5b5e58c56bbd76628c952d2b78556d305f3c", + "reference": "9b3e5b5e58c56bbd76628c952d2b78556d305f3c", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/polyfill-ctype": "~1.8" + "php": "^7.2.5", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" + }, + "conflict": { + "symfony/mailer": "<4.4" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10", + "symfony/dependency-injection": "^4.4|^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "5.0-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\Filesystem\\": "" + "Symfony\\Component\\Mime\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -5172,39 +4485,46 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Filesystem Component", + "description": "A library to manipulate MIME messages", "homepage": "https://symfony.com", - "time": "2020-01-17T08:50:08+00:00" + "keywords": [ + "mime", + "mime-type" + ], + "time": "2020-02-04T09:41:09+00:00" }, { - "name": "symfony/finder", - "version": "v3.4.37", + "name": "symfony/polyfill-ctype", + "version": "v1.14.0", "source": { "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "a90a9d3b9f458a5cdeabfa4090b20c000ca3962f" + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "fbdeaec0df06cf3d51c93de80c7eb76e271f5a38" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/a90a9d3b9f458a5cdeabfa4090b20c000ca3962f", - "reference": "a90a9d3b9f458a5cdeabfa4090b20c000ca3962f", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/fbdeaec0df06cf3d51c93de80c7eb76e271f5a38", + "reference": "fbdeaec0df06cf3d51c93de80c7eb76e271f5a38", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" + "php": ">=5.3.3" + }, + "suggest": { + "ext-ctype": "For best performance" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "1.14-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\Finder\\": "" + "Symfony\\Polyfill\\Ctype\\": "" }, - "exclude-from-classmap": [ - "/Tests/" + "files": [ + "bootstrap.php" ] }, "notification-url": "https://packagist.org/downloads/", @@ -5213,52 +4533,58 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Finder Component", + "description": "Symfony polyfill for ctype functions", "homepage": "https://symfony.com", - "time": "2020-01-01T11:03:25+00:00" + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "time": "2020-01-13T11:15:53+00:00" }, { - "name": "symfony/http-foundation", - "version": "v3.4.37", + "name": "symfony/polyfill-intl-idn", + "version": "v1.14.0", "source": { "type": "git", - "url": "https://github.com/symfony/http-foundation.git", - "reference": "f3abd07a56111ebe6a1ad6f1cbc23e4f8983f8f5" + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "6842f1a39cf7d580655688069a03dd7cd83d244a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/f3abd07a56111ebe6a1ad6f1cbc23e4f8983f8f5", - "reference": "f3abd07a56111ebe6a1ad6f1cbc23e4f8983f8f5", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/6842f1a39cf7d580655688069a03dd7cd83d244a", + "reference": "6842f1a39cf7d580655688069a03dd7cd83d244a", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php70": "~1.6" + "php": ">=5.3.3", + "symfony/polyfill-mbstring": "^1.3", + "symfony/polyfill-php72": "^1.10" }, - "require-dev": { - "symfony/expression-language": "~2.8|~3.0|~4.0" + "suggest": { + "ext-intl": "For best performance" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "1.14-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\HttpFoundation\\": "" + "Symfony\\Polyfill\\Intl\\Idn\\": "" }, - "exclude-from-classmap": [ - "/Tests/" + "files": [ + "bootstrap.php" ] }, "notification-url": "https://packagist.org/downloads/", @@ -5267,47 +4593,55 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Laurent Bassin", + "email": "laurent@bassin.info" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony HttpFoundation Component", + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", "homepage": "https://symfony.com", - "time": "2020-01-04T12:05:51+00:00" + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "time": "2020-01-17T12:01:36+00:00" }, { - "name": "symfony/polyfill-ctype", - "version": "v1.13.1", + "name": "symfony/polyfill-mbstring", + "version": "v1.14.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3" + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "34094cfa9abe1f0f14f48f490772db7a775559f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", - "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/34094cfa9abe1f0f14f48f490772db7a775559f2", + "reference": "34094cfa9abe1f0f14f48f490772db7a775559f2", "shasum": "" }, "require": { "php": ">=5.3.3" }, "suggest": { - "ext-ctype": "For best performance" + "ext-mbstring": "For best performance" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.13-dev" + "dev-master": "1.14-dev" } }, "autoload": { "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" + "Symfony\\Polyfill\\Mbstring\\": "" }, "files": [ "bootstrap.php" @@ -5319,53 +4653,51 @@ ], "authors": [ { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for ctype functions", + "description": "Symfony polyfill for the Mbstring extension", "homepage": "https://symfony.com", "keywords": [ "compatibility", - "ctype", + "mbstring", "polyfill", - "portable" + "portable", + "shim" ], - "time": "2019-11-27T13:56:44+00:00" + "time": "2020-01-13T11:15:53+00:00" }, { - "name": "symfony/polyfill-mbstring", - "version": "v1.13.1", + "name": "symfony/polyfill-php72", + "version": "v1.14.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "7b4aab9743c30be783b73de055d24a39cf4b954f" + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "46ecacf4751dd0dc81e4f6bf01dbf9da1dc1dadf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7b4aab9743c30be783b73de055d24a39cf4b954f", - "reference": "7b4aab9743c30be783b73de055d24a39cf4b954f", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/46ecacf4751dd0dc81e4f6bf01dbf9da1dc1dadf", + "reference": "46ecacf4751dd0dc81e4f6bf01dbf9da1dc1dadf", "shasum": "" }, "require": { "php": ">=5.3.3" }, - "suggest": { - "ext-mbstring": "For best performance" - }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.13-dev" + "dev-master": "1.14-dev" } }, "autoload": { "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" + "Symfony\\Polyfill\\Php72\\": "" }, "files": [ "bootstrap.php" @@ -5385,44 +4717,42 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for the Mbstring extension", + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", - "mbstring", "polyfill", "portable", "shim" ], - "time": "2019-11-27T14:18:11+00:00" + "time": "2020-01-13T11:15:53+00:00" }, { - "name": "symfony/polyfill-php70", - "version": "v1.13.1", + "name": "symfony/polyfill-php73", + "version": "v1.14.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php70.git", - "reference": "af23c7bb26a73b850840823662dda371484926c4" + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "5e66a0fa1070bf46bec4bea7962d285108edd675" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/af23c7bb26a73b850840823662dda371484926c4", - "reference": "af23c7bb26a73b850840823662dda371484926c4", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/5e66a0fa1070bf46bec4bea7962d285108edd675", + "reference": "5e66a0fa1070bf46bec4bea7962d285108edd675", "shasum": "" }, "require": { - "paragonie/random_compat": "~1.0|~2.0|~9.99", "php": ">=5.3.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.13-dev" + "dev-master": "1.14-dev" } }, "autoload": { "psr-4": { - "Symfony\\Polyfill\\Php70\\": "" + "Symfony\\Polyfill\\Php73\\": "" }, "files": [ "bootstrap.php" @@ -5445,7 +4775,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -5453,29 +4783,29 @@ "portable", "shim" ], - "time": "2019-11-27T13:56:44+00:00" + "time": "2020-01-13T11:15:53+00:00" }, { "name": "symfony/process", - "version": "v3.4.37", + "version": "v4.4.5", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "5b9d2bcffe4678911a4c941c00b7c161252cf09a" + "reference": "bf9166bac906c9e69fb7a11d94875e7ced97bcd7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/5b9d2bcffe4678911a4c941c00b7c161252cf09a", - "reference": "5b9d2bcffe4678911a4c941c00b7c161252cf09a", + "url": "https://api.github.com/repos/symfony/process/zipball/bf9166bac906c9e69fb7a11d94875e7ced97bcd7", + "reference": "bf9166bac906c9e69fb7a11d94875e7ced97bcd7", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" + "php": "^7.1.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -5502,31 +4832,89 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2020-01-01T11:03:25+00:00" + "time": "2020-02-07T20:06:44+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "144c5e51266b281231e947b51223ba14acf1a749" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/144c5e51266b281231e947b51223ba14acf1a749", + "reference": "144c5e51266b281231e947b51223ba14acf1a749", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "psr/container": "^1.0" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-11-18T17:27:11+00:00" }, { "name": "symfony/yaml", - "version": "v3.4.37", + "version": "v4.4.5", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "aa46bc2233097d5212332c907f9911533acfbf80" + "reference": "94d005c176db2080e98825d98e01e8b311a97a88" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/aa46bc2233097d5212332c907f9911533acfbf80", - "reference": "aa46bc2233097d5212332c907f9911533acfbf80", + "url": "https://api.github.com/repos/symfony/yaml/zipball/94d005c176db2080e98825d98e01e8b311a97a88", + "reference": "94d005c176db2080e98825d98e01e8b311a97a88", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", + "php": "^7.1.3", "symfony/polyfill-ctype": "~1.8" }, "conflict": { "symfony/console": "<3.4" }, "require-dev": { - "symfony/console": "~3.4|~4.0" + "symfony/console": "^3.4|^4.0|^5.0" }, "suggest": { "symfony/console": "For validating YAML files using the lint command" @@ -5534,7 +4922,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -5561,7 +4949,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2020-01-13T08:00:59+00:00" + "time": "2020-02-03T10:46:43+00:00" }, { "name": "theseer/tokenizer", @@ -5656,16 +5044,16 @@ }, { "name": "webmozart/assert", - "version": "1.6.0", + "version": "1.7.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "573381c0a64f155a0d9a23f4b0c797194805b925" + "reference": "aed98a490f9a8f78468232db345ab9cf606cf598" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/573381c0a64f155a0d9a23f4b0c797194805b925", - "reference": "573381c0a64f155a0d9a23f4b0c797194805b925", + "url": "https://api.github.com/repos/webmozart/assert/zipball/aed98a490f9a8f78468232db345ab9cf606cf598", + "reference": "aed98a490f9a8f78468232db345ab9cf606cf598", "shasum": "" }, "require": { @@ -5700,7 +5088,7 @@ "check", "validate" ], - "time": "2019-11-24T13:36:37+00:00" + "time": "2020-02-14T12:15:55+00:00" }, { "name": "weew/helpers-array", @@ -5854,32 +5242,33 @@ ], "description": "Sends PHP test coverage information to Codacy.", "homepage": "https://github.com/codacy/php-codacy-coverage", + "abandoned": true, "time": "2020-01-10T10:52:12+00:00" }, { "name": "codeception/aspect-mock", - "version": "3.0.2", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/Codeception/AspectMock.git", - "reference": "130afd10a3d8131d267f393ee1ec322e3e583d67" + "reference": "72fc3d6877ede7ff255ee2c96b7b57d4f87d0f30" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/AspectMock/zipball/130afd10a3d8131d267f393ee1ec322e3e583d67", - "reference": "130afd10a3d8131d267f393ee1ec322e3e583d67", + "url": "https://api.github.com/repos/Codeception/AspectMock/zipball/72fc3d6877ede7ff255ee2c96b7b57d4f87d0f30", + "reference": "72fc3d6877ede7ff255ee2c96b7b57d4f87d0f30", "shasum": "" }, "require": { - "goaop/framework": "^2.2.0", + "goaop/framework": "^2.2.0 | ^3.0.0-RC2", "php": ">=7.0.0", "phpunit/phpunit": "> 6.0.0", - "symfony/finder": "~2.4|~3.0|~4.0" + "symfony/finder": ">=2.4 <6.0" }, "require-dev": { - "codeception/base": "^2.4", - "codeception/specify": "~0.3", - "codeception/verify": "~0.2" + "codeception/codeception": "^4.0", + "codeception/specify": "^1.0", + "codeception/verify": "^1.2" }, "type": "library", "autoload": { @@ -5898,7 +5287,7 @@ } ], "description": "Experimental Mocking Framework powered by Aspects", - "time": "2018-10-07T16:21:11+00:00" + "time": "2020-02-29T15:39:49+00:00" }, { "name": "gitonomy/gitlib", @@ -6280,16 +5669,16 @@ }, { "name": "pdepend/pdepend", - "version": "2.7.0", + "version": "2.7.1", "source": { "type": "git", "url": "https://github.com/pdepend/pdepend.git", - "reference": "cba74e118ce806f97fcb108c00d61ebf2a5a936e" + "reference": "daba1cf0a6edaf172fa02a17807ae29f4c1c7471" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pdepend/pdepend/zipball/cba74e118ce806f97fcb108c00d61ebf2a5a936e", - "reference": "cba74e118ce806f97fcb108c00d61ebf2a5a936e", + "url": "https://api.github.com/repos/pdepend/pdepend/zipball/daba1cf0a6edaf172fa02a17807ae29f4c1c7471", + "reference": "daba1cf0a6edaf172fa02a17807ae29f4c1c7471", "shasum": "" }, "require": { @@ -6323,7 +5712,7 @@ "BSD-3-Clause" ], "description": "Official version of pdepend to be handled with Composer", - "time": "2020-01-24T08:09:26+00:00" + "time": "2020-02-08T12:06:13+00:00" }, { "name": "php-coveralls/php-coveralls", @@ -6388,22 +5777,22 @@ }, { "name": "phpmd/phpmd", - "version": "2.8.1", + "version": "2.8.2", "source": { "type": "git", "url": "https://github.com/phpmd/phpmd.git", - "reference": "5664b95d484797582f5af9536238deb9ecde58a1" + "reference": "714629ed782537f638fe23c4346637659b779a77" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpmd/phpmd/zipball/5664b95d484797582f5af9536238deb9ecde58a1", - "reference": "5664b95d484797582f5af9536238deb9ecde58a1", + "url": "https://api.github.com/repos/phpmd/phpmd/zipball/714629ed782537f638fe23c4346637659b779a77", + "reference": "714629ed782537f638fe23c4346637659b779a77", "shasum": "" }, "require": { "composer/xdebug-handler": "^1.0", "ext-xml": "*", - "pdepend/pdepend": "^2.6", + "pdepend/pdepend": "^2.7.1", "php": ">=5.3.9" }, "require-dev": { @@ -6454,7 +5843,7 @@ "phpmd", "pmd" ], - "time": "2019-12-27T11:09:06+00:00" + "time": "2020-02-16T20:15:50+00:00" }, { "name": "rregeer/phpunit-coverage-check", @@ -6500,23 +5889,27 @@ }, { "name": "sebastian/finder-facade", - "version": "1.2.2", + "version": "1.2.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/finder-facade.git", - "reference": "4a3174709c2dc565fe5fb26fcf827f6a1fc7b09f" + "reference": "167c45d131f7fc3d159f56f191a0a22228765e16" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/finder-facade/zipball/4a3174709c2dc565fe5fb26fcf827f6a1fc7b09f", - "reference": "4a3174709c2dc565fe5fb26fcf827f6a1fc7b09f", + "url": "https://api.github.com/repos/sebastianbergmann/finder-facade/zipball/167c45d131f7fc3d159f56f191a0a22228765e16", + "reference": "167c45d131f7fc3d159f56f191a0a22228765e16", "shasum": "" }, "require": { - "symfony/finder": "~2.3|~3.0|~4.0", - "theseer/fdomdocument": "~1.3" + "php": "^7.1", + "symfony/finder": "^2.3|^3.0|^4.0|^5.0", + "theseer/fdomdocument": "^1.6" }, "type": "library", + "extra": { + "branch-alias": [] + }, "autoload": { "classmap": [ "src/" @@ -6535,25 +5928,26 @@ ], "description": "FinderFacade is a convenience wrapper for Symfony's Finder component.", "homepage": "https://github.com/sebastianbergmann/finder-facade", - "time": "2017-11-18T17:31:49+00:00" + "time": "2020-01-16T08:08:45+00:00" }, { "name": "sebastian/phpcpd", - "version": "3.0.1", + "version": "4.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpcpd.git", - "reference": "dfed51c1288790fc957c9433e2f49ab152e8a564" + "reference": "0d9afa762f2400de077b2192f4a9d127de0bb78e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpcpd/zipball/dfed51c1288790fc957c9433e2f49ab152e8a564", - "reference": "dfed51c1288790fc957c9433e2f49ab152e8a564", + "url": "https://api.github.com/repos/sebastianbergmann/phpcpd/zipball/0d9afa762f2400de077b2192f4a9d127de0bb78e", + "reference": "0d9afa762f2400de077b2192f4a9d127de0bb78e", "shasum": "" }, "require": { - "php": "^5.6|^7.0", - "phpunit/php-timer": "^1.0.6", + "ext-dom": "*", + "php": "^7.1", + "phpunit/php-timer": "^2.0", "sebastian/finder-facade": "^1.1", "sebastian/version": "^1.0|^2.0", "symfony/console": "^2.7|^3.0|^4.0" @@ -6564,7 +5958,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -6585,7 +5979,7 @@ ], "description": "Copy/Paste Detector (CPD) for PHP code.", "homepage": "https://github.com/sebastianbergmann/phpcpd", - "time": "2017-11-16T08:49:28+00:00" + "time": "2018-09-17T17:17:27+00:00" }, { "name": "squizlabs/php_codesniffer", @@ -6640,32 +6034,32 @@ }, { "name": "symfony/config", - "version": "v3.4.37", + "version": "v4.4.5", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "6abc18b2a97f63508d23929bbb2ae65aaa07bace" + "reference": "cbfef5ae91ccd3b06621c18d58cd355c68c87ae9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/6abc18b2a97f63508d23929bbb2ae65aaa07bace", - "reference": "6abc18b2a97f63508d23929bbb2ae65aaa07bace", + "url": "https://api.github.com/repos/symfony/config/zipball/cbfef5ae91ccd3b06621c18d58cd355c68c87ae9", + "reference": "cbfef5ae91ccd3b06621c18d58cd355c68c87ae9", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/filesystem": "~2.8|~3.0|~4.0", + "php": "^7.1.3", + "symfony/filesystem": "^3.4|^4.0|^5.0", "symfony/polyfill-ctype": "~1.8" }, "conflict": { - "symfony/dependency-injection": "<3.3", - "symfony/finder": "<3.3" + "symfony/finder": "<3.4" }, "require-dev": { - "symfony/dependency-injection": "~3.3|~4.0", - "symfony/event-dispatcher": "~3.3|~4.0", - "symfony/finder": "~3.3|~4.0", - "symfony/yaml": "~3.0|~4.0" + "symfony/event-dispatcher": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/messenger": "^4.1|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/yaml": "^3.4|^4.0|^5.0" }, "suggest": { "symfony/yaml": "To use the yaml reference dumper" @@ -6673,7 +6067,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -6700,39 +6094,41 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2020-01-04T12:05:51+00:00" + "time": "2020-02-04T09:32:40+00:00" }, { "name": "symfony/dependency-injection", - "version": "v3.4.37", + "version": "v4.4.5", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "22000f10c9e1cfef051e8b4de46815b41a0223fc" + "reference": "ebb2e882e8c9e2eb990aa61ddcd389848466e342" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/22000f10c9e1cfef051e8b4de46815b41a0223fc", - "reference": "22000f10c9e1cfef051e8b4de46815b41a0223fc", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/ebb2e882e8c9e2eb990aa61ddcd389848466e342", + "reference": "ebb2e882e8c9e2eb990aa61ddcd389848466e342", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "psr/container": "^1.0" + "php": "^7.1.3", + "psr/container": "^1.0", + "symfony/service-contracts": "^1.1.6|^2" }, "conflict": { - "symfony/config": "<3.3.7", - "symfony/finder": "<3.3", + "symfony/config": "<4.3|>=5.0", + "symfony/finder": "<3.4", "symfony/proxy-manager-bridge": "<3.4", "symfony/yaml": "<3.4" }, "provide": { - "psr/container-implementation": "1.0" + "psr/container-implementation": "1.0", + "symfony/service-implementation": "1.0" }, "require-dev": { - "symfony/config": "~3.3|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/yaml": "~3.4|~4.0" + "symfony/config": "^4.3", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0" }, "suggest": { "symfony/config": "", @@ -6744,7 +6140,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -6771,11 +6167,11 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2020-01-08T11:20:51+00:00" + "time": "2020-02-29T09:50:10+00:00" }, { "name": "symfony/stopwatch", - "version": "v3.4.37", + "version": "v3.4.38", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", @@ -6871,9 +6267,9 @@ "platform": { "php": "~7.2.0||~7.3.0", "ext-curl": "*", + "ext-dom": "*", "ext-json": "*", - "ext-openssl": "*", - "ext-dom": "*" + "ext-openssl": "*" }, "platform-dev": [] } diff --git a/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php b/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php index fc4ff64c2..bf16e5b49 100644 --- a/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php +++ b/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php @@ -6,8 +6,7 @@ */ namespace Magento\FunctionalTestingFramework\Allure\Event; -use Symfony\Component\HttpFoundation\File\MimeType\ExtensionGuesser; -use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser; +use Symfony\Component\Mime\MimeTypes; use Yandex\Allure\Adapter\AllureException; use Yandex\Allure\Adapter\Event\AddAttachmentEvent; @@ -73,7 +72,7 @@ private function copyFile($filePath, $outputPath) */ private function guessFileMimeType($filePath) { - $type = MimeTypeGuesser::getInstance()->guess($filePath); + $type = MimeTypes::getDefault()->guessMimeType($filePath); if (!isset($type)) { return DEFAULT_MIME_TYPE; } @@ -87,11 +86,11 @@ private function guessFileMimeType($filePath) */ private function guessFileExtension($mimeType) { - $candidate = ExtensionGuesser::getInstance()->guess($mimeType); - if (!isset($candidate)) { + $candidate = MimeTypes::getDefault()->getExtensions($mimeType); + if (empty($candidate)) { return DEFAULT_FILE_EXTENSION; } - return $candidate; + return reset($candidate); } /** From d82e6cf1e798a3266ae23582ae53fc6b77fa452d Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Wed, 18 Mar 2020 09:48:53 -0500 Subject: [PATCH 308/888] Revert configs --- .../Helper/Acceptance.php | 42 +++++++++++++++ .../Helper/MagentoFakerData.php | 54 +++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 src/Magento/FunctionalTestingFramework/Helper/Acceptance.php create mode 100644 src/Magento/FunctionalTestingFramework/Helper/MagentoFakerData.php diff --git a/src/Magento/FunctionalTestingFramework/Helper/Acceptance.php b/src/Magento/FunctionalTestingFramework/Helper/Acceptance.php new file mode 100644 index 000000000..fafe167af --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Helper/Acceptance.php @@ -0,0 +1,42 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\FunctionalTestingFramework\Helper; + +use Magento\FunctionalTestingFramework\Module\MagentoWebDriver; +use Codeception\Module; + +/** + * Class Acceptance + * + * Define global actions + * All public methods declared in helper class will be available in $I + */ +class Acceptance extends Module +{ + /** + * Reconfig WebDriver. + * + * @param string $config + * @param string $value + * @return void + */ + public function changeConfiguration($config, $value) + { + $this->getModule(MagentoWebDriver::class)->_reconfigure([$config => $value]); + } + + /** + * Get WebDriver configuration. + * + * @param string $config + * @return string + */ + public function getConfiguration($config) + { + return $this->getModule(MagentoWebDriver::class)->_getConfig($config); + } +} diff --git a/src/Magento/FunctionalTestingFramework/Helper/MagentoFakerData.php b/src/Magento/FunctionalTestingFramework/Helper/MagentoFakerData.php new file mode 100644 index 000000000..a5b19b4c6 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Helper/MagentoFakerData.php @@ -0,0 +1,54 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\FunctionalTestingFramework\Helper; + +/** + * Class MagentoFakerData + */ +class MagentoFakerData extends \Codeception\Module +{ + /** + * Get Customer data. + * + * @param array $additional + * @return array + */ + public function getCustomerData(array $additional = []) + { + return [$additional]; + } + + /** + * Get category data. + * + * @return array + */ + public function getCategoryData() + { + return []; + } + + /** + * Get simple product data. + * + * @return array + */ + public function getProductData() + { + return []; + } + + /** + * Get Content Page Data. + * + * @return array + */ + public function getContentPage() + { + return []; + } +} From d95952fc38a74e14b62d6eb1c44439f2f4da1d84 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 19 Mar 2020 12:19:38 -0500 Subject: [PATCH 309/888] MQE-2032: Remove temporary solutions for MFTF 3.0 development needs --- .../Config/MftfApplicationConfig.php | 6 ------ .../Console/BuildProjectCommand.php | 5 ++--- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php b/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php index 5181e8dc9..ab06b5612 100644 --- a/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php +++ b/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php @@ -100,12 +100,6 @@ private function __construct( $this->phase = $phase; $this->verboseEnabled = $verboseEnabled; - - //TODO: overriding pipeline config, to be removed for MFTF 3.0.0 - if (strtolower($debugLevel) === 'none') { - $debugLevel = self::LEVEL_DEFAULT; - } - if (isset($debugLevel) && !in_array(strtolower($debugLevel), self::MFTF_DEBUG_LEVEL)) { throw new TestFrameworkException("{$debugLevel} is not a debug level. Use 'DEFAULT' or 'DEVELOPER'"); } diff --git a/src/Magento/FunctionalTestingFramework/Console/BuildProjectCommand.php b/src/Magento/FunctionalTestingFramework/Console/BuildProjectCommand.php index cc8d9776e..23736925f 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BuildProjectCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BuildProjectCommand.php @@ -107,12 +107,11 @@ function ($type, $buffer) use ($output) { ); } - // Temporary enable upgrade at build time for testing - //if ($input->getOption('upgrade')) { + if ($input->getOption('upgrade')) { $upgradeCommand = new UpgradeTestsCommand(); $upgradeOptions = new ArrayInput([]); $upgradeCommand->run($upgradeOptions, $output); - //} + } } /** From c09d4632d8ec1e47fa91e83e7cfaf8987b237c34 Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Thu, 19 Mar 2020 13:23:13 -0500 Subject: [PATCH 310/888] Escaped Liquid tag syntax --- docs/best-practices.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/best-practices.md b/docs/best-practices.md index c9068a90b..613f398ca 100644 --- a/docs/best-practices.md +++ b/docs/best-practices.md @@ -12,12 +12,16 @@ Instead of writing everything by yourself - use `extends` attribute to refer to **Reusable Resources** +{%raw%} + * Tests (reusable with `<test extends="...">` argument) * Action Group (reusable with including `<actionGroup ref="...">`, or extending `<actionGroup extends="...">`) * Pages (reusable with reference `{{PageDefinition.url}}`) * Sections (reusable with reference `{{SectionDefinition.elementDefinition}}`) * Data Entities (reusable with reference `<createData entity="...">"` or extending `<entity extends="...">`) +{%endraw%} + <div class="bs-callout bs-callout-warning" markdown="1"> Avoid using resources that are marked as **Deprecated**. Usually there is a replacement provided for a deprecated resource. From f4cad0bd20c598ffa3d3bb6b1a9ff9f88bc90589 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Thu, 19 Mar 2020 14:00:15 -0500 Subject: [PATCH 311/888] MQE-2023: CHANGELOG.MD and Composer version bump Updated changelog --- CHANGELOG.md | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d1ae20a2..5cd4e226d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,30 @@ Magento Functional Testing Framework Changelog ================================================ -3.0.0 ------ +3.0.0 RC1 +--------- + +### Enhancements +* Customizability + * Introduced MFTF helpers `<helper>` to create custom actions outside of MFTF. + * Removed deprecated actions `<executeSelenium>` and `<performOn>`. +* Maintainability + * Schema updates for test entities to only allow single entity per file. + * Removed support to read test entities from `<magento>dev/tests/acceptance/tests/functional/Magento/FunctionalTest`. + * Removed support for PHP 7.0 and 7.1. +* Traceability + * Removed `--debug` option NONE to disallow ability to turn off schema validation. + * Notices added for test entity naming convention violations. + * Metadata file names changed to `*Meta.xml`. +* Readability + * Support only nested assertion syntax [See assertions page for details](./docs/test/assertions.md) +* Upgrade scripts added to upgrade tests to MFTF major version requirements. See upgrade instructions below. +* Bumped dependencies to latest possible versions + +### Fixes +* Throw exception during generation when leaving out .url for `amOnPage`. +* `request_timeout` and `connection_timeout` added to functional.suite.yml.dist. +* Fixed `ModuleResolver` to resolve test modules moved out of deprecated path. + ### Upgrade Instructions * Run `bin/mftf reset --hard` to remove old generated configurations. * Run `bin/mftf build:project` to generate new configurations. From a658cd43a2fcaf35b85d5c6b9b3a182ed9140357 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Thu, 19 Mar 2020 14:49:38 -0500 Subject: [PATCH 312/888] MQE-2023: CHANGELOG.MD and Composer version bump Changelog updates --- CHANGELOG.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5cd4e226d..3edf84411 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,9 +8,11 @@ Magento Functional Testing Framework Changelog * Introduced MFTF helpers `<helper>` to create custom actions outside of MFTF. * Removed deprecated actions `<executeSelenium>` and `<performOn>`. * Maintainability - * Schema updates for test entities to only allow single entity per file. + * Schema updates for test entities to only allow single entity per file except Data and Metadata. + * Support for sub-folders in test modules. * Removed support to read test entities from `<magento>dev/tests/acceptance/tests/functional/Magento/FunctionalTest`. * Removed support for PHP 7.0 and 7.1. + * Removed file attribute for `<module>` in suiteSchema. * Traceability * Removed `--debug` option NONE to disallow ability to turn off schema validation. * Notices added for test entity naming convention violations. @@ -18,7 +20,7 @@ Magento Functional Testing Framework Changelog * Readability * Support only nested assertion syntax [See assertions page for details](./docs/test/assertions.md) * Upgrade scripts added to upgrade tests to MFTF major version requirements. See upgrade instructions below. -* Bumped dependencies to latest possible versions +* Bumped dependencies to latest possible versions. ### Fixes * Throw exception during generation when leaving out .url for `amOnPage`. From 7df1df8998a95a5deb53610104a144ed0bcff420 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 19 Mar 2020 15:07:45 -0500 Subject: [PATCH 313/888] Revert "Revert configs" This reverts commit d82e6cf1 --- .../Helper/Acceptance.php | 42 --------------- .../Helper/MagentoFakerData.php | 54 ------------------- 2 files changed, 96 deletions(-) delete mode 100644 src/Magento/FunctionalTestingFramework/Helper/Acceptance.php delete mode 100644 src/Magento/FunctionalTestingFramework/Helper/MagentoFakerData.php diff --git a/src/Magento/FunctionalTestingFramework/Helper/Acceptance.php b/src/Magento/FunctionalTestingFramework/Helper/Acceptance.php deleted file mode 100644 index fafe167af..000000000 --- a/src/Magento/FunctionalTestingFramework/Helper/Acceptance.php +++ /dev/null @@ -1,42 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\FunctionalTestingFramework\Helper; - -use Magento\FunctionalTestingFramework\Module\MagentoWebDriver; -use Codeception\Module; - -/** - * Class Acceptance - * - * Define global actions - * All public methods declared in helper class will be available in $I - */ -class Acceptance extends Module -{ - /** - * Reconfig WebDriver. - * - * @param string $config - * @param string $value - * @return void - */ - public function changeConfiguration($config, $value) - { - $this->getModule(MagentoWebDriver::class)->_reconfigure([$config => $value]); - } - - /** - * Get WebDriver configuration. - * - * @param string $config - * @return string - */ - public function getConfiguration($config) - { - return $this->getModule(MagentoWebDriver::class)->_getConfig($config); - } -} diff --git a/src/Magento/FunctionalTestingFramework/Helper/MagentoFakerData.php b/src/Magento/FunctionalTestingFramework/Helper/MagentoFakerData.php deleted file mode 100644 index a5b19b4c6..000000000 --- a/src/Magento/FunctionalTestingFramework/Helper/MagentoFakerData.php +++ /dev/null @@ -1,54 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\FunctionalTestingFramework\Helper; - -/** - * Class MagentoFakerData - */ -class MagentoFakerData extends \Codeception\Module -{ - /** - * Get Customer data. - * - * @param array $additional - * @return array - */ - public function getCustomerData(array $additional = []) - { - return [$additional]; - } - - /** - * Get category data. - * - * @return array - */ - public function getCategoryData() - { - return []; - } - - /** - * Get simple product data. - * - * @return array - */ - public function getProductData() - { - return []; - } - - /** - * Get Content Page Data. - * - * @return array - */ - public function getContentPage() - { - return []; - } -} From a1bc07c3fd89bf4230c1d65971faf910557c55c9 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 23 Mar 2020 10:02:20 -0500 Subject: [PATCH 314/888] MQE-1980: dependency static test fix and static test refactoring --- .../StaticCheck/TestDependencyCheck.php | 201 +++++------------- .../Upgrade/RemoveModuleFileInSuiteFiles.php | 5 +- .../Upgrade/RenameMetadataFiles.php | 3 +- .../Upgrade/SplitMultipleEntitiesFiles.php | 5 +- .../Upgrade/UpdateAssertionSchema.php | 3 +- .../Upgrade/UpdateTestSchemaPaths.php | 5 +- .../Util/Script/ScriptUtil.php | 135 +++++++++++- 7 files changed, 204 insertions(+), 153 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php index bc1b06cc5..4ee77f4d7 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php @@ -6,16 +6,8 @@ namespace Magento\FunctionalTestingFramework\StaticCheck; -use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; -use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Exceptions\XmlException; -use Magento\FunctionalTestingFramework\Page\Handlers\PageObjectHandler; -use Magento\FunctionalTestingFramework\Page\Handlers\SectionObjectHandler; -use Magento\FunctionalTestingFramework\Test\Handlers\ActionGroupObjectHandler; -use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; -use Magento\FunctionalTestingFramework\Util\TestGenerator; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Finder\Finder; use Exception; @@ -24,13 +16,11 @@ /** * Class TestDependencyCheck * @package Magento\FunctionalTestingFramework\StaticCheck - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class TestDependencyCheck implements StaticCheckInterface { const EXTENDS_REGEX_PATTERN = '/extends=["\']([^\'"]*)/'; const ACTIONGROUP_REGEX_PATTERN = '/ref=["\']([^\'"]*)/'; - const ACTIONGROUP_ARGUMENT_REGEX_PATTERN = '/<argument[^\/>]*name="([^"\']*)/'; const ERROR_LOG_FILENAME = 'mftf-dependency-checks'; const ERROR_LOG_MESSAGE = 'MFTF File Dependency Check'; @@ -83,6 +73,13 @@ class TestDependencyCheck implements StaticCheckInterface */ private $allEntities = []; + /** + * ScriptUtil instance + * + * @var ScriptUtil + */ + private $scriptUtil; + /** * Checks test dependencies, determined by references in tests versus the dependencies listed in the Magento module * @@ -92,7 +89,8 @@ class TestDependencyCheck implements StaticCheckInterface */ public function execute(InputInterface $input) { - $allModules = ScriptUtil::getAllModulePaths(); + $this->scriptUtil = new ScriptUtil(); + $allModules = $this->scriptUtil->getAllModulePaths(); if (!class_exists('\Magento\Framework\Component\ComponentRegistrar')) { return "TEST DEPENDENCY CHECK ABORTED: MFTF must be attached or pointing to Magento codebase."; @@ -108,9 +106,9 @@ public function execute(InputInterface $input) DIRECTORY_SEPARATOR . 'Data' . DIRECTORY_SEPARATOR, ]; // These files can contain references to other modules. - $testXmlFiles = ScriptUtil::getModuleXmlFilesByScope($allModules, $filePaths[0]); - $actionGroupXmlFiles = ScriptUtil::getModuleXmlFilesByScope($allModules, $filePaths[1]); - $dataXmlFiles= ScriptUtil::getModuleXmlFilesByScope($allModules, $filePaths[2]); + $testXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($allModules, $filePaths[0]); + $actionGroupXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($allModules, $filePaths[1]); + $dataXmlFiles= $this->scriptUtil->getModuleXmlFilesByScope($allModules, $filePaths[2]); $this->errors = []; $this->errors += $this->findErrorsInFileSet($testXmlFiles); @@ -118,7 +116,7 @@ public function execute(InputInterface $input) $this->errors += $this->findErrorsInFileSet($dataXmlFiles); // hold on to the output and print any errors to a file - $this->output = ScriptUtil::printErrorsToFile( + $this->output = $this->scriptUtil->printErrorsToFile( $this->errors, self::ERROR_LOG_FILENAME, self::ERROR_LOG_MESSAGE @@ -147,17 +145,16 @@ public function getOutput() * Finds all reference errors in given set of files * @param Finder $files * @return array - * @throws TestReferenceException * @throws XmlException */ private function findErrorsInFileSet($files) { $testErrors = []; foreach ($files as $filePath) { - $modulePath = dirname(dirname(dirname(dirname($filePath)))); - $moduleFullName = array_search($modulePath, $this->moduleNameToPath) ?? null; + $this->allEntities = []; + $moduleName = $this->getModuleName($filePath); // Not a module, is either dev/tests/acceptance or loose folder with test materials - if ($moduleFullName == null) { + if ($moduleName == null) { continue; } @@ -172,108 +169,37 @@ private function findErrorsInFileSet($files) $braceReferences[1] = array_unique($braceReferences[1]); $braceReferences[2] = array_filter(array_unique($braceReferences[2])); - // resolve data entity references - $this->resolveDataEntityReferences($braceReferences[0], $contents); + // resolve entity references + $this->allEntities = array_merge( + $this->allEntities, + $this->scriptUtil->resolveEntityReferences($braceReferences[0], $contents) + ); - //resolve entity references - $this->resolveParametrizedReferences($braceReferences[2], $contents); + // resolve parameterized references + $this->allEntities = array_merge( + $this->allEntities, + $this->scriptUtil->resolveParametrizedReferences($braceReferences[2], $contents) + ); - // Check actionGroup references - $this->resolveEntityReferences($actionGroupReferences[1]); + // resolve entity by names + $this->allEntities = array_merge( + $this->allEntities, + $this->scriptUtil->resolveEntityByNames($actionGroupReferences[1]) + ); - // Check extended objects - $this->resolveEntityReferences($extendReferences[1]); + // resolve entity by names + $this->allEntities = array_merge( + $this->allEntities, + $this->scriptUtil->resolveEntityByNames($extendReferences[1]) + ); // Find violating references and set error output - $violatingReferences = $this->findViolatingReferences($moduleFullName); - $testErrors = $this->setErrorOutput($violatingReferences, $filePath); + $violatingReferences = $this->findViolatingReferences($moduleName); + $testErrors = array_merge($testErrors, $this->setErrorOutput($violatingReferences, $filePath)); } return $testErrors; } - /** - * Drill down into params in {{ref.params('string', $data.key$, entity.reference)}} - * and resolve references. - * - * @param array $braceReferences - * @param string $contents - * @return void - * @throws XmlException - */ - private function resolveParametrizedReferences($braceReferences, $contents) - { - foreach ($braceReferences as $parameterizedReference) { - preg_match( - ActionObject::ACTION_ATTRIBUTE_VARIABLE_REGEX_PARAMETER, - $parameterizedReference, - $arguments - ); - $splitArguments = explode(',', ltrim(rtrim($arguments[0], ")"), "(")); - foreach ($splitArguments as $argument) { - // Do nothing for 'string' or $persisted.data$ - if (preg_match(ActionObject::STRING_PARAMETER_REGEX, $argument)) { - continue; - } elseif (preg_match(TestGenerator::PERSISTED_OBJECT_NOTATION_REGEX, $argument)) { - continue; - } - // trim `data.field` to `data` - preg_match('/([^.]+)/', $argument, $entityName); - // Double check that {{data.field}} isn't an argument for an ActionGroup - $entity = $this->findEntity($entityName[1]); - preg_match_all(self::ACTIONGROUP_ARGUMENT_REGEX_PATTERN, $contents, $possibleArgument); - if (array_search($entityName[1], $possibleArgument[1]) !== false) { - continue; - } - if ($entity !== null) { - $this->allEntities[$entity->getName()] = $entity; - } - } - } - } - - /** - * Check `data` entities in {{data.field}} or {{data.field('param')}} and resolve references - * - * @param array $braceReferences - * @param string $contents - * @return void - * @throws XmlException - - */ - private function resolveDataEntityReferences($braceReferences, $contents) - { - foreach ($braceReferences as $reference) { - // trim `{{data.field}}` to `data` - preg_match('/{{([^.]+)/', $reference, $entityName); - // Double check that {{data.field}} isn't an argument for an ActionGroup - $entity = $this->findEntity($entityName[1]); - preg_match_all(self::ACTIONGROUP_ARGUMENT_REGEX_PATTERN, $contents, $possibleArgument); - if (array_search($entityName[1], $possibleArgument[1]) !== false) { - continue; - } - if ($entity !== null) { - $this->allEntities[$entity->getName()] = $entity; - } - } - } - - /** - * Resolve entity references - * - * @param array $references - * @return void - * @throws XmlException - */ - private function resolveEntityReferences($references) - { - foreach ($references as $reference) { - $entity = $this->findEntity($reference); - if ($entity !== null) { - $this->allEntities[$entity->getName()] = $entity; - } - } - } - /** * Find violating references * @@ -351,7 +277,10 @@ private function buildComposerDependencyList() $flattenedDependencies = []; foreach ($this->moduleNameToPath as $moduleName => $pathToModule) { - $composerData = json_decode(file_get_contents($pathToModule . DIRECTORY_SEPARATOR . "composer.json"), true); + $composerData = json_decode( + file_get_contents($pathToModule . DIRECTORY_SEPARATOR . "composer.json"), + true + ); $this->allDependencies[$moduleName] = $composerData['require']; } foreach ($this->allDependencies as $moduleName => $dependencies) { @@ -403,43 +332,31 @@ private function getModuleDependenciesFromReferences($array) // Should it append ALL filenames, including merges? $allFiles = explode(",", $item->getFilename()); foreach ($allFiles as $file) { - $modulePath = dirname(dirname(dirname(dirname($file)))); - $fullModuleName = array_search($modulePath, $this->moduleNameToPath); - $composerModuleName = $this->moduleNameToComposerName[$fullModuleName]; - $filenames[$item->getName()][] = $composerModuleName; + $moduleName = $this->getModuleName($file); + if (isset($this->moduleNameToComposerName[$moduleName])) { + $composerModuleName = $this->moduleNameToComposerName[$moduleName]; + $filenames[$item->getName()][] = $composerModuleName; + } } } return $filenames; } /** - * Attempts to find any MFTF entity by its name. Returns null if none are found. - * @param string $name - * @return mixed - * @throws XmlException + * Return module name for a file path + * + * @param string $filePath + * @return string|null */ - private function findEntity($name) + private function getModuleName($filePath) { - if ($name == '_ENV' || $name == '_CREDS') { - return null; - } - - if (DataObjectHandler::getInstance()->getObject($name)) { - return DataObjectHandler::getInstance()->getObject($name); - } elseif (PageObjectHandler::getInstance()->getObject($name)) { - return PageObjectHandler::getInstance()->getObject($name); - } elseif (SectionObjectHandler::getInstance()->getObject($name)) { - return SectionObjectHandler::getInstance()->getObject($name); - } - - try { - return ActionGroupObjectHandler::getInstance()->getObject($name); - } catch (TestReferenceException $e) { - } - try { - return TestObjectHandler::getInstance()->getObject($name); - } catch (TestReferenceException $e) { + $moduleName = null; + foreach ($this->moduleNameToPath as $name => $path) { + if (strpos($filePath, $path) !== false) { + $moduleName = $name; + break; + } } - return null; + return $moduleName; } } diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/RemoveModuleFileInSuiteFiles.php b/src/Magento/FunctionalTestingFramework/Upgrade/RemoveModuleFileInSuiteFiles.php index ac36742f1..a42fbbf31 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/RemoveModuleFileInSuiteFiles.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/RemoveModuleFileInSuiteFiles.php @@ -64,15 +64,16 @@ class RemoveModuleFileInSuiteFiles implements UpgradeInterface */ public function execute(InputInterface $input, OutputInterface $output) { + $scriptUtil = new ScriptUtil(); $this->setOutputStyle($input, $output); $this->output = $output; $testPaths[] = $input->getArgument('path'); if (empty($testPaths[0])) { - $testPaths = ScriptUtil::getAllModulePaths(); + $testPaths = $scriptUtil->getAllModulePaths(); } // Get module suite xml files - $xmlFiles = ScriptUtil::getModuleXmlFilesByScope($testPaths, 'Suite'); + $xmlFiles = $scriptUtil->getModuleXmlFilesByScope($testPaths, 'Suite'); $this->processXmlFiles($xmlFiles); return ("Removed module file reference in {$this->testsUpdated} suite file(s)."); diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/RenameMetadataFiles.php b/src/Magento/FunctionalTestingFramework/Upgrade/RenameMetadataFiles.php index 960456010..5be881a62 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/RenameMetadataFiles.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/RenameMetadataFiles.php @@ -26,9 +26,10 @@ class RenameMetadataFiles implements UpgradeInterface */ public function execute(InputInterface $input, OutputInterface $output) { + $scriptUtil = new ScriptUtil(); $testPaths[] = $input->getArgument('path'); if (empty($testPaths[0])) { - $testPaths = ScriptUtil::getAllModulePaths(); + $testPaths = $scriptUtil->getAllModulePaths(); } foreach ($testPaths as $testsPath) { diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php b/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php index fd7957bda..b0190d959 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/SplitMultipleEntitiesFiles.php @@ -69,16 +69,17 @@ class SplitMultipleEntitiesFiles implements UpgradeInterface */ public function execute(InputInterface $input, OutputInterface $output) { + $scriptUtil = new ScriptUtil(); $this->output = $output; $this->testsUpdated = 0; $testPaths[] = $input->getArgument('path'); if (empty($testPaths[0])) { - $testPaths = ScriptUtil::getAllModulePaths(); + $testPaths = $scriptUtil->getAllModulePaths(); } // Process module xml files foreach ($this->entityCategories as $type => $urn) { - $xmlFiles = ScriptUtil::getModuleXmlFilesByScope($testPaths, $type); + $xmlFiles = $scriptUtil->getModuleXmlFilesByScope($testPaths, $type); $this->processXmlFiles($xmlFiles, $type, $urn); } diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php index 95f7c9750..2628be851 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php @@ -28,9 +28,10 @@ class UpdateAssertionSchema implements UpgradeInterface */ public function execute(InputInterface $input, OutputInterface $output) { + $scriptUtil = new ScriptUtil(); $testPaths[] = $input->getArgument('path'); if (empty($testPaths[0])) { - $testPaths = ScriptUtil::getAllModulePaths(); + $testPaths = $scriptUtil->getAllModulePaths(); } $testsUpdated = 0; diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateTestSchemaPaths.php b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateTestSchemaPaths.php index 09140d1cd..e6d3358d6 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateTestSchemaPaths.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateTestSchemaPaths.php @@ -57,16 +57,17 @@ class UpdateTestSchemaPaths implements UpgradeInterface */ public function execute(InputInterface $input, OutputInterface $output) { + $scriptUtil = new ScriptUtil(); $this->output = $output; $this->testsUpdated = 0; $testPaths[] = $input->getArgument('path'); if (empty($testPaths[0])) { - $testPaths = ScriptUtil::getAllModulePaths(); + $testPaths = $scriptUtil->getAllModulePaths(); } // Process module xml files foreach ($this->typeToUrns as $type => $urn) { - $xmlFiles = ScriptUtil::getModuleXmlFilesByScope($testPaths, $type); + $xmlFiles = $scriptUtil->getModuleXmlFilesByScope($testPaths, $type); $this->processXmlFiles($xmlFiles, $urn); } diff --git a/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php b/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php index e1534d655..9f765f023 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php @@ -6,24 +6,36 @@ namespace Magento\FunctionalTestingFramework\Util\Script; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; +use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Symfony\Component\Finder\Finder; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\Util\ModuleResolver; +use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; +use Magento\FunctionalTestingFramework\Page\Handlers\PageObjectHandler; +use Magento\FunctionalTestingFramework\Page\Handlers\SectionObjectHandler; +use Magento\FunctionalTestingFramework\Test\Handlers\ActionGroupObjectHandler; +use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; +use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; +use Magento\FunctionalTestingFramework\Util\TestGenerator; /** * ScriptUtil class that contains helper functions for static and upgrade scripts * * @package Magento\FunctionalTestingFramework\Util\Script + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class ScriptUtil { + const ACTIONGROUP_ARGUMENT_REGEX_PATTERN = '/<argument[^\/>]*name="([^"\']*)/'; + /** * Return all installed Magento module paths * * @return array * @throws TestFrameworkException */ - public static function getAllModulePaths() + public function getAllModulePaths() { MftfApplicationConfig::create( true, @@ -43,7 +55,7 @@ public static function getAllModulePaths() * @param string $message * @return string */ - public static function printErrorsToFile($errors, $filename, $message) + public function printErrorsToFile($errors, $filename, $message) { if (empty($errors)) { return $message . ": No errors found."; @@ -70,7 +82,7 @@ public static function printErrorsToFile($errors, $filename, $message) * @param string $scope * @return Finder|array */ - public static function getModuleXmlFilesByScope($modulePaths, $scope) + public function getModuleXmlFilesByScope($modulePaths, $scope) { $found = false; $scopePath = DIRECTORY_SEPARATOR . ucfirst($scope) . DIRECTORY_SEPARATOR; @@ -85,4 +97,121 @@ public static function getModuleXmlFilesByScope($modulePaths, $scope) } return $found ? $finder->files() : []; } + + /** + * Resolve entity reference in {{entity.field}} or {{entity.field('param')}} + * + * @param array $braceReferences + * @param string $contents + * @return array + * @throws XmlException + */ + public function resolveEntityReferences($braceReferences, $contents) + { + $entities = []; + foreach ($braceReferences as $reference) { + // trim `{{data.field}}` to `data` + preg_match('/{{([^.]+)/', $reference, $entityName); + // Double check that {{data.field}} isn't an argument for an ActionGroup + $entity = $this->findEntity($entityName[1]); + preg_match_all(self::ACTIONGROUP_ARGUMENT_REGEX_PATTERN, $contents, $possibleArgument); + if (array_search($entityName[1], $possibleArgument[1]) !== false) { + continue; + } + if ($entity !== null) { + $entities[$entity->getName()] = $entity; + } + } + return $entities; + } + + /** + * Drill down into params in {{ref.params('string', $data.key$, entity.reference)}} to resolve entity reference + * + * @param array $braceReferences + * @param string $contents + * @return array + * @throws XmlException + */ + public function resolveParametrizedReferences($braceReferences, $contents) + { + $entities = []; + foreach ($braceReferences as $parameterizedReference) { + preg_match( + ActionObject::ACTION_ATTRIBUTE_VARIABLE_REGEX_PARAMETER, + $parameterizedReference, + $arguments + ); + $splitArguments = explode(',', ltrim(rtrim($arguments[0], ")"), "(")); + foreach ($splitArguments as $argument) { + // Do nothing for 'string' or $persisted.data$ + if (preg_match(ActionObject::STRING_PARAMETER_REGEX, $argument)) { + continue; + } elseif (preg_match(TestGenerator::PERSISTED_OBJECT_NOTATION_REGEX, $argument)) { + continue; + } + // trim `data.field` to `data` + preg_match('/([^.]+)/', $argument, $entityName); + // Double check that {{data.field}} isn't an argument for an ActionGroup + $entity = $this->findEntity($entityName[1]); + preg_match_all(self::ACTIONGROUP_ARGUMENT_REGEX_PATTERN, $contents, $possibleArgument); + if (array_search($entityName[1], $possibleArgument[1]) !== false) { + continue; + } + if ($entity !== null) { + $entities[$entity->getName()] = $entity; + } + } + } + return $entities; + } + + /** + * Resolve entity by names + * + * @param array $references + * @return array + * @throws XmlException + */ + public function resolveEntityByNames($references) + { + $entities = []; + foreach ($references as $reference) { + $entity = $this->findEntity($reference); + if ($entity !== null) { + $entities[$entity->getName()] = $entity; + } + } + return $entities; + } + + /** + * Attempts to find any MFTF entity by its name. Returns null if none are found + * + * @param string $name + * @return mixed + * @throws XmlException + */ + public function findEntity($name) + { + if ($name == '_ENV' || $name == '_CREDS') { + return null; + } + + if (DataObjectHandler::getInstance()->getObject($name)) { + return DataObjectHandler::getInstance()->getObject($name); + } elseif (PageObjectHandler::getInstance()->getObject($name)) { + return PageObjectHandler::getInstance()->getObject($name); + } elseif (SectionObjectHandler::getInstance()->getObject($name)) { + return SectionObjectHandler::getInstance()->getObject($name); + } elseif (ActionGroupObjectHandler::getInstance()->getObject($name)) { + return ActionGroupObjectHandler::getInstance()->getObject($name); + } + + try { + return TestObjectHandler::getInstance()->getObject($name); + } catch (TestReferenceException $e) { + } + return null; + } } From 730a3d4b110e809384e1fb85ae41536a138ae0a9 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 23 Mar 2020 11:26:05 -0500 Subject: [PATCH 315/888] MQE-2039: fatal error in actionGroupArguments static check when there is an action group file missing ActionGroup in filename --- .../StaticCheck/ActionGroupArgumentsCheck.php | 29 ++++++++++++++----- .../Handlers/ActionGroupObjectHandler.php | 9 ++++++ 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php index 556ad45be..881ee69ab 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php @@ -6,12 +6,9 @@ namespace Magento\FunctionalTestingFramework\StaticCheck; -use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; -use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Test\Handlers\ActionGroupObjectHandler; use Magento\FunctionalTestingFramework\Test\Objects\ActionGroupObject; use Symfony\Component\Console\Input\InputInterface; -use Magento\FunctionalTestingFramework\Util\ModuleResolver; use Symfony\Component\Finder\Finder; use Exception; use Magento\FunctionalTestingFramework\Util\Script\ScriptUtil; @@ -22,7 +19,6 @@ */ class ActionGroupArgumentsCheck implements StaticCheckInterface { - const ACTIONGROUP_XML_REGEX_PATTERN = '/<actionGroup\sname=(?: (?!<\/actionGroup>).)*/mxs'; const ACTIONGROUP_ARGUMENT_REGEX_PATTERN = '/<argument[^\/>]*name="([^"\']*)/mxs'; const ACTIONGROUP_NAME_REGEX_PATTERN = '/<actionGroup name=["\']([^\'"]*)/'; @@ -42,6 +38,13 @@ class ActionGroupArgumentsCheck implements StaticCheckInterface */ private $output; + /** + * ScriptUtil instance + * + * @var ScriptUtil + */ + private $scriptUtil; + /** * Checks unused arguments in action groups and prints out error to file. * @@ -51,16 +54,17 @@ class ActionGroupArgumentsCheck implements StaticCheckInterface */ public function execute(InputInterface $input) { - $allModules = ScriptUtil::getAllModulePaths(); + $this->scriptUtil = new ScriptUtil(); + $allModules = $this->scriptUtil->getAllModulePaths(); - $actionGroupXmlFiles = ScriptUtil::getModuleXmlFilesByScope( + $actionGroupXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope( $allModules, DIRECTORY_SEPARATOR . 'ActionGroup' . DIRECTORY_SEPARATOR ); $this->errors = $this->findErrorsInFileSet($actionGroupXmlFiles); - $this->output = ScriptUtil::printErrorsToFile( + $this->output = $this->scriptUtil->printErrorsToFile( $this->errors, self::ERROR_LOG_FILENAME, self::ERROR_LOG_MESSAGE @@ -132,10 +136,19 @@ private function findUnusedArguments($actionGroupXml) preg_match_all(self::ACTIONGROUP_ARGUMENT_REGEX_PATTERN, $actionGroupXml, $arguments); preg_match(self::ACTIONGROUP_NAME_REGEX_PATTERN, $actionGroupXml, $actionGroupName); + $validActionGroup = false; try { $actionGroup = ActionGroupObjectHandler::getInstance()->getObject($actionGroupName[1]); - } catch (XmlException $e) { + if ($actionGroup) { + $validActionGroup = true; + } + } catch (Exception $e) { + } + + if (!$validActionGroup) { + return $unusedArguments; } + foreach ($arguments[1] as $argument) { //pattern to match all argument references $patterns = [ diff --git a/src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php b/src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php index 7f1d49d5c..5a87a32f6 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php @@ -6,6 +6,7 @@ namespace Magento\FunctionalTestingFramework\Test\Handlers; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\ObjectManager\ObjectHandlerInterface; use Magento\FunctionalTestingFramework\ObjectManagerFactory; use Magento\FunctionalTestingFramework\Test\Objects\ActionGroupObject; @@ -49,6 +50,7 @@ class ActionGroupObjectHandler implements ObjectHandlerInterface * Singleton getter for instance of ActionGroupObjectHandler * * @return ActionGroupObjectHandler + * @throws XmlException */ public static function getInstance(): ActionGroupObjectHandler { @@ -61,6 +63,7 @@ public static function getInstance(): ActionGroupObjectHandler /** * ActionGroupObjectHandler constructor. + * @throws XmlException */ private function __construct() { @@ -73,6 +76,8 @@ private function __construct() * * @param string $actionGroupName * @return ActionGroupObject + * @throws TestFrameworkException + * @throws XmlException */ public function getObject($actionGroupName) { @@ -88,6 +93,8 @@ public function getObject($actionGroupName) * Function to return all objects for which the handler is responsible * * @return array + * @throws TestFrameworkException + * @throws XmlException */ public function getAllObjects(): array { @@ -101,6 +108,7 @@ public function getAllObjects(): array * Method which populates field array with objects from parsed action_group.xml * * @return void + * @throws XmlException * @SuppressWarnings(PHPMD.UnusedPrivateMethod) */ private function initActionGroups() @@ -137,6 +145,7 @@ private function initActionGroups() * * @param ActionGroupObject $actionGroupObject * @return ActionGroupObject + * @throws XmlException * @throws TestFrameworkException */ private function extendActionGroup($actionGroupObject): ActionGroupObject From 8b59708c36f0e67e4d93f2cf717b9583b513e04e Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 26 Mar 2020 15:36:52 -0500 Subject: [PATCH 316/888] MQE-1957: Entity Deprecation Reference - Static Check --- docs/commands/mftf.md | 6 + .../Console/StaticChecksCommand.php | 9 +- .../DeprecatedEntityUsageCheck.php | 598 ++++++++++++++++++ .../StaticCheck/StaticChecksList.php | 1 + .../Test/Objects/TestObject.php | 30 +- .../Test/Util/TestObjectExtractor.php | 3 +- .../Util/Script/ScriptUtil.php | 60 +- 7 files changed, 697 insertions(+), 10 deletions(-) create mode 100644 src/Magento/FunctionalTestingFramework/StaticCheck/DeprecatedEntityUsageCheck.php diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 6d2dedfd1..5b62e9c24 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -439,6 +439,12 @@ If no script name argument is specified, all existing static check scripts will vendor/bin/mftf static-checks [<names>]... ``` +#### Options + +| Option | Description | +|-----------------------|-----------------------------------------------------------------------------------------------------------| +| `-p, --path` | Path to a MFTF test module to run "deprecatedEntityUsage" static check script. Option is ignored by other static check scripts. + #### Examples To check what existing static check scripts are available diff --git a/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php b/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php index 30c9cd600..6473f36bd 100644 --- a/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php @@ -15,6 +15,7 @@ use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Exception; @@ -52,6 +53,12 @@ protected function configure() 'names', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, 'name(s) of specific static check script(s) to run' + )->addOption( + 'path', + 'p', + InputOption::VALUE_OPTIONAL, + 'Path to a MFTF test module to run "deprecatedEntityUsage" static check script. ' . PHP_EOL + . 'Option is ignored by other static check scripts.' . PHP_EOL ); } @@ -66,7 +73,7 @@ protected function configure() protected function execute(InputInterface $input, OutputInterface $output) { try { - $this->validateInputArguments($input, $output); + $this->validateInputArguments($input); } catch (InvalidArgumentException $e) { LoggingUtil::getInstance()->getLogger(StaticChecksCommand::class)->error($e->getMessage()); $output->writeln($e->getMessage() . " Please fix input arguments and rerun."); diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/DeprecatedEntityUsageCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/DeprecatedEntityUsageCheck.php new file mode 100644 index 000000000..8b4f7fab2 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/DeprecatedEntityUsageCheck.php @@ -0,0 +1,598 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\FunctionalTestingFramework\StaticCheck; + +use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Exceptions\XmlException; +use Magento\FunctionalTestingFramework\Page\Objects\SectionObject; +use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; +use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Finder\Finder; +use Exception; +use Magento\FunctionalTestingFramework\Util\Script\ScriptUtil; +use Magento\FunctionalTestingFramework\DataGenerator\Handlers\OperationDefinitionObjectHandler; +use Magento\FunctionalTestingFramework\DataGenerator\Objects\OperationDefinitionObject; +use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; +use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; +use Symfony\Component\Finder\SplFileInfo; +use DOMNodeList; +use DOMElement; + +/** + * Class DeprecatedEntityUsageCheck + * @package Magento\FunctionalTestingFramework\StaticCheck + */ +class DeprecatedEntityUsageCheck implements StaticCheckInterface +{ + const EXTENDS_REGEX_PATTERN = '/extends=["\']([^\'"]*)/'; + const ACTIONGROUP_REGEX_PATTERN = '/ref=["\']([^\'"]*)/'; + + const ERROR_LOG_FILENAME = 'mftf-deprecated-entity-usage-checks'; + const ERROR_LOG_MESSAGE = 'MFTF Deprecated Entity Usage Check'; + + /** + * Array containing all errors found after running the execute() function + * + * @var array + */ + private $errors = []; + + /** + * String representing the output summary found after running the execute() function + * + * @var string + */ + private $output; + + /** + * ScriptUtil instance + * + * @var ScriptUtil + */ + private $scriptUtil; + + /** + * Data operations + * + * @var array + */ + private $dataOperations = ['create', 'update', 'get', 'delete']; + + /** + * Checks test dependencies, determined by references in tests versus the dependencies listed in the Magento module + * + * @param InputInterface $input + * @return string + * @throws Exception; + */ + public function execute(InputInterface $input) + { + $this->scriptUtil = new ScriptUtil(); + + $modulePaths = []; + $includeRootPath = true; + $path = $input->getOption('path'); + if ($path) { + if (!realpath($path)) { + throw new InvalidArgumentException("Invalid --path option: " . $path); + } + MftfApplicationConfig::create( + true, + MftfApplicationConfig::UNIT_TEST_PHASE, + false, + MftfApplicationConfig::LEVEL_DEFAULT, + true + ); + $modulePaths[] = realpath($path); + $includeRootPath = false; + } else { + $modulePaths = $this->scriptUtil->getAllModulePaths(); + } + + // These files can contain references to other entities + $testXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, 'Test'); + $actionGroupXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, 'ActionGroup'); + $suiteXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, 'Suite'); + if ($includeRootPath) { + $rootSuiteXmlFiles = $this->scriptUtil->getRootSuiteXmlFiles(); + } + $dataXmlFiles= $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, 'Data'); + + $this->errors = []; + $this->errors += $this->findReferenceErrorsInActionFiles($testXmlFiles); + $this->errors += $this->findReferenceErrorsInActionFiles($actionGroupXmlFiles); + $this->errors += $this->findReferenceErrorsInActionFiles($suiteXmlFiles); + if ($includeRootPath && !empty($rootSuiteXmlFiles)) { + $this->errors += $this->findReferenceErrorsInActionFiles($rootSuiteXmlFiles); + } + $this->errors += $this->findReferenceErrorsInDataFiles($dataXmlFiles); + + // Hold on to the output and print any errors to a file + $this->output = $this->scriptUtil->printErrorsToFile( + $this->errors, + self::ERROR_LOG_FILENAME, + self::ERROR_LOG_MESSAGE + ); + } + + /** + * Return array containing all errors found after running the execute() function + * + * @return array + */ + public function getErrors() + { + return $this->errors; + } + + /** + * Return string of a short human readable result of the check. For example: "No Dependency errors found." + * + * @return string + */ + public function getOutput() + { + return $this->output; + } + + /** + * Find reference errors in set of action files + * + * @param Finder $files + * @return array + * @throws XmlException + */ + private function findReferenceErrorsInActionFiles($files) + { + $testErrors = []; + /** @var SplFileInfo $filePath */ + foreach ($files as $filePath) { + $contents = file_get_contents($filePath); + preg_match_all(ActionObject::ACTION_ATTRIBUTE_VARIABLE_REGEX_PATTERN, $contents, $braceReferences); + preg_match_all(self::ACTIONGROUP_REGEX_PATTERN, $contents, $actionGroupReferences); + preg_match_all(self::EXTENDS_REGEX_PATTERN, $contents, $extendReferences); + + $domDocument = new \DOMDocument(); + $domDocument->load($filePath); + $createdDataReferences = $this->getAttributesFromDOMNodeList( + $domDocument->getElementsByTagName('createData'), + 'entity' + ); + $updatedDataReferences = $this->getAttributesFromDOMNodeList( + $domDocument->getElementsByTagName('updateData'), + 'entity' + ); + $getDataReferences = $this->getAttributesFromDOMNodeList( + $domDocument->getElementsByTagName('getData'), + 'entity' + ); + + // Remove Duplicates + $actionGroupReferences[1] = array_unique($actionGroupReferences[1]); + $extendReferences[1] = array_unique($extendReferences[1]); + $braceReferences[0] = array_unique($braceReferences[0]); + $braceReferences[2] = array_filter(array_unique($braceReferences[2])); + $createdDataReferences = array_unique($createdDataReferences); + $updatedDataReferences = array_unique($updatedDataReferences); + $getDataReferences = array_unique($getDataReferences); + + // Resolve entity references + $entityReferences = $this->scriptUtil->resolveEntityReferences($braceReferences[0], $contents, true); + + // Resolve parameterized references + $entityReferences = array_merge( + $entityReferences, + $this->scriptUtil->resolveParametrizedReferences($braceReferences[2], $contents, true) + ); + + // Resolve action group entity by names + $entityReferences = array_merge( + $entityReferences, + $this->scriptUtil->resolveEntityByNames($actionGroupReferences[1]) + ); + + // Resolve extends entity by names + $entityReferences = array_merge( + $entityReferences, + $this->scriptUtil->resolveEntityByNames($extendReferences[1]) + ); + + // Resolve create data entity by names + $entityReferences = array_merge( + $entityReferences, + $this->scriptUtil->resolveEntityByNames($createdDataReferences) + ); + + // Resolve update data entity by names + $entityReferences = array_merge( + $entityReferences, + $this->scriptUtil->resolveEntityByNames($updatedDataReferences) + ); + + // Resolve get data entity by names + $entityReferences = array_merge( + $entityReferences, + $this->scriptUtil->resolveEntityByNames($getDataReferences) + ); + + // Find violating references + $violatingReferences = $this->findViolatingReferences($entityReferences); + + // Find metadata references from persist data + $metadataReferences = $this->getMetadataFromData($createdDataReferences, 'create'); + $metadataReferences = array_merge_recursive( + $metadataReferences, + $this->getMetadataFromData($updatedDataReferences, 'update') + ); + $metadataReferences = array_merge_recursive( + $metadataReferences, + $this->getMetadataFromData($getDataReferences, 'get') + ); + + // Find violating references + $violatingReferences = array_merge( + $violatingReferences, + $this->findViolatingMetadataReferences($metadataReferences) + ); + + // Set error output + $testErrors = array_merge($testErrors, $this->setErrorOutput($violatingReferences, $filePath)); + } + return $testErrors; + } + + /** + * Find reference errors in a set of data files + * + * @param Finder $files + * @return array + */ + private function findReferenceErrorsInDataFiles($files) + { + $testErrors = []; + /** @var SplFileInfo $filePath */ + foreach ($files as $filePath) { + $dataReferences = []; + $metadataReferences = []; + $domDocument = new \DOMDocument(); + $domDocument->load($filePath); + $entities = $domDocument->getElementsByTagName('entity'); + foreach ($entities as $entity) { + /** @var DOMElement $entity */ + $entityName = $entity->getAttribute('name'); + $metadataType = $entity->getAttribute('type'); + $parentEntityName = $entity->getAttribute('extends'); + if (!empty($metadataType && !isset($metadataReferences[$entityName][$metadataType]))) { + $metadataReferences[$entityName][$metadataType] = 'all'; + } + if (!empty($parentEntityName)) { + $dataReferences[$entityName][] = $parentEntityName; + } + // Find metadata reference in `var` elements + $varElements = $entity->getElementsByTagName('var'); + foreach ($varElements as $varElement) { + /** @var DOMElement $varElement */ + $metadataType = $varElement->getAttribute('entityType'); + if (!empty($metadataType) && !isset($metadataReferences[$entityName][$metadataType])) { + $metadataReferences[$entityName][$metadataType] = 'all'; + } + } + // Find metadata reference in `requiredEntity` elements, and + // Find data references in `requiredEntity` elements + $requiredElements = $entity->getElementsByTagName('requiredEntity'); + foreach ($requiredElements as $requiredElement) { + /** @var DOMElement $requiredElement */ + $metadataType = $requiredElement->getAttribute('type'); + if (!empty($metadataType) && !isset($metadataReferences[$entityName][$metadataType])) { + $metadataReferences[$entityName][$metadataType] = 'all'; + } + $dataReferences[$entityName][] = $requiredElement->nodeValue; + } + } + + // Find violating references + // Metadata references is unique + $violatingReferences = $this->findViolatingMetadataReferences($metadataReferences); + // Data references is not unique + $violatingReferences = array_merge_recursive( + $violatingReferences, + $this->findViolatingDataReferences($this->twoDimensionArrayUnique($dataReferences)) + ); + + // Set error output + $testErrors = array_merge($testErrors, $this->setErrorOutput($violatingReferences, $filePath)); + } + return $testErrors; + } + + /** + * Trim duplicate values from two-dimensional array. Dimension 1 array key is unique. + * + * @param array $inArray + * @return array + */ + private function twoDimensionArrayUnique($inArray) + { + $outArray = []; + foreach ($inArray as $key => $arr) { + $outArray[$key] = array_unique($arr); + } + return $outArray; + } + + /** + * Return attribute value for each node in DOMNodeList as an array + * + * @param DOMNodeList $nodes + * @param string $attributeName + * @return array + */ + private function getAttributesFromDOMNodeList($nodes, $attributeName) + { + $attributes = []; + /** @var DOMElement $node */ + foreach ($nodes as $node) { + $attributeValue = $node->getAttribute($attributeName); + if (!empty($attributeValue)) { + $attributes[] = $attributeValue; + } + } + return $attributes; + } + + /** + * Find metadata from data array + * + * @param array $references + * @param string $type + * @return array + */ + private function getMetadataFromData($references, $type) + { + $metaDataReferences = []; + try { + foreach ($references as $dataName) { + /** @var EntityDataObject $dataEntity */ + $dataEntity = $this->scriptUtil->findEntity($dataName); + if ($dataEntity) { + $metadata = $dataEntity->getType(); + if (!empty($metadata)) { + $metaDataReferences[$dataName][$metadata] = $type; + } + } + } + } catch (Exception $e) { + } + return $metaDataReferences; + } + + /** + * Find violating metadata references. Input array format is either + * + * [ + * $dataName1 => [ + * $metaDataName1 = [ + * 'create', + * 'update', + * ], + * ], + * $dataName2 => [ + * $metaDataName2 => 'create', + * ], + * $dataName3 => [ + * $metaDataName3 = [ + * 'get', + * 'create', + * 'update', + * ], + * ], + * ... + * ] + * + * or + * + * [ + * $dataName1 => [ + * $metaDataName1 => 'all', + * ], + * $dataName2 => [ + * $metaDataName2 => 'all', + * ], + * $dataName5 => [ + * $metaDataName5 => 'all', + * ], + * ... + * ] + * + * @param array $references + * @return array + */ + private function findViolatingMetadataReferences($references) + { + $allObjects = OperationDefinitionObjectHandler::getInstance()->getAllObjects(); + + // Find Violations + $violatingReferences = []; + foreach ($references as $dataName => $metadataArray) { + foreach ($metadataArray as $metadata => $types) { + $operations = []; + $strict = true; + if (is_array($types)) { + $operations = $types; + } elseif ($types === 'all') { + $operations = $this->dataOperations; + $strict = false; + } else { + $operations = [$types]; + } + + $deprecated = null; + $exists = false; + foreach ($operations as $operation) { + if (array_key_exists($operation . $metadata, $allObjects)) { + $exists = true; + /** @var OperationDefinitionObject $entity */ + $entity = $allObjects[$operation . $metadata]; + // When not strictly checking, it's not deprecated as long as we found one that's not deprecated + if (!$strict && empty($entity->getDeprecated())) { + $deprecated = false; + break; + } + // When strictly checking, it's deprecated as long as we found one that's deprecated + if ($strict && !empty($entity->getDeprecated())) { + $deprecated = true; + break; + } + } + } + if ($exists && !$strict && $deprecated !== false) { + $deprecated = true; + } + if ($strict && $deprecated !== true) { + $deprecated = false; + } + + if ($deprecated) { + $violatingReferences["\"{$dataName}\" references deprecated"][] = [ + 'name' => $metadata, + // TODO add filename in OperationDefinitionObject + 'file' => 'metadata xml file', + ]; + } + } + } + return $violatingReferences; + } + + /** + * Find violating data references. Input array format is + * + * [ + * $dataName1 => [ $requiredDataName1, $requiredDataName2, $requiredDataName3], + * $dataName2 => [ $requiredDataName2, $requiredDataName5, $requiredDataName7], + * ... + * ] + * + * @param array $references + * @return array + */ + private function findViolatingDataReferences($references) + { + // Find Violations + $violatingReferences = []; + foreach ($references as $dataName => $requiredDataNames) { + foreach ($requiredDataNames as $requiredDataName) { + try { + /** @var EntityDataObject $requiredData */ + $requiredData = DataObjectHandler::getInstance()->getObject($requiredDataName); + if ($requiredData && $requiredData->getDeprecated()) { + $violatingReferences["\"{$dataName}\" references deprecated"][] = [ + 'name' => $requiredDataName, + 'file' => $requiredData->getFilename(), + ]; + } + } catch (Exception $e) { + } + } + } + return $violatingReferences; + } + + /** + * Find violating references. Input array format is + * + * [ + * 'actionGroupName' => $actionGroupEntity, + * 'dataGroupName' => $dataEntity, + * 'testName' => $testEntity, + * 'pageName' => $pageEntity, + * 'section.field' => $fieldElementEntity, + * ... + * ] + * + * @param array $references + * @return array + */ + private function findViolatingReferences($references) + { + // Find Violations + $violatingReferences = []; + foreach ($references as $key => $entity) { + if ($entity->getDeprecated()) { + $classType = get_class($entity); + $name = $entity->getName(); + if ($classType === 'Magento\FunctionalTestingFramework\Page\Objects\ElementObject') { + $name = $key; + list($section, $field) = explode('.', $key, 2); + /** @var SectionObject $references[$section] */ + $file = $references[$section]->getFilename(); + } else { + $file = $entity->getFilename(); + } + $violatingReferences[$this->getSubjectFromClassType($classType)][] = [ + 'name' => $name, + 'file' => $file, + ]; + } + } + return $violatingReferences; + } + + /** + * Build and return error output for violating references + * + * @param array $violatingReferences + * @param SplFileInfo $path + * @return mixed + */ + private function setErrorOutput($violatingReferences, $path) + { + $testErrors = []; + + if (!empty($violatingReferences)) { + // Build error output + $errorOutput = "\nFile \"{$path->getRealPath()}\" contains:\n"; + foreach ($violatingReferences as $subject => $data) { + $errorOutput .= "\t- {$subject}:\n"; + foreach ($data as $item) { + $errorOutput .= "\t\t\"" . $item['name'] . "\" in " . $item['file'] . "\n"; + } + } + $testErrors[$path->getRealPath()][] = $errorOutput; + } + + return $testErrors; + } + + /** + * Return subject string for a class name + * + * @param string $classname + * @return string|null + */ + private function getSubjectFromClassType($classname) + { + $subject = null; + if ($classname === 'Magento\FunctionalTestingFramework\Test\Objects\ActionGroupObject') { + $subject = 'Deprecated ActionGroup(s)'; + } elseif ($classname === 'Magento\FunctionalTestingFramework\Test\Objects\TestObject') { + $subject = 'Deprecated Test(s)'; + } elseif ($classname === 'Magento\FunctionalTestingFramework\Page\Objects\SectionObject') { + $subject = 'Deprecated Section(s)'; + } elseif ($classname === 'Magento\FunctionalTestingFramework\Page\Objects\PageObject') { + $subject = 'Deprecated Page(s)'; + } elseif ($classname === 'Magento\FunctionalTestingFramework\Page\Objects\ElementObject') { + $subject = 'Deprecated Element(s)'; + } elseif ($classname === 'Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject') { + $subject = 'Deprecated Data(s)'; + } elseif ($classname === 'Magento\FunctionalTestingFramework\DataGenerator\Objects\OperationDefinitionObject') { + $subject = 'Deprecated Metadata(s)'; + } + return $subject; + } +} diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php b/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php index ffa63389d..45619cdc2 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php @@ -30,6 +30,7 @@ public function __construct(array $checks = []) $this->checks = [ 'testDependencies' => new TestDependencyCheck(), 'actionGroupArguments' => new ActionGroupArgumentsCheck(), + 'deprecatedEntityUsage' => new DeprecatedEntityUsageCheck(), ] + $checks; } diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php index 504d207b4..01319bc67 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php @@ -78,6 +78,13 @@ class TestObject */ private $cachedOrderedActions = null; + /** + * Deprecation message. + * + * @var string|null + */ + private $deprecated; + /** * TestObject constructor. * @@ -87,15 +94,24 @@ class TestObject * @param TestHookObject[] $hooks * @param string $filename * @param string $parentTest + * @param string|null $deprecated */ - public function __construct($name, $parsedSteps, $annotations, $hooks, $filename = null, $parentTest = null) - { + public function __construct( + $name, + $parsedSteps, + $annotations, + $hooks, + $filename = null, + $parentTest = null, + $deprecated = null + ) { $this->name = $name; $this->parsedSteps = $parsedSteps; $this->annotations = $annotations; $this->hooks = $hooks; $this->filename = $filename; $this->parentTest = $parentTest; + $this->deprecated = $deprecated; } /** @@ -128,6 +144,16 @@ public function getParentName() return $this->parentTest; } + /** + * Returns deprecated messages. + * + * @return string|null + */ + public function getDeprecated() + { + return $this->deprecated; + } + /** * Getter for the skip_test boolean * diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php index a25db0935..18a034807 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php @@ -177,7 +177,8 @@ public function extractTestData($testData) $testAnnotations, $testHooks, $filename, - $testReference + $testReference, + $deprecated ); } catch (XmlException $exception) { throw new XmlException($exception->getMessage() . ' in Test ' . $filename); diff --git a/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php b/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php index 9f765f023..914a8e9f1 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php @@ -8,6 +8,9 @@ use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Exceptions\XmlException; +use Magento\FunctionalTestingFramework\Page\Objects\ElementObject; +use Magento\FunctionalTestingFramework\Page\Objects\SectionObject; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Symfony\Component\Finder\Finder; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\Util\ModuleResolver; @@ -28,6 +31,7 @@ class ScriptUtil { const ACTIONGROUP_ARGUMENT_REGEX_PATTERN = '/<argument[^\/>]*name="([^"\']*)/'; + const ROOT_SUITE_DIR = 'tests/_suite'; /** * Return all installed Magento module paths @@ -98,15 +102,34 @@ public function getModuleXmlFilesByScope($modulePaths, $scope) return $found ? $finder->files() : []; } + /** + * Return suite XML files in TESTS_BP/ROOT_SUITE_DIR directory + * + * @return Finder|array + * @throws TestFrameworkException + */ + public function getRootSuiteXmlFiles() + { + $rootSuitePath = FilePathFormatter::format(TESTS_BP) . self::ROOT_SUITE_DIR; + if (!realpath($rootSuitePath)) { + return []; + } + $finder = new Finder(); + $finder->files()->followLinks()->in($rootSuitePath)->name("*.xml"); + + return $finder->files(); + } + /** * Resolve entity reference in {{entity.field}} or {{entity.field('param')}} * - * @param array $braceReferences - * @param string $contents + * @param array $braceReferences + * @param string $contents + * @param boolean $resolveSectionElement * @return array * @throws XmlException */ - public function resolveEntityReferences($braceReferences, $contents) + public function resolveEntityReferences($braceReferences, $contents, $resolveSectionElement = false) { $entities = []; foreach ($braceReferences as $reference) { @@ -120,6 +143,18 @@ public function resolveEntityReferences($braceReferences, $contents) } if ($entity !== null) { $entities[$entity->getName()] = $entity; + if ($resolveSectionElement) { + if (get_class($entity) === 'Magento\FunctionalTestingFramework\Page\Objects\SectionObject') { + // trim `{{data.field}}` to `field` + preg_match('/.([^.]+)}}/', $reference, $elementName); + /** @var ElementObject $element */ + /** @var SectionObject $entity */ + $element = $entity->getElement($elementName[1]); + if ($element) { + $entities[$entity->getName() . '.' . $elementName[1]] = $element; + } + } + } } } return $entities; @@ -128,12 +163,13 @@ public function resolveEntityReferences($braceReferences, $contents) /** * Drill down into params in {{ref.params('string', $data.key$, entity.reference)}} to resolve entity reference * - * @param array $braceReferences - * @param string $contents + * @param array $braceReferences + * @param string $contents + * @param boolean $resolveSectionElement * @return array * @throws XmlException */ - public function resolveParametrizedReferences($braceReferences, $contents) + public function resolveParametrizedReferences($braceReferences, $contents, $resolveSectionElement = false) { $entities = []; foreach ($braceReferences as $parameterizedReference) { @@ -160,6 +196,18 @@ public function resolveParametrizedReferences($braceReferences, $contents) } if ($entity !== null) { $entities[$entity->getName()] = $entity; + if ($resolveSectionElement) { + if (get_class($entity) === 'Magento\FunctionalTestingFramework\Page\Objects\SectionObject') { + // trim `data.field` to `field` + preg_match('/.([^.]+)/', $argument, $elementName); + /** @var ElementObject $element */ + /** @var SectionObject $entity */ + $element = $entity->getElement($elementName[1]); + if ($element) { + $entities[$entity->getName() . '.' . $elementName[1]] = $element; + } + } + } } } } From a91e11af42be4bf0d21f977ca2f6be3d216c146a Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 26 Mar 2020 16:37:01 -0500 Subject: [PATCH 317/888] MQE-1957: Entity Deprecation Reference - Static Check --- .../DeprecatedEntityUsageCheck.php | 33 +++++++++++-------- .../StaticCheck/TestDependencyCheck.php | 2 +- .../Util/Script/ScriptUtil.php | 5 +-- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/DeprecatedEntityUsageCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/DeprecatedEntityUsageCheck.php index 8b4f7fab2..1a3f565b2 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/DeprecatedEntityUsageCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/DeprecatedEntityUsageCheck.php @@ -10,7 +10,10 @@ use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Page\Objects\SectionObject; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; -use Symfony\Component\Console\Exception\InvalidArgumentException; +use Magento\FunctionalTestingFramework\Page\Objects\ElementObject; +use Magento\FunctionalTestingFramework\Test\Objects\ActionGroupObject; +use Magento\FunctionalTestingFramework\Page\Objects\PageObject; +use Magento\FunctionalTestingFramework\Test\Objects\TestObject; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Finder\Finder; use Exception; @@ -26,6 +29,7 @@ /** * Class DeprecatedEntityUsageCheck * @package Magento\FunctionalTestingFramework\StaticCheck + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class DeprecatedEntityUsageCheck implements StaticCheckInterface { @@ -68,7 +72,7 @@ class DeprecatedEntityUsageCheck implements StaticCheckInterface * * @param InputInterface $input * @return string - * @throws Exception; + * @throws Exception */ public function execute(InputInterface $input) { @@ -79,7 +83,7 @@ public function execute(InputInterface $input) $path = $input->getOption('path'); if ($path) { if (!realpath($path)) { - throw new InvalidArgumentException("Invalid --path option: " . $path); + return "Invalid --path option: " . $path; } MftfApplicationConfig::create( true, @@ -251,6 +255,7 @@ private function findReferenceErrorsInActionFiles($files) * * @param Finder $files * @return array + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ private function findReferenceErrorsInDataFiles($files) { @@ -329,7 +334,7 @@ private function twoDimensionArrayUnique($inArray) * Return attribute value for each node in DOMNodeList as an array * * @param DOMNodeList $nodes - * @param string $attributeName + * @param string $attributeName * @return array */ private function getAttributesFromDOMNodeList($nodes, $attributeName) @@ -411,6 +416,8 @@ private function getMetadataFromData($references, $type) * * @param array $references * @return array + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) */ private function findViolatingMetadataReferences($references) { @@ -526,9 +533,9 @@ private function findViolatingReferences($references) if ($entity->getDeprecated()) { $classType = get_class($entity); $name = $entity->getName(); - if ($classType === 'Magento\FunctionalTestingFramework\Page\Objects\ElementObject') { + if ($classType === ElementObject::class) { $name = $key; - list($section, $field) = explode('.', $key, 2); + list($section,) = explode('.', $key, 2); /** @var SectionObject $references[$section] */ $file = $references[$section]->getFilename(); } else { @@ -578,19 +585,19 @@ private function setErrorOutput($violatingReferences, $path) private function getSubjectFromClassType($classname) { $subject = null; - if ($classname === 'Magento\FunctionalTestingFramework\Test\Objects\ActionGroupObject') { + if ($classname === ActionGroupObject::class) { $subject = 'Deprecated ActionGroup(s)'; - } elseif ($classname === 'Magento\FunctionalTestingFramework\Test\Objects\TestObject') { + } elseif ($classname === TestObject::class) { $subject = 'Deprecated Test(s)'; - } elseif ($classname === 'Magento\FunctionalTestingFramework\Page\Objects\SectionObject') { + } elseif ($classname === SectionObject::class) { $subject = 'Deprecated Section(s)'; - } elseif ($classname === 'Magento\FunctionalTestingFramework\Page\Objects\PageObject') { + } elseif ($classname === PageObject::class) { $subject = 'Deprecated Page(s)'; - } elseif ($classname === 'Magento\FunctionalTestingFramework\Page\Objects\ElementObject') { + } elseif ($classname === ElementObject::class) { $subject = 'Deprecated Element(s)'; - } elseif ($classname === 'Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject') { + } elseif ($classname === EntityDataObject::class) { $subject = 'Deprecated Data(s)'; - } elseif ($classname === 'Magento\FunctionalTestingFramework\DataGenerator\Objects\OperationDefinitionObject') { + } elseif ($classname === OperationDefinitionObject::class) { $subject = 'Deprecated Metadata(s)'; } return $subject; diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php index 4ee77f4d7..b97791a6d 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php @@ -85,7 +85,7 @@ class TestDependencyCheck implements StaticCheckInterface * * @param InputInterface $input * @return string - * @throws Exception; + * @throws Exception */ public function execute(InputInterface $input) { diff --git a/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php b/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php index 914a8e9f1..6ef275207 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php @@ -144,7 +144,7 @@ public function resolveEntityReferences($braceReferences, $contents, $resolveSec if ($entity !== null) { $entities[$entity->getName()] = $entity; if ($resolveSectionElement) { - if (get_class($entity) === 'Magento\FunctionalTestingFramework\Page\Objects\SectionObject') { + if (get_class($entity) === SectionObject::class) { // trim `{{data.field}}` to `field` preg_match('/.([^.]+)}}/', $reference, $elementName); /** @var ElementObject $element */ @@ -168,6 +168,7 @@ public function resolveEntityReferences($braceReferences, $contents, $resolveSec * @param boolean $resolveSectionElement * @return array * @throws XmlException + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function resolveParametrizedReferences($braceReferences, $contents, $resolveSectionElement = false) { @@ -197,7 +198,7 @@ public function resolveParametrizedReferences($braceReferences, $contents, $reso if ($entity !== null) { $entities[$entity->getName()] = $entity; if ($resolveSectionElement) { - if (get_class($entity) === 'Magento\FunctionalTestingFramework\Page\Objects\SectionObject') { + if (get_class($entity) === SectionObject::class) { // trim `data.field` to `field` preg_match('/.([^.]+)/', $argument, $elementName); /** @var ElementObject $element */ From 20cecfd1afd334ef773679487045d193336b4dbf Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Fri, 27 Mar 2020 12:45:11 -0500 Subject: [PATCH 318/888] Fix an issue with MimeType guesser and latest release of "symfony/http-foundation" --- composer.json | 18 +- composer.lock | 2206 +++++++---------- .../Allure/Event/AddUniqueAttachmentEvent.php | 11 +- 3 files changed, 864 insertions(+), 1371 deletions(-) diff --git a/composer.json b/composer.json index 0ff50a2e8..0580bebd6 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "2.6.3", + "version": "2.6.4", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { @@ -11,22 +11,26 @@ "require": { "php": "7.0.2||7.0.4||~7.0.6||~7.1.0||~7.2.0||~7.3.0", "ext-curl": "*", + "ext-dom": "*", "ext-json": "*", "ext-openssl": "*", "allure-framework/allure-codeception": "~1.3.0", "aws/aws-sdk-php": "^3.132", "codeception/codeception": "~2.4.5", - "composer/composer": "^1.4", - "consolidation/robo": "^1.0.0", + "composer/composer": "^1.6", "csharpru/vault-php": "~3.5.3", "csharpru/vault-php-guzzle6-transport": "^2.0", "flow/jsonpath": ">0.2", "fzaninotto/faker": "^1.6", "monolog/monolog": "^1.0", "mustache/mustache": "~2.5", - "symfony/process": "^2.8 || ^3.1 || ^4.0", - "vlucas/phpdotenv": "^2.4", - "php-webdriver/webdriver": "^1.8.0" + "php-webdriver/webdriver": "^1.8.0", + "symfony/console": "^4.4", + "symfony/finder": "^4.4", + "symfony/http-foundation": "^5.0", + "symfony/mime": "^5.0", + "symfony/process": "^4.4", + "vlucas/phpdotenv": "^2.4" }, "require-dev": { "squizlabs/php_codesniffer": "~3.2", @@ -52,7 +56,7 @@ "files": ["src/Magento/FunctionalTestingFramework/_bootstrap.php"], "psr-4": { "Magento\\FunctionalTestingFramework\\": "src/Magento/FunctionalTestingFramework", - "MFTF\\": "dev/tests/functional/MFTF" + "MFTF\\": "dev/tests/functional/tests/MFTF" } }, "autoload-dev": { diff --git a/composer.lock b/composer.lock index 6f370593b..8db8cfd7d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "83e4e17679bff5fdd472c246dca8ac48", + "content-hash": "7ea360e95d97749990efab6a97c186da", "packages": [ { "name": "allure-framework/allure-codeception", @@ -59,23 +59,23 @@ }, { "name": "allure-framework/allure-php-api", - "version": "1.1.6", + "version": "1.1.8", "source": { "type": "git", "url": "https://github.com/allure-framework/allure-php-commons.git", - "reference": "2c62a70d60eca190253a6b80e9aa4c2ebc2e6e7f" + "reference": "5ae2deac1c7e1b992cfa572167370de45bdd346d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/allure-framework/allure-php-commons/zipball/2c62a70d60eca190253a6b80e9aa4c2ebc2e6e7f", - "reference": "2c62a70d60eca190253a6b80e9aa4c2ebc2e6e7f", + "url": "https://api.github.com/repos/allure-framework/allure-php-commons/zipball/5ae2deac1c7e1b992cfa572167370de45bdd346d", + "reference": "5ae2deac1c7e1b992cfa572167370de45bdd346d", "shasum": "" }, "require": { "jms/serializer": "^0.16 || ^1.0", "php": ">=5.4.0", "ramsey/uuid": "^3.0", - "symfony/http-foundation": "^2.0 || ^3.0 || ^4.0" + "symfony/http-foundation": "^2.0 || ^3.0 || ^4.0 || ^5.0" }, "require-dev": { "phpunit/phpunit": "^4.0.0" @@ -108,20 +108,20 @@ "php", "report" ], - "time": "2020-01-09T10:26:09+00:00" + "time": "2020-03-13T10:47:35+00:00" }, { "name": "aws/aws-sdk-php", - "version": "3.133.7", + "version": "3.133.45", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "cd6fb07aed2cc68088251e3c572d111d67d558a3" + "reference": "928a23e2ee7e195a66f93d0758895e26958c3b7d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/cd6fb07aed2cc68088251e3c572d111d67d558a3", - "reference": "cd6fb07aed2cc68088251e3c572d111d67d558a3", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/928a23e2ee7e195a66f93d0758895e26958c3b7d", + "reference": "928a23e2ee7e195a66f93d0758895e26958c3b7d", "shasum": "" }, "require": { @@ -192,20 +192,20 @@ "s3", "sdk" ], - "time": "2020-02-04T19:11:15+00:00" + "time": "2020-03-26T18:12:15+00:00" }, { "name": "behat/gherkin", - "version": "v4.6.0", + "version": "v4.6.2", "source": { "type": "git", "url": "https://github.com/Behat/Gherkin.git", - "reference": "ab0a02ea14893860bca00f225f5621d351a3ad07" + "reference": "51ac4500c4dc30cbaaabcd2f25694299df666a31" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Behat/Gherkin/zipball/ab0a02ea14893860bca00f225f5621d351a3ad07", - "reference": "ab0a02ea14893860bca00f225f5621d351a3ad07", + "url": "https://api.github.com/repos/Behat/Gherkin/zipball/51ac4500c4dc30cbaaabcd2f25694299df666a31", + "reference": "51ac4500c4dc30cbaaabcd2f25694299df666a31", "shasum": "" }, "require": { @@ -251,7 +251,7 @@ "gherkin", "parser" ], - "time": "2019-01-16T14:22:17+00:00" + "time": "2020-03-17T14:03:26+00:00" }, { "name": "cache/cache", @@ -439,30 +439,27 @@ }, { "name": "codeception/phpunit-wrapper", - "version": "6.8.0", + "version": "7.0.6", "source": { "type": "git", "url": "https://github.com/Codeception/phpunit-wrapper.git", - "reference": "20e054e9cee8de0523322367bcccde8e6a3db263" + "reference": "e8528cb777cf5a5ccea1cf57a3522b142625d1b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/phpunit-wrapper/zipball/20e054e9cee8de0523322367bcccde8e6a3db263", - "reference": "20e054e9cee8de0523322367bcccde8e6a3db263", + "url": "https://api.github.com/repos/Codeception/phpunit-wrapper/zipball/e8528cb777cf5a5ccea1cf57a3522b142625d1b5", + "reference": "e8528cb777cf5a5ccea1cf57a3522b142625d1b5", "shasum": "" }, "require": { - "phpunit/php-code-coverage": ">=4.0.4 <6.0", - "phpunit/phpunit": ">=6.5.13 <7.0", - "sebastian/comparator": ">=1.2.4 <3.0", - "sebastian/diff": ">=1.4 <4.0" - }, - "replace": { - "codeception/phpunit-wrapper": "*" + "phpunit/php-code-coverage": "^6.0", + "phpunit/phpunit": "^7.0", + "sebastian/comparator": "^2.0", + "sebastian/diff": "^3.0" }, "require-dev": { "codeception/specify": "*", - "vlucas/phpdotenv": "^3.0" + "vlucas/phpdotenv": "^2.4" }, "type": "library", "autoload": { @@ -481,24 +478,24 @@ } ], "description": "PHPUnit classes used by Codeception", - "time": "2020-01-03T08:01:16+00:00" + "time": "2018-03-31T18:49:51+00:00" }, { "name": "codeception/stub", - "version": "2.1.0", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/Codeception/Stub.git", - "reference": "853657f988942f7afb69becf3fd0059f192c705a" + "reference": "f50bc271f392a2836ff80690ce0c058efe1ae03e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/Stub/zipball/853657f988942f7afb69becf3fd0059f192c705a", - "reference": "853657f988942f7afb69becf3fd0059f192c705a", + "url": "https://api.github.com/repos/Codeception/Stub/zipball/f50bc271f392a2836ff80690ce0c058efe1ae03e", + "reference": "f50bc271f392a2836ff80690ce0c058efe1ae03e", "shasum": "" }, "require": { - "codeception/phpunit-wrapper": ">6.0.15 <6.1.0 | ^6.6.1 | ^7.7.1 | ^8.0.3" + "phpunit/phpunit": ">=4.8 <8.0" }, "type": "library", "autoload": { @@ -511,7 +508,7 @@ "MIT" ], "description": "Flexible Stub wrapper for PHPUnit's Mock Builder", - "time": "2019-03-02T15:35:10+00:00" + "time": "2018-07-26T11:55:37+00:00" }, { "name": "composer/ca-bundle", @@ -571,16 +568,16 @@ }, { "name": "composer/composer", - "version": "1.9.3", + "version": "1.10.1", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "1291a16ce3f48bfdeca39d64fca4875098af4d7b" + "reference": "b912a45da3e2b22f5cb5a23e441b697a295ba011" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/1291a16ce3f48bfdeca39d64fca4875098af4d7b", - "reference": "1291a16ce3f48bfdeca39d64fca4875098af4d7b", + "url": "https://api.github.com/repos/composer/composer/zipball/b912a45da3e2b22f5cb5a23e441b697a295ba011", + "reference": "b912a45da3e2b22f5cb5a23e441b697a295ba011", "shasum": "" }, "require": { @@ -593,17 +590,17 @@ "psr/log": "^1.0", "seld/jsonlint": "^1.4", "seld/phar-utils": "^1.0", - "symfony/console": "^2.7 || ^3.0 || ^4.0", - "symfony/filesystem": "^2.7 || ^3.0 || ^4.0", - "symfony/finder": "^2.7 || ^3.0 || ^4.0", - "symfony/process": "^2.7 || ^3.0 || ^4.0" + "symfony/console": "^2.7 || ^3.0 || ^4.0 || ^5.0", + "symfony/filesystem": "^2.7 || ^3.0 || ^4.0 || ^5.0", + "symfony/finder": "^2.7 || ^3.0 || ^4.0 || ^5.0", + "symfony/process": "^2.7 || ^3.0 || ^4.0 || ^5.0" }, "conflict": { "symfony/console": "2.8.38" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7", - "phpunit/phpunit-mock-objects": "^2.3 || ^3.0" + "phpspec/prophecy": "^1.10", + "symfony/phpunit-bridge": "^3.4" }, "suggest": { "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages", @@ -616,7 +613,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.9-dev" + "dev-master": "1.10-dev" } }, "autoload": { @@ -647,7 +644,7 @@ "dependency", "package" ], - "time": "2020-02-04T11:58:49+00:00" + "time": "2020-03-13T19:34:27+00:00" }, { "name": "composer/semver", @@ -712,16 +709,16 @@ }, { "name": "composer/spdx-licenses", - "version": "1.5.2", + "version": "1.5.3", "source": { "type": "git", "url": "https://github.com/composer/spdx-licenses.git", - "reference": "7ac1e6aec371357df067f8a688c3d6974df68fa5" + "reference": "0c3e51e1880ca149682332770e25977c70cf9dae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/7ac1e6aec371357df067f8a688c3d6974df68fa5", - "reference": "7ac1e6aec371357df067f8a688c3d6974df68fa5", + "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/0c3e51e1880ca149682332770e25977c70cf9dae", + "reference": "0c3e51e1880ca149682332770e25977c70cf9dae", "shasum": "" }, "require": { @@ -768,20 +765,20 @@ "spdx", "validator" ], - "time": "2019-07-29T10:31:59+00:00" + "time": "2020-02-14T07:44:31+00:00" }, { "name": "composer/xdebug-handler", - "version": "1.4.0", + "version": "1.4.1", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "cbe23383749496fe0f373345208b79568e4bc248" + "reference": "1ab9842d69e64fb3a01be6b656501032d1b78cb7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/cbe23383749496fe0f373345208b79568e4bc248", - "reference": "cbe23383749496fe0f373345208b79568e4bc248", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/1ab9842d69e64fb3a01be6b656501032d1b78cb7", + "reference": "1ab9842d69e64fb3a01be6b656501032d1b78cb7", "shasum": "" }, "require": { @@ -812,566 +809,7 @@ "Xdebug", "performance" ], - "time": "2019-11-06T16:40:04+00:00" - }, - { - "name": "consolidation/annotated-command", - "version": "2.12.0", - "source": { - "type": "git", - "url": "https://github.com/consolidation/annotated-command.git", - "reference": "512a2e54c98f3af377589de76c43b24652bcb789" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/consolidation/annotated-command/zipball/512a2e54c98f3af377589de76c43b24652bcb789", - "reference": "512a2e54c98f3af377589de76c43b24652bcb789", - "shasum": "" - }, - "require": { - "consolidation/output-formatters": "^3.4", - "php": ">=5.4.5", - "psr/log": "^1", - "symfony/console": "^2.8|^3|^4", - "symfony/event-dispatcher": "^2.5|^3|^4", - "symfony/finder": "^2.5|^3|^4" - }, - "require-dev": { - "g1a/composer-test-scenarios": "^3", - "php-coveralls/php-coveralls": "^1", - "phpunit/phpunit": "^6", - "squizlabs/php_codesniffer": "^2.7" - }, - "type": "library", - "extra": { - "scenarios": { - "symfony4": { - "require": { - "symfony/console": "^4.0" - }, - "config": { - "platform": { - "php": "7.1.3" - } - } - }, - "symfony2": { - "require": { - "symfony/console": "^2.8" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.36" - }, - "remove": [ - "php-coveralls/php-coveralls" - ], - "config": { - "platform": { - "php": "5.4.8" - } - }, - "scenario-options": { - "create-lockfile": "false" - } - }, - "phpunit4": { - "require-dev": { - "phpunit/phpunit": "^4.8.36" - }, - "remove": [ - "php-coveralls/php-coveralls" - ], - "config": { - "platform": { - "php": "5.4.8" - } - } - } - }, - "branch-alias": { - "dev-master": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "Consolidation\\AnnotatedCommand\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Greg Anderson", - "email": "greg.1.anderson@greenknowe.org" - } - ], - "description": "Initialize Symfony Console commands from annotated command class methods.", - "time": "2019-03-08T16:55:03+00:00" - }, - { - "name": "consolidation/config", - "version": "1.2.1", - "source": { - "type": "git", - "url": "https://github.com/consolidation/config.git", - "reference": "cac1279bae7efb5c7fb2ca4c3ba4b8eb741a96c1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/consolidation/config/zipball/cac1279bae7efb5c7fb2ca4c3ba4b8eb741a96c1", - "reference": "cac1279bae7efb5c7fb2ca4c3ba4b8eb741a96c1", - "shasum": "" - }, - "require": { - "dflydev/dot-access-data": "^1.1.0", - "grasmash/expander": "^1", - "php": ">=5.4.0" - }, - "require-dev": { - "g1a/composer-test-scenarios": "^3", - "php-coveralls/php-coveralls": "^1", - "phpunit/phpunit": "^5", - "squizlabs/php_codesniffer": "2.*", - "symfony/console": "^2.5|^3|^4", - "symfony/yaml": "^2.8.11|^3|^4" - }, - "suggest": { - "symfony/yaml": "Required to use Consolidation\\Config\\Loader\\YamlConfigLoader" - }, - "type": "library", - "extra": { - "scenarios": { - "symfony4": { - "require-dev": { - "symfony/console": "^4.0" - }, - "config": { - "platform": { - "php": "7.1.3" - } - } - }, - "symfony2": { - "require-dev": { - "symfony/console": "^2.8", - "symfony/event-dispatcher": "^2.8", - "phpunit/phpunit": "^4.8.36" - }, - "remove": [ - "php-coveralls/php-coveralls" - ], - "config": { - "platform": { - "php": "5.4.8" - } - } - } - }, - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Consolidation\\Config\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Greg Anderson", - "email": "greg.1.anderson@greenknowe.org" - } - ], - "description": "Provide configuration services for a commandline tool.", - "time": "2019-03-03T19:37:04+00:00" - }, - { - "name": "consolidation/log", - "version": "1.1.1", - "source": { - "type": "git", - "url": "https://github.com/consolidation/log.git", - "reference": "b2e887325ee90abc96b0a8b7b474cd9e7c896e3a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/consolidation/log/zipball/b2e887325ee90abc96b0a8b7b474cd9e7c896e3a", - "reference": "b2e887325ee90abc96b0a8b7b474cd9e7c896e3a", - "shasum": "" - }, - "require": { - "php": ">=5.4.5", - "psr/log": "^1.0", - "symfony/console": "^2.8|^3|^4" - }, - "require-dev": { - "g1a/composer-test-scenarios": "^3", - "php-coveralls/php-coveralls": "^1", - "phpunit/phpunit": "^6", - "squizlabs/php_codesniffer": "^2" - }, - "type": "library", - "extra": { - "scenarios": { - "symfony4": { - "require": { - "symfony/console": "^4.0" - }, - "config": { - "platform": { - "php": "7.1.3" - } - } - }, - "symfony2": { - "require": { - "symfony/console": "^2.8" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.36" - }, - "remove": [ - "php-coveralls/php-coveralls" - ], - "config": { - "platform": { - "php": "5.4.8" - } - } - }, - "phpunit4": { - "require-dev": { - "phpunit/phpunit": "^4.8.36" - }, - "remove": [ - "php-coveralls/php-coveralls" - ], - "config": { - "platform": { - "php": "5.4.8" - } - } - } - }, - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Consolidation\\Log\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Greg Anderson", - "email": "greg.1.anderson@greenknowe.org" - } - ], - "description": "Improved Psr-3 / Psr\\Log logger based on Symfony Console components.", - "time": "2019-01-01T17:30:51+00:00" - }, - { - "name": "consolidation/output-formatters", - "version": "3.5.0", - "source": { - "type": "git", - "url": "https://github.com/consolidation/output-formatters.git", - "reference": "99ec998ffb697e0eada5aacf81feebfb13023605" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/consolidation/output-formatters/zipball/99ec998ffb697e0eada5aacf81feebfb13023605", - "reference": "99ec998ffb697e0eada5aacf81feebfb13023605", - "shasum": "" - }, - "require": { - "dflydev/dot-access-data": "^1.1.0", - "php": ">=5.4.0", - "symfony/console": "^2.8|^3|^4", - "symfony/finder": "^2.5|^3|^4" - }, - "require-dev": { - "g1a/composer-test-scenarios": "^3", - "php-coveralls/php-coveralls": "^1", - "phpunit/phpunit": "^5.7.27", - "squizlabs/php_codesniffer": "^2.7", - "symfony/var-dumper": "^2.8|^3|^4", - "victorjonsson/markdowndocs": "^1.3" - }, - "suggest": { - "symfony/var-dumper": "For using the var_dump formatter" - }, - "type": "library", - "extra": { - "scenarios": { - "symfony4": { - "require": { - "symfony/console": "^4.0" - }, - "require-dev": { - "phpunit/phpunit": "^6" - }, - "config": { - "platform": { - "php": "7.1.3" - } - } - }, - "symfony3": { - "require": { - "symfony/console": "^3.4", - "symfony/finder": "^3.4", - "symfony/var-dumper": "^3.4" - }, - "config": { - "platform": { - "php": "5.6.32" - } - } - }, - "symfony2": { - "require": { - "symfony/console": "^2.8" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.36" - }, - "remove": [ - "php-coveralls/php-coveralls" - ], - "config": { - "platform": { - "php": "5.4.8" - } - }, - "scenario-options": { - "create-lockfile": "false" - } - } - }, - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Consolidation\\OutputFormatters\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Greg Anderson", - "email": "greg.1.anderson@greenknowe.org" - } - ], - "description": "Format text by applying transformations provided by plug-in formatters.", - "time": "2019-05-30T23:16:01+00:00" - }, - { - "name": "consolidation/robo", - "version": "1.4.11", - "source": { - "type": "git", - "url": "https://github.com/consolidation/Robo.git", - "reference": "5fa1d901776a628167a325baa9db95d8edf13a80" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/consolidation/Robo/zipball/5fa1d901776a628167a325baa9db95d8edf13a80", - "reference": "5fa1d901776a628167a325baa9db95d8edf13a80", - "shasum": "" - }, - "require": { - "consolidation/annotated-command": "^2.11.0", - "consolidation/config": "^1.2", - "consolidation/log": "~1", - "consolidation/output-formatters": "^3.1.13", - "consolidation/self-update": "^1", - "grasmash/yaml-expander": "^1.3", - "league/container": "^2.2", - "php": ">=5.5.0", - "symfony/console": "^2.8|^3|^4", - "symfony/event-dispatcher": "^2.5|^3|^4", - "symfony/filesystem": "^2.5|^3|^4", - "symfony/finder": "^2.5|^3|^4", - "symfony/process": "^2.5|^3|^4" - }, - "replace": { - "codegyre/robo": "< 1.0" - }, - "require-dev": { - "codeception/aspect-mock": "^1|^2.1.1", - "codeception/base": "^2.3.7", - "codeception/verify": "^0.3.2", - "g1a/composer-test-scenarios": "^3", - "goaop/framework": "~2.1.2", - "goaop/parser-reflection": "^1.1.0", - "natxet/cssmin": "3.0.4", - "nikic/php-parser": "^3.1.5", - "patchwork/jsqueeze": "~2", - "pear/archive_tar": "^1.4.4", - "php-coveralls/php-coveralls": "^1", - "phpunit/php-code-coverage": "~2|~4", - "sebastian/comparator": "^1.2.4", - "squizlabs/php_codesniffer": "^2.8" - }, - "suggest": { - "henrikbjorn/lurker": "For monitoring filesystem changes in taskWatch", - "natxet/CssMin": "For minifying CSS files in taskMinify", - "patchwork/jsqueeze": "For minifying JS files in taskMinify", - "pear/archive_tar": "Allows tar archives to be created and extracted in taskPack and taskExtract, respectively." - }, - "bin": [ - "robo" - ], - "type": "library", - "extra": { - "scenarios": { - "symfony4": { - "require": { - "symfony/console": "^4" - }, - "config": { - "platform": { - "php": "7.1.3" - } - } - }, - "symfony2": { - "require": { - "symfony/console": "^2.8" - }, - "remove": [ - "goaop/framework" - ], - "config": { - "platform": { - "php": "5.5.9" - } - }, - "scenario-options": { - "create-lockfile": "false" - } - } - }, - "branch-alias": { - "dev-master": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "Robo\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Davert", - "email": "davert.php@resend.cc" - } - ], - "description": "Modern task runner", - "time": "2019-10-29T15:50:02+00:00" - }, - { - "name": "consolidation/self-update", - "version": "1.1.5", - "source": { - "type": "git", - "url": "https://github.com/consolidation/self-update.git", - "reference": "a1c273b14ce334789825a09d06d4c87c0a02ad54" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/consolidation/self-update/zipball/a1c273b14ce334789825a09d06d4c87c0a02ad54", - "reference": "a1c273b14ce334789825a09d06d4c87c0a02ad54", - "shasum": "" - }, - "require": { - "php": ">=5.5.0", - "symfony/console": "^2.8|^3|^4", - "symfony/filesystem": "^2.5|^3|^4" - }, - "bin": [ - "scripts/release" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "SelfUpdate\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Greg Anderson", - "email": "greg.1.anderson@greenknowe.org" - }, - { - "name": "Alexander Menk", - "email": "menk@mestrona.net" - } - ], - "description": "Provides a self:update command for Symfony Console applications.", - "time": "2018-10-28T01:52:03+00:00" - }, - { - "name": "container-interop/container-interop", - "version": "1.2.0", - "source": { - "type": "git", - "url": "https://github.com/container-interop/container-interop.git", - "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/container-interop/container-interop/zipball/79cbf1341c22ec75643d841642dd5d6acd83bdb8", - "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8", - "shasum": "" - }, - "require": { - "psr/container": "^1.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Interop\\Container\\": "src/Interop/Container/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", - "homepage": "https://github.com/container-interop/container-interop", - "abandoned": "psr/container", - "time": "2017-02-14T19:40:03+00:00" + "time": "2020-03-01T12:26:26+00:00" }, { "name": "csharpru/vault-php", @@ -1459,91 +897,32 @@ "description": "Guzzle6 transport for Vault PHP client", "time": "2019-03-10T06:17:37+00:00" }, - { - "name": "dflydev/dot-access-data", - "version": "v1.1.0", - "source": { - "type": "git", - "url": "https://github.com/dflydev/dflydev-dot-access-data.git", - "reference": "3fbd874921ab2c041e899d044585a2ab9795df8a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/3fbd874921ab2c041e899d044585a2ab9795df8a", - "reference": "3fbd874921ab2c041e899d044585a2ab9795df8a", - "shasum": "" - }, - "require": { - "php": ">=5.3.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "psr-0": { - "Dflydev\\DotAccessData": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Dragonfly Development Inc.", - "email": "info@dflydev.com", - "homepage": "http://dflydev.com" - }, - { - "name": "Beau Simensen", - "email": "beau@dflydev.com", - "homepage": "http://beausimensen.com" - }, - { - "name": "Carlos Frutos", - "email": "carlos@kiwing.it", - "homepage": "https://github.com/cfrutos" - } - ], - "description": "Given a deep data structure, access data by dot notation.", - "homepage": "https://github.com/dflydev/dflydev-dot-access-data", - "keywords": [ - "access", - "data", - "dot", - "notation" - ], - "time": "2017-01-20T21:14:22+00:00" - }, { "name": "doctrine/annotations", - "version": "v1.4.0", + "version": "v1.8.0", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "54cacc9b81758b14e3ce750f205a393d52339e97" + "reference": "904dca4eb10715b92569fbcd79e201d5c349b6bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/54cacc9b81758b14e3ce750f205a393d52339e97", - "reference": "54cacc9b81758b14e3ce750f205a393d52339e97", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/904dca4eb10715b92569fbcd79e201d5c349b6bc", + "reference": "904dca4eb10715b92569fbcd79e201d5c349b6bc", "shasum": "" }, "require": { "doctrine/lexer": "1.*", - "php": "^5.6 || ^7.0" + "php": "^7.1" }, "require-dev": { "doctrine/cache": "1.*", - "phpunit/phpunit": "^5.7" + "phpunit/phpunit": "^7.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4.x-dev" + "dev-master": "1.7.x-dev" } }, "autoload": { @@ -1556,6 +935,10 @@ "MIT" ], "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -1564,10 +947,6 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -1584,7 +963,7 @@ "docblock", "parser" ], - "time": "2017-02-24T16:22:25+00:00" + "time": "2019-10-01T18:55:10+00:00" }, { "name": "doctrine/cache", @@ -1725,32 +1104,34 @@ }, { "name": "doctrine/instantiator", - "version": "1.0.5", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + "reference": "ae466f726242e637cebdd526a7d991b9433bacf1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/ae466f726242e637cebdd526a7d991b9433bacf1", + "reference": "ae466f726242e637cebdd526a7d991b9433bacf1", "shasum": "" }, "require": { - "php": ">=5.3,<8.0-DEV" + "php": "^7.1" }, "require-dev": { - "athletic/athletic": "~0.1.8", + "doctrine/coding-standard": "^6.0", "ext-pdo": "*", "ext-phar": "*", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~2.0" + "phpbench/phpbench": "^0.13", + "phpstan/phpstan-phpunit": "^0.11", + "phpstan/phpstan-shim": "^0.11", + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { @@ -1770,37 +1151,39 @@ } ], "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://github.com/doctrine/instantiator", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", "keywords": [ "constructor", "instantiate" ], - "time": "2015-06-14T21:17:01+00:00" + "time": "2019-10-21T16:45:58+00:00" }, { "name": "doctrine/lexer", - "version": "1.0.2", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/doctrine/lexer.git", - "reference": "1febd6c3ef84253d7c815bed85fc622ad207a9f8" + "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/1febd6c3ef84253d7c815bed85fc622ad207a9f8", - "reference": "1febd6c3ef84253d7c815bed85fc622ad207a9f8", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6", + "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6", "shasum": "" }, "require": { - "php": ">=5.3.2" + "php": "^7.2" }, "require-dev": { - "phpunit/phpunit": "^4.5" + "doctrine/coding-standard": "^6.0", + "phpstan/phpstan": "^0.11.8", + "phpunit/phpunit": "^8.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { @@ -1813,14 +1196,14 @@ "MIT" ], "authors": [ - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, { "name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com" }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, { "name": "Johannes Schmitt", "email": "schmittjoh@gmail.com" @@ -1835,7 +1218,7 @@ "parser", "php" ], - "time": "2019-06-08T11:03:04+00:00" + "time": "2019-10-30T14:39:59+00:00" }, { "name": "flow/jsonpath", @@ -1928,101 +1311,6 @@ ], "time": "2019-12-12T13:22:17+00:00" }, - { - "name": "grasmash/expander", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/grasmash/expander.git", - "reference": "95d6037344a4be1dd5f8e0b0b2571a28c397578f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/grasmash/expander/zipball/95d6037344a4be1dd5f8e0b0b2571a28c397578f", - "reference": "95d6037344a4be1dd5f8e0b0b2571a28c397578f", - "shasum": "" - }, - "require": { - "dflydev/dot-access-data": "^1.1.0", - "php": ">=5.4" - }, - "require-dev": { - "greg-1-anderson/composer-test-scenarios": "^1", - "phpunit/phpunit": "^4|^5.5.4", - "satooshi/php-coveralls": "^1.0.2|dev-master", - "squizlabs/php_codesniffer": "^2.7" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Grasmash\\Expander\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Matthew Grasmick" - } - ], - "description": "Expands internal property references in PHP arrays file.", - "time": "2017-12-21T22:14:55+00:00" - }, - { - "name": "grasmash/yaml-expander", - "version": "1.4.0", - "source": { - "type": "git", - "url": "https://github.com/grasmash/yaml-expander.git", - "reference": "3f0f6001ae707a24f4d9733958d77d92bf9693b1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/grasmash/yaml-expander/zipball/3f0f6001ae707a24f4d9733958d77d92bf9693b1", - "reference": "3f0f6001ae707a24f4d9733958d77d92bf9693b1", - "shasum": "" - }, - "require": { - "dflydev/dot-access-data": "^1.1.0", - "php": ">=5.4", - "symfony/yaml": "^2.8.11|^3|^4" - }, - "require-dev": { - "greg-1-anderson/composer-test-scenarios": "^1", - "phpunit/phpunit": "^4.8|^5.5.4", - "satooshi/php-coveralls": "^1.0.2|dev-master", - "squizlabs/php_codesniffer": "^2.7" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Grasmash\\YamlExpander\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Matthew Grasmick" - } - ], - "description": "Expands internal property references in a yaml file.", - "time": "2017-12-16T16:06:03+00:00" - }, { "name": "guzzlehttp/guzzle", "version": "6.5.2", @@ -2304,16 +1592,16 @@ }, { "name": "jms/serializer", - "version": "1.14.0", + "version": "1.14.1", "source": { "type": "git", "url": "https://github.com/schmittjoh/serializer.git", - "reference": "ee96d57024af9a7716d56fcbe3aa94b3d030f3ca" + "reference": "ba908d278fff27ec01fb4349f372634ffcd697c0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/ee96d57024af9a7716d56fcbe3aa94b3d030f3ca", - "reference": "ee96d57024af9a7716d56fcbe3aa94b3d030f3ca", + "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/ba908d278fff27ec01fb4349f372634ffcd697c0", + "reference": "ba908d278fff27ec01fb4349f372634ffcd697c0", "shasum": "" }, "require": { @@ -2366,13 +1654,13 @@ "MIT" ], "authors": [ - { - "name": "Asmir Mustafic", - "email": "goetas@gmail.com" - }, { "name": "Johannes M. Schmitt", "email": "schmittjoh@gmail.com" + }, + { + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" } ], "description": "Library for (de-)serializing data of any complexity; supports XML, JSON, and YAML.", @@ -2384,7 +1672,7 @@ "serialization", "xml" ], - "time": "2019-04-17T08:12:16+00:00" + "time": "2020-02-22T20:59:37+00:00" }, { "name": "justinrainbow/json-schema", @@ -2392,104 +1680,34 @@ "source": { "type": "git", "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "44c6787311242a979fa15c704327c20e7221a0e4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/44c6787311242a979fa15c704327c20e7221a0e4", - "reference": "44c6787311242a979fa15c704327c20e7221a0e4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", - "json-schema/json-schema-test-suite": "1.2.0", - "phpunit/phpunit": "^4.8.35" - }, - "bin": [ - "bin/validate-json" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "JsonSchema\\": "src/JsonSchema/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bruno Prieto Reis", - "email": "bruno.p.reis@gmail.com" - }, - { - "name": "Justin Rainbow", - "email": "justin.rainbow@gmail.com" - }, - { - "name": "Igor Wiedler", - "email": "igor@wiedler.ch" - }, - { - "name": "Robert Schönthal", - "email": "seroscho@googlemail.com" - } - ], - "description": "A library to validate a json schema.", - "homepage": "https://github.com/justinrainbow/json-schema", - "keywords": [ - "json", - "schema" - ], - "time": "2019-09-25T14:49:45+00:00" - }, - { - "name": "league/container", - "version": "2.4.1", - "source": { - "type": "git", - "url": "https://github.com/thephpleague/container.git", - "reference": "43f35abd03a12977a60ffd7095efd6a7808488c0" + "reference": "44c6787311242a979fa15c704327c20e7221a0e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/container/zipball/43f35abd03a12977a60ffd7095efd6a7808488c0", - "reference": "43f35abd03a12977a60ffd7095efd6a7808488c0", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/44c6787311242a979fa15c704327c20e7221a0e4", + "reference": "44c6787311242a979fa15c704327c20e7221a0e4", "shasum": "" }, "require": { - "container-interop/container-interop": "^1.2", - "php": "^5.4.0 || ^7.0" - }, - "provide": { - "container-interop/container-interop-implementation": "^1.2", - "psr/container-implementation": "^1.0" - }, - "replace": { - "orno/di": "~2.0" + "php": ">=5.3.3" }, "require-dev": { - "phpunit/phpunit": "4.*" + "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", + "json-schema/json-schema-test-suite": "1.2.0", + "phpunit/phpunit": "^4.8.35" }, + "bin": [ + "bin/validate-json" + ], "type": "library", "extra": { "branch-alias": { - "dev-2.x": "2.x-dev", - "dev-1.x": "1.x-dev" + "dev-master": "5.0.x-dev" } }, "autoload": { "psr-4": { - "League\\Container\\": "src" + "JsonSchema\\": "src/JsonSchema/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2498,37 +1716,42 @@ ], "authors": [ { - "name": "Phil Bennett", - "email": "philipobenito@gmail.com", - "homepage": "http://www.philipobenito.com", - "role": "Developer" + "name": "Bruno Prieto Reis", + "email": "bruno.p.reis@gmail.com" + }, + { + "name": "Justin Rainbow", + "email": "justin.rainbow@gmail.com" + }, + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + }, + { + "name": "Robert Schönthal", + "email": "seroscho@googlemail.com" } ], - "description": "A fast and intuitive dependency injection container.", - "homepage": "https://github.com/thephpleague/container", + "description": "A library to validate a json schema.", + "homepage": "https://github.com/justinrainbow/json-schema", "keywords": [ - "container", - "dependency", - "di", - "injection", - "league", - "provider", - "service" + "json", + "schema" ], - "time": "2017-05-10T09:20:27+00:00" + "time": "2019-09-25T14:49:45+00:00" }, { "name": "league/flysystem", - "version": "1.0.63", + "version": "1.0.66", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "8132daec326565036bc8e8d1876f77ec183a7bd6" + "reference": "021569195e15f8209b1c4bebb78bd66aa4f08c21" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/8132daec326565036bc8e8d1876f77ec183a7bd6", - "reference": "8132daec326565036bc8e8d1876f77ec183a7bd6", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/021569195e15f8209b1c4bebb78bd66aa4f08c21", + "reference": "021569195e15f8209b1c4bebb78bd66aa4f08c21", "shasum": "" }, "require": { @@ -2540,7 +1763,7 @@ }, "require-dev": { "phpspec/phpspec": "^3.4", - "phpunit/phpunit": "^5.7.10" + "phpunit/phpunit": "^5.7.26" }, "suggest": { "ext-fileinfo": "Required for MimeType", @@ -2599,7 +1822,7 @@ "sftp", "storage" ], - "time": "2020-01-04T16:30:31+00:00" + "time": "2020-03-17T18:58:12+00:00" }, { "name": "monolog/monolog", @@ -2784,25 +2007,28 @@ }, { "name": "myclabs/deep-copy", - "version": "1.7.0", + "version": "1.9.5", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e" + "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", - "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/b2c28789e80a97badd14145fda39b545d83ca3ef", + "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "php": "^7.1" + }, + "replace": { + "myclabs/deep-copy": "self.version" }, "require-dev": { "doctrine/collections": "^1.0", "doctrine/common": "^2.6", - "phpunit/phpunit": "^4.1" + "phpunit/phpunit": "^7.1" }, "type": "library", "autoload": { @@ -2825,7 +2051,7 @@ "object", "object graph" ], - "time": "2017-10-19T19:58:43+00:00" + "time": "2020-01-17T21:11:47+00:00" }, { "name": "paragonie/random_compat", @@ -2976,16 +2202,16 @@ }, { "name": "php-webdriver/webdriver", - "version": "1.8.0", + "version": "1.8.2", "source": { "type": "git", "url": "https://github.com/php-webdriver/php-webdriver.git", - "reference": "3e33ee3b8a688d719c55acdd7c6788e3006e1d3e" + "reference": "3308a70be084d6d7fd1ee5787b4c2e6eb4b70aab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/3e33ee3b8a688d719c55acdd7c6788e3006e1d3e", - "reference": "3e33ee3b8a688d719c55acdd7c6788e3006e1d3e", + "url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/3308a70be084d6d7fd1ee5787b4c2e6eb4b70aab", + "reference": "3308a70be084d6d7fd1ee5787b4c2e6eb4b70aab", "shasum": "" }, "require": { @@ -3017,12 +2243,12 @@ } }, "autoload": { - "files": [ - "lib/Exception/TimeoutException.php" - ], "psr-4": { "Facebook\\WebDriver\\": "lib/" - } + }, + "files": [ + "lib/Exception/TimeoutException.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3037,7 +2263,7 @@ "selenium", "webdriver" ], - "time": "2020-02-10T15:04:25+00:00" + "time": "2020-03-04T14:40:12+00:00" }, { "name": "phpcollection/phpcollection", @@ -3089,35 +2315,33 @@ }, { "name": "phpdocumentor/reflection-common", - "version": "1.0.1", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" + "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", - "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a", + "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a", "shasum": "" }, "require": { - "php": ">=5.5" + "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "^4.6" + "phpunit/phpunit": "~6" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src" - ] + "phpDocumentor\\Reflection\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -3139,45 +2363,42 @@ "reflection", "static analysis" ], - "time": "2017-09-11T18:02:19+00:00" + "time": "2018-08-07T13:53:10+00:00" }, { "name": "phpdocumentor/reflection-docblock", - "version": "4.3.4", + "version": "5.1.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c" + "reference": "cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/da3fd972d6bafd628114f7e7e036f45944b62e9c", - "reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e", + "reference": "cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e", "shasum": "" }, "require": { - "php": "^7.0", - "phpdocumentor/reflection-common": "^1.0.0 || ^2.0.0", - "phpdocumentor/type-resolver": "~0.4 || ^1.0.0", - "webmozart/assert": "^1.0" + "ext-filter": "^7.1", + "php": "^7.2", + "phpdocumentor/reflection-common": "^2.0", + "phpdocumentor/type-resolver": "^1.0", + "webmozart/assert": "^1" }, "require-dev": { - "doctrine/instantiator": "^1.0.5", - "mockery/mockery": "^1.0", - "phpdocumentor/type-resolver": "0.4.*", - "phpunit/phpunit": "^6.4" + "doctrine/instantiator": "^1", + "mockery/mockery": "^1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.x-dev" + "dev-master": "5.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] + "phpDocumentor\\Reflection\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -3188,37 +2409,41 @@ { "name": "Mike van Riel", "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "account@ijaap.nl" } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2019-12-28T18:55:12+00:00" + "time": "2020-02-22T12:28:44+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "0.5.1", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "cf842904952e64e703800d094cdf34e715a8a3ae" + "reference": "7462d5f123dfc080dfdf26897032a6513644fc95" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/cf842904952e64e703800d094cdf34e715a8a3ae", - "reference": "cf842904952e64e703800d094cdf34e715a8a3ae", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/7462d5f123dfc080dfdf26897032a6513644fc95", + "reference": "7462d5f123dfc080dfdf26897032a6513644fc95", "shasum": "" }, "require": { - "php": "^7.0", - "phpdocumentor/reflection-common": "^1.0" + "php": "^7.2", + "phpdocumentor/reflection-common": "^2.0" }, "require-dev": { - "mockery/mockery": "^1.0", - "phpunit/phpunit": "^6.4" + "ext-tokenizer": "^7.2", + "mockery/mockery": "~1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.x-dev" } }, "autoload": { @@ -3236,24 +2461,25 @@ "email": "me@mikevanriel.com" } ], - "time": "2017-12-30T13:23:38+00:00" + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "time": "2020-02-18T18:59:58+00:00" }, { "name": "phpoption/phpoption", - "version": "1.7.2", + "version": "1.7.3", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "77f7c4d2e65413aff5b5a8cc8b3caf7a28d81959" + "reference": "4acfd6a4b33a509d8c88f50e5222f734b6aeebae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/77f7c4d2e65413aff5b5a8cc8b3caf7a28d81959", - "reference": "77f7c4d2e65413aff5b5a8cc8b3caf7a28d81959", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/4acfd6a4b33a509d8c88f50e5222f734b6aeebae", + "reference": "4acfd6a4b33a509d8c88f50e5222f734b6aeebae", "shasum": "" }, "require": { - "php": "^5.5.9 || ^7.0" + "php": "^5.5.9 || ^7.0 || ^8.0" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.3", @@ -3291,20 +2517,20 @@ "php", "type" ], - "time": "2019-12-15T19:35:24+00:00" + "time": "2020-03-21T18:07:53+00:00" }, { "name": "phpspec/prophecy", - "version": "v1.10.2", + "version": "v1.10.3", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "b4400efc9d206e83138e2bb97ed7f5b14b831cd9" + "reference": "451c3cd1418cf640de218914901e51b064abb093" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/b4400efc9d206e83138e2bb97ed7f5b14b831cd9", - "reference": "b4400efc9d206e83138e2bb97ed7f5b14b831cd9", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/451c3cd1418cf640de218914901e51b064abb093", + "reference": "451c3cd1418cf640de218914901e51b064abb093", "shasum": "" }, "require": { @@ -3354,44 +2580,44 @@ "spy", "stub" ], - "time": "2020-01-20T15:57:02+00:00" + "time": "2020-03-05T15:02:03+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "5.3.2", + "version": "6.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "c89677919c5dd6d3b3852f230a663118762218ac" + "reference": "4cab20a326d14de7575a8e235c70d879b569a57a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c89677919c5dd6d3b3852f230a663118762218ac", - "reference": "c89677919c5dd6d3b3852f230a663118762218ac", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/4cab20a326d14de7575a8e235c70d879b569a57a", + "reference": "4cab20a326d14de7575a8e235c70d879b569a57a", "shasum": "" }, "require": { "ext-dom": "*", "ext-xmlwriter": "*", - "php": "^7.0", + "php": "^7.1", "phpunit/php-file-iterator": "^1.4.2", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^2.0.1", + "phpunit/php-token-stream": "^3.0", "sebastian/code-unit-reverse-lookup": "^1.0.1", - "sebastian/environment": "^3.0", + "sebastian/environment": "^3.1", "sebastian/version": "^2.0.1", "theseer/tokenizer": "^1.1" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^7.0" }, "suggest": { - "ext-xdebug": "^2.5.5" + "ext-xdebug": "^2.6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.3.x-dev" + "dev-master": "6.0-dev" } }, "autoload": { @@ -3417,7 +2643,7 @@ "testing", "xunit" ], - "time": "2018-04-06T15:36:58+00:00" + "time": "2018-05-28T11:49:20+00:00" }, { "name": "phpunit/php-file-iterator", @@ -3509,28 +2735,28 @@ }, { "name": "phpunit/php-timer", - "version": "1.0.9", + "version": "2.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" + "reference": "1038454804406b0b5f5f520358e78c1c2f71501e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/1038454804406b0b5f5f520358e78c1c2f71501e", + "reference": "1038454804406b0b5f5f520358e78c1c2f71501e", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "2.1-dev" } }, "autoload": { @@ -3545,7 +2771,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -3554,33 +2780,33 @@ "keywords": [ "timer" ], - "time": "2017-02-26T11:10:40+00:00" + "time": "2019-06-07T04:22:29+00:00" }, { "name": "phpunit/php-token-stream", - "version": "2.0.2", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "791198a2c6254db10131eecfe8c06670700904db" + "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db", - "reference": "791198a2c6254db10131eecfe8c06670700904db", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/995192df77f63a59e47f025390d2d1fdf8f425ff", + "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff", "shasum": "" }, "require": { "ext-tokenizer": "*", - "php": "^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^6.2.4" + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "3.1-dev" } }, "autoload": { @@ -3603,20 +2829,20 @@ "keywords": [ "tokenizer" ], - "time": "2017-11-27T05:48:46+00:00" + "time": "2019-09-17T06:23:10+00:00" }, { "name": "phpunit/phpunit", - "version": "6.5.14", + "version": "7.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "bac23fe7ff13dbdb461481f706f0e9fe746334b7" + "reference": "536f4d853c12d8189963435088e8ff7c0daeab2e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/bac23fe7ff13dbdb461481f706f0e9fe746334b7", - "reference": "bac23fe7ff13dbdb461481f706f0e9fe746334b7", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/536f4d853c12d8189963435088e8ff7c0daeab2e", + "reference": "536f4d853c12d8189963435088e8ff7c0daeab2e", "shasum": "" }, "require": { @@ -3628,15 +2854,15 @@ "myclabs/deep-copy": "^1.6.1", "phar-io/manifest": "^1.0.1", "phar-io/version": "^1.0", - "php": "^7.0", + "php": "^7.1", "phpspec/prophecy": "^1.7", - "phpunit/php-code-coverage": "^5.3", + "phpunit/php-code-coverage": "^6.0.1", "phpunit/php-file-iterator": "^1.4.3", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-timer": "^1.0.9", - "phpunit/phpunit-mock-objects": "^5.0.9", + "phpunit/php-timer": "^2.0", + "phpunit/phpunit-mock-objects": "^6.0", "sebastian/comparator": "^2.1", - "sebastian/diff": "^2.0", + "sebastian/diff": "^3.0", "sebastian/environment": "^3.1", "sebastian/exporter": "^3.1", "sebastian/global-state": "^2.0", @@ -3644,16 +2870,12 @@ "sebastian/resource-operations": "^1.0", "sebastian/version": "^2.0.1" }, - "conflict": { - "phpdocumentor/reflection-docblock": "3.0.2", - "phpunit/dbunit": "<3.0" - }, "require-dev": { "ext-pdo": "*" }, "suggest": { "ext-xdebug": "*", - "phpunit/php-invoker": "^1.1" + "phpunit/php-invoker": "^2.0" }, "bin": [ "phpunit" @@ -3661,7 +2883,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "6.5.x-dev" + "dev-master": "7.0-dev" } }, "autoload": { @@ -3687,33 +2909,30 @@ "testing", "xunit" ], - "time": "2019-02-01T05:22:47+00:00" + "time": "2018-03-26T07:36:48+00:00" }, { "name": "phpunit/phpunit-mock-objects", - "version": "5.0.10", + "version": "6.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f" + "reference": "f9756fd4f43f014cb2dca98deeaaa8ce5500a36e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/cd1cf05c553ecfec36b170070573e540b67d3f1f", - "reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/f9756fd4f43f014cb2dca98deeaaa8ce5500a36e", + "reference": "f9756fd4f43f014cb2dca98deeaaa8ce5500a36e", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.5", - "php": "^7.0", + "php": "^7.1", "phpunit/php-text-template": "^1.2.1", "sebastian/exporter": "^3.1" }, - "conflict": { - "phpunit/phpunit": "<6.0" - }, "require-dev": { - "phpunit/phpunit": "^6.5.11" + "phpunit/phpunit": "^7.0" }, "suggest": { "ext-soap": "*" @@ -3721,7 +2940,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0.x-dev" + "dev-master": "6.1-dev" } }, "autoload": { @@ -3747,7 +2966,7 @@ "xunit" ], "abandoned": true, - "time": "2018-08-09T05:50:03+00:00" + "time": "2018-05-29T13:54:20+00:00" }, { "name": "psr/cache", @@ -3896,16 +3115,16 @@ }, { "name": "psr/log", - "version": "1.1.2", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801" + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801", - "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801", + "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc", "shasum": "" }, "require": { @@ -3939,7 +3158,7 @@ "psr", "psr-3" ], - "time": "2019-11-01T11:05:21+00:00" + "time": "2020-03-23T09:12:05+00:00" }, { "name": "psr/simple-cache", @@ -4031,16 +3250,16 @@ }, { "name": "ramsey/uuid", - "version": "3.9.2", + "version": "3.9.3", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "7779489a47d443f845271badbdcedfe4df8e06fb" + "reference": "7e1633a6964b48589b142d60542f9ed31bd37a92" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/7779489a47d443f845271badbdcedfe4df8e06fb", - "reference": "7779489a47d443f845271badbdcedfe4df8e06fb", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/7e1633a6964b48589b142d60542f9ed31bd37a92", + "reference": "7e1633a6964b48589b142d60542f9ed31bd37a92", "shasum": "" }, "require": { @@ -4114,7 +3333,7 @@ "identifier", "uuid" ], - "time": "2019-12-17T08:18:51+00:00" + "time": "2020-02-21T04:36:14+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -4227,28 +3446,29 @@ }, { "name": "sebastian/diff", - "version": "2.0.1", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd" + "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", - "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/720fcc7e9b5cf384ea68d9d930d480907a0c1a29", + "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29", "shasum": "" }, "require": { - "php": "^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^6.2" + "phpunit/phpunit": "^7.5 || ^8.0", + "symfony/process": "^2 || ^3.3 || ^4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -4273,9 +3493,12 @@ "description": "Diff implementation", "homepage": "https://github.com/sebastianbergmann/diff", "keywords": [ - "diff" + "diff", + "udiff", + "unidiff", + "unified diff" ], - "time": "2017-08-03T08:09:46+00:00" + "time": "2019-02-04T06:01:07+00:00" }, { "name": "sebastian/environment", @@ -4726,16 +3949,16 @@ }, { "name": "seld/phar-utils", - "version": "1.0.2", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/Seldaek/phar-utils.git", - "reference": "84715761c35808076b00908a20317a3a8a67d17e" + "reference": "8800503d56b9867d43d9c303b9cbcc26016e82f0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/84715761c35808076b00908a20317a3a8a67d17e", - "reference": "84715761c35808076b00908a20317a3a8a67d17e", + "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/8800503d56b9867d43d9c303b9cbcc26016e82f0", + "reference": "8800503d56b9867d43d9c303b9cbcc26016e82f0", "shasum": "" }, "require": { @@ -4764,44 +3987,236 @@ ], "description": "PHAR file format utilities, for when PHP phars you up", "keywords": [ - "phra" + "phar" ], - "time": "2020-01-13T10:41:09+00:00" + "time": "2020-02-14T15:25:33+00:00" }, { "name": "symfony/browser-kit", - "version": "v3.4.37", + "version": "v4.4.6", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "ede0c5fa204586e3fa51053fbea9cea8a5a3ee8b" + "reference": "4e9a171559f5a9018c90ba9e85b4084d4e045186" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/4e9a171559f5a9018c90ba9e85b4084d4e045186", + "reference": "4e9a171559f5a9018c90ba9e85b4084d4e045186", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/dom-crawler": "^3.4|^4.0|^5.0" + }, + "require-dev": { + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/http-client": "^4.3|^5.0", + "symfony/mime": "^4.3|^5.0", + "symfony/process": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\BrowserKit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony BrowserKit Component", + "homepage": "https://symfony.com", + "time": "2020-03-15T10:05:03+00:00" + }, + { + "name": "symfony/console", + "version": "v4.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "20bc0c1068565103075359f5ce9e0639b36f92d1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/20bc0c1068565103075359f5ce9e0639b36f92d1", + "reference": "20bc0c1068565103075359f5ce9e0639b36f92d1", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.8", + "symfony/service-contracts": "^1.1|^2" + }, + "conflict": { + "symfony/dependency-injection": "<3.4", + "symfony/event-dispatcher": "<4.3|>=5", + "symfony/lock": "<4.4", + "symfony/process": "<3.3" + }, + "provide": { + "psr/log-implementation": "1.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/event-dispatcher": "^4.3", + "symfony/lock": "^4.4|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/var-dumper": "^4.3|^5.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Console Component", + "homepage": "https://symfony.com", + "time": "2020-03-16T08:56:54+00:00" + }, + { + "name": "symfony/css-selector", + "version": "v4.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "402251c6fd69806a70a2b0e1426d16f8487f0f9a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/402251c6fd69806a70a2b0e1426d16f8487f0f9a", + "reference": "402251c6fd69806a70a2b0e1426d16f8487f0f9a", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony CssSelector Component", + "homepage": "https://symfony.com", + "time": "2020-03-16T08:56:54+00:00" + }, + { + "name": "symfony/dom-crawler", + "version": "v4.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "7e7c7957f6d53757d36b61a1f7408ef0b6683040" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/ede0c5fa204586e3fa51053fbea9cea8a5a3ee8b", - "reference": "ede0c5fa204586e3fa51053fbea9cea8a5a3ee8b", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/7e7c7957f6d53757d36b61a1f7408ef0b6683040", + "reference": "7e7c7957f6d53757d36b61a1f7408ef0b6683040", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/dom-crawler": "~2.8|~3.0|~4.0" + "php": "^7.1.3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "masterminds/html5": "<2.6" }, "require-dev": { - "symfony/css-selector": "~2.8|~3.0|~4.0", - "symfony/process": "~2.8|~3.0|~4.0" + "masterminds/html5": "^2.6", + "symfony/css-selector": "^3.4|^4.0|^5.0" }, "suggest": { - "symfony/process": "" + "symfony/css-selector": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.4-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\BrowserKit\\": "" + "Symfony\\Component\\DomCrawler\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -4821,59 +4236,57 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony BrowserKit Component", + "description": "Symfony DomCrawler Component", "homepage": "https://symfony.com", - "time": "2020-01-01T11:03:25+00:00" + "time": "2020-03-16T11:24:17+00:00" }, { - "name": "symfony/console", - "version": "v3.4.37", + "name": "symfony/event-dispatcher", + "version": "v4.4.6", "source": { "type": "git", - "url": "https://github.com/symfony/console.git", - "reference": "7c5bdd346f9d90a2d22d4e1fe61e02dc19b98f12" + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "cf57788d1ca64ee7e689698dc0295d25c9fe3780" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/7c5bdd346f9d90a2d22d4e1fe61e02dc19b98f12", - "reference": "7c5bdd346f9d90a2d22d4e1fe61e02dc19b98f12", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/cf57788d1ca64ee7e689698dc0295d25c9fe3780", + "reference": "cf57788d1ca64ee7e689698dc0295d25c9fe3780", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/debug": "~2.8|~3.0|~4.0", - "symfony/polyfill-mbstring": "~1.0" + "php": "^7.1.3", + "symfony/event-dispatcher-contracts": "^1.1" }, "conflict": { - "symfony/dependency-injection": "<3.4", - "symfony/process": "<3.3" + "symfony/dependency-injection": "<3.4" }, "provide": { - "psr/log-implementation": "1.0" + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "1.1" }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "~3.3|~4.0", - "symfony/dependency-injection": "~3.4|~4.0", - "symfony/event-dispatcher": "~2.8|~3.0|~4.0", - "symfony/lock": "~3.4|~4.0", - "symfony/process": "~3.3|~4.0" + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/stopwatch": "^3.4|^4.0|^5.0" }, "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/lock": "", - "symfony/process": "" + "symfony/dependency-injection": "", + "symfony/http-kernel": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.4-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\Console\\": "" + "Symfony\\Component\\EventDispatcher\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -4893,40 +4306,41 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Console Component", + "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2020-01-10T07:52:48+00:00" + "time": "2020-03-16T11:24:17+00:00" }, { - "name": "symfony/css-selector", - "version": "v3.4.37", + "name": "symfony/event-dispatcher-contracts", + "version": "v1.1.7", "source": { "type": "git", - "url": "https://github.com/symfony/css-selector.git", - "reference": "e1b3e1a0621d6e48ee46092b4c7d8280f746b3c5" + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "c43ab685673fb6c8d84220c77897b1d6cdbe1d18" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/e1b3e1a0621d6e48ee46092b4c7d8280f746b3c5", - "reference": "e1b3e1a0621d6e48ee46092b4c7d8280f746b3c5", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/c43ab685673fb6c8d84220c77897b1d6cdbe1d18", + "reference": "c43ab685673fb6c8d84220c77897b1d6cdbe1d18", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" + "php": "^7.1.3" + }, + "suggest": { + "psr/event-dispatcher": "", + "symfony/event-dispatcher-implementation": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "1.1-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\CssSelector\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Symfony\\Contracts\\EventDispatcher\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4934,55 +4348,53 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Jean-François Simon", - "email": "jeanfrancois.simon@sensiolabs.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony CssSelector Component", + "description": "Generic abstractions related to dispatching event", "homepage": "https://symfony.com", - "time": "2020-01-01T11:03:25+00:00" + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-09-17T09:54:03+00:00" }, { - "name": "symfony/debug", - "version": "v3.4.37", + "name": "symfony/filesystem", + "version": "v5.0.6", "source": { "type": "git", - "url": "https://github.com/symfony/debug.git", - "reference": "70dd18e93bb8bdf3c4db7fde832619fef9828cf8" + "url": "https://github.com/symfony/filesystem.git", + "reference": "81daae1bc46cb8eef557f5faa36e9c785f983db1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/70dd18e93bb8bdf3c4db7fde832619fef9828cf8", - "reference": "70dd18e93bb8bdf3c4db7fde832619fef9828cf8", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/81daae1bc46cb8eef557f5faa36e9c785f983db1", + "reference": "81daae1bc46cb8eef557f5faa36e9c785f983db1", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "psr/log": "~1.0" - }, - "conflict": { - "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" - }, - "require-dev": { - "symfony/http-kernel": "~2.8|~3.0|~4.0" + "php": "^7.2.5", + "symfony/polyfill-ctype": "~1.8" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "5.0-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\Debug\\": "" + "Symfony\\Component\\Filesystem\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -5002,44 +4414,36 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Debug Component", + "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2020-01-08T16:36:15+00:00" + "time": "2020-03-16T13:02:39+00:00" }, { - "name": "symfony/dom-crawler", - "version": "v3.4.37", + "name": "symfony/finder", + "version": "v4.4.6", "source": { "type": "git", - "url": "https://github.com/symfony/dom-crawler.git", - "reference": "c6fcc96c530ef18dcb4e605e3e9a97c483a160e6" + "url": "https://github.com/symfony/finder.git", + "reference": "ea69c129aed9fdeca781d4b77eb20b62cf5d5357" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/c6fcc96c530ef18dcb4e605e3e9a97c483a160e6", - "reference": "c6fcc96c530ef18dcb4e605e3e9a97c483a160e6", + "url": "https://api.github.com/repos/symfony/finder/zipball/ea69c129aed9fdeca781d4b77eb20b62cf5d5357", + "reference": "ea69c129aed9fdeca781d4b77eb20b62cf5d5357", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.0" - }, - "require-dev": { - "symfony/css-selector": "~2.8|~3.0|~4.0" - }, - "suggest": { - "symfony/css-selector": "" + "php": "^7.1.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.4-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\DomCrawler\\": "" + "Symfony\\Component\\Finder\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -5059,50 +4463,42 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony DomCrawler Component", + "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2020-01-01T11:03:25+00:00" + "time": "2020-02-14T07:42:58+00:00" }, { - "name": "symfony/event-dispatcher", - "version": "v3.4.37", + "name": "symfony/http-foundation", + "version": "v5.0.6", "source": { "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "79ede8f2836e5ec910ebb325bde40f987244baa8" + "url": "https://github.com/symfony/http-foundation.git", + "reference": "2da08283c33cfa34d6e332a01436931e318f5f80" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/79ede8f2836e5ec910ebb325bde40f987244baa8", - "reference": "79ede8f2836e5ec910ebb325bde40f987244baa8", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/2da08283c33cfa34d6e332a01436931e318f5f80", + "reference": "2da08283c33cfa34d6e332a01436931e318f5f80", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" - }, - "conflict": { - "symfony/dependency-injection": "<3.3" + "php": "^7.2.5", + "symfony/mime": "^4.4|^5.0", + "symfony/polyfill-mbstring": "~1.1" }, "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~2.8|~3.0|~4.0", - "symfony/dependency-injection": "~3.3|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/stopwatch": "~2.8|~3.0|~4.0" - }, - "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" + "predis/predis": "~1.0", + "symfony/expression-language": "^4.4|^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "5.0-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\EventDispatcher\\": "" + "Symfony\\Component\\HttpFoundation\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -5122,37 +4518,45 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony EventDispatcher Component", + "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2020-01-04T12:05:51+00:00" + "time": "2020-03-23T12:42:46+00:00" }, { - "name": "symfony/filesystem", - "version": "v3.4.37", + "name": "symfony/mime", + "version": "v5.0.6", "source": { "type": "git", - "url": "https://github.com/symfony/filesystem.git", - "reference": "0a0d3b4bda11aa3a0464531c40e681e184e75628" + "url": "https://github.com/symfony/mime.git", + "reference": "e9927cabc1519d2498d02b743f2cab6e4722ad3d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/0a0d3b4bda11aa3a0464531c40e681e184e75628", - "reference": "0a0d3b4bda11aa3a0464531c40e681e184e75628", + "url": "https://api.github.com/repos/symfony/mime/zipball/e9927cabc1519d2498d02b743f2cab6e4722ad3d", + "reference": "e9927cabc1519d2498d02b743f2cab6e4722ad3d", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/polyfill-ctype": "~1.8" + "php": "^7.2.5", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" + }, + "conflict": { + "symfony/mailer": "<4.4" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10", + "symfony/dependency-injection": "^4.4|^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "5.0-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\Filesystem\\": "" + "Symfony\\Component\\Mime\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -5172,39 +4576,46 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Filesystem Component", + "description": "A library to manipulate MIME messages", "homepage": "https://symfony.com", - "time": "2020-01-17T08:50:08+00:00" + "keywords": [ + "mime", + "mime-type" + ], + "time": "2020-03-16T12:10:54+00:00" }, { - "name": "symfony/finder", - "version": "v3.4.37", + "name": "symfony/polyfill-ctype", + "version": "v1.15.0", "source": { "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "a90a9d3b9f458a5cdeabfa4090b20c000ca3962f" + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "4719fa9c18b0464d399f1a63bf624b42b6fa8d14" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/a90a9d3b9f458a5cdeabfa4090b20c000ca3962f", - "reference": "a90a9d3b9f458a5cdeabfa4090b20c000ca3962f", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/4719fa9c18b0464d399f1a63bf624b42b6fa8d14", + "reference": "4719fa9c18b0464d399f1a63bf624b42b6fa8d14", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" + "php": ">=5.3.3" + }, + "suggest": { + "ext-ctype": "For best performance" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "1.15-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\Finder\\": "" + "Symfony\\Polyfill\\Ctype\\": "" }, - "exclude-from-classmap": [ - "/Tests/" + "files": [ + "bootstrap.php" ] }, "notification-url": "https://packagist.org/downloads/", @@ -5213,52 +4624,58 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Finder Component", + "description": "Symfony polyfill for ctype functions", "homepage": "https://symfony.com", - "time": "2020-01-01T11:03:25+00:00" + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "time": "2020-02-27T09:26:54+00:00" }, { - "name": "symfony/http-foundation", - "version": "v3.4.37", + "name": "symfony/polyfill-intl-idn", + "version": "v1.15.0", "source": { "type": "git", - "url": "https://github.com/symfony/http-foundation.git", - "reference": "f3abd07a56111ebe6a1ad6f1cbc23e4f8983f8f5" + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/f3abd07a56111ebe6a1ad6f1cbc23e4f8983f8f5", - "reference": "f3abd07a56111ebe6a1ad6f1cbc23e4f8983f8f5", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf", + "reference": "47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php70": "~1.6" + "php": ">=5.3.3", + "symfony/polyfill-mbstring": "^1.3", + "symfony/polyfill-php72": "^1.10" }, - "require-dev": { - "symfony/expression-language": "~2.8|~3.0|~4.0" + "suggest": { + "ext-intl": "For best performance" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "1.15-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\HttpFoundation\\": "" + "Symfony\\Polyfill\\Intl\\Idn\\": "" }, - "exclude-from-classmap": [ - "/Tests/" + "files": [ + "bootstrap.php" ] }, "notification-url": "https://packagist.org/downloads/", @@ -5267,47 +4684,55 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Laurent Bassin", + "email": "laurent@bassin.info" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony HttpFoundation Component", + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", "homepage": "https://symfony.com", - "time": "2020-01-04T12:05:51+00:00" + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "time": "2020-03-09T19:04:49+00:00" }, { - "name": "symfony/polyfill-ctype", - "version": "v1.13.1", + "name": "symfony/polyfill-mbstring", + "version": "v1.15.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3" + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", - "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/81ffd3a9c6d707be22e3012b827de1c9775fc5ac", + "reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac", "shasum": "" }, "require": { "php": ">=5.3.3" }, "suggest": { - "ext-ctype": "For best performance" + "ext-mbstring": "For best performance" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.13-dev" + "dev-master": "1.15-dev" } }, "autoload": { "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" + "Symfony\\Polyfill\\Mbstring\\": "" }, "files": [ "bootstrap.php" @@ -5319,53 +4744,51 @@ ], "authors": [ { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for ctype functions", + "description": "Symfony polyfill for the Mbstring extension", "homepage": "https://symfony.com", "keywords": [ "compatibility", - "ctype", + "mbstring", "polyfill", - "portable" + "portable", + "shim" ], - "time": "2019-11-27T13:56:44+00:00" + "time": "2020-03-09T19:04:49+00:00" }, { - "name": "symfony/polyfill-mbstring", - "version": "v1.13.1", + "name": "symfony/polyfill-php72", + "version": "v1.15.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "7b4aab9743c30be783b73de055d24a39cf4b954f" + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "37b0976c78b94856543260ce09b460a7bc852747" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7b4aab9743c30be783b73de055d24a39cf4b954f", - "reference": "7b4aab9743c30be783b73de055d24a39cf4b954f", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/37b0976c78b94856543260ce09b460a7bc852747", + "reference": "37b0976c78b94856543260ce09b460a7bc852747", "shasum": "" }, "require": { "php": ">=5.3.3" }, - "suggest": { - "ext-mbstring": "For best performance" - }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.13-dev" + "dev-master": "1.15-dev" } }, "autoload": { "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" + "Symfony\\Polyfill\\Php72\\": "" }, "files": [ "bootstrap.php" @@ -5385,44 +4808,42 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for the Mbstring extension", + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", - "mbstring", "polyfill", "portable", "shim" ], - "time": "2019-11-27T14:18:11+00:00" + "time": "2020-02-27T09:26:54+00:00" }, { - "name": "symfony/polyfill-php70", - "version": "v1.13.1", + "name": "symfony/polyfill-php73", + "version": "v1.15.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php70.git", - "reference": "af23c7bb26a73b850840823662dda371484926c4" + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/af23c7bb26a73b850840823662dda371484926c4", - "reference": "af23c7bb26a73b850840823662dda371484926c4", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7", + "reference": "0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7", "shasum": "" }, "require": { - "paragonie/random_compat": "~1.0|~2.0|~9.99", "php": ">=5.3.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.13-dev" + "dev-master": "1.15-dev" } }, "autoload": { "psr-4": { - "Symfony\\Polyfill\\Php70\\": "" + "Symfony\\Polyfill\\Php73\\": "" }, "files": [ "bootstrap.php" @@ -5445,7 +4866,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -5453,29 +4874,29 @@ "portable", "shim" ], - "time": "2019-11-27T13:56:44+00:00" + "time": "2020-02-27T09:26:54+00:00" }, { "name": "symfony/process", - "version": "v3.4.37", + "version": "v4.4.6", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "5b9d2bcffe4678911a4c941c00b7c161252cf09a" + "reference": "b9863d0f7b684d7c4c13e665325b5ff047de0aee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/5b9d2bcffe4678911a4c941c00b7c161252cf09a", - "reference": "5b9d2bcffe4678911a4c941c00b7c161252cf09a", + "url": "https://api.github.com/repos/symfony/process/zipball/b9863d0f7b684d7c4c13e665325b5ff047de0aee", + "reference": "b9863d0f7b684d7c4c13e665325b5ff047de0aee", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" + "php": "^7.1.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -5502,31 +4923,89 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2020-01-01T11:03:25+00:00" + "time": "2020-03-23T12:37:11+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "144c5e51266b281231e947b51223ba14acf1a749" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/144c5e51266b281231e947b51223ba14acf1a749", + "reference": "144c5e51266b281231e947b51223ba14acf1a749", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "psr/container": "^1.0" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-11-18T17:27:11+00:00" }, { "name": "symfony/yaml", - "version": "v3.4.37", + "version": "v4.4.6", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "aa46bc2233097d5212332c907f9911533acfbf80" + "reference": "43d7a46b1f80b4fd2ecfac4a9a4cc1f22d029fbb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/aa46bc2233097d5212332c907f9911533acfbf80", - "reference": "aa46bc2233097d5212332c907f9911533acfbf80", + "url": "https://api.github.com/repos/symfony/yaml/zipball/43d7a46b1f80b4fd2ecfac4a9a4cc1f22d029fbb", + "reference": "43d7a46b1f80b4fd2ecfac4a9a4cc1f22d029fbb", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", + "php": "^7.1.3", "symfony/polyfill-ctype": "~1.8" }, "conflict": { "symfony/console": "<3.4" }, "require-dev": { - "symfony/console": "~3.4|~4.0" + "symfony/console": "^3.4|^4.0|^5.0" }, "suggest": { "symfony/console": "For validating YAML files using the lint command" @@ -5534,7 +5013,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -5561,7 +5040,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2020-01-13T08:00:59+00:00" + "time": "2020-03-16T08:56:54+00:00" }, { "name": "theseer/tokenizer", @@ -5656,16 +5135,16 @@ }, { "name": "webmozart/assert", - "version": "1.6.0", + "version": "1.7.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "573381c0a64f155a0d9a23f4b0c797194805b925" + "reference": "aed98a490f9a8f78468232db345ab9cf606cf598" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/573381c0a64f155a0d9a23f4b0c797194805b925", - "reference": "573381c0a64f155a0d9a23f4b0c797194805b925", + "url": "https://api.github.com/repos/webmozart/assert/zipball/aed98a490f9a8f78468232db345ab9cf606cf598", + "reference": "aed98a490f9a8f78468232db345ab9cf606cf598", "shasum": "" }, "require": { @@ -5700,7 +5179,7 @@ "check", "validate" ], - "time": "2019-11-24T13:36:37+00:00" + "time": "2020-02-14T12:15:55+00:00" }, { "name": "weew/helpers-array", @@ -5854,32 +5333,33 @@ ], "description": "Sends PHP test coverage information to Codacy.", "homepage": "https://github.com/codacy/php-codacy-coverage", + "abandoned": true, "time": "2020-01-10T10:52:12+00:00" }, { "name": "codeception/aspect-mock", - "version": "3.0.2", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/Codeception/AspectMock.git", - "reference": "130afd10a3d8131d267f393ee1ec322e3e583d67" + "reference": "72fc3d6877ede7ff255ee2c96b7b57d4f87d0f30" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/AspectMock/zipball/130afd10a3d8131d267f393ee1ec322e3e583d67", - "reference": "130afd10a3d8131d267f393ee1ec322e3e583d67", + "url": "https://api.github.com/repos/Codeception/AspectMock/zipball/72fc3d6877ede7ff255ee2c96b7b57d4f87d0f30", + "reference": "72fc3d6877ede7ff255ee2c96b7b57d4f87d0f30", "shasum": "" }, "require": { - "goaop/framework": "^2.2.0", + "goaop/framework": "^2.2.0 | ^3.0.0-RC2", "php": ">=7.0.0", "phpunit/phpunit": "> 6.0.0", - "symfony/finder": "~2.4|~3.0|~4.0" + "symfony/finder": ">=2.4 <6.0" }, "require-dev": { - "codeception/base": "^2.4", - "codeception/specify": "~0.3", - "codeception/verify": "~0.2" + "codeception/codeception": "^4.0", + "codeception/specify": "^1.0", + "codeception/verify": "^1.2" }, "type": "library", "autoload": { @@ -5898,24 +5378,26 @@ } ], "description": "Experimental Mocking Framework powered by Aspects", - "time": "2018-10-07T16:21:11+00:00" + "time": "2020-02-29T15:39:49+00:00" }, { "name": "gitonomy/gitlib", - "version": "v1.2.0", + "version": "v1.2.1", "source": { "type": "git", "url": "https://github.com/gitonomy/gitlib.git", - "reference": "a0bea921266ad1c9626d712e7f8687dcc08ca528" + "reference": "718ca021c67f3ea8f6a5fa5d231ec49675068868" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/gitonomy/gitlib/zipball/a0bea921266ad1c9626d712e7f8687dcc08ca528", - "reference": "a0bea921266ad1c9626d712e7f8687dcc08ca528", + "url": "https://api.github.com/repos/gitonomy/gitlib/zipball/718ca021c67f3ea8f6a5fa5d231ec49675068868", + "reference": "718ca021c67f3ea8f6a5fa5d231ec49675068868", "shasum": "" }, "require": { + "ext-pcre": "*", "php": "^5.6 || ^7.0", + "symfony/polyfill-mbstring": "^1.7", "symfony/process": "^3.4|^4.0|^5.0" }, "require-dev": { @@ -5923,6 +5405,7 @@ "psr/log": "^1.0" }, "suggest": { + "ext-fileinfo": "Required to determine the mimetype of a blob", "psr/log": "Required to use loggers for reporting of execution" }, "type": "library", @@ -5959,8 +5442,7 @@ } ], "description": "Library for accessing git", - "homepage": "http://gitonomy.com", - "time": "2019-12-08T12:42:25+00:00" + "time": "2020-03-23T12:43:44+00:00" }, { "name": "goaop/framework", @@ -6280,16 +5762,16 @@ }, { "name": "pdepend/pdepend", - "version": "2.7.0", + "version": "2.7.1", "source": { "type": "git", "url": "https://github.com/pdepend/pdepend.git", - "reference": "cba74e118ce806f97fcb108c00d61ebf2a5a936e" + "reference": "daba1cf0a6edaf172fa02a17807ae29f4c1c7471" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pdepend/pdepend/zipball/cba74e118ce806f97fcb108c00d61ebf2a5a936e", - "reference": "cba74e118ce806f97fcb108c00d61ebf2a5a936e", + "url": "https://api.github.com/repos/pdepend/pdepend/zipball/daba1cf0a6edaf172fa02a17807ae29f4c1c7471", + "reference": "daba1cf0a6edaf172fa02a17807ae29f4c1c7471", "shasum": "" }, "require": { @@ -6323,7 +5805,7 @@ "BSD-3-Clause" ], "description": "Official version of pdepend to be handled with Composer", - "time": "2020-01-24T08:09:26+00:00" + "time": "2020-02-08T12:06:13+00:00" }, { "name": "php-coveralls/php-coveralls", @@ -6388,22 +5870,22 @@ }, { "name": "phpmd/phpmd", - "version": "2.8.1", + "version": "2.8.2", "source": { "type": "git", "url": "https://github.com/phpmd/phpmd.git", - "reference": "5664b95d484797582f5af9536238deb9ecde58a1" + "reference": "714629ed782537f638fe23c4346637659b779a77" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpmd/phpmd/zipball/5664b95d484797582f5af9536238deb9ecde58a1", - "reference": "5664b95d484797582f5af9536238deb9ecde58a1", + "url": "https://api.github.com/repos/phpmd/phpmd/zipball/714629ed782537f638fe23c4346637659b779a77", + "reference": "714629ed782537f638fe23c4346637659b779a77", "shasum": "" }, "require": { "composer/xdebug-handler": "^1.0", "ext-xml": "*", - "pdepend/pdepend": "^2.6", + "pdepend/pdepend": "^2.7.1", "php": ">=5.3.9" }, "require-dev": { @@ -6454,7 +5936,7 @@ "phpmd", "pmd" ], - "time": "2019-12-27T11:09:06+00:00" + "time": "2020-02-16T20:15:50+00:00" }, { "name": "rregeer/phpunit-coverage-check", @@ -6500,23 +5982,27 @@ }, { "name": "sebastian/finder-facade", - "version": "1.2.2", + "version": "1.2.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/finder-facade.git", - "reference": "4a3174709c2dc565fe5fb26fcf827f6a1fc7b09f" + "reference": "167c45d131f7fc3d159f56f191a0a22228765e16" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/finder-facade/zipball/4a3174709c2dc565fe5fb26fcf827f6a1fc7b09f", - "reference": "4a3174709c2dc565fe5fb26fcf827f6a1fc7b09f", + "url": "https://api.github.com/repos/sebastianbergmann/finder-facade/zipball/167c45d131f7fc3d159f56f191a0a22228765e16", + "reference": "167c45d131f7fc3d159f56f191a0a22228765e16", "shasum": "" }, "require": { - "symfony/finder": "~2.3|~3.0|~4.0", - "theseer/fdomdocument": "~1.3" + "php": "^7.1", + "symfony/finder": "^2.3|^3.0|^4.0|^5.0", + "theseer/fdomdocument": "^1.6" }, "type": "library", + "extra": { + "branch-alias": [] + }, "autoload": { "classmap": [ "src/" @@ -6535,25 +6021,26 @@ ], "description": "FinderFacade is a convenience wrapper for Symfony's Finder component.", "homepage": "https://github.com/sebastianbergmann/finder-facade", - "time": "2017-11-18T17:31:49+00:00" + "time": "2020-01-16T08:08:45+00:00" }, { "name": "sebastian/phpcpd", - "version": "3.0.1", + "version": "4.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpcpd.git", - "reference": "dfed51c1288790fc957c9433e2f49ab152e8a564" + "reference": "0d9afa762f2400de077b2192f4a9d127de0bb78e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpcpd/zipball/dfed51c1288790fc957c9433e2f49ab152e8a564", - "reference": "dfed51c1288790fc957c9433e2f49ab152e8a564", + "url": "https://api.github.com/repos/sebastianbergmann/phpcpd/zipball/0d9afa762f2400de077b2192f4a9d127de0bb78e", + "reference": "0d9afa762f2400de077b2192f4a9d127de0bb78e", "shasum": "" }, "require": { - "php": "^5.6|^7.0", - "phpunit/php-timer": "^1.0.6", + "ext-dom": "*", + "php": "^7.1", + "phpunit/php-timer": "^2.0", "sebastian/finder-facade": "^1.1", "sebastian/version": "^1.0|^2.0", "symfony/console": "^2.7|^3.0|^4.0" @@ -6564,7 +6051,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -6585,7 +6072,7 @@ ], "description": "Copy/Paste Detector (CPD) for PHP code.", "homepage": "https://github.com/sebastianbergmann/phpcpd", - "time": "2017-11-16T08:49:28+00:00" + "time": "2018-09-17T17:17:27+00:00" }, { "name": "squizlabs/php_codesniffer", @@ -6640,32 +6127,32 @@ }, { "name": "symfony/config", - "version": "v3.4.37", + "version": "v4.4.6", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "6abc18b2a97f63508d23929bbb2ae65aaa07bace" + "reference": "235e5afffd3a1a1b0dd0221973cbf670bc3be1d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/6abc18b2a97f63508d23929bbb2ae65aaa07bace", - "reference": "6abc18b2a97f63508d23929bbb2ae65aaa07bace", + "url": "https://api.github.com/repos/symfony/config/zipball/235e5afffd3a1a1b0dd0221973cbf670bc3be1d4", + "reference": "235e5afffd3a1a1b0dd0221973cbf670bc3be1d4", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/filesystem": "~2.8|~3.0|~4.0", + "php": "^7.1.3", + "symfony/filesystem": "^3.4|^4.0|^5.0", "symfony/polyfill-ctype": "~1.8" }, "conflict": { - "symfony/dependency-injection": "<3.3", - "symfony/finder": "<3.3" + "symfony/finder": "<3.4" }, "require-dev": { - "symfony/dependency-injection": "~3.3|~4.0", - "symfony/event-dispatcher": "~3.3|~4.0", - "symfony/finder": "~3.3|~4.0", - "symfony/yaml": "~3.0|~4.0" + "symfony/event-dispatcher": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/messenger": "^4.1|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/yaml": "^3.4|^4.0|^5.0" }, "suggest": { "symfony/yaml": "To use the yaml reference dumper" @@ -6673,7 +6160,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -6700,39 +6187,41 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2020-01-04T12:05:51+00:00" + "time": "2020-03-16T11:24:17+00:00" }, { "name": "symfony/dependency-injection", - "version": "v3.4.37", + "version": "v4.4.6", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "22000f10c9e1cfef051e8b4de46815b41a0223fc" + "reference": "b4242fc7f18c8bf5427f84d5afe2131c9b323a04" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/22000f10c9e1cfef051e8b4de46815b41a0223fc", - "reference": "22000f10c9e1cfef051e8b4de46815b41a0223fc", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/b4242fc7f18c8bf5427f84d5afe2131c9b323a04", + "reference": "b4242fc7f18c8bf5427f84d5afe2131c9b323a04", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "psr/container": "^1.0" + "php": "^7.1.3", + "psr/container": "^1.0", + "symfony/service-contracts": "^1.1.6|^2" }, "conflict": { - "symfony/config": "<3.3.7", - "symfony/finder": "<3.3", + "symfony/config": "<4.3|>=5.0", + "symfony/finder": "<3.4", "symfony/proxy-manager-bridge": "<3.4", "symfony/yaml": "<3.4" }, "provide": { - "psr/container-implementation": "1.0" + "psr/container-implementation": "1.0", + "symfony/service-implementation": "1.0" }, "require-dev": { - "symfony/config": "~3.3|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/yaml": "~3.4|~4.0" + "symfony/config": "^4.3", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0" }, "suggest": { "symfony/config": "", @@ -6744,7 +6233,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -6771,11 +6260,11 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2020-01-08T11:20:51+00:00" + "time": "2020-03-18T07:51:32+00:00" }, { "name": "symfony/stopwatch", - "version": "v3.4.37", + "version": "v3.4.38", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", @@ -6871,6 +6360,7 @@ "platform": { "php": "7.0.2||7.0.4||~7.0.6||~7.1.0||~7.2.0||~7.3.0", "ext-curl": "*", + "ext-dom": "*", "ext-json": "*", "ext-openssl": "*" }, diff --git a/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php b/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php index fc4ff64c2..bf16e5b49 100644 --- a/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php +++ b/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php @@ -6,8 +6,7 @@ */ namespace Magento\FunctionalTestingFramework\Allure\Event; -use Symfony\Component\HttpFoundation\File\MimeType\ExtensionGuesser; -use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser; +use Symfony\Component\Mime\MimeTypes; use Yandex\Allure\Adapter\AllureException; use Yandex\Allure\Adapter\Event\AddAttachmentEvent; @@ -73,7 +72,7 @@ private function copyFile($filePath, $outputPath) */ private function guessFileMimeType($filePath) { - $type = MimeTypeGuesser::getInstance()->guess($filePath); + $type = MimeTypes::getDefault()->guessMimeType($filePath); if (!isset($type)) { return DEFAULT_MIME_TYPE; } @@ -87,11 +86,11 @@ private function guessFileMimeType($filePath) */ private function guessFileExtension($mimeType) { - $candidate = ExtensionGuesser::getInstance()->guess($mimeType); - if (!isset($candidate)) { + $candidate = MimeTypes::getDefault()->getExtensions($mimeType); + if (empty($candidate)) { return DEFAULT_FILE_EXTENSION; } - return $candidate; + return reset($candidate); } /** From d254019ee3fcba11cc0731535d4c13e2a3ea1176 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Fri, 27 Mar 2020 13:20:18 -0500 Subject: [PATCH 319/888] Fix an issue with MimeType guesser and latest release of "symfony/http-foundation" --- .travis.yml | 1 - composer.json | 6 +- composer.lock | 154 +++++++++++++++++++++++++------------------------- 3 files changed, 79 insertions(+), 82 deletions(-) diff --git a/.travis.yml b/.travis.yml index 913c74f48..f807d7415 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: php php: - - 7.0 - 7.1 - 7.2 - 7.3 diff --git a/composer.json b/composer.json index 0580bebd6..3b517567d 100755 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ "sort-packages": true }, "require": { - "php": "7.0.2||7.0.4||~7.0.6||~7.1.0||~7.2.0||~7.3.0", + "php": "~7.1.0||~7.2.0||~7.3.0", "ext-curl": "*", "ext-dom": "*", "ext-json": "*", @@ -27,8 +27,8 @@ "php-webdriver/webdriver": "^1.8.0", "symfony/console": "^4.4", "symfony/finder": "^4.4", - "symfony/http-foundation": "^5.0", - "symfony/mime": "^5.0", + "symfony/http-foundation": "^4.4", + "symfony/mime": "^4.4", "symfony/process": "^4.4", "vlucas/phpdotenv": "^2.4" }, diff --git a/composer.lock b/composer.lock index 8db8cfd7d..7eb7a0d88 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7ea360e95d97749990efab6a97c186da", + "content-hash": "551059dcd56ad85b0ff76545e0ec6834", "packages": [ { "name": "allure-framework/allure-codeception", @@ -112,16 +112,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.133.45", + "version": "3.133.46", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "928a23e2ee7e195a66f93d0758895e26958c3b7d" + "reference": "98d359e61b365f3040ca61c66ae8883334cf5d74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/928a23e2ee7e195a66f93d0758895e26958c3b7d", - "reference": "928a23e2ee7e195a66f93d0758895e26958c3b7d", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/98d359e61b365f3040ca61c66ae8883334cf5d74", + "reference": "98d359e61b365f3040ca61c66ae8883334cf5d74", "shasum": "" }, "require": { @@ -192,7 +192,7 @@ "s3", "sdk" ], - "time": "2020-03-26T18:12:15+00:00" + "time": "2020-03-27T18:15:32+00:00" }, { "name": "behat/gherkin", @@ -1160,30 +1160,28 @@ }, { "name": "doctrine/lexer", - "version": "1.2.0", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/doctrine/lexer.git", - "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6" + "reference": "1febd6c3ef84253d7c815bed85fc622ad207a9f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6", - "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/1febd6c3ef84253d7c815bed85fc622ad207a9f8", + "reference": "1febd6c3ef84253d7c815bed85fc622ad207a9f8", "shasum": "" }, "require": { - "php": "^7.2" + "php": ">=5.3.2" }, "require-dev": { - "doctrine/coding-standard": "^6.0", - "phpstan/phpstan": "^0.11.8", - "phpunit/phpunit": "^8.2" + "phpunit/phpunit": "^4.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { @@ -1196,14 +1194,14 @@ "MIT" ], "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Roman Borschel", "email": "roman@code-factory.org" }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Johannes Schmitt", "email": "schmittjoh@gmail.com" @@ -1218,7 +1216,7 @@ "parser", "php" ], - "time": "2019-10-30T14:39:59+00:00" + "time": "2019-06-08T11:03:04+00:00" }, { "name": "flow/jsonpath", @@ -2367,38 +2365,41 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.1.0", + "version": "4.3.4", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e" + "reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e", - "reference": "cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/da3fd972d6bafd628114f7e7e036f45944b62e9c", + "reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c", "shasum": "" }, "require": { - "ext-filter": "^7.1", - "php": "^7.2", - "phpdocumentor/reflection-common": "^2.0", - "phpdocumentor/type-resolver": "^1.0", - "webmozart/assert": "^1" + "php": "^7.0", + "phpdocumentor/reflection-common": "^1.0.0 || ^2.0.0", + "phpdocumentor/type-resolver": "~0.4 || ^1.0.0", + "webmozart/assert": "^1.0" }, "require-dev": { - "doctrine/instantiator": "^1", - "mockery/mockery": "^1" + "doctrine/instantiator": "^1.0.5", + "mockery/mockery": "^1.0", + "phpdocumentor/type-resolver": "0.4.*", + "phpunit/phpunit": "^6.4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.x-dev" + "dev-master": "4.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": "src" + "phpDocumentor\\Reflection\\": [ + "src/" + ] } }, "notification-url": "https://packagist.org/downloads/", @@ -2409,36 +2410,33 @@ { "name": "Mike van Riel", "email": "me@mikevanriel.com" - }, - { - "name": "Jaap van Otterdijk", - "email": "account@ijaap.nl" } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2020-02-22T12:28:44+00:00" + "time": "2019-12-28T18:55:12+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "1.1.0", + "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "7462d5f123dfc080dfdf26897032a6513644fc95" + "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/7462d5f123dfc080dfdf26897032a6513644fc95", - "reference": "7462d5f123dfc080dfdf26897032a6513644fc95", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", + "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", "shasum": "" }, "require": { - "php": "^7.2", + "php": "^7.1", "phpdocumentor/reflection-common": "^2.0" }, "require-dev": { - "ext-tokenizer": "^7.2", - "mockery/mockery": "~1" + "ext-tokenizer": "^7.1", + "mockery/mockery": "~1", + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { @@ -2462,7 +2460,7 @@ } ], "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "time": "2020-02-18T18:59:58+00:00" + "time": "2019-08-22T18:11:29+00:00" }, { "name": "phpoption/phpoption", @@ -4370,26 +4368,26 @@ }, { "name": "symfony/filesystem", - "version": "v5.0.6", + "version": "v4.4.6", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "81daae1bc46cb8eef557f5faa36e9c785f983db1" + "reference": "6d4fdf28187250f671c1edc9cf921ebfb7fe3809" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/81daae1bc46cb8eef557f5faa36e9c785f983db1", - "reference": "81daae1bc46cb8eef557f5faa36e9c785f983db1", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/6d4fdf28187250f671c1edc9cf921ebfb7fe3809", + "reference": "6d4fdf28187250f671c1edc9cf921ebfb7fe3809", "shasum": "" }, "require": { - "php": "^7.2.5", + "php": "^7.1.3", "symfony/polyfill-ctype": "~1.8" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -4416,7 +4414,7 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2020-03-16T13:02:39+00:00" + "time": "2020-03-16T08:56:54+00:00" }, { "name": "symfony/finder", @@ -4469,31 +4467,31 @@ }, { "name": "symfony/http-foundation", - "version": "v5.0.6", + "version": "v4.4.6", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "2da08283c33cfa34d6e332a01436931e318f5f80" + "reference": "0a3b7711229f816a06fac805f4ed4a8f4641c719" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/2da08283c33cfa34d6e332a01436931e318f5f80", - "reference": "2da08283c33cfa34d6e332a01436931e318f5f80", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/0a3b7711229f816a06fac805f4ed4a8f4641c719", + "reference": "0a3b7711229f816a06fac805f4ed4a8f4641c719", "shasum": "" }, "require": { - "php": "^7.2.5", - "symfony/mime": "^4.4|^5.0", + "php": "^7.1.3", + "symfony/mime": "^4.3|^5.0", "symfony/polyfill-mbstring": "~1.1" }, "require-dev": { "predis/predis": "~1.0", - "symfony/expression-language": "^4.4|^5.0" + "symfony/expression-language": "^3.4|^4.0|^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -4520,24 +4518,24 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2020-03-23T12:42:46+00:00" + "time": "2020-03-23T12:37:11+00:00" }, { "name": "symfony/mime", - "version": "v5.0.6", + "version": "v4.4.6", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "e9927cabc1519d2498d02b743f2cab6e4722ad3d" + "reference": "f6be9d809d805ab5bdb12f2d5843ba2c78533c7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/e9927cabc1519d2498d02b743f2cab6e4722ad3d", - "reference": "e9927cabc1519d2498d02b743f2cab6e4722ad3d", + "url": "https://api.github.com/repos/symfony/mime/zipball/f6be9d809d805ab5bdb12f2d5843ba2c78533c7e", + "reference": "f6be9d809d805ab5bdb12f2d5843ba2c78533c7e", "shasum": "" }, "require": { - "php": "^7.2.5", + "php": "^7.1.3", "symfony/polyfill-intl-idn": "^1.10", "symfony/polyfill-mbstring": "^1.0" }, @@ -4546,12 +4544,12 @@ }, "require-dev": { "egulias/email-validator": "^2.1.10", - "symfony/dependency-injection": "^4.4|^5.0" + "symfony/dependency-injection": "^3.4|^4.1|^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -4582,7 +4580,7 @@ "mime", "mime-type" ], - "time": "2020-03-16T12:10:54+00:00" + "time": "2020-03-16T11:24:17+00:00" }, { "name": "symfony/polyfill-ctype", @@ -4927,20 +4925,20 @@ }, { "name": "symfony/service-contracts", - "version": "v2.0.1", + "version": "v1.1.8", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "144c5e51266b281231e947b51223ba14acf1a749" + "reference": "ffc7f5692092df31515df2a5ecf3b7302b3ddacf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/144c5e51266b281231e947b51223ba14acf1a749", - "reference": "144c5e51266b281231e947b51223ba14acf1a749", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/ffc7f5692092df31515df2a5ecf3b7302b3ddacf", + "reference": "ffc7f5692092df31515df2a5ecf3b7302b3ddacf", "shasum": "" }, "require": { - "php": "^7.2.5", + "php": "^7.1.3", "psr/container": "^1.0" }, "suggest": { @@ -4949,7 +4947,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "1.1-dev" } }, "autoload": { @@ -4981,7 +4979,7 @@ "interoperability", "standards" ], - "time": "2019-11-18T17:27:11+00:00" + "time": "2019-10-14T12:27:06+00:00" }, { "name": "symfony/yaml", @@ -6358,7 +6356,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "7.0.2||7.0.4||~7.0.6||~7.1.0||~7.2.0||~7.3.0", + "php": "~7.1.0||~7.2.0||~7.3.0", "ext-curl": "*", "ext-dom": "*", "ext-json": "*", From e45ea37fda0552e3b24d00065d1bee2c13db8b42 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Fri, 27 Mar 2020 14:39:04 -0500 Subject: [PATCH 320/888] MQE-2052: MFTF uses undeclared dependency --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a41360787..f6ed24d38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ Magento Functional Testing Framework Changelog 2.6.3 ----- +### Fixes +* added dependency to packages MFTF used but never specified in composer.json + +2.6.3 +----- + ### New Feature * `--filter` option was added to `bin/mftf generate:tests` command. For more details please go to https://devdocs.magento.com/mftf/docs/commands/mftf.html#generatetests From 7c0309f2a3e06e7e64dc932abb6fa2538ec29a1c Mon Sep 17 00:00:00 2001 From: Lukasz Bajsarowicz <lukasz.bajsarowicz@gmail.com> Date: Sun, 29 Mar 2020 22:56:46 +0200 Subject: [PATCH 321/888] Update documentation regarding Test object. --- docs/test.md | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/docs/test.md b/docs/test.md index 444f6cf6a..dd882213b 100644 --- a/docs/test.md +++ b/docs/test.md @@ -1,9 +1,9 @@ # Test Test cases in the Magento Functional Testing Framework (MFTF) are defined in XML as [`<tests>`]. -`<tests>` is a [Codeception test container][Codeception] that contains multiple individual tests with test metadata and before and after actions. +`<tests>` is a [Codeception test container][Codeception] that contains individual test [`<test>`] with it's metadata ([`<annotations>`]), before ([`<before>`]) and after ([`<after>`]) section. -MFTF `<tests>` is considered a sequence of actions with associated parameters. +MFTF `<test>` is considered a sequence of actions with associated parameters. Any failed [assertion] within a test constitutes a failed test. <div class="bs-callout bs-callout-info" markdown="1"> @@ -18,7 +18,7 @@ The following diagram shows the structure of an MFTF test case: ## Format -The format of `<tests>` is: +The format of Test XML file is: ```xml <?xml version="1.0" encoding="UTF-8"?> @@ -35,6 +35,7 @@ The format of `<tests>` is: <after> <!-- ACTIONS AND ACTION GROUPS PERFORMED AFTER THE TEST --> </after> + <!-- TEST ACTIONS, ACTION GROUPS, AND ASSERTIONS--> </test> </tests> @@ -44,26 +45,23 @@ The format of `<tests>` is: The following conventions apply to MFTF tests: -* All names within the framework are in the CamelCase format. -* `<test>` name must be alphanumeric. -* Each action and action group has its own identifier `<stepKey>` for reference purposes. -* A test may have any number of [assertions][assertion] at any point within the `<test>`. -* If `<test>` is included in `<suite>`, it **cannot be generated in isolation** to the rest of the contents of the suite (see [suites] for details). * One `<test>` tag is allowed per test XML file. +* All names within the framework are in the **PascalCase** format and must be alphanumeric. +* Each action and action group call has its own identifier `<stepKey>` for reference purposes. +* A test may have any number of [assertions][assertion] at any point within the `<test>`. +* If `<test>` is included in [`<suite>`][suites], it **cannot be generated in isolation** from `<before>` and `<after>` section of the suite (see [suites] for details). ## Elements reference -There are several XML elements that are used in `<tests>` in the MFTF. +There are several XML elements that are used in `<test>` in the MFTF. ### tests {#tests-tag} -`<tests>` is a container for multiple tests. It is a group of test methods that define test flows within a test case. - -`<tests>` must contain at least one [`<test>`]. +`<tests>` is a container for test and must contain exactly one [`<test>`]. ### test {#test-tag} -`<test>` is a set of steps, including [actions] and [assertions][assertion]. It is a sequence of test steps that define test flow within a test method. +`<test>` is a set of steps, including [actions], [assertions][assertion] and Action Group calls. It is a sequence of test steps that define test flow within a test method. Attribute|Type|Use|Description ---|---|---|--- @@ -85,21 +83,20 @@ Allure annotations provide metadata for reporting. ### before {#before-tag} -`<before>` wraps the steps to perform before the [`<test>`]. +`<before>` wraps the steps that are preconditions for the [`<test>`]. For example: Change configuration, create Customer Account, Create Category and Product. `<before>` may contain these child elements: -* Any [`<action>`][actions] -* [`<actionGroup>`] +* Any [Action][actions] +* [`<actionGroup>`]s ### after {#after-tag} -`<after>` wraps the steps to perform after the [`<test>`]. -The steps are run in both successful **and** failed test runs. +`<after>` wraps the steps to perform after the [`<test>`]. The steps are run in both successful **and** failed test runs. The goal of this section is to perform cleanup (revert the environment to the pre-test state). `<after>` may contain: -* Any [`<action>`][actions] +* Any [Action][actions] * [`<actionGroup>`] ### actionGroup {#actiongroup-tag} From 283e94ffcbace8644195bc04035b2ee77742125e Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Tue, 31 Mar 2020 13:40:16 -0500 Subject: [PATCH 322/888] MQE-2042: Port MFTF Coverage to Jenkins --- .../Extension/TestContextExtension.php | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php index c50156f08..918bff47e 100644 --- a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php +++ b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php @@ -32,6 +32,12 @@ class TestContextExtension extends BaseExtension */ public static $events; + /** + * The name of the currently running test + * @var string + */ + public $currentTest; + /** * Initialize local vars * @@ -55,8 +61,20 @@ public function _initialize() * @throws \Exception * @return void */ - public function testStart() + public function testStart(\Codeception\Event\TestEvent $e) { + if (getenv('ENABLE_CODE_COVERAGE') === 'true') { + // Curl against test.php and pass in the test name. Used when gathering code coverage. + $this->currentTest = $e->getTest()->getMetadata()->getName(); + $cURLConnection = curl_init(); + curl_setopt_array($cURLConnection, [ + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_URL => getenv('MAGENTO_BASE_URL') . "/test.php?test=" . $this->currentTest, + ]); + curl_exec($cURLConnection); + curl_close($cURLConnection); + } + PersistedObjectHandler::getInstance()->clearHookObjects(); PersistedObjectHandler::getInstance()->clearTestObjects(); } From cbd7c8593365ae087dbbb28e70bdf051f34c0431 Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Tue, 31 Mar 2020 13:51:12 -0500 Subject: [PATCH 323/888] MQE-2040: Unable to run suites from standalone MFTF (#655) * MQE-2040: Unable to run suites from standalone MFTF added additional path for standalone * MQE-2040: Unable to run suites from standalone MFTF fixed static checks --- .../Config/FileResolver/Root.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Magento/FunctionalTestingFramework/Config/FileResolver/Root.php b/src/Magento/FunctionalTestingFramework/Config/FileResolver/Root.php index 0ff6e4a77..8593aaf47 100644 --- a/src/Magento/FunctionalTestingFramework/Config/FileResolver/Root.php +++ b/src/Magento/FunctionalTestingFramework/Config/FileResolver/Root.php @@ -32,6 +32,19 @@ public function get($filename, $scope) . DIRECTORY_SEPARATOR . '*.xml' ); + // include root suite dir when running standalone version + $altPath = MAGENTO_BP . DIRECTORY_SEPARATOR . 'dev/tests/acceptance'; + + if (realpath($altPath) && ($altPath !== TESTS_BP)) { + $paths = array_merge( + $paths, + glob( + FilePathFormatter::format($altPath) . self::ROOT_SUITE_DIR + . DIRECTORY_SEPARATOR . '*.xml' + ) + ); + } + // Then merge this path into the module based paths // Since we are sharing this code with Module based resolution we will unnecessarily glob against modules in the // dev/tests dir tree, however as we plan to migrate to app/code this will be a temporary unneeded check. From c0e58c41d689c5307b5f156ecadd9cf265523f1a Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Tue, 31 Mar 2020 16:40:38 -0500 Subject: [PATCH 324/888] MQE-2042: Port MFTF Coverage to Jenkins - Add index.php and test.php files --- etc/codecoverage/index.php | 58 ++++++++++++++++++++++++++++++++++++++ etc/codecoverage/test.php | 4 +++ 2 files changed, 62 insertions(+) create mode 100644 etc/codecoverage/index.php create mode 100644 etc/codecoverage/test.php diff --git a/etc/codecoverage/index.php b/etc/codecoverage/index.php new file mode 100644 index 000000000..5ae6c7e3f --- /dev/null +++ b/etc/codecoverage/index.php @@ -0,0 +1,58 @@ +<?php +/** + * Application entry point + * + * Example - run a particular store or website: + * -------------------------------------------- + * require __DIR__ . '/app/bootstrap.php'; + * $params = $_SERVER; + * $params[\Magento\Store\Model\StoreManager::PARAM_RUN_CODE] = 'website2'; + * $params[\Magento\Store\Model\StoreManager::PARAM_RUN_TYPE] = 'website'; + * $bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $params); + * \/** @var \Magento\Framework\App\Http $app *\/ + * $app = $bootstrap->createApplication(\Magento\Framework\App\Http::class); + * $bootstrap->run($app); + * -------------------------------------------- + * + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +try { + require __DIR__ . '/app/bootstrap.php'; +} catch (\Exception $e) { + echo <<<HTML +<div style="font:12px/1.35em arial, helvetica, sans-serif;"> + <div style="margin:0 0 25px 0; border-bottom:1px solid #ccc;"> + <h3 style="margin:0;font-size:1.7em;font-weight:normal;text-transform:none;text-align:left;color:#2f2f2f;"> + Autoload error</h3> + </div> + <p>{$e->getMessage()}</p> +</div> +HTML; + exit(1); +} + +//Patch start +$driver = new pcov\Clobber\Driver\PHPUnit6(); +$coverage = new \SebastianBergmann\CodeCoverage\CodeCoverage($driver); +$coverage->filter()->addDirectoryToWhitelist("app/code/Magento/*"); +$coverage->filter()->removeDirectoryFromWhitelist("app/code/Magento/*/Test"); +$testName = "NO_TEST_NAME"; +if (file_exists(__DIR__ . '/CURRENT_TEST')) { + $testName = file_get_contents(__DIR__ . '/CURRENT_TEST'); +} +$id = !empty($testName) ? $testName : "NO_TEST_NAME"; +$coverage->start($id); +//Patch end + +$bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $_SERVER); +/** @var \Magento\Framework\App\Http $app */ +$app = $bootstrap->createApplication(\Magento\Framework\App\Http::class); +$bootstrap->run($app); + +// Patch start +$coverage->stop(); +$writer = new \SebastianBergmann\CodeCoverage\Report\PHP(); +$writer->process($coverage, '/var/www/html/coverage/reports/' . $id . "_" . md5(mt_rand()) . '.cov'); +// Patch end diff --git a/etc/codecoverage/test.php b/etc/codecoverage/test.php new file mode 100644 index 000000000..0d5daf710 --- /dev/null +++ b/etc/codecoverage/test.php @@ -0,0 +1,4 @@ +<?php +$test = $_GET['test'] ?? "NO_TEST_SPECIFIED"; +file_put_contents('CURRENT_TEST', $test); +echo 'SET CURRENT TEST TO ' . $test; \ No newline at end of file From fbcbe1a48abce101b6ec1e69f64bed74fd8ab353 Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Tue, 31 Mar 2020 17:02:16 -0500 Subject: [PATCH 325/888] MQE-2042: Port MFTF Coverage to Jenkins - Add copyright --- etc/codecoverage/test.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/etc/codecoverage/test.php b/etc/codecoverage/test.php index 0d5daf710..a43388a2c 100644 --- a/etc/codecoverage/test.php +++ b/etc/codecoverage/test.php @@ -1,4 +1,10 @@ <?php + +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + $test = $_GET['test'] ?? "NO_TEST_SPECIFIED"; file_put_contents('CURRENT_TEST', $test); echo 'SET CURRENT TEST TO ' . $test; \ No newline at end of file From 39f62b8f89da5d07cbfabac17fd015f9029ffe38 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Wed, 1 Apr 2020 11:53:46 -0500 Subject: [PATCH 326/888] MQE-2043: Custom helper argument in action group is not resolved --- .../tests/MFTF/DevDocs/ActionGroup/HelperActionGroup.xml | 5 +++-- dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml | 1 + .../Test/Objects/ActionGroupObject.php | 3 +++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/dev/tests/functional/tests/MFTF/DevDocs/ActionGroup/HelperActionGroup.xml b/dev/tests/functional/tests/MFTF/DevDocs/ActionGroup/HelperActionGroup.xml index 4e39a2da1..42159fc66 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/ActionGroup/HelperActionGroup.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/ActionGroup/HelperActionGroup.xml @@ -10,11 +10,12 @@ <actionGroup name="HelperActionGroup"> <arguments> <argument name="test" type="string" /> + <argument name="entityTest" type="entity" /> </arguments> <comment userInput="Action group to demonstrate helper functionality available from action groups." stepKey="comment" /> <helper class="\MFTF\DevDocs\Helper\CustomHelper" method="goTo" stepKey="customHelper"> - <argument name="test">{{contentSection.parametrizedSelector(test)}}</argument> - <argument name="module">['{{test}}', 'Bla']</argument> + <argument name="test">{{contentSection.parametrizedSelector(entityTest.entityField)}}</argument> + <argument name="module">['{{entityTest.entityField}}', 'Bla']</argument> <argument name="url">{{test}}</argument> <argument name="bool">true</argument> <argument name="float">4.400000000234234</argument> diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml b/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml index e7c3bed54..3470a2440 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml @@ -44,6 +44,7 @@ <actionGroup ref="HelperActionGroup" stepKey="actionGroupWithCustomHelper"> <argument name="test" value="{{HelperData.entityField}}" /> + <argument name="entityTest" value="HelperData" /> </actionGroup> </test> </tests> diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php index 3e1afae31..a8027764b 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php @@ -210,6 +210,9 @@ private function getResolvedActionsWithArgs($arguments, $actionReferenceKey) foreach ($this->parsedActions as $action) { $replacementStepKeys[$action->getStepKey()] = $action->getStepKey() . ucfirst($actionReferenceKey); $varAttributes = array_intersect($this->varAttributes, array_keys($action->getCustomActionAttributes())); + if ($action->getType() === ActionObject::ACTION_TYPE_HELPER) { + $varAttributes = array_keys($action->getCustomActionAttributes()); + } // replace createDataKey attributes inside the action group $resolvedActionAttributes = $this->replaceCreateDataKeys($action, $replacementStepKeys); From fd77b39d54bf041d9ce8ea7cd5184d7ebe179b23 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 2 Apr 2020 17:43:21 -0500 Subject: [PATCH 327/888] MQE-1957: Entity Deprecation Reference - Static Check --- .../Console/StaticChecksCommand.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php b/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php index 6473f36bd..82ceb2192 100644 --- a/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php @@ -88,13 +88,17 @@ protected function execute(InputInterface $input, OutputInterface $output) $output->writeln( "\nRunning static check script for: " . $name ); - + $start = microtime(true); $staticCheck->execute($input); + $end = microtime(true); $staticOutput = $staticCheck->getOutput(); LoggingUtil::getInstance()->getLogger(get_class($staticCheck))->info($staticOutput); $output->writeln($staticOutput); $errors += $staticCheck->getErrors(); + $output->writeln( + "\nTotal execution time is " . (string)($end - $start) . " seconds." + ); } if (empty($errors)) { From 844800971f4e6dd5d658a6f5057e54fe79832d51 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 9 Apr 2020 16:10:06 -0500 Subject: [PATCH 328/888] MQE-1957: Entity Deprecation Reference - Static Check --- .../Console/StaticChecksCommand.php | 59 +++++++++++++------ .../DeprecatedEntityUsageCheck.php | 40 ++++++++++--- .../StaticCheck/StaticChecksList.php | 4 +- .../StaticCheck/TestDependencyCheck.php | 7 ++- 4 files changed, 82 insertions(+), 28 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php b/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php index 82ceb2192..c8242c8b1 100644 --- a/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php @@ -18,6 +18,7 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Exception; +use Symfony\Component\Console\Style\SymfonyStyle; class StaticChecksCommand extends Command { @@ -35,6 +36,13 @@ class StaticChecksCommand extends Command */ private $staticCheckObjects; + /** + * Console output style + * + * @var SymfonyStyle + */ + protected $ioStyle; + /** * Configures the current command. * @@ -45,8 +53,8 @@ protected function configure() $list = new StaticChecksList(); $this->allStaticCheckObjects = $list->getStaticChecks(); $staticCheckNames = implode(', ', array_keys($this->allStaticCheckObjects)); - $description = "This command will run all static checks on xml test materials. " - . "Available static check scripts are:\n{$staticCheckNames}"; + $description = 'This command will run all static checks on xml test materials. ' + . 'Available static check scripts are:' . PHP_EOL . $staticCheckNames; $this->setName('static-checks') ->setDescription($description) ->addArgument( @@ -72,36 +80,41 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output) { + $this->ioStyle = new SymfonyStyle($input, $output); try { - $this->validateInputArguments($input); + $this->validateInput($input); } catch (InvalidArgumentException $e) { LoggingUtil::getInstance()->getLogger(StaticChecksCommand::class)->error($e->getMessage()); - $output->writeln($e->getMessage() . " Please fix input arguments and rerun."); + $this->ioStyle->error($e->getMessage() . ' Please fix input argument(s) or option(s) and rerun.'); return 1; } + $cmdFailed = false; $errors = []; foreach ($this->staticCheckObjects as $name => $staticCheck) { LoggingUtil::getInstance()->getLogger(get_class($staticCheck))->info( - "\nRunning static check script for: " . $name - ); - $output->writeln( - "\nRunning static check script for: " . $name + 'Running static check script for: ' . $name . PHP_EOL ); + + $this->ioStyle->text(PHP_EOL . 'Running static check script for: ' . $name . PHP_EOL); $start = microtime(true); - $staticCheck->execute($input); + try { + $staticCheck->execute($input); + } catch (Exception $e) { + $cmdFailed = true; + LoggingUtil::getInstance()->getLogger(get_class($staticCheck))->error($e->getMessage() . PHP_EOL); + $this->ioStyle->error($e->getMessage()); + } $end = microtime(true); + $errors += $staticCheck->getErrors(); $staticOutput = $staticCheck->getOutput(); LoggingUtil::getInstance()->getLogger(get_class($staticCheck))->info($staticOutput); - $output->writeln($staticOutput); - $errors += $staticCheck->getErrors(); - $output->writeln( - "\nTotal execution time is " . (string)($end - $start) . " seconds." - ); - } + $this->ioStyle->text($staticOutput); - if (empty($errors)) { + $this->ioStyle->text('Total execution time is ' . (string)($end - $start) . ' seconds.' . PHP_EOL); + } + if (!$cmdFailed && empty($errors)) { return 0; } else { return 1; @@ -115,7 +128,7 @@ protected function execute(InputInterface $input, OutputInterface $output) * @return void * @throws InvalidArgumentException */ - private function validateInputArguments(InputInterface $input) + private function validateInput(InputInterface $input) { $this->staticCheckObjects = []; $requiredChecksNames = $input->getArgument('names'); @@ -137,8 +150,18 @@ private function validateInputArguments(InputInterface $input) if (!empty($invalidCheckNames)) { throw new InvalidArgumentException( - "Invalid static check script(s): " . implode(', ', $invalidCheckNames) . "." + 'Invalid static check script(s): ' . implode(', ', $invalidCheckNames) . '.' ); } + + if ($input->getOption('path')) { + if ( (count($this->staticCheckObjects) !== 1) + || array_keys($this->staticCheckObjects)[0] !== StaticChecksList::DEPRECATED_ENTITY_USAGE_CHECK_NAME ) + throw new InvalidArgumentException( + '--path option can only be used for "' + . StaticChecksList::DEPRECATED_ENTITY_USAGE_CHECK_NAME + . '".' + ); + } } } diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/DeprecatedEntityUsageCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/DeprecatedEntityUsageCheck.php index 1a3f565b2..f8685a9d8 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/DeprecatedEntityUsageCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/DeprecatedEntityUsageCheck.php @@ -7,6 +7,8 @@ namespace Magento\FunctionalTestingFramework\StaticCheck; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use InvalidArgumentException; +use Exception; use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Page\Objects\SectionObject; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; @@ -16,7 +18,6 @@ use Magento\FunctionalTestingFramework\Test\Objects\TestObject; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Finder\Finder; -use Exception; use Magento\FunctionalTestingFramework\Util\Script\ScriptUtil; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\OperationDefinitionObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Objects\OperationDefinitionObject; @@ -71,7 +72,7 @@ class DeprecatedEntityUsageCheck implements StaticCheckInterface * Checks test dependencies, determined by references in tests versus the dependencies listed in the Magento module * * @param InputInterface $input - * @return string + * @return void * @throws Exception */ public function execute(InputInterface $input) @@ -83,7 +84,7 @@ public function execute(InputInterface $input) $path = $input->getOption('path'); if ($path) { if (!realpath($path)) { - return "Invalid --path option: " . $path; + throw new InvalidArgumentException("Invalid --path option: " . $path); } MftfApplicationConfig::create( true, @@ -92,6 +93,7 @@ public function execute(InputInterface $input) MftfApplicationConfig::LEVEL_DEFAULT, true ); + putenv('CUSTOM_MODULE_PATHS=' . realpath($path)); $modulePaths[] = realpath($path); $includeRootPath = false; } else { @@ -110,9 +112,9 @@ public function execute(InputInterface $input) $this->errors = []; $this->errors += $this->findReferenceErrorsInActionFiles($testXmlFiles); $this->errors += $this->findReferenceErrorsInActionFiles($actionGroupXmlFiles); - $this->errors += $this->findReferenceErrorsInActionFiles($suiteXmlFiles); + $this->errors += $this->findReferenceErrorsInActionFiles($suiteXmlFiles, true); if ($includeRootPath && !empty($rootSuiteXmlFiles)) { - $this->errors += $this->findReferenceErrorsInActionFiles($rootSuiteXmlFiles); + $this->errors += $this->findReferenceErrorsInActionFiles($rootSuiteXmlFiles, true); } $this->errors += $this->findReferenceErrorsInDataFiles($dataXmlFiles); @@ -147,11 +149,12 @@ public function getOutput() /** * Find reference errors in set of action files * - * @param Finder $files + * @param Finder $files + * @param boolean $checkTestRef * @return array * @throws XmlException */ - private function findReferenceErrorsInActionFiles($files) + private function findReferenceErrorsInActionFiles($files, $checkTestRef = false) { $testErrors = []; /** @var SplFileInfo $filePath */ @@ -224,6 +227,23 @@ private function findReferenceErrorsInActionFiles($files) $this->scriptUtil->resolveEntityByNames($getDataReferences) ); + // Find test references if needed + if ($checkTestRef) { + $testReferences = $this->getAttributesFromDOMNodeList( + $domDocument->getElementsByTagName('test'), + 'name' + ); + + // Remove Duplicates + $testReferences = array_unique($testReferences); + + // Resolve test entity by names + $entityReferences = array_merge( + $entityReferences, + $this->scriptUtil->resolveEntityByNames($testReferences) + ); + } + // Find violating references $violatingReferences = $this->findViolatingReferences($entityReferences); @@ -404,12 +424,18 @@ private function getMetadataFromData($references, $type) * [ * $dataName1 => [ * $metaDataName1 => 'all', + * $metaDataName2 => 'all', + * ... * ], * $dataName2 => [ * $metaDataName2 => 'all', + * ... * ], * $dataName5 => [ * $metaDataName5 => 'all', + * $metaDataName4 => 'all', + * $metaDataName1 => 'all', + * ... * ], * ... * ] diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php b/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php index 45619cdc2..063b36f14 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php @@ -13,6 +13,8 @@ */ class StaticChecksList implements StaticCheckListInterface { + const DEPRECATED_ENTITY_USAGE_CHECK_NAME = 'deprecatedEntityUsage'; + /** * Property contains all static check scripts. * @@ -30,7 +32,7 @@ public function __construct(array $checks = []) $this->checks = [ 'testDependencies' => new TestDependencyCheck(), 'actionGroupArguments' => new ActionGroupArgumentsCheck(), - 'deprecatedEntityUsage' => new DeprecatedEntityUsageCheck(), + self::DEPRECATED_ENTITY_USAGE_CHECK_NAME => new DeprecatedEntityUsageCheck(), ] + $checks; } diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php index b97791a6d..9f20f2e08 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php @@ -6,6 +6,7 @@ namespace Magento\FunctionalTestingFramework\StaticCheck; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Symfony\Component\Console\Input\InputInterface; @@ -84,7 +85,7 @@ class TestDependencyCheck implements StaticCheckInterface * Checks test dependencies, determined by references in tests versus the dependencies listed in the Magento module * * @param InputInterface $input - * @return string + * @return void * @throws Exception */ public function execute(InputInterface $input) @@ -93,7 +94,9 @@ public function execute(InputInterface $input) $allModules = $this->scriptUtil->getAllModulePaths(); if (!class_exists('\Magento\Framework\Component\ComponentRegistrar')) { - return "TEST DEPENDENCY CHECK ABORTED: MFTF must be attached or pointing to Magento codebase."; + throw new TestFrameworkException( + "TEST DEPENDENCY CHECK ABORTED: MFTF must be attached or pointing to Magento codebase." + ); } $registrar = new \Magento\Framework\Component\ComponentRegistrar(); $this->moduleNameToPath = $registrar->getPaths(\Magento\Framework\Component\ComponentRegistrar::MODULE); From c406697b3e7721c25219bea32f0e166211d0e8b7 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 13 Apr 2020 18:17:43 -0500 Subject: [PATCH 329/888] MQE-1957: Entity Deprecation Reference - Static Check --- .../Config/FileResolver/Root.php | 2 +- .../DeprecatedEntityUsageCheck.php | 181 ++++++++++++------ .../Util/Script/ScriptUtil.php | 38 +++- 3 files changed, 158 insertions(+), 63 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Config/FileResolver/Root.php b/src/Magento/FunctionalTestingFramework/Config/FileResolver/Root.php index 8593aaf47..230586852 100644 --- a/src/Magento/FunctionalTestingFramework/Config/FileResolver/Root.php +++ b/src/Magento/FunctionalTestingFramework/Config/FileResolver/Root.php @@ -33,7 +33,7 @@ public function get($filename, $scope) ); // include root suite dir when running standalone version - $altPath = MAGENTO_BP . DIRECTORY_SEPARATOR . 'dev/tests/acceptance'; + $altPath = FilePathFormatter::format(MAGENTO_BP) . 'dev/tests/acceptance'; if (realpath($altPath) && ($altPath !== TESTS_BP)) { $paths = array_merge( diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/DeprecatedEntityUsageCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/DeprecatedEntityUsageCheck.php index f8685a9d8..6bcf36b4e 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/DeprecatedEntityUsageCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/DeprecatedEntityUsageCheck.php @@ -9,6 +9,7 @@ use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use InvalidArgumentException; use Exception; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Page\Objects\SectionObject; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; @@ -68,6 +69,41 @@ class DeprecatedEntityUsageCheck implements StaticCheckInterface */ private $dataOperations = ['create', 'update', 'get', 'delete']; + /** + * Test xml files to scan + * + * @var Finder|array + */ + private $testXmlFiles = []; + + /** + * Action group xml files to scan + * + * @var Finder|array + */ + private $actionGroupXmlFiles = []; + + /** + * Suite xml files to scan + * + * @var Finder|array + */ + private $suiteXmlFiles = []; + + /** + * Root suite xml files to scan + * + * @var Finder|array + */ + private $rootSuiteXmlFiles = []; + + /** + * Data xml files to scan + * + * @var Finder|array + */ + private $dataXmlFiles = []; + /** * Checks test dependencies, determined by references in tests versus the dependencies listed in the Magento module * @@ -78,45 +114,16 @@ class DeprecatedEntityUsageCheck implements StaticCheckInterface public function execute(InputInterface $input) { $this->scriptUtil = new ScriptUtil(); - - $modulePaths = []; - $includeRootPath = true; - $path = $input->getOption('path'); - if ($path) { - if (!realpath($path)) { - throw new InvalidArgumentException("Invalid --path option: " . $path); - } - MftfApplicationConfig::create( - true, - MftfApplicationConfig::UNIT_TEST_PHASE, - false, - MftfApplicationConfig::LEVEL_DEFAULT, - true - ); - putenv('CUSTOM_MODULE_PATHS=' . realpath($path)); - $modulePaths[] = realpath($path); - $includeRootPath = false; - } else { - $modulePaths = $this->scriptUtil->getAllModulePaths(); - } - - // These files can contain references to other entities - $testXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, 'Test'); - $actionGroupXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, 'ActionGroup'); - $suiteXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, 'Suite'); - if ($includeRootPath) { - $rootSuiteXmlFiles = $this->scriptUtil->getRootSuiteXmlFiles(); - } - $dataXmlFiles= $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, 'Data'); + $this->loadAllXmlFiles($input); $this->errors = []; - $this->errors += $this->findReferenceErrorsInActionFiles($testXmlFiles); - $this->errors += $this->findReferenceErrorsInActionFiles($actionGroupXmlFiles); - $this->errors += $this->findReferenceErrorsInActionFiles($suiteXmlFiles, true); - if ($includeRootPath && !empty($rootSuiteXmlFiles)) { - $this->errors += $this->findReferenceErrorsInActionFiles($rootSuiteXmlFiles, true); + $this->errors += $this->findReferenceErrorsInActionFiles($this->testXmlFiles); + $this->errors += $this->findReferenceErrorsInActionFiles($this->actionGroupXmlFiles); + $this->errors += $this->findReferenceErrorsInActionFiles($this->suiteXmlFiles, true); + if (!empty($this->rootSuiteXmlFiles)) { + $this->errors += $this->findReferenceErrorsInActionFiles($this->rootSuiteXmlFiles, true); } - $this->errors += $this->findReferenceErrorsInDataFiles($dataXmlFiles); + $this->errors += $this->findReferenceErrorsInDataFiles($this->dataXmlFiles); // Hold on to the output and print any errors to a file $this->output = $this->scriptUtil->printErrorsToFile( @@ -146,6 +153,63 @@ public function getOutput() return $this->output; } + /** + * Read all XML files for scanning + * + * @param InputInterface $input + * @throws Exception + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + */ + private function loadAllXmlFiles($input) + { + $modulePaths = []; + $includeRootPath = true; + $path = $input->getOption('path'); + if ($path) { + if (!realpath($path)) { + throw new InvalidArgumentException('Invalid --path option: ' . $path); + } + MftfApplicationConfig::create( + true, + MftfApplicationConfig::UNIT_TEST_PHASE, + false, + MftfApplicationConfig::LEVEL_DEFAULT, + true + ); + putenv('CUSTOM_MODULE_PATHS=' . realpath($path)); + $modulePaths[] = realpath($path); + $includeRootPath = false; + } else { + $modulePaths = $this->scriptUtil->getAllModulePaths(); + } + + // These files can contain references to other entities + $this->testXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, 'Test'); + $this->actionGroupXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, 'ActionGroup'); + $this->suiteXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, 'Suite'); + if ($includeRootPath) { + $this->rootSuiteXmlFiles = $this->scriptUtil->getRootSuiteXmlFiles(); + } + $this->dataXmlFiles= $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, 'Data'); + + if (empty($this->thistestXmlFiles) + && empty($this->actionGroupXmlFiles) + && empty($this->suiteXmlFiles) + && empty($this->dataXmlFiles) + ) { + if ($path) { + throw new InvalidArgumentException( + 'Invalid --path option: ' + . $path + . PHP_EOL + . 'Please make sure --path points to a valid MFTF Test Module.' + ); + } elseif (empty($this->rootSuiteXmlFiles)) { + throw new TestFrameworkException('No xml file to scan.'); + } + } + } + /** * Find reference errors in set of action files * @@ -190,58 +254,39 @@ private function findReferenceErrorsInActionFiles($files, $checkTestRef = false) // Resolve entity references $entityReferences = $this->scriptUtil->resolveEntityReferences($braceReferences[0], $contents, true); - // Resolve parameterized references $entityReferences = array_merge( $entityReferences, $this->scriptUtil->resolveParametrizedReferences($braceReferences[2], $contents, true) ); - // Resolve action group entity by names $entityReferences = array_merge( $entityReferences, $this->scriptUtil->resolveEntityByNames($actionGroupReferences[1]) ); - // Resolve extends entity by names $entityReferences = array_merge( $entityReferences, $this->scriptUtil->resolveEntityByNames($extendReferences[1]) ); - // Resolve create data entity by names $entityReferences = array_merge( $entityReferences, $this->scriptUtil->resolveEntityByNames($createdDataReferences) ); - // Resolve update data entity by names $entityReferences = array_merge( $entityReferences, $this->scriptUtil->resolveEntityByNames($updatedDataReferences) ); - // Resolve get data entity by names $entityReferences = array_merge( $entityReferences, $this->scriptUtil->resolveEntityByNames($getDataReferences) ); - // Find test references if needed if ($checkTestRef) { - $testReferences = $this->getAttributesFromDOMNodeList( - $domDocument->getElementsByTagName('test'), - 'name' - ); - - // Remove Duplicates - $testReferences = array_unique($testReferences); - - // Resolve test entity by names - $entityReferences = array_merge( - $entityReferences, - $this->scriptUtil->resolveEntityByNames($testReferences) - ); + $entityReferences = array_merge($entityReferences, $this->resolveTestEntityInSuite($domDocument)); } // Find violating references @@ -602,6 +647,30 @@ private function setErrorOutput($violatingReferences, $path) return $testErrors; } + /** + * Resolve test entity in suite + * + * @param \DOMDocument $domDocument + * @return array + */ + private function resolveTestEntityInSuite($domDocument) + { + $testReferences = $this->getAttributesFromDOMNodeList( + $domDocument->getElementsByTagName('test'), + 'name' + ); + + // Remove Duplicates + $testReferences = array_unique($testReferences); + + // Resolve test entity by names + try { + return $this->scriptUtil->resolveEntityByNames($testReferences); + } catch (XmlException $e) { + return []; + } + } + /** * Return subject string for a class name * diff --git a/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php b/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php index 6ef275207..84016721b 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php @@ -32,6 +32,7 @@ class ScriptUtil { const ACTIONGROUP_ARGUMENT_REGEX_PATTERN = '/<argument[^\/>]*name="([^"\']*)/'; const ROOT_SUITE_DIR = 'tests/_suite'; + const DEV_TESTS_DIR = 'dev/tests/acceptance/'; /** * Return all installed Magento module paths @@ -106,18 +107,43 @@ public function getModuleXmlFilesByScope($modulePaths, $scope) * Return suite XML files in TESTS_BP/ROOT_SUITE_DIR directory * * @return Finder|array - * @throws TestFrameworkException + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function getRootSuiteXmlFiles() { - $rootSuitePath = FilePathFormatter::format(TESTS_BP) . self::ROOT_SUITE_DIR; - if (!realpath($rootSuitePath)) { - return []; + $rootSuitePaths = []; + $defaultTestPath = null; + $devTestsPath = null; + + try { + $defaultTestPath = FilePathFormatter::format(TESTS_BP); + } catch (TestFrameworkException $e) { + } + + try { + $devTestsPath = FilePathFormatter::format(MAGENTO_BP) . self::DEV_TESTS_DIR; + } catch (TestFrameworkException $e) { + } + + if ($defaultTestPath) { + $rootSuitePaths[] = $defaultTestPath . self::ROOT_SUITE_DIR; } + + if ($devTestsPath && realpath($devTestsPath) && $devTestsPath !== $defaultTestPath) { + $rootSuitePaths[] = $devTestsPath . self::ROOT_SUITE_DIR; + } + + $found = false; $finder = new Finder(); - $finder->files()->followLinks()->in($rootSuitePath)->name("*.xml"); + foreach ($rootSuitePaths as $rootSuitePath) { + if (!realpath($rootSuitePath)) { + continue; + } + $finder->files()->followLinks()->in($rootSuitePath)->name("*.xml"); + $found = true; + } - return $finder->files(); + return $found ? $finder->files() : []; } /** From 101ead6c33c82dc98d1e5b1db405fd94352a0412 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 13 Apr 2020 18:28:09 -0500 Subject: [PATCH 330/888] MQE-1957: Entity Deprecation Reference - Static Check --- .../StaticCheck/DeprecatedEntityUsageCheck.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/DeprecatedEntityUsageCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/DeprecatedEntityUsageCheck.php index 6bcf36b4e..af5a1835e 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/DeprecatedEntityUsageCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/DeprecatedEntityUsageCheck.php @@ -157,6 +157,7 @@ public function getOutput() * Read all XML files for scanning * * @param InputInterface $input + * @return void * @throws Exception * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ From b6865481b156d00e57bd5688a7435315f49fff74 Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Wed, 15 Apr 2020 13:50:22 -0500 Subject: [PATCH 331/888] Grammar and formatting --- docs/test.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/test.md b/docs/test.md index dd882213b..78021fb26 100644 --- a/docs/test.md +++ b/docs/test.md @@ -1,7 +1,7 @@ # Test Test cases in the Magento Functional Testing Framework (MFTF) are defined in XML as [`<tests>`]. -`<tests>` is a [Codeception test container][Codeception] that contains individual test [`<test>`] with it's metadata ([`<annotations>`]), before ([`<before>`]) and after ([`<after>`]) section. +`<tests>` is a [Codeception test container][Codeception] that contains individual test [`<test>`] with its metadata ([`<annotations>`]), before ([`<before>`]) and after ([`<after>`]) section. MFTF `<test>` is considered a sequence of actions with associated parameters. Any failed [assertion] within a test constitutes a failed test. @@ -18,7 +18,7 @@ The following diagram shows the structure of an MFTF test case: ## Format -The format of Test XML file is: +The format of a test XML file is: ```xml <?xml version="1.0" encoding="UTF-8"?> @@ -35,7 +35,6 @@ The format of Test XML file is: <after> <!-- ACTIONS AND ACTION GROUPS PERFORMED AFTER THE TEST --> </after> - <!-- TEST ACTIONS, ACTION GROUPS, AND ASSERTIONS--> </test> </tests> @@ -47,13 +46,13 @@ The following conventions apply to MFTF tests: * One `<test>` tag is allowed per test XML file. * All names within the framework are in the **PascalCase** format and must be alphanumeric. -* Each action and action group call has its own identifier `<stepKey>` for reference purposes. +* Each action and action group call should have its own identifier `<stepKey>`. * A test may have any number of [assertions][assertion] at any point within the `<test>`. * If `<test>` is included in [`<suite>`][suites], it **cannot be generated in isolation** from `<before>` and `<after>` section of the suite (see [suites] for details). ## Elements reference -There are several XML elements that are used in `<test>` in the MFTF. +There are several XML elements that are used within `<test>` in the MFTF. ### tests {#tests-tag} @@ -92,7 +91,7 @@ Allure annotations provide metadata for reporting. ### after {#after-tag} -`<after>` wraps the steps to perform after the [`<test>`]. The steps are run in both successful **and** failed test runs. The goal of this section is to perform cleanup (revert the environment to the pre-test state). +`<after>` wraps the steps to perform after the [`<test>`]. The steps are run in both successful **and** failed test runs. The goal of this section is to perform cleanup (revert the environment to the pre-test state). `<after>` may contain: From 817214c13c3262f00635b2b474e2f443ea2220f0 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Thu, 16 Apr 2020 11:49:00 -0500 Subject: [PATCH 332/888] MQE-2086: Reduce amount of attachments in Allure reports - Implemented new VERBOSE_ARTIFACTS FLAG --- dev/tests/functional/standalone_bootstrap.php | 3 +++ .../Allure/Adapter/MagentoAllureAdapter.php | 10 ++++++++++ src/Magento/FunctionalTestingFramework/_bootstrap.php | 3 +++ 3 files changed, 16 insertions(+) diff --git a/dev/tests/functional/standalone_bootstrap.php b/dev/tests/functional/standalone_bootstrap.php index 34516236e..58030231d 100755 --- a/dev/tests/functional/standalone_bootstrap.php +++ b/dev/tests/functional/standalone_bootstrap.php @@ -53,6 +53,9 @@ defined('WAIT_TIMEOUT') || define('WAIT_TIMEOUT', 30); $env->setEnvironmentVariable('WAIT_TIMEOUT', WAIT_TIMEOUT); + defined('VERBOSE_ARTIFACTS') || define('VERBOSE_ARTIFACTS', false); + $env->setEnvironmentVariable('VERBOSE_ARTIFACTS', VERBOSE_ARTIFACTS); + try { new DateTimeZone(DEFAULT_TIMEZONE); } catch (\Exception $e) { diff --git a/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php b/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php index e9e1c344c..5b5a96b22 100644 --- a/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php +++ b/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php @@ -10,6 +10,7 @@ use Magento\FunctionalTestingFramework\Test\Objects\ActionGroupObject; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Magento\FunctionalTestingFramework\Util\TestGenerator; +use Yandex\Allure\Adapter\Model\Provider; use Yandex\Allure\Adapter\Model\Status; use Yandex\Allure\Adapter\Model\Step; use Yandex\Allure\Codeception\AllureCodeception; @@ -250,6 +251,8 @@ public function testError(FailEvent $failEvent) */ public function testEnd() { + // Peek top of testCaseStorage to check of failure + $testFailed = $this->getLifecycle()->getTestCaseStorage()->get()->getFailure(); // Pops top of stepStorage, need to add it back in after processing $rootStep = $this->getLifecycle()->getStepStorage()->pollLast(); $formattedSteps = []; @@ -257,6 +260,13 @@ public function testEnd() $actionGroupStepKey = null; foreach ($rootStep->getSteps() as $step) { + //Remove Attachments if verbose flag is not true AND test did not fail + if (getenv('VERBOSE_ARTIFACTS') !== true && $testFailed === null) { + foreach ($step->getAttachments() as $index => $attachment) { + $step->removeAttachment($index); + unlink(Provider::getOutputDirectory() . DIRECTORY_SEPARATOR . $attachment->getSource()); + } + } $stepKey = str_replace($actionGroupStepKey, '', $step->getName()); if ($stepKey !== '[]' && $stepKey !== null) { $step->setName($stepKey); diff --git a/src/Magento/FunctionalTestingFramework/_bootstrap.php b/src/Magento/FunctionalTestingFramework/_bootstrap.php index e35b20bad..b655fb28e 100644 --- a/src/Magento/FunctionalTestingFramework/_bootstrap.php +++ b/src/Magento/FunctionalTestingFramework/_bootstrap.php @@ -53,6 +53,9 @@ defined('WAIT_TIMEOUT') || define('WAIT_TIMEOUT', 30); $env->setEnvironmentVariable('WAIT_TIMEOUT', WAIT_TIMEOUT); + defined('VERBOSE_ARTIFACTS') || define('VERBOSE_ARTIFACTS', false); + $env->setEnvironmentVariable('VERBOSE_ARTIFACTS', VERBOSE_ARTIFACTS); + try { new DateTimeZone(DEFAULT_TIMEZONE); } catch (\Exception $e) { From b84ced35a73ff9d915bcd1c9313d6822e9b12a63 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Thu, 16 Apr 2020 12:40:57 -0500 Subject: [PATCH 333/888] MQE-2086: Reduce amount of attachments in Allure reports - Static check fixes --- .../Allure/Adapter/MagentoAllureAdapter.php | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php b/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php index 5b5a96b22..bc0d0a91c 100644 --- a/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php +++ b/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php @@ -10,6 +10,7 @@ use Magento\FunctionalTestingFramework\Test\Objects\ActionGroupObject; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Magento\FunctionalTestingFramework\Util\TestGenerator; +use Yandex\Allure\Adapter\Model\Failure; use Yandex\Allure\Adapter\Model\Provider; use Yandex\Allure\Adapter\Model\Status; use Yandex\Allure\Adapter\Model\Step; @@ -260,13 +261,7 @@ public function testEnd() $actionGroupStepKey = null; foreach ($rootStep->getSteps() as $step) { - //Remove Attachments if verbose flag is not true AND test did not fail - if (getenv('VERBOSE_ARTIFACTS') !== true && $testFailed === null) { - foreach ($step->getAttachments() as $index => $attachment) { - $step->removeAttachment($index); - unlink(Provider::getOutputDirectory() . DIRECTORY_SEPARATOR . $attachment->getSource()); - } - } + $this->removeAttachments($step, $testFailed); $stepKey = str_replace($actionGroupStepKey, '', $step->getName()); if ($stepKey !== '[]' && $stepKey !== null) { $step->setName($stepKey); @@ -364,4 +359,21 @@ private function retrieveStepKey($stepLine) return $stepKey; } + + /** + * Removes attachments from step depending on MFTF configuration + * @param Step $step + * @param Failure $testFailed + * @return void + */ + private function removeAttachments($step, $testFailed) + { + //Remove Attachments if verbose flag is not true AND test did not fail + if (getenv('VERBOSE_ARTIFACTS') !== true && $testFailed === null) { + foreach ($step->getAttachments() as $index => $attachment) { + $step->removeAttachment($index); + unlink(Provider::getOutputDirectory() . DIRECTORY_SEPARATOR . $attachment->getSource()); + } + } + } } From 0fca63b1d22918b0198ca7a903eeb50cba758c72 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Fri, 17 Apr 2020 09:16:10 -0500 Subject: [PATCH 334/888] MQE-2086: Reduce amount of attachments in Allure reports - Docs update --- docs/configuration.md | 14 ++++++++++++++ etc/config/.env.example | 3 +++ 2 files changed, 17 insertions(+) diff --git a/docs/configuration.md b/docs/configuration.md index 9466f2bcc..11882084e 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -299,6 +299,20 @@ Example: CREDENTIAL_AWS_SECRETS_MANAGER_PROFILE=default ``` +### VERBOSE_ARTIFACTS + +Determines if passed tests should still have all their Allure artifacts. These artifacts include `.txt` attachments for things like `dontSee` actions and `createData` actions. + +If enabled, all tests will have all of their normal Allure artifacts. + +If disabled, passed tests will have their Allure artifacts trimmed. Failed tests will still contain all their artifacts. + +This is set `false` by default. + +```conf +VERBOSE_ARTIFACTS=true +``` + ### ENABLE_BROWSER_LOG Enables addition of browser logs to Allure steps diff --git a/etc/config/.env.example b/etc/config/.env.example index 349d7da9c..86df31b3d 100644 --- a/etc/config/.env.example +++ b/etc/config/.env.example @@ -59,6 +59,9 @@ MODULE_WHITELIST=Magento_Framework,ConfigurableProductWishlist,ConfigurableProdu #*** Default timeout for wait actions #WAIT_TIMEOUT=30 +#*** Uncomment and set to enable all tests, regardless of passing status, to have all their Allure artifacts. +#VERBOSE_ARTIFACTS=true + #*** Uncomment and set to enable browser log entries on actions in Allure. Blacklist is used to filter logs of a specific "source" #ENABLE_BROWSER_LOG=true #BROWSER_LOG_BLACKLIST=other From 5ac5683da4f0666c7098f62dcbb08c476ef09d2c Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Fri, 17 Apr 2020 10:08:05 -0500 Subject: [PATCH 335/888] MQE-1704: MFTF Compatibility with PHPUnit 9 (#657) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * MQE-1704: MFTF Compatibility with PHPUnit 8 Upgraded PhpUnit + Codeception * MQE-1704: MFTF Compatibility with PHPUnit 8 Added codeception modeule-* dependencies to fix functional tests * MQE-1704: MFTF Compatibility with PHPUnit 8 fixed static checks * MQE-1704: MFTF Compatibility with PHPUnit 8 Fixed phpmd error * MQE-1704: MFTF Compatibility with PHPUnit 8 Removed pauseExecution to use pause * MQE-1704: MFTF Compatibility with PHPUnit 8 Override switchToIFrame to include find by ID. * MQE-2040: Unable to run suites from standalone MFTF fixed static checks, fixed for MagentoAllureAdapter * MQE-1704: MFTF Compatibility with PHPUnit 9 Updated to PHPUnit 9 and fixed unit tests * MQE-1704: MFTF Compatibility with PHPUnit 9 remove PHP 7.2 support * MQE-1704: MFTF Compatibility with PHPUnit 9 added Pause to MagentoWebDriver.php for step generation in console/allure * MQE-2078: [PHPUnit 9] assertContains and assertNotContains breaking c… (#673) * MQE-2078: [PHPUnit 9] assertContains and assertNotContains breaking changes added new actions assertStringContainsString assertStringContainsStringIgnoringCase * MQE-2078: [PHPUnit 9] assertContains and assertNotContains breaking changes Added additional documentation for assertContains * Grammar fixes Co-authored-by: Donald Booth <dobooth@adobe.com> Co-authored-by: Donald Booth <dobooth@adobe.com> --- .travis.yml | 1 - composer.json | 13 +- composer.lock | 1091 ++++++++++------- .../Allure/AllureHelperTest.php | 2 +- .../Composer/ComposerInstallTest.php | 2 +- .../Composer/ComposerPackageTest.php | 2 +- .../Config/Reader/FilesystemTest.php | 4 +- .../Console/BaseGenerateCommandTest.php | 2 +- .../Handlers/PersistedObjectHandlerTest.php | 6 +- .../Objects/EntityDataObjectTest.php | 4 +- .../OperationDataArrayResolverTest.php | 4 +- .../Util/DataExtensionUtilTest.php | 2 +- .../Page/Objects/ElementObjectTest.php | 4 +- .../Suite/Handlers/SuiteObjectHandlerTest.php | 2 +- .../Suite/SuiteGeneratorTest.php | 10 +- .../Test/Config/ActionGroupDomTest.php | 2 +- .../Test/Config/DomTest.php | 4 +- .../Test/Handlers/TestObjectHandlerTest.php | 2 +- .../Test/Objects/ActionGroupObjectTest.php | 8 +- .../Test/Objects/ActionObjectTest.php | 4 +- .../ActionGroupAnnotationExtractorTest.php | 4 +- .../Util/ActionGroupObjectExtractorTest.php | 4 +- .../Test/Util/ActionMergeUtilTest.php | 4 +- .../Test/Util/ActionObjectExtractorTest.php | 4 +- .../Test/Util/AnnotationExtractorTest.php | 4 +- .../Test/Util/ObjectExtensionUtilTest.php | 4 +- .../Util/ModuleResolverTest.php | 6 +- .../Util/TestGeneratorTest.php | 12 +- dev/tests/unit/Util/MagentoTestCase.php | 4 +- .../verification/Resources/AssertTest.txt | 7 +- .../Resources/BasicFunctionalTest.txt | 2 +- .../ActionGroup/XmlDuplicateActionGroup.xml | 4 +- .../TestModule/Test/AssertTest.xml | 22 +- .../BasicFunctionalTest.xml | 2 +- .../XmlDuplicateTest/XmlDuplicateTest.xml | 12 +- .../Tests/SchemaValidationTest.php | 2 +- .../Tests/SuiteGenerationTest.php | 8 +- docs/test/actions.md | 6 +- docs/test/assertions.md | 47 +- etc/di.xml | 2 +- .../Allure/Adapter/MagentoAllureAdapter.php | 29 +- .../Module/MagentoWebDriver.php | 29 +- .../Test/etc/Actions/assertActions.xsd | 60 + .../Test/etc/actionTypeTags.xsd | 4 +- .../Util/TestGenerator.php | 4 + 45 files changed, 885 insertions(+), 570 deletions(-) diff --git a/.travis.yml b/.travis.yml index fba3b46ae..bc0d6a5db 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: php php: - - 7.2 - 7.3 services: - docker diff --git a/composer.json b/composer.json index a66ce80bb..1e5cebdce 100755 --- a/composer.json +++ b/composer.json @@ -9,14 +9,17 @@ "sort-packages": true }, "require": { - "php": "~7.2.0||~7.3.0", + "php": "^7.3", "ext-curl": "*", "ext-dom": "*", "ext-json": "*", "ext-openssl": "*", - "allure-framework/allure-codeception": "~1.3.0", + "allure-framework/allure-codeception": "~1.4.0", "aws/aws-sdk-php": "^3.132", - "codeception/codeception": "~2.4.5", + "codeception/codeception": "~4.1.4", + "codeception/module-asserts": "^1.1", + "codeception/module-sequence": "^1.0", + "codeception/module-webdriver": "^1.0", "composer/composer": "^1.6", "csharpru/vault-php": "~3.5.3", "csharpru/vault-php-guzzle6-transport": "^2.0", @@ -31,14 +34,14 @@ }, "require-dev": { "squizlabs/php_codesniffer": "~3.2", - "sebastian/phpcpd": "~3.0 || ~4.0", + "sebastian/phpcpd": "~4.0||~5.0", "brainmaestro/composer-git-hooks": "^2.3.1", "doctrine/cache": "<1.7.0", "codeception/aspect-mock": "^3.0", "goaop/framework": "2.2.0", "codacy/coverage": "^1.4", "phpmd/phpmd": "^2.6.0", - "phpunit/phpunit": "~6.5.0 || ~7.0.0", + "phpunit/phpunit": "~9.0.0", "rregeer/phpunit-coverage-check": "^0.1.4", "php-coveralls/php-coveralls": "^1.0", "symfony/stopwatch": "~3.4.6" diff --git a/composer.lock b/composer.lock index bbab8dbd4..22e562cef 100644 --- a/composer.lock +++ b/composer.lock @@ -4,26 +4,26 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "8ad8319a9bd27934c8bdc036729d4fac", + "content-hash": "727146c7b29909e5d60e4c7f3ed5f268", "packages": [ { "name": "allure-framework/allure-codeception", - "version": "1.3.0", + "version": "1.4.3", "source": { "type": "git", "url": "https://github.com/allure-framework/allure-codeception.git", - "reference": "9d31d781b3622b028f1f6210bc76ba88438bd518" + "reference": "9e0e25f8960fa5ac17c65c932ea8153ce6700713" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/allure-framework/allure-codeception/zipball/9d31d781b3622b028f1f6210bc76ba88438bd518", - "reference": "9d31d781b3622b028f1f6210bc76ba88438bd518", + "url": "https://api.github.com/repos/allure-framework/allure-codeception/zipball/9e0e25f8960fa5ac17c65c932ea8153ce6700713", + "reference": "9e0e25f8960fa5ac17c65c932ea8153ce6700713", "shasum": "" }, "require": { - "allure-framework/allure-php-api": "~1.1.0", - "codeception/codeception": "~2.1", - "php": ">=5.4.0", + "allure-framework/allure-php-api": "~1.1.8", + "codeception/codeception": "^2.3|^3.0|^4.0", + "php": ">=5.6", "symfony/filesystem": ">=2.6", "symfony/finder": ">=2.6" }, @@ -55,7 +55,7 @@ "steps", "testing" ], - "time": "2018-12-18T19:47:23+00:00" + "time": "2020-03-13T11:07:13+00:00" }, { "name": "allure-framework/allure-php-api", @@ -112,16 +112,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.133.38", + "version": "3.133.44", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "5ec9442162d83f94918bc17136a2b674a04784e5" + "reference": "00df425deebdde3f3bebfde446a4250695dc47e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/5ec9442162d83f94918bc17136a2b674a04784e5", - "reference": "5ec9442162d83f94918bc17136a2b674a04784e5", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/00df425deebdde3f3bebfde446a4250695dc47e4", + "reference": "00df425deebdde3f3bebfde446a4250695dc47e4", "shasum": "" }, "require": { @@ -192,7 +192,7 @@ "s3", "sdk" ], - "time": "2020-03-17T18:16:01+00:00" + "time": "2020-03-25T18:15:47+00:00" }, { "name": "behat/gherkin", @@ -348,57 +348,51 @@ }, { "name": "codeception/codeception", - "version": "2.4.5", + "version": "4.1.4", "source": { "type": "git", "url": "https://github.com/Codeception/Codeception.git", - "reference": "5fee32d5c82791548931cbc34806b4de6aa1abfc" + "reference": "55d8d1d882fa0777e47de17b04c29b3c50fe29e7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/Codeception/zipball/5fee32d5c82791548931cbc34806b4de6aa1abfc", - "reference": "5fee32d5c82791548931cbc34806b4de6aa1abfc", + "url": "https://api.github.com/repos/Codeception/Codeception/zipball/55d8d1d882fa0777e47de17b04c29b3c50fe29e7", + "reference": "55d8d1d882fa0777e47de17b04c29b3c50fe29e7", "shasum": "" }, "require": { "behat/gherkin": "^4.4.0", - "codeception/phpunit-wrapper": "^6.0.9|^7.0.6", - "codeception/stub": "^2.0", + "codeception/lib-asserts": "^1.0", + "codeception/phpunit-wrapper": ">6.0.15 <6.1.0 | ^6.6.1 | ^7.7.1 | ^8.1.1 | ^9.0", + "codeception/stub": "^2.0 | ^3.0", + "ext-curl": "*", "ext-json": "*", "ext-mbstring": "*", - "facebook/webdriver": ">=1.1.3 <2.0", - "guzzlehttp/guzzle": ">=4.1.4 <7.0", - "guzzlehttp/psr7": "~1.0", + "guzzlehttp/psr7": "~1.4", "php": ">=5.6.0 <8.0", - "symfony/browser-kit": ">=2.7 <5.0", - "symfony/console": ">=2.7 <5.0", - "symfony/css-selector": ">=2.7 <5.0", - "symfony/dom-crawler": ">=2.7 <5.0", - "symfony/event-dispatcher": ">=2.7 <5.0", - "symfony/finder": ">=2.7 <5.0", - "symfony/yaml": ">=2.7 <5.0" + "symfony/console": ">=2.7 <6.0", + "symfony/css-selector": ">=2.7 <6.0", + "symfony/event-dispatcher": ">=2.7 <6.0", + "symfony/finder": ">=2.7 <6.0", + "symfony/yaml": ">=2.7 <6.0" }, "require-dev": { + "codeception/module-asserts": "*@dev", + "codeception/module-cli": "*@dev", + "codeception/module-db": "*@dev", + "codeception/module-filesystem": "*@dev", + "codeception/module-phpbrowser": "*@dev", "codeception/specify": "~0.3", - "facebook/graph-sdk": "~5.3", - "flow/jsonpath": "~0.2", + "codeception/util-universalframework": "*@dev", "monolog/monolog": "~1.8", - "pda/pheanstalk": "~3.0", - "php-amqplib/php-amqplib": "~2.4", - "predis/predis": "^1.0", "squizlabs/php_codesniffer": "~2.0", - "symfony/process": ">=2.7 <5.0", - "vlucas/phpdotenv": "^2.4.0" + "symfony/process": ">=2.7 <6.0", + "vlucas/phpdotenv": "^2.0 | ^3.0 | ^4.0" }, "suggest": { - "aws/aws-sdk-php": "For using AWS Auth in REST module and Queue module", - "codeception/phpbuiltinserver": "Start and stop PHP built-in web server for your tests", "codeception/specify": "BDD-style code blocks", "codeception/verify": "BDD-style assertions", - "flow/jsonpath": "For using JSONPath in REST module", - "league/factory-muffin": "For DataFactory module", - "league/factory-muffin-faker": "For Faker support in DataFactory module", - "phpseclib/phpseclib": "for SFTP option in FTP Module", + "hoa/console": "For interactive console functionality", "stecman/symfony-console-completion": "For BASH autocompletion", "symfony/phpunit-bridge": "For phpunit-bridge support" }, @@ -411,7 +405,7 @@ }, "autoload": { "psr-4": { - "Codeception\\": "src\\Codeception", + "Codeception\\": "src/Codeception", "Codeception\\Extension\\": "ext" } }, @@ -435,36 +429,229 @@ "functional testing", "unit testing" ], - "time": "2018-08-01T07:21:49+00:00" + "time": "2020-03-23T17:07:20+00:00" + }, + { + "name": "codeception/lib-asserts", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/Codeception/lib-asserts.git", + "reference": "74bfe433af24e2f75c6386b9d843ec69029f4337" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/lib-asserts/zipball/74bfe433af24e2f75c6386b9d843ec69029f4337", + "reference": "74bfe433af24e2f75c6386b9d843ec69029f4337", + "shasum": "" + }, + "require": { + "codeception/phpunit-wrapper": ">6.0.15 <6.1.0 | ^6.6.1 | ^7.7.1 | ^8.0.3 | ^9.0", + "php": ">=5.6.0 <8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Bodnarchuk", + "email": "davert@mail.ua", + "homepage": "http://codegyre.com" + }, + { + "name": "Gintautas Miselis" + } + ], + "description": "Assertion methods used by Codeception core and Asserts module", + "homepage": "http://codeception.com/", + "keywords": [ + "codeception" + ], + "time": "2020-02-07T17:47:55+00:00" + }, + { + "name": "codeception/module-asserts", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/Codeception/module-asserts.git", + "reference": "87c83ca3ccfbc0d79f5effb57e1f82eeaab0cb3e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/module-asserts/zipball/87c83ca3ccfbc0d79f5effb57e1f82eeaab0cb3e", + "reference": "87c83ca3ccfbc0d79f5effb57e1f82eeaab0cb3e", + "shasum": "" + }, + "require": { + "codeception/codeception": "*@dev", + "codeception/lib-asserts": "^1.0.0", + "php": ">=5.6.0 <8.0" + }, + "conflict": { + "codeception/codeception": "<4.0" + }, + "require-dev": { + "codeception/util-robohelpers": "dev-master" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Bodnarchuk" + }, + { + "name": "Gintautas Miselis" + } + ], + "description": "Codeception module containing various assertions", + "homepage": "http://codeception.com/", + "keywords": [ + "assertions", + "asserts", + "codeception" + ], + "time": "2019-11-13T17:32:27+00:00" + }, + { + "name": "codeception/module-sequence", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/Codeception/module-sequence.git", + "reference": "70563527b768194d6ab22e1ff943a5e69741c5dd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/module-sequence/zipball/70563527b768194d6ab22e1ff943a5e69741c5dd", + "reference": "70563527b768194d6ab22e1ff943a5e69741c5dd", + "shasum": "" + }, + "require": { + "codeception/codeception": "4.0.x-dev | ^4.0", + "php": ">=5.6.0 <8.0" + }, + "require-dev": { + "codeception/util-robohelpers": "dev-master" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Bodnarchuk" + } + ], + "description": "Sequence module for Codeception", + "homepage": "http://codeception.com/", + "keywords": [ + "codeception" + ], + "time": "2019-10-10T12:08:50+00:00" + }, + { + "name": "codeception/module-webdriver", + "version": "1.0.6", + "source": { + "type": "git", + "url": "https://github.com/Codeception/module-webdriver.git", + "reference": "9ee54108860859b120ed4a22e50f37d33aa3a518" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/module-webdriver/zipball/9ee54108860859b120ed4a22e50f37d33aa3a518", + "reference": "9ee54108860859b120ed4a22e50f37d33aa3a518", + "shasum": "" + }, + "require": { + "codeception/codeception": "^4.0", + "php": ">=5.6.0 <8.0", + "php-webdriver/webdriver": "^1.6.0" + }, + "require-dev": { + "codeception/util-robohelpers": "dev-master" + }, + "suggest": { + "codeception/phpbuiltinserver": "Start and stop PHP built-in web server for your tests" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Bodnarchuk" + }, + { + "name": "Gintautas Miselis" + }, + { + "name": "Zaahid Bateson" + } + ], + "description": "WebDriver module for Codeception", + "homepage": "http://codeception.com/", + "keywords": [ + "acceptance-testing", + "browser-testing", + "codeception" + ], + "time": "2020-03-23T17:08:27+00:00" }, { "name": "codeception/phpunit-wrapper", - "version": "7.0.6", + "version": "9.0.1", "source": { "type": "git", "url": "https://github.com/Codeception/phpunit-wrapper.git", - "reference": "e8528cb777cf5a5ccea1cf57a3522b142625d1b5" + "reference": "cf5954ca7cbe9ac6eddd3c9e9ce866c27ec8b906" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/phpunit-wrapper/zipball/e8528cb777cf5a5ccea1cf57a3522b142625d1b5", - "reference": "e8528cb777cf5a5ccea1cf57a3522b142625d1b5", + "url": "https://api.github.com/repos/Codeception/phpunit-wrapper/zipball/cf5954ca7cbe9ac6eddd3c9e9ce866c27ec8b906", + "reference": "cf5954ca7cbe9ac6eddd3c9e9ce866c27ec8b906", "shasum": "" }, "require": { - "phpunit/php-code-coverage": "^6.0", - "phpunit/phpunit": "^7.0", - "sebastian/comparator": "^2.0", - "sebastian/diff": "^3.0" + "php": ">=7.2", + "phpunit/phpunit": "^9.0" }, "require-dev": { "codeception/specify": "*", - "vlucas/phpdotenv": "^2.4" + "vlucas/phpdotenv": "^3.0" }, "type": "library", "autoload": { "psr-4": { - "Codeception\\PHPUnit\\": "src\\" + "Codeception\\PHPUnit\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -475,27 +662,30 @@ { "name": "Davert", "email": "davert.php@resend.cc" + }, + { + "name": "Naktibalda" } ], "description": "PHPUnit classes used by Codeception", - "time": "2018-03-31T18:49:51+00:00" + "time": "2020-03-20T07:44:37+00:00" }, { "name": "codeception/stub", - "version": "2.0.4", + "version": "3.6.1", "source": { "type": "git", "url": "https://github.com/Codeception/Stub.git", - "reference": "f50bc271f392a2836ff80690ce0c058efe1ae03e" + "reference": "a3ba01414cbee76a1bced9f9b6b169cc8d203880" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/Stub/zipball/f50bc271f392a2836ff80690ce0c058efe1ae03e", - "reference": "f50bc271f392a2836ff80690ce0c058efe1ae03e", + "url": "https://api.github.com/repos/Codeception/Stub/zipball/a3ba01414cbee76a1bced9f9b6b169cc8d203880", + "reference": "a3ba01414cbee76a1bced9f9b6b169cc8d203880", "shasum": "" }, "require": { - "phpunit/phpunit": ">=4.8 <8.0" + "phpunit/phpunit": "^8.4 | ^9.0" }, "type": "library", "autoload": { @@ -508,7 +698,7 @@ "MIT" ], "description": "Flexible Stub wrapper for PHPUnit's Mock Builder", - "time": "2018-07-26T11:55:37+00:00" + "time": "2020-02-07T18:42:28+00:00" }, { "name": "composer/ca-bundle", @@ -2009,22 +2199,22 @@ }, { "name": "phar-io/manifest", - "version": "1.0.1", + "version": "1.0.3", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0" + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0", - "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", "shasum": "" }, "require": { "ext-dom": "*", "ext-phar": "*", - "phar-io/version": "^1.0.1", + "phar-io/version": "^2.0", "php": "^5.6 || ^7.0" }, "type": "library", @@ -2060,20 +2250,20 @@ } ], "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "time": "2017-03-05T18:14:27+00:00" + "time": "2018-07-08T19:23:20+00:00" }, { "name": "phar-io/version", - "version": "1.0.1", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/phar-io/version.git", - "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df" + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df", - "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df", + "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", "shasum": "" }, "require": { @@ -2107,7 +2297,7 @@ } ], "description": "Library for handling version information and constraints", - "time": "2017-03-05T17:38:23+00:00" + "time": "2018-07-08T19:19:57+00:00" }, { "name": "php-webdriver/webdriver", @@ -2375,20 +2565,20 @@ }, { "name": "phpoption/phpoption", - "version": "1.7.2", + "version": "1.7.3", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "77f7c4d2e65413aff5b5a8cc8b3caf7a28d81959" + "reference": "4acfd6a4b33a509d8c88f50e5222f734b6aeebae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/77f7c4d2e65413aff5b5a8cc8b3caf7a28d81959", - "reference": "77f7c4d2e65413aff5b5a8cc8b3caf7a28d81959", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/4acfd6a4b33a509d8c88f50e5222f734b6aeebae", + "reference": "4acfd6a4b33a509d8c88f50e5222f734b6aeebae", "shasum": "" }, "require": { - "php": "^5.5.9 || ^7.0" + "php": "^5.5.9 || ^7.0 || ^8.0" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.3", @@ -2426,7 +2616,7 @@ "php", "type" ], - "time": "2019-12-15T19:35:24+00:00" + "time": "2020-03-21T18:07:53+00:00" }, { "name": "phpspec/prophecy", @@ -2493,40 +2683,41 @@ }, { "name": "phpunit/php-code-coverage", - "version": "6.0.5", + "version": "8.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "4cab20a326d14de7575a8e235c70d879b569a57a" + "reference": "31e94ccc084025d6abee0585df533eb3a792b96a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/4cab20a326d14de7575a8e235c70d879b569a57a", - "reference": "4cab20a326d14de7575a8e235c70d879b569a57a", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/31e94ccc084025d6abee0585df533eb3a792b96a", + "reference": "31e94ccc084025d6abee0585df533eb3a792b96a", "shasum": "" }, "require": { "ext-dom": "*", "ext-xmlwriter": "*", - "php": "^7.1", - "phpunit/php-file-iterator": "^1.4.2", - "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^3.0", - "sebastian/code-unit-reverse-lookup": "^1.0.1", - "sebastian/environment": "^3.1", - "sebastian/version": "^2.0.1", - "theseer/tokenizer": "^1.1" + "php": "^7.3", + "phpunit/php-file-iterator": "^3.0", + "phpunit/php-text-template": "^2.0", + "phpunit/php-token-stream": "^4.0", + "sebastian/code-unit-reverse-lookup": "^2.0", + "sebastian/environment": "^5.0", + "sebastian/version": "^3.0", + "theseer/tokenizer": "^1.1.3" }, "require-dev": { - "phpunit/phpunit": "^7.0" + "phpunit/phpunit": "^9.0" }, "suggest": { - "ext-xdebug": "^2.6.0" + "ext-pcov": "*", + "ext-xdebug": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "6.0-dev" + "dev-master": "8.0-dev" } }, "autoload": { @@ -2552,29 +2743,32 @@ "testing", "xunit" ], - "time": "2018-05-28T11:49:20+00:00" + "time": "2020-02-19T13:41:19+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "1.4.5", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" + "reference": "354d4a5faa7449a377a18b94a2026ca3415e3d7a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/354d4a5faa7449a377a18b94a2026ca3415e3d7a", + "reference": "354d4a5faa7449a377a18b94a2026ca3415e3d7a", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4.x-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -2589,7 +2783,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -2599,26 +2793,38 @@ "filesystem", "iterator" ], - "time": "2017-11-27T13:52:08+00:00" + "time": "2020-02-07T06:05:22+00:00" }, { - "name": "phpunit/php-text-template", - "version": "1.2.1", + "name": "phpunit/php-invoker", + "version": "3.0.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "7579d5a1ba7f3ac11c80004d205877911315ae7a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/7579d5a1ba7f3ac11c80004d205877911315ae7a", + "reference": "7579d5a1ba7f3ac11c80004d205877911315ae7a", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^7.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^9.0" + }, + "suggest": { + "ext-pcntl": "*" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, "autoload": { "classmap": [ "src/" @@ -2635,37 +2841,34 @@ "role": "lead" } ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", "keywords": [ - "template" + "process" ], - "time": "2015-06-21T13:50:34+00:00" + "time": "2020-02-07T06:06:11+00:00" }, { - "name": "phpunit/php-timer", - "version": "2.1.2", + "name": "phpunit/php-text-template", + "version": "2.0.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "1038454804406b0b5f5f520358e78c1c2f71501e" + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "526dc996cc0ebdfa428cd2dfccd79b7b53fee346" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/1038454804406b0b5f5f520358e78c1c2f71501e", - "reference": "1038454804406b0b5f5f520358e78c1c2f71501e", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/526dc996cc0ebdfa428cd2dfccd79b7b53fee346", + "reference": "526dc996cc0ebdfa428cd2dfccd79b7b53fee346", "shasum": "" }, "require": { - "php": "^7.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.0" + "php": "^7.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -2684,38 +2887,37 @@ "role": "lead" } ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", "keywords": [ - "timer" + "template" ], - "time": "2019-06-07T04:22:29+00:00" + "time": "2020-02-01T07:43:44+00:00" }, { - "name": "phpunit/php-token-stream", - "version": "3.1.1", + "name": "phpunit/php-timer", + "version": "3.0.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff" + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "4118013a4d0f97356eae8e7fb2f6c6472575d1df" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/995192df77f63a59e47f025390d2d1fdf8f425ff", - "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/4118013a4d0f97356eae8e7fb2f6c6472575d1df", + "reference": "4118013a4d0f97356eae8e7fb2f6c6472575d1df", "shasum": "" }, "require": { - "ext-tokenizer": "*", - "php": "^7.1" + "php": "^7.3" }, "require-dev": { - "phpunit/phpunit": "^7.0" + "phpunit/phpunit": "^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -2730,69 +2932,42 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", "keywords": [ - "tokenizer" + "timer" ], - "time": "2019-09-17T06:23:10+00:00" + "time": "2020-02-07T06:08:11+00:00" }, { - "name": "phpunit/phpunit", - "version": "7.0.3", + "name": "phpunit/php-token-stream", + "version": "4.0.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "536f4d853c12d8189963435088e8ff7c0daeab2e" + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "b2560a0c33f7710e4d7f8780964193e8e8f8effe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/536f4d853c12d8189963435088e8ff7c0daeab2e", - "reference": "536f4d853c12d8189963435088e8ff7c0daeab2e", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/b2560a0c33f7710e4d7f8780964193e8e8f8effe", + "reference": "b2560a0c33f7710e4d7f8780964193e8e8f8effe", "shasum": "" }, "require": { - "ext-dom": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-mbstring": "*", - "ext-xml": "*", - "myclabs/deep-copy": "^1.6.1", - "phar-io/manifest": "^1.0.1", - "phar-io/version": "^1.0", - "php": "^7.1", - "phpspec/prophecy": "^1.7", - "phpunit/php-code-coverage": "^6.0.1", - "phpunit/php-file-iterator": "^1.4.3", - "phpunit/php-text-template": "^1.2.1", - "phpunit/php-timer": "^2.0", - "phpunit/phpunit-mock-objects": "^6.0", - "sebastian/comparator": "^2.1", - "sebastian/diff": "^3.0", - "sebastian/environment": "^3.1", - "sebastian/exporter": "^3.1", - "sebastian/global-state": "^2.0", - "sebastian/object-enumerator": "^3.0.3", - "sebastian/resource-operations": "^1.0", - "sebastian/version": "^2.0.1" + "ext-tokenizer": "*", + "php": "^7.3" }, "require-dev": { - "ext-pdo": "*" + "phpunit/phpunit": "^9.0" }, - "suggest": { - "ext-xdebug": "*", - "phpunit/php-invoker": "^2.0" - }, - "bin": [ - "phpunit" - ], "type": "library", "extra": { "branch-alias": { - "dev-master": "7.0-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -2807,54 +2982,80 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "email": "sebastian@phpunit.de" } ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", "keywords": [ - "phpunit", - "testing", - "xunit" + "tokenizer" ], - "time": "2018-03-26T07:36:48+00:00" + "time": "2020-02-07T06:19:00+00:00" }, { - "name": "phpunit/phpunit-mock-objects", - "version": "6.1.2", + "name": "phpunit/phpunit", + "version": "9.0.2", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "f9756fd4f43f014cb2dca98deeaaa8ce5500a36e" + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "c0ecbfb898ab8b24d8a59a23520f7b2a73e27b5b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/f9756fd4f43f014cb2dca98deeaaa8ce5500a36e", - "reference": "f9756fd4f43f014cb2dca98deeaaa8ce5500a36e", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c0ecbfb898ab8b24d8a59a23520f7b2a73e27b5b", + "reference": "c0ecbfb898ab8b24d8a59a23520f7b2a73e27b5b", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.0.5", - "php": "^7.1", - "phpunit/php-text-template": "^1.2.1", - "sebastian/exporter": "^3.1" + "doctrine/instantiator": "^1.2.0", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.9.1", + "phar-io/manifest": "^1.0.3", + "phar-io/version": "^2.0.1", + "php": "^7.3", + "phpspec/prophecy": "^1.8.1", + "phpunit/php-code-coverage": "^8.0.1", + "phpunit/php-file-iterator": "^3.0", + "phpunit/php-invoker": "^3.0", + "phpunit/php-text-template": "^2.0", + "phpunit/php-timer": "^3.0", + "sebastian/comparator": "^4.0", + "sebastian/diff": "^4.0", + "sebastian/environment": "^5.0.1", + "sebastian/exporter": "^4.0", + "sebastian/global-state": "^4.0", + "sebastian/object-enumerator": "^4.0", + "sebastian/resource-operations": "^3.0", + "sebastian/type": "^2.0", + "sebastian/version": "^3.0" }, "require-dev": { - "phpunit/phpunit": "^7.0" + "ext-pdo": "*" }, "suggest": { - "ext-soap": "*" + "ext-soap": "*", + "ext-xdebug": "*" }, + "bin": [ + "phpunit" + ], "type": "library", "extra": { "branch-alias": { - "dev-master": "6.1-dev" + "dev-master": "9.0-dev" } }, "autoload": { "classmap": [ "src/" + ], + "files": [ + "src/Framework/Assert/Functions.php" ] }, "notification-url": "https://packagist.org/downloads/", @@ -2868,14 +3069,14 @@ "role": "lead" } ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", "keywords": [ - "mock", + "phpunit", + "testing", "xunit" ], - "abandoned": true, - "time": "2018-05-29T13:54:20+00:00" + "time": "2020-03-31T08:57:51+00:00" }, { "name": "psr/cache", @@ -3024,16 +3225,16 @@ }, { "name": "psr/log", - "version": "1.1.2", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801" + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801", - "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801", + "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc", "shasum": "" }, "require": { @@ -3067,7 +3268,7 @@ "psr", "psr-3" ], - "time": "2019-11-01T11:05:21+00:00" + "time": "2020-03-23T09:12:05+00:00" }, { "name": "psr/simple-cache", @@ -3246,28 +3447,28 @@ }, { "name": "sebastian/code-unit-reverse-lookup", - "version": "1.0.1", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" + "reference": "5b5dbe0044085ac41df47e79d34911a15b96d82e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", - "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5b5dbe0044085ac41df47e79d34911a15b96d82e", + "reference": "5b5dbe0044085ac41df47e79d34911a15b96d82e", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "php": "^7.3" }, "require-dev": { - "phpunit/phpunit": "^5.7 || ^6.0" + "phpunit/phpunit": "^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -3287,34 +3488,34 @@ ], "description": "Looks up which function or method a line of code belongs to", "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "time": "2017-03-04T06:30:41+00:00" + "time": "2020-02-07T06:20:13+00:00" }, { "name": "sebastian/comparator", - "version": "2.1.3", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9" + "reference": "85b3435da967696ed618ff745f32be3ff4a2b8e8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/34369daee48eafb2651bea869b4b15d75ccc35f9", - "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/85b3435da967696ed618ff745f32be3ff4a2b8e8", + "reference": "85b3435da967696ed618ff745f32be3ff4a2b8e8", "shasum": "" }, "require": { - "php": "^7.0", - "sebastian/diff": "^2.0 || ^3.0", - "sebastian/exporter": "^3.1" + "php": "^7.3", + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" }, "require-dev": { - "phpunit/phpunit": "^6.4" + "phpunit/phpunit": "^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1.x-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -3327,6 +3528,10 @@ "BSD-3-Clause" ], "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, { "name": "Jeff Welch", "email": "whatthejeff@gmail.com" @@ -3338,10 +3543,6 @@ { "name": "Bernhard Schussek", "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" } ], "description": "Provides the functionality to compare PHP values for equality", @@ -3351,33 +3552,33 @@ "compare", "equality" ], - "time": "2018-02-01T13:46:46+00:00" + "time": "2020-02-07T06:08:51+00:00" }, { "name": "sebastian/diff", - "version": "3.0.2", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29" + "reference": "c0c26c9188b538bfa985ae10c9f05d278f12060d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/720fcc7e9b5cf384ea68d9d930d480907a0c1a29", - "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c0c26c9188b538bfa985ae10c9f05d278f12060d", + "reference": "c0c26c9188b538bfa985ae10c9f05d278f12060d", "shasum": "" }, "require": { - "php": "^7.1" + "php": "^7.3" }, "require-dev": { - "phpunit/phpunit": "^7.5 || ^8.0", - "symfony/process": "^2 || ^3.3 || ^4" + "phpunit/phpunit": "^9.0", + "symfony/process": "^4 || ^5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -3390,13 +3591,13 @@ "BSD-3-Clause" ], "authors": [ - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - }, { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" } ], "description": "Diff implementation", @@ -3407,32 +3608,35 @@ "unidiff", "unified diff" ], - "time": "2019-02-04T06:01:07+00:00" + "time": "2020-02-07T06:09:38+00:00" }, { "name": "sebastian/environment", - "version": "3.1.0", + "version": "5.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5" + "reference": "c39c1db0a5cffc98173f3de5a17d489d1043fd7b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5", - "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/c39c1db0a5cffc98173f3de5a17d489d1043fd7b", + "reference": "c39c1db0a5cffc98173f3de5a17d489d1043fd7b", "shasum": "" }, "require": { - "php": "^7.0" + "php": "^7.3" }, "require-dev": { - "phpunit/phpunit": "^6.1" + "phpunit/phpunit": "^9.0" + }, + "suggest": { + "ext-posix": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1.x-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -3457,34 +3661,34 @@ "environment", "hhvm" ], - "time": "2017-07-01T08:51:00+00:00" + "time": "2020-03-31T12:14:15+00:00" }, { "name": "sebastian/exporter", - "version": "3.1.2", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e" + "reference": "80c26562e964016538f832f305b2286e1ec29566" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/68609e1261d215ea5b21b7987539cbfbe156ec3e", - "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/80c26562e964016538f832f305b2286e1ec29566", + "reference": "80c26562e964016538f832f305b2286e1ec29566", "shasum": "" }, "require": { - "php": "^7.0", - "sebastian/recursion-context": "^3.0" + "php": "^7.3", + "sebastian/recursion-context": "^4.0" }, "require-dev": { "ext-mbstring": "*", - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1.x-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -3524,27 +3728,30 @@ "export", "exporter" ], - "time": "2019-09-14T09:02:43+00:00" + "time": "2020-02-07T06:10:52+00:00" }, { "name": "sebastian/global-state", - "version": "2.0.0", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" + "reference": "bdb1e7c79e592b8c82cb1699be3c8743119b8a72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", - "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bdb1e7c79e592b8c82cb1699be3c8743119b8a72", + "reference": "bdb1e7c79e592b8c82cb1699be3c8743119b8a72", "shasum": "" }, "require": { - "php": "^7.0" + "php": "^7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "ext-dom": "*", + "phpunit/phpunit": "^9.0" }, "suggest": { "ext-uopz": "*" @@ -3552,7 +3759,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -3575,34 +3782,34 @@ "keywords": [ "global state" ], - "time": "2017-04-27T15:39:26+00:00" + "time": "2020-02-07T06:11:37+00:00" }, { "name": "sebastian/object-enumerator", - "version": "3.0.3", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5" + "reference": "e67516b175550abad905dc952f43285957ef4363" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5", - "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/e67516b175550abad905dc952f43285957ef4363", + "reference": "e67516b175550abad905dc952f43285957ef4363", "shasum": "" }, "require": { - "php": "^7.0", - "sebastian/object-reflector": "^1.1.1", - "sebastian/recursion-context": "^3.0" + "php": "^7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0.x-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -3622,32 +3829,32 @@ ], "description": "Traverses array structures and object graphs to enumerate all referenced objects", "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2017-08-03T12:35:26+00:00" + "time": "2020-02-07T06:12:23+00:00" }, { "name": "sebastian/object-reflector", - "version": "1.1.1", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "773f97c67f28de00d397be301821b06708fca0be" + "reference": "f4fd0835cabb0d4a6546d9fe291e5740037aa1e7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", - "reference": "773f97c67f28de00d397be301821b06708fca0be", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/f4fd0835cabb0d4a6546d9fe291e5740037aa1e7", + "reference": "f4fd0835cabb0d4a6546d9fe291e5740037aa1e7", "shasum": "" }, "require": { - "php": "^7.0" + "php": "^7.3" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -3667,32 +3874,32 @@ ], "description": "Allows reflection of object attributes, including inherited and non-public ones", "homepage": "https://github.com/sebastianbergmann/object-reflector/", - "time": "2017-03-29T09:07:27+00:00" + "time": "2020-02-07T06:19:40+00:00" }, { "name": "sebastian/recursion-context", - "version": "3.0.0", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" + "reference": "cdd86616411fc3062368b720b0425de10bd3d579" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", - "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/cdd86616411fc3062368b720b0425de10bd3d579", + "reference": "cdd86616411fc3062368b720b0425de10bd3d579", "shasum": "" }, "require": { - "php": "^7.0" + "php": "^7.3" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0.x-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -3705,14 +3912,14 @@ "BSD-3-Clause" ], "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, { "name": "Adam Harvey", "email": "aharvey@php.net" @@ -3720,29 +3927,32 @@ ], "description": "Provides functionality to recursively process PHP variables", "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2017-03-03T06:23:57+00:00" + "time": "2020-02-07T06:18:20+00:00" }, { "name": "sebastian/resource-operations", - "version": "1.0.0", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" + "reference": "8c98bf0dfa1f9256d0468b9803a1e1df31b6fa98" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/8c98bf0dfa1f9256d0468b9803a1e1df31b6fa98", + "reference": "8c98bf0dfa1f9256d0468b9803a1e1df31b6fa98", "shasum": "" }, "require": { - "php": ">=5.6.0" + "php": "^7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -3762,29 +3972,75 @@ ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2015-07-28T20:34:47+00:00" + "time": "2020-02-07T06:13:02+00:00" + }, + { + "name": "sebastian/type", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "9e8f42f740afdea51f5f4e8cec2035580e797ee1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/9e8f42f740afdea51f5f4e8cec2035580e797ee1", + "reference": "9e8f42f740afdea51f5f4e8cec2035580e797ee1", + "shasum": "" + }, + "require": { + "php": "^7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "time": "2020-02-07T06:13:43+00:00" }, { "name": "sebastian/version", - "version": "2.0.1", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + "reference": "0411bde656dce64202b39c2f4473993a9081d39e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/0411bde656dce64202b39c2f4473993a9081d39e", + "reference": "0411bde656dce64202b39c2f4473993a9081d39e", "shasum": "" }, "require": { - "php": ">=5.6" + "php": "^7.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -3805,7 +4061,7 @@ ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", - "time": "2016-10-03T07:35:21+00:00" + "time": "2020-01-21T06:36:37+00:00" }, { "name": "seld/jsonlint", @@ -3900,77 +4156,18 @@ ], "time": "2020-02-14T15:25:33+00:00" }, - { - "name": "symfony/browser-kit", - "version": "v4.4.5", - "source": { - "type": "git", - "url": "https://github.com/symfony/browser-kit.git", - "reference": "090ce406505149d6852a7c03b0346dec3b8cf612" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/090ce406505149d6852a7c03b0346dec3b8cf612", - "reference": "090ce406505149d6852a7c03b0346dec3b8cf612", - "shasum": "" - }, - "require": { - "php": "^7.1.3", - "symfony/dom-crawler": "^3.4|^4.0|^5.0" - }, - "require-dev": { - "symfony/css-selector": "^3.4|^4.0|^5.0", - "symfony/http-client": "^4.3|^5.0", - "symfony/mime": "^4.3|^5.0", - "symfony/process": "^3.4|^4.0|^5.0" - }, - "suggest": { - "symfony/process": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\BrowserKit\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony BrowserKit Component", - "homepage": "https://symfony.com", - "time": "2020-02-23T10:00:59+00:00" - }, { "name": "symfony/console", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "4fa15ae7be74e53f6ec8c83ed403b97e23b665e9" + "reference": "10bb3ee3c97308869d53b3e3d03f6ac23ff985f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/4fa15ae7be74e53f6ec8c83ed403b97e23b665e9", - "reference": "4fa15ae7be74e53f6ec8c83ed403b97e23b665e9", + "url": "https://api.github.com/repos/symfony/console/zipball/10bb3ee3c97308869d53b3e3d03f6ac23ff985f7", + "reference": "10bb3ee3c97308869d53b3e3d03f6ac23ff985f7", "shasum": "" }, "require": { @@ -4033,29 +4230,29 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2020-02-24T13:10:00+00:00" + "time": "2020-03-30T11:41:10+00:00" }, { "name": "symfony/css-selector", - "version": "v4.4.5", + "version": "v5.0.5", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "d0a6dd288fa8848dcc3d1f58b94de6a7cc5d2d22" + "reference": "a0b51ba9938ccc206d9284de7eb527c2d4550b44" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/d0a6dd288fa8848dcc3d1f58b94de6a7cc5d2d22", - "reference": "d0a6dd288fa8848dcc3d1f58b94de6a7cc5d2d22", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/a0b51ba9938ccc206d9284de7eb527c2d4550b44", + "reference": "a0b51ba9938ccc206d9284de7eb527c2d4550b44", "shasum": "" }, "require": { - "php": "^7.1.3" + "php": "^7.2.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.4-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -4086,68 +4283,7 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "time": "2020-02-04T09:01:01+00:00" - }, - { - "name": "symfony/dom-crawler", - "version": "v4.4.5", - "source": { - "type": "git", - "url": "https://github.com/symfony/dom-crawler.git", - "reference": "11dcf08f12f29981bf770f097a5d64d65bce5929" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/11dcf08f12f29981bf770f097a5d64d65bce5929", - "reference": "11dcf08f12f29981bf770f097a5d64d65bce5929", - "shasum": "" - }, - "require": { - "php": "^7.1.3", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.0" - }, - "conflict": { - "masterminds/html5": "<2.6" - }, - "require-dev": { - "masterminds/html5": "^2.6", - "symfony/css-selector": "^3.4|^4.0|^5.0" - }, - "suggest": { - "symfony/css-selector": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\DomCrawler\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony DomCrawler Component", - "homepage": "https://symfony.com", - "time": "2020-02-29T10:05:28+00:00" + "time": "2020-02-04T09:41:09+00:00" }, { "name": "symfony/event-dispatcher", @@ -5291,20 +5427,22 @@ }, { "name": "gitonomy/gitlib", - "version": "v1.2.0", + "version": "v1.2.1", "source": { "type": "git", "url": "https://github.com/gitonomy/gitlib.git", - "reference": "a0bea921266ad1c9626d712e7f8687dcc08ca528" + "reference": "718ca021c67f3ea8f6a5fa5d231ec49675068868" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/gitonomy/gitlib/zipball/a0bea921266ad1c9626d712e7f8687dcc08ca528", - "reference": "a0bea921266ad1c9626d712e7f8687dcc08ca528", + "url": "https://api.github.com/repos/gitonomy/gitlib/zipball/718ca021c67f3ea8f6a5fa5d231ec49675068868", + "reference": "718ca021c67f3ea8f6a5fa5d231ec49675068868", "shasum": "" }, "require": { + "ext-pcre": "*", "php": "^5.6 || ^7.0", + "symfony/polyfill-mbstring": "^1.7", "symfony/process": "^3.4|^4.0|^5.0" }, "require-dev": { @@ -5312,6 +5450,7 @@ "psr/log": "^1.0" }, "suggest": { + "ext-fileinfo": "Required to determine the mimetype of a blob", "psr/log": "Required to use loggers for reporting of execution" }, "type": "library", @@ -5348,8 +5487,7 @@ } ], "description": "Library for accessing git", - "homepage": "http://gitonomy.com", - "time": "2019-12-08T12:42:25+00:00" + "time": "2020-03-23T12:43:44+00:00" }, { "name": "goaop/framework", @@ -5889,26 +6027,29 @@ }, { "name": "sebastian/finder-facade", - "version": "1.2.3", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/finder-facade.git", - "reference": "167c45d131f7fc3d159f56f191a0a22228765e16" + "reference": "9d3e74b845a2ce50e19b25b5f0c2718e153bee6c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/finder-facade/zipball/167c45d131f7fc3d159f56f191a0a22228765e16", - "reference": "167c45d131f7fc3d159f56f191a0a22228765e16", + "url": "https://api.github.com/repos/sebastianbergmann/finder-facade/zipball/9d3e74b845a2ce50e19b25b5f0c2718e153bee6c", + "reference": "9d3e74b845a2ce50e19b25b5f0c2718e153bee6c", "shasum": "" }, "require": { - "php": "^7.1", - "symfony/finder": "^2.3|^3.0|^4.0|^5.0", + "ext-ctype": "*", + "php": "^7.3", + "symfony/finder": "^4.1|^5.0", "theseer/fdomdocument": "^1.6" }, "type": "library", "extra": { - "branch-alias": [] + "branch-alias": { + "dev-master": "2.0-dev" + } }, "autoload": { "classmap": [ @@ -5928,29 +6069,29 @@ ], "description": "FinderFacade is a convenience wrapper for Symfony's Finder component.", "homepage": "https://github.com/sebastianbergmann/finder-facade", - "time": "2020-01-16T08:08:45+00:00" + "time": "2020-02-08T06:07:58+00:00" }, { "name": "sebastian/phpcpd", - "version": "4.1.0", + "version": "5.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpcpd.git", - "reference": "0d9afa762f2400de077b2192f4a9d127de0bb78e" + "reference": "8724382966b1861df4e12db915eaed2165e10bf3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpcpd/zipball/0d9afa762f2400de077b2192f4a9d127de0bb78e", - "reference": "0d9afa762f2400de077b2192f4a9d127de0bb78e", + "url": "https://api.github.com/repos/sebastianbergmann/phpcpd/zipball/8724382966b1861df4e12db915eaed2165e10bf3", + "reference": "8724382966b1861df4e12db915eaed2165e10bf3", "shasum": "" }, "require": { "ext-dom": "*", - "php": "^7.1", - "phpunit/php-timer": "^2.0", - "sebastian/finder-facade": "^1.1", - "sebastian/version": "^1.0|^2.0", - "symfony/console": "^2.7|^3.0|^4.0" + "php": "^7.3", + "phpunit/php-timer": "^3.0", + "sebastian/finder-facade": "^2.0", + "sebastian/version": "^3.0", + "symfony/console": "^4.0|^5.0" }, "bin": [ "phpcpd" @@ -5958,7 +6099,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -5979,7 +6120,7 @@ ], "description": "Copy/Paste Detector (CPD) for PHP code.", "homepage": "https://github.com/sebastianbergmann/phpcpd", - "time": "2018-09-17T17:17:27+00:00" + "time": "2020-02-22T06:03:17+00:00" }, { "name": "squizlabs/php_codesniffer", @@ -6265,7 +6406,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "~7.2.0||~7.3.0", + "php": "^7.3", "ext-curl": "*", "ext-dom": "*", "ext-json": "*", diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php index b7eafaead..f0041e074 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php @@ -22,7 +22,7 @@ class AllureHelperTest extends TestCase /** * Clear Allure Lifecycle */ - public function tearDown() + public function tearDown(): void { Allure::setDefaultLifecycle(); AspectMock::clean(); diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerInstallTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerInstallTest.php index e4977184f..445e615a9 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerInstallTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerInstallTest.php @@ -18,7 +18,7 @@ class ComposerInstallTest extends MagentoTestCase */ private $composer; - public function setUp() + public function setUp(): void { $composerJson = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'Composer' . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'dir1' . DIRECTORY_SEPARATOR . 'dir2' . DIRECTORY_SEPARATOR . 'composer.json'; diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerPackageTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerPackageTest.php index 4802f0c33..dfe691651 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerPackageTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerPackageTest.php @@ -19,7 +19,7 @@ class ComposerPackageTest extends MagentoTestCase */ private $composer; - public function setUp() + public function setUp(): void { $composerJson = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'Composer' . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'dir1' . DIRECTORY_SEPARATOR . 'dir2' . DIRECTORY_SEPARATOR . 'composer.json'; diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Config/Reader/FilesystemTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Config/Reader/FilesystemTest.php index b59858e7f..e12ccbe5c 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Config/Reader/FilesystemTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Config/Reader/FilesystemTest.php @@ -19,7 +19,7 @@ class FilesystemTest extends TestCase * Before test functionality * @return void */ - public function setUp() + public function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); } @@ -100,7 +100,7 @@ public function createPseudoFileSystem($fileList) * After class functionality * @return void */ - public static function tearDownAfterClass() + public static function tearDownAfterClass(): void { TestLoggingUtil::getInstance()->clearMockLoggingUtil(); parent::tearDownAfterClass(); diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php index 234f677e8..c57dfe471 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php @@ -15,7 +15,7 @@ class BaseGenerateCommandTest extends TestCase { - public function tearDown() + public function tearDown(): void { AspectMock::clean(); } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php index 592b87f4e..0e3367a70 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php @@ -27,7 +27,7 @@ class PersistedObjectHandlerTest extends MagentoTestCase * Before test functionality * @return void */ - public function setUp() + public function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); } @@ -510,7 +510,7 @@ public function mockCurlHandler($response) ]); } - public function tearDown() + public function tearDown(): void { // Clear out Singleton between tests $property = new \ReflectionProperty(PersistedObjectHandler::class, "INSTANCE"); @@ -524,7 +524,7 @@ public function tearDown() * After class functionality * @return void */ - public static function tearDownAfterClass() + public static function tearDownAfterClass(): void { TestLoggingUtil::getInstance()->clearMockLoggingUtil(); parent::tearDownAfterClass(); diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Objects/EntityDataObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Objects/EntityDataObjectTest.php index 802a6c108..ef7dfac9b 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Objects/EntityDataObjectTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Objects/EntityDataObjectTest.php @@ -40,7 +40,7 @@ class EntityDataObjectTest extends MagentoTestCase * Before test functionality * @return void */ - public function setUp() + public function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); } @@ -141,7 +141,7 @@ public function testGetCamelCaseKeys() * After class functionality * @return void */ - public static function tearDownAfterClass() + public static function tearDownAfterClass(): void { TestLoggingUtil::getInstance()->clearMockLoggingUtil(); } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php index fb6dcd865..1e77c8158 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php @@ -41,7 +41,7 @@ class OperationDataArrayResolverTest extends MagentoTestCase * Before test functionality * @return void */ - public function setUp() + public function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); } @@ -481,7 +481,7 @@ public function testNestedMetadataArrayOfDiverseObjects() * After class functionality * @return void */ - public static function tearDownAfterClass() + public static function tearDownAfterClass(): void { TestLoggingUtil::getInstance()->clearMockLoggingUtil(); } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Util/DataExtensionUtilTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Util/DataExtensionUtilTest.php index e72c15b31..b921229e0 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Util/DataExtensionUtilTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Util/DataExtensionUtilTest.php @@ -22,7 +22,7 @@ class EntityDataExtensionTest extends MagentoTestCase * Before method functionality * @return void */ - protected function setUp() + protected function setUp(): void { AspectMock::clean(); } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/ElementObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/ElementObjectTest.php index d585f4085..02fb0f465 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/ElementObjectTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/ElementObjectTest.php @@ -32,7 +32,7 @@ public function testTimeoutNotNull() $element = new ElementObject('name', 'type', 'selector', null, '15', false); $timeout = $element->getTimeout(); $this->assertEquals(15, $timeout); - $this->assertInternalType('int', $timeout); + $this->assertIsInt($timeout); } /** @@ -43,7 +43,7 @@ public function testTimeoutCastFromString() $element = new ElementObject('name', 'type', 'selector', null, 'helloString', true); $timeout = $element->getTimeout(); $this->assertEquals(0, $timeout); - $this->assertInternalType('int', $timeout); + $this->assertIsInt($timeout); } /** diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/Handlers/SuiteObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/Handlers/SuiteObjectHandlerTest.php index e45127f4c..c065b1fbf 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/Handlers/SuiteObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/Handlers/SuiteObjectHandlerTest.php @@ -19,7 +19,7 @@ class SuiteObjectHandlerTest extends MagentoTestCase { - public function setUp() + public function setUp(): void { $resolverMock = new MockModuleResolverBuilder(); $resolverMock->setup(); diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php index 842be4f88..d3bf71f5f 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php @@ -29,7 +29,7 @@ class SuiteGeneratorTest extends MagentoTestCase /** * Setup entry append and clear for Suite Generator */ - public static function setUpBeforeClass() + public static function setUpBeforeClass(): void { AspectMock::double(SuiteGenerator::class, [ 'clearPreviousSessionConfigEntries' => null, @@ -41,7 +41,7 @@ public static function setUpBeforeClass() * Before test functionality * @return void */ - public function setUp() + public function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); $resolverMock = new MockModuleResolverBuilder(); @@ -181,7 +181,7 @@ public function testInvalidSuiteTestPair() // Set up Expected Exception $this->expectException(TestReferenceException::class); - $this->expectExceptionMessageRegExp('(Suite: "Suite2" Tests: "Test1")'); + $this->expectExceptionMessageMatches('(Suite: "Suite2" Tests: "Test1")'); // parse and generate suite object with mocked data and manifest $mockSuiteGenerator = SuiteGenerator::getInstance(); @@ -205,7 +205,7 @@ public function testNonExistentSuiteTestPair() // Set up Expected Exception $this->expectException(TestReferenceException::class); - $this->expectExceptionMessageRegExp('#Suite3 is not defined#'); + $this->expectExceptionMessageMatches('#Suite3 is not defined#'); // parse and generate suite object with mocked data and manifest $mockSuiteGenerator = SuiteGenerator::getInstance(); @@ -274,7 +274,7 @@ private function setMockTestAndSuiteParserOutput($testData, $suiteData) /** * clean up function runs after all tests */ - public static function tearDownAfterClass() + public static function tearDownAfterClass(): void { TestLoggingUtil::getInstance()->clearMockLoggingUtil(); parent::tearDownAfterClass(); diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Config/ActionGroupDomTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Config/ActionGroupDomTest.php index 6a0c926be..767d06628 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Config/ActionGroupDomTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Config/ActionGroupDomTest.php @@ -65,7 +65,7 @@ public function testActionGroupDomDuplicateActionGroupsValidation() $exceptionCollector = new ExceptionCollector(); new ActionGroupDom($sampleXml, 'dupeNameActionGroup.xml', $exceptionCollector); $this->expectException(\Exception::class); - $this->expectExceptionMessageRegExp("/name: actionGroupName is used more than once./"); + $this->expectExceptionMessageMatches("/name: actionGroupName is used more than once./"); $exceptionCollector->throwException(); } } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Config/DomTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Config/DomTest.php index e00926978..719c629d4 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Config/DomTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Config/DomTest.php @@ -28,7 +28,7 @@ public function testTestStepKeyDuplicateValidation() new ActionGroupDom($sampleXml, 'dupeStepKeyTest.xml', $exceptionCollector); $this->expectException(\Exception::class); - $this->expectExceptionMessageRegExp("/stepKey: key1 is used more than once. \(Parent: testName\)/"); + $this->expectExceptionMessageMatches("/stepKey: key1 is used more than once. \(Parent: testName\)/"); $exceptionCollector->throwException(); } @@ -49,7 +49,7 @@ public function testTestNameDuplicateValidation() $exceptionCollector = new ExceptionCollector(); new ActionGroupDom($sampleXml, 'dupeTestsTest.xml', $exceptionCollector); $this->expectException(\Exception::class); - $this->expectExceptionMessageRegExp("/name: testName is used more than once./"); + $this->expectExceptionMessageMatches("/name: testName is used more than once./"); $exceptionCollector->throwException(); } } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php index a4504ab07..7dededc1a 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php @@ -283,7 +283,7 @@ private function setMockParserOutput($data) * * @return void */ - public function tearDown() + public function tearDown(): void { AspectMock::clean(); } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionGroupObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionGroupObjectTest.php index 796e8a28b..db32de3b7 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionGroupObjectTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionGroupObjectTest.php @@ -28,7 +28,7 @@ class ActionGroupObjectTest extends MagentoTestCase * Before test functionality * @return void */ - public function setUp() + public function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); } @@ -243,7 +243,7 @@ public function testExceptionOnMissingActions() ->build(); $this->expectException(TestReferenceException::class); - $this->expectExceptionMessageRegExp('/Arguments missed .* for actionGroup/'); + $this->expectExceptionMessageMatches('/Arguments missed .* for actionGroup/'); $actionGroupUnderTest->getSteps(['arg2' => 'data1'], self::ACTION_GROUP_MERGE_KEY); } @@ -257,7 +257,7 @@ public function testExceptionOnMissingArguments() ->build(); $this->expectException(TestReferenceException::class); - $this->expectExceptionMessageRegExp('/Arguments missed .* for actionGroup/'); + $this->expectExceptionMessageMatches('/Arguments missed .* for actionGroup/'); $actionGroupUnderTest->getSteps(null, self::ACTION_GROUP_MERGE_KEY); } @@ -355,7 +355,7 @@ private function assertOnMergeKeyAndActionValue($actions, $expectedValue, $expec * After class functionality * @return void */ - public static function tearDownAfterClass() + public static function tearDownAfterClass(): void { TestLoggingUtil::getInstance()->clearMockLoggingUtil(); } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php index 24a7e2ee6..42830ce9f 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php @@ -28,7 +28,7 @@ class ActionObjectTest extends MagentoTestCase * Before test functionality * @return void */ - public function setUp() + public function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); } @@ -393,7 +393,7 @@ private function mockDataHandlerWithData($dataObject) * After class functionality * @return void */ - public static function tearDownAfterClass() + public static function tearDownAfterClass(): void { TestLoggingUtil::getInstance()->clearMockLoggingUtil(); } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionGroupAnnotationExtractorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionGroupAnnotationExtractorTest.php index 392c870d9..a3d2cca86 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionGroupAnnotationExtractorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionGroupAnnotationExtractorTest.php @@ -16,7 +16,7 @@ class ActionGroupAnnotationExtractorTest extends TestCase * Before test functionality * @return void */ - public function setUp() + public function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); } @@ -48,7 +48,7 @@ public function testActionGroupExtractAnnotations() * After class functionality * @return void */ - public static function tearDownAfterClass() + public static function tearDownAfterClass(): void { TestLoggingUtil::getInstance()->clearMockLoggingUtil(); } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionGroupObjectExtractorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionGroupObjectExtractorTest.php index 47b797c1c..2d399cfb1 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionGroupObjectExtractorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionGroupObjectExtractorTest.php @@ -17,7 +17,7 @@ class ActionGroupObjectExtractorTest extends MagentoTestCase /** * Setup method */ - public function setUp() + public function setUp(): void { $this->testActionGroupObjectExtractor = new ActionGroupObjectExtractor(); TestLoggingUtil::getInstance()->setMockLoggingUtil(); @@ -63,7 +63,7 @@ private function createBasicActionObjectArray( /** * clean up function runs after all tests */ - public static function tearDownAfterClass() + public static function tearDownAfterClass(): void { TestLoggingUtil::getInstance()->clearMockLoggingUtil(); } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php index 7917d663b..7996837ff 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php @@ -23,7 +23,7 @@ class ActionMergeUtilTest extends MagentoTestCase * Before test functionality * @return void */ - public function setUp() + public function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); } @@ -292,7 +292,7 @@ public function testInvalidSecretFunctions() * After class functionality * @return void */ - public static function tearDownAfterClass() + public static function tearDownAfterClass(): void { TestLoggingUtil::getInstance()->clearMockLoggingUtil(); } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionObjectExtractorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionObjectExtractorTest.php index f584adea9..5f30f8422 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionObjectExtractorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionObjectExtractorTest.php @@ -18,7 +18,7 @@ class ActionObjectExtractorTest extends MagentoTestCase /** * Setup method */ - public function setUp() + public function setUp(): void { $this->testActionObjectExtractor = new ActionObjectExtractor(); TestLoggingUtil::getInstance()->setMockLoggingUtil(); @@ -130,7 +130,7 @@ private function createBasicActionObjectArray($stepKey = 'testAction1', $before /** * clean up function runs after all tests */ - public static function tearDownAfterClass() + public static function tearDownAfterClass(): void { TestLoggingUtil::getInstance()->clearMockLoggingUtil(); } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/AnnotationExtractorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/AnnotationExtractorTest.php index fb93cbb88..bfb108ce8 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/AnnotationExtractorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/AnnotationExtractorTest.php @@ -19,7 +19,7 @@ class AnnotationExtractorTest extends TestCase * Before test functionality * @return void */ - public function setUp() + public function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); } @@ -209,7 +209,7 @@ public function testTestCaseIdUniqueness() * After class functionality * @return void */ - public static function tearDownAfterClass() + public static function tearDownAfterClass(): void { TestLoggingUtil::getInstance()->clearMockLoggingUtil(); } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ObjectExtensionUtilTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ObjectExtensionUtilTest.php index 9982b8040..4b9830a59 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ObjectExtensionUtilTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ObjectExtensionUtilTest.php @@ -28,7 +28,7 @@ class ObjectExtensionUtilTest extends TestCase * Before test functionality * @return void */ - public function setUp() + public function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); $resolverMock = new MockModuleResolverBuilder(); @@ -39,7 +39,7 @@ public function setUp() * After class functionality * @return void */ - public static function tearDownAfterClass() + public static function tearDownAfterClass(): void { TestLoggingUtil::getInstance()->clearMockLoggingUtil(); } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php index 5244e6995..694f6c190 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php @@ -25,7 +25,7 @@ class ModuleResolverTest extends MagentoTestCase * Before test functionality * @return void */ - public function setUp() + public function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); } @@ -34,7 +34,7 @@ public function setUp() * After class functionality * @return void */ - public static function tearDownAfterClass() + public static function tearDownAfterClass(): void { TestLoggingUtil::getInstance()->clearMockLoggingUtil(); } @@ -987,7 +987,7 @@ private function mockForceGenerate($forceGenerate) * After method functionality * @return void */ - protected function tearDown() + protected function tearDown(): void { // re set env if (!isset($_ENV['MAGENTO_ADMIN_USERNAME'])) { diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php index e11b0f9b2..9eefbd94a 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php @@ -23,7 +23,7 @@ class TestGeneratorTest extends MagentoTestCase * * @return void */ - public function tearDown() + public function tearDown(): void { AspectMock::clean(); } @@ -70,8 +70,8 @@ public function testSkippedNoGeneration() $testGeneratorObject = TestGenerator::getInstance("", ["sampleTest" => $testObject]); $output = $testGeneratorObject->assembleTestPhp($testObject); - $this->assertContains('This test is skipped', $output); - $this->assertNotContains($actionInput, $output); + $this->assertStringContainsString('This test is skipped', $output); + $this->assertStringNotContainsString($actionInput, $output); } /** @@ -106,9 +106,9 @@ public function testAllowSkipped() $testGeneratorObject = TestGenerator::getInstance("", ["sampleTest" => $testObject]); $output = $testGeneratorObject->assembleTestPhp($testObject); - $this->assertNotContains('This test is skipped', $output); - $this->assertContains($actionInput, $output); - $this->assertContains($beforeActionInput, $output); + $this->assertStringNotContainsString('This test is skipped', $output); + $this->assertStringContainsString($actionInput, $output); + $this->assertStringContainsString($beforeActionInput, $output); } /** diff --git a/dev/tests/unit/Util/MagentoTestCase.php b/dev/tests/unit/Util/MagentoTestCase.php index 6a4e5d35b..9d3a0a6f4 100644 --- a/dev/tests/unit/Util/MagentoTestCase.php +++ b/dev/tests/unit/Util/MagentoTestCase.php @@ -14,7 +14,7 @@ */ class MagentoTestCase extends TestCase { - public static function setUpBeforeClass() + public static function setUpBeforeClass(): void { if (!self::fileExists(DOCS_OUTPUT_DIR)) { mkdir(DOCS_OUTPUT_DIR, 0755, true); @@ -26,7 +26,7 @@ public static function setUpBeforeClass() * Teardown for removing AspectMock Double References * @return void */ - public static function tearDownAfterClass() + public static function tearDownAfterClass(): void { AspectMock::clean(); array_map('unlink', glob(DOCS_OUTPUT_DIR . DIRECTORY_SEPARATOR . "*")); diff --git a/dev/tests/verification/Resources/AssertTest.txt b/dev/tests/verification/Resources/AssertTest.txt index c0cf932ae..7697b7baf 100644 --- a/dev/tests/verification/Resources/AssertTest.txt +++ b/dev/tests/verification/Resources/AssertTest.txt @@ -45,6 +45,8 @@ class AssertTestCest $I->assertArrayNotHasKey("kiwi", ['orange' => 2, 'apple' => 1], "pass"); // stepKey: assertArrayNotHasKey $I->assertArraySubset([1, 2], [1, 2, 3, 5], "pass"); // stepKey: assertArraySubset $I->assertContains("ab", ['item1' => 'a', 'item2' => 'ab'], "pass"); // stepKey: assertContains + $I->assertStringContainsString("apple", "apple", "pass"); // stepKey: assertStringContainsString + $I->assertStringContainsStringIgnoringCase("Banana", "banana", "pass"); // stepKey: assertStringContainsStringIgnoringCase $I->assertCount(2, ['a', 'b'], "pass"); // stepKey: assertCount $I->assertEmpty([], "pass"); // stepKey: assertEmpty $I->assertEquals($text, "Copyright © 2013-2017 Magento, Inc. All rights reserved.", "pass"); // stepKey: assertEquals1 @@ -62,8 +64,9 @@ class AssertTestCest $I->assertLessOrEquals(5, 2, "pass"); // stepKey: assertLessOrEquals $I->assertLessThan(5, 2, "pass"); // stepKey: assertLessThan $I->assertLessThanOrEqual(5, 2, "pass"); // stepKey: assertLessThanOrEquals - $I->assertNotContains("bc", ['item1' => 'a', 'item2' => 'ab'], "pass"); // stepKey: assertNotContains1 - $I->assertNotContains("bc", $text, "pass"); // stepKey: assertNotContains2 + $I->assertNotContains("bc", ['item1' => 'a', 'item2' => 'ab'], "pass"); // stepKey: assertNotContains + $I->assertStringNotContainsString("apple", "banana", "pass"); // stepKey: assertStringNotContainsString + $I->assertStringNotContainsStringIgnoringCase("apple", "banana", "pass"); // stepKey: assertStringNotContainsStringIgnoringCase $I->assertNotEmpty([1, 2], "pass"); // stepKey: assertNotEmpty1 $I->assertNotEmpty($text, "pass"); // stepKey: assertNotEmpty2 $I->assertNotEquals(2, 5, "pass", 0); // stepKey: assertNotEquals diff --git a/dev/tests/verification/Resources/BasicFunctionalTest.txt b/dev/tests/verification/Resources/BasicFunctionalTest.txt index 7f7e25c60..d07d333a2 100644 --- a/dev/tests/verification/Resources/BasicFunctionalTest.txt +++ b/dev/tests/verification/Resources/BasicFunctionalTest.txt @@ -138,7 +138,7 @@ class BasicFunctionalTestCest $I->moveForward(); // stepKey: moveForwardKey1 $I->moveMouseOver(".functionalTestSelector"); // stepKey: moveMouseOverKey1 $I->openNewTab(); // stepKey: openNewTabKey1 - $I->pauseExecution(); // stepKey: pauseExecutionKey1 + $I->pause(); // stepKey: pauseKey1 $I->pressKey("#page", "a"); // stepKey: pressKey1 $I->pressKey("#page", ['ctrl', 'a'],'new'); // stepKey: pressKey2 $I->pressKey("#page", ['shift', '111'],'1','x'); // stepKey: pressKey3 diff --git a/dev/tests/verification/TestModule/ActionGroup/XmlDuplicateActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/XmlDuplicateActionGroup.xml index 90f7090b0..464322f27 100644 --- a/dev/tests/verification/TestModule/ActionGroup/XmlDuplicateActionGroup.xml +++ b/dev/tests/verification/TestModule/ActionGroup/XmlDuplicateActionGroup.xml @@ -122,8 +122,8 @@ <openNewTab stepKey="newtab12"/> <parseFloat stepKey="parsefloat1"/> <parseFloat stepKey="parsefloat12"/> - <pauseExecution stepKey="pause1"/> - <pauseExecution stepKey="pause12"/> + <pause stepKey="pause1"/> + <pause stepKey="pause12"/> <pressKey selector="1" stepKey="press1"/> <pressKey selector="1" stepKey="press12"/> <reloadPage stepKey="reload1"/> diff --git a/dev/tests/verification/TestModule/Test/AssertTest.xml b/dev/tests/verification/TestModule/Test/AssertTest.xml index d17b60fae..fd81c9bea 100644 --- a/dev/tests/verification/TestModule/Test/AssertTest.xml +++ b/dev/tests/verification/TestModule/Test/AssertTest.xml @@ -39,6 +39,14 @@ <expectedResult type="string">ab</expectedResult> <actualResult type="const">['item1' => 'a', 'item2' => 'ab']</actualResult> </assertContains> + <assertStringContainsString stepKey="assertStringContainsString" message="pass"> + <expectedResult type="string">apple</expectedResult> + <actualResult type="string">apple</actualResult> + </assertStringContainsString> + <assertStringContainsStringIgnoringCase stepKey="assertStringContainsStringIgnoringCase" message="pass"> + <expectedResult type="string">Banana</expectedResult> + <actualResult type="string">banana</actualResult> + </assertStringContainsStringIgnoringCase> <assertCount stepKey="assertCount" message="pass"> <expectedResult type="int">2</expectedResult> <actualResult type="const">['a', 'b']</actualResult> @@ -103,14 +111,18 @@ <expectedResult type="int">5</expectedResult> <actualResult type="int">2</actualResult> </assertLessThanOrEqual> - <assertNotContains stepKey="assertNotContains1" message="pass"> + <assertNotContains stepKey="assertNotContains" message="pass"> <expectedResult type="string">bc</expectedResult> <actualResult type="const">['item1' => 'a', 'item2' => 'ab']</actualResult> </assertNotContains> - <assertNotContains stepKey="assertNotContains2" message="pass"> - <expectedResult type="string">bc</expectedResult> - <actualResult type="variable">text</actualResult> - </assertNotContains> + <assertStringNotContainsString stepKey="assertStringNotContainsString" message="pass"> + <expectedResult type="string">apple</expectedResult> + <actualResult type="string">banana</actualResult> + </assertStringNotContainsString> + <assertStringNotContainsStringIgnoringCase stepKey="assertStringNotContainsStringIgnoringCase" message="pass"> + <expectedResult type="string">apple</expectedResult> + <actualResult type="string">banana</actualResult> + </assertStringNotContainsStringIgnoringCase> <assertNotEmpty stepKey="assertNotEmpty1" message="pass"> <actualResult type="const">[1, 2]</actualResult> </assertNotEmpty> diff --git a/dev/tests/verification/TestModule/Test/BasicFunctionalTest/BasicFunctionalTest.xml b/dev/tests/verification/TestModule/Test/BasicFunctionalTest/BasicFunctionalTest.xml index ea2a48e9e..63c4857a0 100644 --- a/dev/tests/verification/TestModule/Test/BasicFunctionalTest/BasicFunctionalTest.xml +++ b/dev/tests/verification/TestModule/Test/BasicFunctionalTest/BasicFunctionalTest.xml @@ -87,7 +87,7 @@ <moveForward stepKey="moveForwardKey1"/> <moveMouseOver selector=".functionalTestSelector" stepKey="moveMouseOverKey1"/> <openNewTab stepKey="openNewTabKey1"/> - <pauseExecution stepKey="pauseExecutionKey1"/> + <pause stepKey="pauseKey1"/> <pressKey selector="#page" userInput="a" stepKey="pressKey1"/> <pressKey selector="#page" parameterArray="[['ctrl','a'],'new']" stepKey="pressKey2"/> <pressKey selector="#page" parameterArray="[['shift','111'],'1','x']" stepKey="pressKey3"/> diff --git a/dev/tests/verification/TestModule/Test/XmlDuplicateTest/XmlDuplicateTest.xml b/dev/tests/verification/TestModule/Test/XmlDuplicateTest/XmlDuplicateTest.xml index 6df962ffa..905a04779 100644 --- a/dev/tests/verification/TestModule/Test/XmlDuplicateTest/XmlDuplicateTest.xml +++ b/dev/tests/verification/TestModule/Test/XmlDuplicateTest/XmlDuplicateTest.xml @@ -125,8 +125,8 @@ <openNewTab stepKey="newtab12"/> <parseFloat stepKey="parsefloat1"/> <parseFloat stepKey="parsefloat12"/> - <pauseExecution stepKey="pause1"/> - <pauseExecution stepKey="pause12"/> + <pause stepKey="pause1"/> + <pause stepKey="pause12"/> <pressKey selector="1" stepKey="press1"/> <pressKey selector="1" stepKey="press12"/> <reloadPage stepKey="reload1"/> @@ -337,8 +337,8 @@ <openNewTab stepKey="newtab12"/> <parseFloat stepKey="parsefloat1"/> <parseFloat stepKey="parsefloat12"/> - <pauseExecution stepKey="pause1"/> - <pauseExecution stepKey="pause12"/> + <pause stepKey="pause1"/> + <pause stepKey="pause12"/> <pressKey selector="1" stepKey="press1"/> <pressKey selector="1" stepKey="press12"/> <reloadPage stepKey="reload1"/> @@ -548,8 +548,8 @@ <openNewTab stepKey="newtab12"/> <parseFloat stepKey="parsefloat1"/> <parseFloat stepKey="parsefloat12"/> - <pauseExecution stepKey="pause1"/> - <pauseExecution stepKey="pause12"/> + <pause stepKey="pause1"/> + <pause stepKey="pause12"/> <pressKey selector="1" stepKey="press1"/> <pressKey selector="1" stepKey="press12"/> <reloadPage stepKey="reload1"/> diff --git a/dev/tests/verification/Tests/SchemaValidationTest.php b/dev/tests/verification/Tests/SchemaValidationTest.php index 92442bd37..c6187974c 100644 --- a/dev/tests/verification/Tests/SchemaValidationTest.php +++ b/dev/tests/verification/Tests/SchemaValidationTest.php @@ -35,7 +35,7 @@ public function testInvalidTestSchema() * After method functionality * @return void */ - protected function tearDown() + protected function tearDown(): void { AspectMock::clean(); } diff --git a/dev/tests/verification/Tests/SuiteGenerationTest.php b/dev/tests/verification/Tests/SuiteGenerationTest.php index 485ef6411..926287aad 100644 --- a/dev/tests/verification/Tests/SuiteGenerationTest.php +++ b/dev/tests/verification/Tests/SuiteGenerationTest.php @@ -39,7 +39,7 @@ class SuiteGenerationTest extends MftfTestCase /** * Set up config.yml for testing */ - public static function setUpBeforeClass() + public static function setUpBeforeClass(): void { // destroy _generated if it exists if (file_exists(self::GENERATE_RESULT_DIR)) { @@ -47,7 +47,7 @@ public static function setUpBeforeClass() } } - public function setUp() + public function setUp(): void { // copy config yml file to test dir $fileSystem = new \Symfony\Component\Filesystem\Filesystem(); @@ -392,7 +392,7 @@ public function testSuiteCommentsGeneration() * revert any changes made to config.yml * remove _generated directory */ - public function tearDown() + public function tearDown(): void { DirSetupUtil::rmdirRecursive(self::GENERATE_RESULT_DIR); @@ -406,7 +406,7 @@ public function tearDown() /** * Remove yml if created during tests and did not exist before */ - public static function tearDownAfterClass() + public static function tearDownAfterClass(): void { TestLoggingUtil::getInstance()->clearMockLoggingUtil(); } diff --git a/docs/test/actions.md b/docs/test/actions.md index 9cf3d43f6..a403b0942 100644 --- a/docs/test/actions.md +++ b/docs/test/actions.md @@ -1422,9 +1422,9 @@ Attribute|Type|Use|Description `before`|string|optional| `stepKey` of action that must be executed next. `after`|string|optional| `stepKey` of preceding action. -### pauseExecution +### pause -See [pauseExecution docs on codeception.com](http://codeception.com/docs/modules/WebDriver#pauseExecution). +See [pause docs on codeception.com](https://codeception.com/docs/02-GettingStarted). Attribute|Type|Use|Description ---|---|---|--- @@ -1436,7 +1436,7 @@ Attribute|Type|Use|Description ```xml <!-- Halt test execution until the `enter` key is pressed to continue. --> -<pauseExecution stepKey="pause"/> +<pause stepKey="pause"/> ``` ### pressKey diff --git a/docs/test/assertions.md b/docs/test/assertions.md index dfe4c3d4b..8577c85c3 100644 --- a/docs/test/assertions.md +++ b/docs/test/assertions.md @@ -1,6 +1,5 @@ # Assertions - Assertions serve to pass or fail the [test](../test.md#test-tag) if a condition is not met. These assertions will look familiar to you if you've used any other testing framework, like PHPUnit. All assertions contain the same [common actions attributes](./actions.md#common-attributes): `stepKey`, `before`, and `after`. @@ -31,6 +30,8 @@ To use variables embedded in a string in `expected` and `actual` of your asserti `actual="A long assert string {$stepKeyOfGrab} with an embedded variable reference." actualType="variable"` +In case of `assertContains` actions, `<expectedResult>` is the needle and `<actualResult>` is the haystack. + ## Example The following example shows a common test that gets text from a page and asserts that it matches what we expect to see. If it does not, the test will fail at the assert step. @@ -130,6 +131,28 @@ Attribute|Type|Use|Description `before`|string|optional| `stepKey` of action that must be executed next. `after`|string|optional| `stepKey` of the preceding action. +### assertStringContainsString + +See [assertStringContainsString docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertStringContainsString). + +Attribute|Type|Use|Description +---|---|---|--- +`message`|string|optional|Text describing the cause of the failure. +`stepKey`|string|required| Unique identifier of the text step. +`before`|string|optional| `stepKey` of the action that must be executed next. +`after`|string|optional| `stepKey` of the preceding action. + +### assertStringContainsStringIgnoringCase + +See [assertStringContainsStringIgnoringCase docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertStringContainsStringIgnoringCase). + +Attribute|Type|Use|Description +---|---|---|--- +`message`|string|optional|Message describing the cause of failure. +`stepKey`|string|required| A unique identifier of the text step. +`before`|string|optional| `stepKey` of the action that must be executed next. +`after`|string|optional| `stepKey` of the preceding action. + ### assertCount See [assertCount docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertCount). @@ -307,6 +330,28 @@ Attribute|Type|Use|Description `before`|string|optional| `stepKey` of action that must be executed next. `after`|string|optional| `stepKey` of the preceding action. +### assertStringNotContainsString + +See [assertStringNotContainsString docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertStringNotContainsString). + +Attribute|Type|Use|Description +---|---|---|--- +`message`|string|optional|Text of informational message about a cause of failure. +`stepKey`|string|required| A unique identifier of the text step. +`before`|string|optional| `stepKey` of action that must be executed next. +`after`|string|optional| `stepKey` of the preceding action. + +### assertStringContainsStringIgnoringCase + +See [assertStringNotContainsStringIgnoringCase docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertStringNotContainsStringIgnoringCase). + +Attribute|Type|Use|Description +---|---|---|--- +`message`|string|optional|Text of informational message about a cause of failure. +`stepKey`|string|required| A unique identifier of the text step. +`before`|string|optional| `stepKey` of action that must be executed next. +`after`|string|optional| `stepKey` of the preceding action. + ### assertNotEmpty See [assertNotEmpty docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertNotEmpty). diff --git a/etc/di.xml b/etc/di.xml index 1dd91896a..9b0c53af1 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -8,7 +8,7 @@ <!-- Entity value gets replaced in Dom.php before reading $xml --> <!DOCTYPE config [ - <!ENTITY commonTestActions "acceptPopup|actionGroup|amOnPage|amOnUrl|amOnSubdomain|appendField|assertArrayIsSorted|assertArraySubset|assertElementContainsAttribute|attachFile|cancelPopup|checkOption|clearField|click|clickWithLeftButton|clickWithRightButton|closeAdminNotification|closeTab|comment|conditionalClick|createData|deleteData|updateData|getData|dontSee|dontSeeJsError|dontSeeCheckboxIsChecked|dontSeeCookie|dontSeeCurrentUrlEquals|dontSeeCurrentUrlMatches|dontSeeElement|dontSeeElementInDOM|dontSeeInCurrentUrl|dontSeeInField|dontSeeInFormFields|dontSeeInPageSource|dontSeeInSource|dontSeeInTitle|dontSeeLink|dontSeeOptionIsSelected|doubleClick|dragAndDrop|entity|executeJS|fillField|formatMoney|generateDate|grabAttributeFrom|grabCookie|grabFromCurrentUrl|grabMultiple|grabPageSource|grabTextFrom|grabValueFrom|loadSessionSnapshot|loginAsAdmin|magentoCLI|magentoCron|makeScreenshot|maximizeWindow|moveBack|moveForward|moveMouseOver|mSetLocale|mResetLocale|openNewTab|pauseExecution|parseFloat|pressKey|reloadPage|resetCookie|submitForm|resizeWindow|saveSessionSnapshot|scrollTo|scrollToTopOfPage|searchAndMultiSelectOption|see|seeCheckboxIsChecked|seeCookie|seeCurrentUrlEquals|seeCurrentUrlMatches|seeElement|seeElementInDOM|seeInCurrentUrl|seeInField|seeInFormFields|seeInPageSource|seeInPopup|seeInSource|seeInTitle|seeLink|seeNumberOfElements|seeOptionIsSelected|selectOption|setCookie|submitForm|switchToIFrame|switchToNextTab|switchToPreviousTab|switchToWindow|typeInPopup|uncheckOption|unselectOption|wait|waitForAjaxLoad|waitForElement|waitForElementChange|waitForElementNotVisible|waitForElementVisible|waitForPwaElementNotVisible|waitForPwaElementVisible|waitForJS|waitForLoadingMaskToDisappear|waitForPageLoad|waitForText|assertArrayHasKey|assertArrayNotHasKey|assertArraySubset|assertContains|assertCount|assertEmpty|assertEquals|assertFalse|assertFileExists|assertFileNotExists|assertGreaterOrEquals|assertGreaterThan|assertGreaterThanOrEqual|assertInstanceOf|assertInternalType|assertIsEmpty|assertLessOrEquals|assertLessThan|assertLessThanOrEqual|assertNotContains|assertNotEmpty|assertNotEquals|assertNotInstanceOf|assertNotNull|assertNotRegExp|assertNotSame|assertNull|assertRegExp|assertSame|assertStringStartsNotWith|assertStringStartsWith|assertTrue|expectException|fail|dontSeeFullUrlEquals|dontSee|dontSeeFullUrlMatches|dontSeeInFullUrl|seeFullUrlEquals|seeFullUrlMatches|seeInFullUrl|grabFromFullUrl|helper"> + <!ENTITY commonTestActions "acceptPopup|actionGroup|amOnPage|amOnUrl|amOnSubdomain|appendField|assertArrayIsSortasserted|assertArraySubset|assertElementContainsAttribute|attachFile|cancelPopup|checkOption|clearField|click|clickWithLeftButton|clickWithRightButton|closeAdminNotification|closeTab|comment|conditionalClick|createData|deleteData|updateData|getData|dontSee|dontSeeJsError|dontSeeCheckboxIsChecked|dontSeeCookie|dontSeeCurrentUrlEquals|dontSeeCurrentUrlMatches|dontSeeElement|dontSeeElementInDOM|dontSeeInCurrentUrl|dontSeeInField|dontSeeInFormFields|dontSeeInPageSource|dontSeeInSource|dontSeeInTitle|dontSeeLink|dontSeeOptionIsSelected|doubleClick|dragAndDrop|entity|executeJS|fillField|formatMoney|generateDate|grabAttributeFrom|grabCookie|grabFromCurrentUrl|grabMultiple|grabPageSource|grabTextFrom|grabValueFrom|loadSessionSnapshot|loginAsAdmin|magentoCLI|magentoCron|makeScreenshot|maximizeWindow|moveBack|moveForward|moveMouseOver|mSetLocale|mResetLocale|openNewTab|pause|parseFloat|pressKey|reloadPage|resetCookie|submitForm|resizeWindow|saveSessionSnapshot|scrollTo|scrollToTopOfPage|searchAndMultiSelectOption|see|seeCheckboxIsChecked|seeCookie|seeCurrentUrlEquals|seeCurrentUrlMatches|seeElement|seeElementInDOM|seeInCurrentUrl|seeInField|seeInFormFields|seeInPageSource|seeInPopup|seeInSource|seeInTitle|seeLink|seeNumberOfElements|seeOptionIsSelected|selectOption|setCookie|submitForm|switchToIFrame|switchToNextTab|switchToPreviousTab|switchToWindow|typeInPopup|uncheckOption|unselectOption|wait|waitForAjaxLoad|waitForElement|waitForElementChange|waitForElementNotVisible|waitForElementVisible|waitForPwaElementNotVisible|waitForPwaElementVisible|waitForJS|waitForLoadingMaskToDisappear|waitForPageLoad|waitForText|assertArrayHasKey|assertArrayNotHasKey|assertArraySubset|assertContains|assertStringContainsString|assertStringContainsStringIgnoringCase|assertCount|assertEmpty|assertEquals|assertFalse|assertFileExists|assertFileNotExists|assertGreaterOrEquals|assertGreaterThan|assertGreaterThanOrEqual|assertInstanceOf|assertInternalType|assertIsEmpty|assertLessOrEquals|assertLessThan|assertLessThanOrEqual|assertNotContains|assertStringNotContainsString|assertStringNotContainsStringIgnoringCase|assertNotEmpty|assertNotEquals|assertNotInstanceOf|assertNotNull|assertNotRegExp|assertNotSame|assertNull|assertRegExp|assertSame|assertStringStartsNotWith|assertStringStartsWith|assertTrue|expectException|fail|dontSeeFullUrlEquals|dontSee|dontSeeFullUrlMatches|dontSeeInFullUrl|seeFullUrlEquals|seeFullUrlMatches|seeInFullUrl|grabFromFullUrl|helper"> ]> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../src/Magento/FunctionalTestingFramework/ObjectManager/etc/config.xsd"> diff --git a/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php b/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php index e9e1c344c..d555d6b19 100644 --- a/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php +++ b/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php @@ -5,6 +5,8 @@ */ namespace Magento\FunctionalTestingFramework\Allure\Adapter; +use Codeception\Codecept; +use Codeception\Test\Cest; use Codeception\Step\Comment; use Magento\FunctionalTestingFramework\Suite\Handlers\SuiteObjectHandler; use Magento\FunctionalTestingFramework\Test\Objects\ActionGroupObject; @@ -12,6 +14,7 @@ use Magento\FunctionalTestingFramework\Util\TestGenerator; use Yandex\Allure\Adapter\Model\Status; use Yandex\Allure\Adapter\Model\Step; +use Yandex\Allure\Adapter\Allure; use Yandex\Allure\Codeception\AllureCodeception; use Yandex\Allure\Adapter\Event\StepStartedEvent; use Yandex\Allure\Adapter\Event\StepFinishedEvent; @@ -19,9 +22,11 @@ use Yandex\Allure\Adapter\Event\TestCaseFailedEvent; use Yandex\Allure\Adapter\Event\TestCaseFinishedEvent; use Yandex\Allure\Adapter\Event\TestCaseBrokenEvent; +use Yandex\Allure\Adapter\Event\AddAttachmentEvent; use Codeception\Event\FailEvent; use Codeception\Event\SuiteEvent; use Codeception\Event\StepEvent; +use Codeception\Event\TestEvent; /** * Class MagentoAllureAdapter @@ -245,10 +250,11 @@ public function testError(FailEvent $failEvent) /** * Override of parent method, polls stepStorage for testcase and formats it according to actionGroup nesting. - * + * @param TestEvent $testEvent + * @throws \Yandex\Allure\Adapter\AllureException * @return void */ - public function testEnd() + public function testEnd(TestEvent $testEvent) { // Pops top of stepStorage, need to add it back in after processing $rootStep = $this->getLifecycle()->getStepStorage()->pollLast(); @@ -309,9 +315,28 @@ function () use ($rootStep, $formattedSteps) { $this->getLifecycle()->getStepStorage()->put($rootStep); + $this->addAttachmentEvent($testEvent); + $this->getLifecycle()->fire(new TestCaseFinishedEvent()); } + /** + * Fire add attachment event + * @param TestEvent $testEvent + * @throws \Yandex\Allure\Adapter\AllureException + * @return void + */ + private function addAttachmentEvent(TestEvent $testEvent) + { + // attachments supported since Codeception 3.0 + if (version_compare(Codecept::VERSION, '3.0.0') > -1 && $testEvent->getTest() instanceof Cest) { + $artifacts = $testEvent->getTest()->getMetadata()->getReports(); + foreach ($artifacts as $name => $artifact) { + Allure::lifecycle()->fire(new AddAttachmentEvent($artifact, $name, null)); + } + } + } + /** * Reads action group stepKey from step. * diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index b02675163..4ff1dc271 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -6,6 +6,7 @@ namespace Magento\FunctionalTestingFramework\Module; +use Codeception\Lib\Actor\Shared\Pause; use Codeception\Module\WebDriver; use Codeception\Test\Descriptor; use Codeception\TestInterface; @@ -52,6 +53,7 @@ class MagentoWebDriver extends WebDriver { use AttachmentSupport; + use Pause; const MAGENTO_CRON_INTERVAL = 60; const MAGENTO_CRON_COMMAND = 'cron:run'; @@ -256,7 +258,7 @@ public function dontSeeInCurrentUrl($needle) $actualUrl = $this->webDriver->getCurrentURL(); $comparison = "Expected: $needle\nActual: $actualUrl"; AllureHelper::addAttachmentToCurrentStep($comparison, 'Comparison'); - $this->assertNotContains($needle, $actualUrl); + $this->assertStringNotContainsString($needle, $actualUrl); } /** @@ -325,7 +327,7 @@ public function seeInCurrentUrl($needle) $actualUrl = $this->webDriver->getCurrentURL(); $comparison = "Expected: $needle\nActual: $actualUrl"; AllureHelper::addAttachmentToCurrentStep($comparison, 'Comparison'); - $this->assertContains($needle, $actualUrl); + $this->assertStringContainsString($needle, $actualUrl); } /** @@ -708,7 +710,7 @@ public function assertElementContainsAttribute($selector, $attribute, $value) // 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); + $this->assertStringContainsString($value, $attributes); } } @@ -1080,4 +1082,25 @@ private function executeCronjobs($cronGroups, $timeout, $arguments): string return sprintf('%s (wait: %ss, execution: %ss)', $cronResult, $waitFor, round($timeEnd - $timeStart, 2)); } + + /** + * Switch to another frame on the page by name, ID, CSS or XPath. + * + * @param string|null $locator + * @return void + * @throws \Exception + */ + public function switchToIFrame($locator = null) + { + try { + parent::switchToIFrame($locator); + } catch (\Exception $e) { + $els = $this->_findElements("#$locator"); + if (!count($els)) { + $this->debug('Failed to find locator by ID: ' . $e->getMessage()); + throw new \Exception("IFrame with $locator was not found."); + } + $this->webDriver->switchTo()->frame($els[0]); + } + } } diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/assertActions.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/assertActions.xsd index 22f306382..694429a30 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/assertActions.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/assertActions.xsd @@ -16,6 +16,8 @@ <xs:element type="assertArrayNotHasKeyType" name="assertArrayNotHasKey" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertArraySubsetType" name="assertArraySubset" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertContainsType" name="assertContains" minOccurs="0" maxOccurs="unbounded"/> + <xs:element type="assertStringContainsStringType" name="assertStringContainsString" minOccurs="0" maxOccurs="unbounded"/> + <xs:element type="assertStringContainsStringIgnoringCaseType" name="assertStringContainsStringIgnoringCase" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertCountType" name="assertCount" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertEmptyType" name="assertEmpty" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertEqualsType" name="assertEquals" minOccurs="0" maxOccurs="unbounded"/> @@ -32,6 +34,8 @@ <xs:element type="assertLessThanType" name="assertLessThan" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertLessThanOrEqualType" name="assertLessThanOrEqual" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertNotContainsType" name="assertNotContains" minOccurs="0" maxOccurs="unbounded"/> + <xs:element type="assertStringNotContainsStringType" name="assertStringNotContainsString" minOccurs="0" maxOccurs="unbounded"/> + <xs:element type="assertStringNotContainsStringIgnoringCaseType" name="assertStringNotContainsStringIgnoringCase" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertNotEmptyType" name="assertNotEmpty" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertNotEqualsType" name="assertNotEquals" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertNotInstanceOfType" name="assertNotInstanceOf" minOccurs="0" maxOccurs="unbounded"/> @@ -156,6 +160,34 @@ <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> + <xs:complexType name="assertStringContainsStringType"> + <xs:annotation> + <xs:documentation> + Asserts that given string contains a value. + </xs:documentation> + </xs:annotation> + <xs:choice maxOccurs="unbounded"> + <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> + <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> + </xs:choice> + <xs:attribute ref="message"/> + <xs:attributeGroup ref="commonActionAttributes"/> + </xs:complexType> + + <xs:complexType name="assertStringContainsStringIgnoringCaseType"> + <xs:annotation> + <xs:documentation> + Asserts that given string contains a value ignoring case. + </xs:documentation> + </xs:annotation> + <xs:choice maxOccurs="unbounded"> + <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> + <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> + </xs:choice> + <xs:attribute ref="message"/> + <xs:attributeGroup ref="commonActionAttributes"/> + </xs:complexType> + <xs:complexType name="assertCountType"> <xs:annotation> <xs:documentation> @@ -376,6 +408,34 @@ <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> + <xs:complexType name="assertStringNotContainsStringType"> + <xs:annotation> + <xs:documentation> + Asserts that given string does not contain a value. + </xs:documentation> + </xs:annotation> + <xs:choice maxOccurs="unbounded"> + <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> + <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> + </xs:choice> + <xs:attribute ref="message"/> + <xs:attributeGroup ref="commonActionAttributes"/> + </xs:complexType> + + <xs:complexType name="assertStringNotContainsStringIgnoringCaseType"> + <xs:annotation> + <xs:documentation> + Asserts that given string does not contain a value ignoring case. + </xs:documentation> + </xs:annotation> + <xs:choice maxOccurs="unbounded"> + <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> + <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> + </xs:choice> + <xs:attribute ref="message"/> + <xs:attributeGroup ref="commonActionAttributes"/> + </xs:complexType> + <xs:complexType name="assertNotEmptyType"> <xs:annotation> <xs:documentation> diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/actionTypeTags.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/actionTypeTags.xsd index 7bcdbdf50..def2964af 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/actionTypeTags.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/actionTypeTags.xsd @@ -43,7 +43,7 @@ <xs:element type="moveForwardType" name="moveForward" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="moveMouseOverType" name="moveMouseOver" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="openNewTabType" name="openNewTab" minOccurs="0" maxOccurs="unbounded"/> - <xs:element type="pauseExecutionType" name="pauseExecution" minOccurs="0" maxOccurs="unbounded"/> + <xs:element type="pauseType" name="pause" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="pressKeyType" name="pressKey" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="reloadPageType" name="reloadPage" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="resetCookieType" name="resetCookie" minOccurs="0" maxOccurs="unbounded"/> @@ -415,7 +415,7 @@ </xs:simpleContent> </xs:complexType> - <xs:complexType name="pauseExecutionType"> + <xs:complexType name="pauseType"> <xs:annotation> <xs:documentation> Pauses test execution in debug mode. To proceed test, press "ENTER" in console. Useful for test writing. diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 19319d0d7..be4c38e02 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1294,6 +1294,10 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato case "assertCount": case "assertContains": case "assertNotContains": + case "assertStringContainsString": + case "assertStringContainsStringIgnoringCase": + case "assertStringNotContainsString": + case "assertStringNotContainsStringIgnoringCase": case "expectException": $testSteps .= $this->wrapFunctionCall( $actor, From f712fc31bbf6f8b079c96e77d80df6742d010c18 Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Wed, 15 Apr 2020 10:35:28 -0500 Subject: [PATCH 336/888] MQE-2076: [PHPUnit 9] assertEquals and assertNotEquals optional parameters removed --- etc/di.xml | 2 +- .../Test/etc/Actions/assertActions.xsd | 100 +++++++++++++++++- .../Util/TestGenerator.php | 27 ++++- 3 files changed, 123 insertions(+), 6 deletions(-) diff --git a/etc/di.xml b/etc/di.xml index 9b0c53af1..0a9da0422 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -8,7 +8,7 @@ <!-- Entity value gets replaced in Dom.php before reading $xml --> <!DOCTYPE config [ - <!ENTITY commonTestActions "acceptPopup|actionGroup|amOnPage|amOnUrl|amOnSubdomain|appendField|assertArrayIsSortasserted|assertArraySubset|assertElementContainsAttribute|attachFile|cancelPopup|checkOption|clearField|click|clickWithLeftButton|clickWithRightButton|closeAdminNotification|closeTab|comment|conditionalClick|createData|deleteData|updateData|getData|dontSee|dontSeeJsError|dontSeeCheckboxIsChecked|dontSeeCookie|dontSeeCurrentUrlEquals|dontSeeCurrentUrlMatches|dontSeeElement|dontSeeElementInDOM|dontSeeInCurrentUrl|dontSeeInField|dontSeeInFormFields|dontSeeInPageSource|dontSeeInSource|dontSeeInTitle|dontSeeLink|dontSeeOptionIsSelected|doubleClick|dragAndDrop|entity|executeJS|fillField|formatMoney|generateDate|grabAttributeFrom|grabCookie|grabFromCurrentUrl|grabMultiple|grabPageSource|grabTextFrom|grabValueFrom|loadSessionSnapshot|loginAsAdmin|magentoCLI|magentoCron|makeScreenshot|maximizeWindow|moveBack|moveForward|moveMouseOver|mSetLocale|mResetLocale|openNewTab|pause|parseFloat|pressKey|reloadPage|resetCookie|submitForm|resizeWindow|saveSessionSnapshot|scrollTo|scrollToTopOfPage|searchAndMultiSelectOption|see|seeCheckboxIsChecked|seeCookie|seeCurrentUrlEquals|seeCurrentUrlMatches|seeElement|seeElementInDOM|seeInCurrentUrl|seeInField|seeInFormFields|seeInPageSource|seeInPopup|seeInSource|seeInTitle|seeLink|seeNumberOfElements|seeOptionIsSelected|selectOption|setCookie|submitForm|switchToIFrame|switchToNextTab|switchToPreviousTab|switchToWindow|typeInPopup|uncheckOption|unselectOption|wait|waitForAjaxLoad|waitForElement|waitForElementChange|waitForElementNotVisible|waitForElementVisible|waitForPwaElementNotVisible|waitForPwaElementVisible|waitForJS|waitForLoadingMaskToDisappear|waitForPageLoad|waitForText|assertArrayHasKey|assertArrayNotHasKey|assertArraySubset|assertContains|assertStringContainsString|assertStringContainsStringIgnoringCase|assertCount|assertEmpty|assertEquals|assertFalse|assertFileExists|assertFileNotExists|assertGreaterOrEquals|assertGreaterThan|assertGreaterThanOrEqual|assertInstanceOf|assertInternalType|assertIsEmpty|assertLessOrEquals|assertLessThan|assertLessThanOrEqual|assertNotContains|assertStringNotContainsString|assertStringNotContainsStringIgnoringCase|assertNotEmpty|assertNotEquals|assertNotInstanceOf|assertNotNull|assertNotRegExp|assertNotSame|assertNull|assertRegExp|assertSame|assertStringStartsNotWith|assertStringStartsWith|assertTrue|expectException|fail|dontSeeFullUrlEquals|dontSee|dontSeeFullUrlMatches|dontSeeInFullUrl|seeFullUrlEquals|seeFullUrlMatches|seeInFullUrl|grabFromFullUrl|helper"> + <!ENTITY commonTestActions "acceptPopup|actionGroup|amOnPage|amOnUrl|amOnSubdomain|appendField|assertArrayIsSortasserted|assertArraySubset|assertElementContainsAttribute|attachFile|cancelPopup|checkOption|clearField|click|clickWithLeftButton|clickWithRightButton|closeAdminNotification|closeTab|comment|conditionalClick|createData|deleteData|updateData|getData|dontSee|dontSeeJsError|dontSeeCheckboxIsChecked|dontSeeCookie|dontSeeCurrentUrlEquals|dontSeeCurrentUrlMatches|dontSeeElement|dontSeeElementInDOM|dontSeeInCurrentUrl|dontSeeInField|dontSeeInFormFields|dontSeeInPageSource|dontSeeInSource|dontSeeInTitle|dontSeeLink|dontSeeOptionIsSelected|doubleClick|dragAndDrop|entity|executeJS|fillField|formatMoney|generateDate|grabAttributeFrom|grabCookie|grabFromCurrentUrl|grabMultiple|grabPageSource|grabTextFrom|grabValueFrom|loadSessionSnapshot|loginAsAdmin|magentoCLI|magentoCron|makeScreenshot|maximizeWindow|moveBack|moveForward|moveMouseOver|mSetLocale|mResetLocale|openNewTab|pause|parseFloat|pressKey|reloadPage|resetCookie|submitForm|resizeWindow|saveSessionSnapshot|scrollTo|scrollToTopOfPage|searchAndMultiSelectOption|see|seeCheckboxIsChecked|seeCookie|seeCurrentUrlEquals|seeCurrentUrlMatches|seeElement|seeElementInDOM|seeInCurrentUrl|seeInField|seeInFormFields|seeInPageSource|seeInPopup|seeInSource|seeInTitle|seeLink|seeNumberOfElements|seeOptionIsSelected|selectOption|setCookie|submitForm|switchToIFrame|switchToNextTab|switchToPreviousTab|switchToWindow|typeInPopup|uncheckOption|unselectOption|wait|waitForAjaxLoad|waitForElement|waitForElementChange|waitForElementNotVisible|waitForElementVisible|waitForPwaElementNotVisible|waitForPwaElementVisible|waitForJS|waitForLoadingMaskToDisappear|waitForPageLoad|waitForText|assertArrayHasKey|assertArrayNotHasKey|assertArraySubset|assertContains|assertStringContainsString|assertStringContainsStringIgnoringCase|assertCount|assertEmpty|assertEquals|assertFalse|assertFileExists|assertFileNotExists|assertGreaterOrEquals|assertGreaterThan|assertGreaterThanOrEqual|assertInstanceOf|assertInternalType|assertIsEmpty|assertLessOrEquals|assertLessThan|assertLessThanOrEqual|assertNotContains|assertStringNotContainsString|assertStringNotContainsStringIgnoringCase|assertNotEmpty|assertNotEquals|assertNotInstanceOf|assertNotNull|assertNotRegExp|assertNotSame|assertNull|assertRegExp|assertSame|assertStringStartsNotWith|assertStringStartsWith|assertTrue|expectException|fail|dontSeeFullUrlEquals|dontSee|dontSeeFullUrlMatches|dontSeeInFullUrl|seeFullUrlEquals|seeFullUrlMatches|seeInFullUrl|grabFromFullUrl|helper|assertEqualsWithDelta|assertEqualsCanonicalizing|assertEqualsIgnoringCase|assertNotEqualsWithDelta|assertNotEqualsCanonicalizing|assertNotEqualsIgnoringCase"> ]> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../src/Magento/FunctionalTestingFramework/ObjectManager/etc/config.xsd"> diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/assertActions.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/assertActions.xsd index 694429a30..402c3bd18 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/assertActions.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/assertActions.xsd @@ -21,6 +21,9 @@ <xs:element type="assertCountType" name="assertCount" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertEmptyType" name="assertEmpty" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertEqualsType" name="assertEquals" minOccurs="0" maxOccurs="unbounded"/> + <xs:element type="assertEqualsWithDeltaType" name="assertEqualsWithDelta" minOccurs="0" maxOccurs="unbounded"/> + <xs:element type="assertEqualsCanonicalizingType" name="assertEqualsCanonicalizing" minOccurs="0" maxOccurs="unbounded"/> + <xs:element type="assertEqualsIgnoringCaseType" name="assertEqualsIgnoringCase" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertFalseType" name="assertFalse" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertFileExistsType" name="assertFileExists" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertFileNotExistsType" name="assertFileNotExists" minOccurs="0" maxOccurs="unbounded"/> @@ -38,6 +41,9 @@ <xs:element type="assertStringNotContainsStringIgnoringCaseType" name="assertStringNotContainsStringIgnoringCase" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertNotEmptyType" name="assertNotEmpty" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertNotEqualsType" name="assertNotEquals" minOccurs="0" maxOccurs="unbounded"/> + <xs:element type="assertNotEqualsWithDeltaType" name="assertNotEqualsWithDelta" minOccurs="0" maxOccurs="unbounded"/> + <xs:element type="assertNotEqualsCanonicalizingType" name="assertNotEqualsCanonicalizing" minOccurs="0" maxOccurs="unbounded"/> + <xs:element type="assertNotEqualsIgnoringCaseType" name="assertNotEqualsIgnoringCase" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertNotInstanceOfType" name="assertNotInstanceOf" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertNotNullType" name="assertNotNull" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertNotRegExpType" name="assertNotRegExp" minOccurs="0" maxOccurs="unbounded"/> @@ -218,7 +224,21 @@ <xs:complexType name="assertEqualsType"> <xs:annotation> <xs:documentation> - Asserts that two given variables are equal. Can be given a "delta" to allow precision tolerance in floating point comparison. + Asserts that two given variables are equal. + </xs:documentation> + </xs:annotation> + <xs:choice maxOccurs="unbounded"> + <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> + <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> + </xs:choice> + <xs:attribute ref="message"/> + <xs:attributeGroup ref="commonActionAttributes"/> + </xs:complexType> + + <xs:complexType name="assertEqualsWithDeltaType"> + <xs:annotation> + <xs:documentation> + Asserts that two given variables are equal. Accepts a delta. </xs:documentation> </xs:annotation> <xs:choice maxOccurs="unbounded"> @@ -230,6 +250,36 @@ <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> + <xs:complexType name="assertEqualsIgnoringCaseType"> + <xs:annotation> + <xs:documentation> + Asserts that two given variables are equal. + </xs:documentation> + </xs:annotation> + <xs:choice maxOccurs="unbounded"> + <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> + <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> + </xs:choice> + <xs:attribute ref="message"/> + <xs:attributeGroup ref="commonActionAttributes"/> + </xs:complexType> + + <xs:complexType name="assertEqualsCanonicalizingType"> + <xs:annotation> + <xs:documentation> + Asserts that two given variables are equal. The contents are canonicalized before they are compared. + For instance, when the two variables $expected and $actual are arrays, then these arrays are + sorted before they are compared. + </xs:documentation> + </xs:annotation> + <xs:choice maxOccurs="unbounded"> + <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> + <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> + </xs:choice> + <xs:attribute ref="message"/> + <xs:attributeGroup ref="commonActionAttributes"/> + </xs:complexType> + <xs:complexType name="assertFalseType"> <xs:annotation> <xs:documentation> @@ -452,7 +502,7 @@ <xs:complexType name="assertNotEqualsType"> <xs:annotation> <xs:documentation> - Asserts that actual and expected are not equal. Can be given a "delta" to allow precision tolerance in floating point comparison. + Asserts that actual and expected are not equal. </xs:documentation> </xs:annotation> <xs:choice maxOccurs="unbounded"> @@ -460,7 +510,51 @@ <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> </xs:choice> <xs:attribute ref="message"/> + <xs:attributeGroup ref="commonActionAttributes"/> + </xs:complexType> + + <xs:complexType name="assertNotEqualsWithDeltaType"> + <xs:annotation> + <xs:documentation> + Asserts that two given variables are not equal. Accepts a delta. + </xs:documentation> + </xs:annotation> + <xs:choice maxOccurs="unbounded"> + <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> + <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> + </xs:choice> <xs:attribute ref="delta"/> + <xs:attribute ref="message"/> + <xs:attributeGroup ref="commonActionAttributes"/> + </xs:complexType> + + <xs:complexType name="assertNotEqualsIgnoringCaseType"> + <xs:annotation> + <xs:documentation> + Asserts that actual and expected are not equal. + </xs:documentation> + </xs:annotation> + <xs:choice maxOccurs="unbounded"> + <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> + <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> + </xs:choice> + <xs:attribute ref="message"/> + <xs:attributeGroup ref="commonActionAttributes"/> + </xs:complexType> + + <xs:complexType name="assertNotEqualsCanonicalizingType"> + <xs:annotation> + <xs:documentation> + Asserts that two given variables are equal. The contents are canonicalized before they are compared. + For instance, when the two variables $expected and $actual are arrays, then these arrays are + sorted before they are compared. + </xs:documentation> + </xs:annotation> + <xs:choice maxOccurs="unbounded"> + <xs:element name="expectedResult" type="expectedResultType" minOccurs="0"/> + <xs:element name="actualResult" type="actualResultType" minOccurs="0"/> + </xs:choice> + <xs:attribute ref="message"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> @@ -669,4 +763,4 @@ <xs:enumeration value="const"/> </xs:restriction> </xs:simpleType> -</xs:schema> \ No newline at end of file +</xs:schema> diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index be4c38e02..c919f6188 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1272,7 +1272,6 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $visible ); break; - case "assertEquals": case "assertGreaterOrEquals": case "assertGreaterThan": case "assertGreaterThanOrEqual": @@ -1280,7 +1279,6 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato case "assertLessOrEquals": case "assertLessThan": case "assertLessThanOrEqual": - case "assertNotEquals": case "assertInstanceOf": case "assertNotInstanceOf": case "assertNotRegExp": @@ -1308,6 +1306,31 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $assertDelta ); break; + case "assertEquals": + case "assertNotEquals": + case "assertEqualsIgnoringCase": + case "assertNotEqualsIgnoringCase": + case "assertEqualsCanonicalizing": + case "assertNotEqualsCanonicalizing": + $testSteps .= $this->wrapFunctionCall( + $actor, + $actionObject, + $assertExpected, + $assertActual, + $assertMessage + ); + break; + case "assertEqualsWithDelta": + case "assertNotEqualsWithDelta": + $testSteps .= $this->wrapFunctionCall( + $actor, + $actionObject, + $assertExpected, + $assertActual, + $assertDelta, + $assertMessage + ); + break; case "assertElementContainsAttribute": // If a blank string or null is passed in we need to pass a blank string to the function. if (empty($assertExpected)) { From 8d6b4fc63dbd2ab714dd9e2f36dde5ac33d1ad84 Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Thu, 16 Apr 2020 13:29:50 -0500 Subject: [PATCH 337/888] MQE-2076: [PHPUnit 9] assertEquals and assertNotEquals optional parameters removed --- .../verification/Resources/AssertTest.txt | 10 +++++-- .../TestModule/Test/AssertTest.xml | 29 +++++++++++++++++-- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/dev/tests/verification/Resources/AssertTest.txt b/dev/tests/verification/Resources/AssertTest.txt index 7697b7baf..dfbee497b 100644 --- a/dev/tests/verification/Resources/AssertTest.txt +++ b/dev/tests/verification/Resources/AssertTest.txt @@ -69,7 +69,7 @@ class AssertTestCest $I->assertStringNotContainsStringIgnoringCase("apple", "banana", "pass"); // stepKey: assertStringNotContainsStringIgnoringCase $I->assertNotEmpty([1, 2], "pass"); // stepKey: assertNotEmpty1 $I->assertNotEmpty($text, "pass"); // stepKey: assertNotEmpty2 - $I->assertNotEquals(2, 5, "pass", 0); // stepKey: assertNotEquals + $I->assertNotEquals(2, 5, "pass"); // stepKey: assertNotEquals $I->assertNotNull("abc", "pass"); // stepKey: assertNotNull1 $I->assertNotNull($text, "pass"); // stepKey: assertNotNull2 $I->assertNotRegExp("/foo/", "bar", "pass"); // stepKey: assertNotRegExp @@ -105,7 +105,7 @@ class AssertTestCest $I->assertNotContains("bc", $text, "pass"); // stepKey: assertNotContains2BackwardCompatible $I->assertNotEmpty([1, 2], "pass"); // stepKey: assertNotEmpty1BackwardCompatible $I->assertNotEmpty($text, "pass"); // stepKey: assertNotEmpty2BackwardCompatible - $I->assertNotEquals(2, 5, "pass", 0); // stepKey: assertNotEqualsBackwardCompatible + $I->assertNotEquals(2, 5, "pass"); // stepKey: assertNotEqualsBackwardCompatible $I->assertNotNull("abc", "pass"); // stepKey: assertNotNull1BackwardCompatible $I->assertNotNull($text, "pass"); // stepKey: assertNotNull2BackwardCompatible $I->assertNotRegExp("/foo/", "bar", "pass"); // stepKey: assertNotRegExpBackwardCompatible @@ -155,5 +155,11 @@ class AssertTestCest $I->assertElementContainsAttribute("#username", "value", $I->retrieveEntityField('createData1', 'firstname', 'test')); // stepKey: assertElementContainsAttribute8 $I->comment("assert entity resolution"); $I->assertEquals("John", "Doe", "pass"); // stepKey: assertEqualsEntity + $I->assertEqualsWithDelta(10.0000, 10.0000, 1, "pass"); // stepKey: a1 + $I->assertNotEqualsWithDelta(10.0000, 12.0000, 1, "pass"); // stepKey: a2 + $I->assertEqualsCanonicalizing(["4", "2", "1", "3"], ["1", "2", "3", "4"], "pass"); // stepKey: a3 + $I->assertNotEqualsCanonicalizing(["5", "8", "7", "9"], ["1", "2", "3", "4"], "pass"); // stepKey: a4 + $I->assertEqualsIgnoringCase("Cat", "cat", "pass"); // stepKey: a5 + $I->assertNotEqualsIgnoringCase("Cat", "Dog", "pass"); // stepKey: a6 } } diff --git a/dev/tests/verification/TestModule/Test/AssertTest.xml b/dev/tests/verification/TestModule/Test/AssertTest.xml index fd81c9bea..91d02c7ce 100644 --- a/dev/tests/verification/TestModule/Test/AssertTest.xml +++ b/dev/tests/verification/TestModule/Test/AssertTest.xml @@ -129,7 +129,7 @@ <assertNotEmpty stepKey="assertNotEmpty2" message="pass"> <actualResult type="variable">text</actualResult> </assertNotEmpty> - <assertNotEquals stepKey="assertNotEquals" message="pass" delta=""> + <assertNotEquals stepKey="assertNotEquals" message="pass"> <expectedResult type="int">2</expectedResult> <actualResult type="int">5</actualResult> </assertNotEquals> @@ -259,7 +259,7 @@ <assertNotEmpty stepKey="assertNotEmpty2BackwardCompatible" message="pass"> <actualResult type="variable">text</actualResult> </assertNotEmpty> - <assertNotEquals stepKey="assertNotEqualsBackwardCompatible" message="pass" delta=""> + <assertNotEquals stepKey="assertNotEqualsBackwardCompatible" message="pass"> <actualResult type="int">5</actualResult> <expectedResult type="int">2</expectedResult> </assertNotEquals> @@ -415,5 +415,30 @@ <expectedResult type="string">{{simpleData.firstname}}</expectedResult> <actualResult type="string">{{simpleData.lastname}}</actualResult> </assertEquals> + + <assertEqualsWithDelta stepKey="a1" message="pass" delta="1"> + <expectedResult type="const">10.0000</expectedResult> + <actualResult type="const">10.0000</actualResult> + </assertEqualsWithDelta> + <assertNotEqualsWithDelta stepKey="a2" message="pass" delta="1"> + <expectedResult type="const">10.0000</expectedResult> + <actualResult type="const">12.0000</actualResult> + </assertNotEqualsWithDelta> + <assertEqualsCanonicalizing stepKey="a3" message="pass"> + <expectedResult type="array">[4, 2, 1, 3]</expectedResult> + <actualResult type="array">[1, 2, 3, 4]</actualResult> + </assertEqualsCanonicalizing> + <assertNotEqualsCanonicalizing stepKey="a4" message="pass"> + <expectedResult type="array">[5, 8, 7, 9]</expectedResult> + <actualResult type="array">[1, 2, 3, 4]</actualResult> + </assertNotEqualsCanonicalizing> + <assertEqualsIgnoringCase stepKey="a5" message="pass"> + <expectedResult type="string">Cat</expectedResult> + <actualResult type="string">cat</actualResult> + </assertEqualsIgnoringCase> + <assertNotEqualsIgnoringCase stepKey="a6" message="pass"> + <expectedResult type="string">Cat</expectedResult> + <actualResult type="string">Dog</actualResult> + </assertNotEqualsIgnoringCase> </test> </tests> From 1aad234e1241e082d4b62f004170fd7f14f85b67 Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Fri, 17 Apr 2020 10:04:54 -0500 Subject: [PATCH 338/888] MQE-2076: [PHPUnit 9] assertEquals and assertNotEquals optional parameters removed --- docs/test/assertions.md | 66 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/docs/test/assertions.md b/docs/test/assertions.md index 8577c85c3..8c7d31be5 100644 --- a/docs/test/assertions.md +++ b/docs/test/assertions.md @@ -179,6 +179,17 @@ Attribute|Type|Use|Description See [assertEquals docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertEquals). +Attribute|Type|Use|Description +---|---|---|--- +`message`|string|optional|Text of informational message about a cause of failure. +`stepKey`|string|required| A unique identifier of the text step. +`before`|string|optional| `stepKey` of action that must be executed next. +`after`|string|optional| `stepKey` of the preceding action. + +### assertEqualsWithDelta + +See [assertEqualsWithDelta docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertEqualsWithDelta). + Attribute|Type|Use|Description ---|---|---|--- `delta`|string|optional| @@ -187,6 +198,28 @@ Attribute|Type|Use|Description `before`|string|optional| `stepKey` of action that must be executed next. `after`|string|optional| `stepKey` of the preceding action. +### assertEqualsCanonicalizing + +See [assertEqualsCanonicalizing docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertEqualsCanonicalizing). + +Attribute|Type|Use|Description +---|---|---|--- +`message`|string|optional|Text of informational message about a cause of failure. +`stepKey`|string|required| A unique identifier of the text step. +`before`|string|optional| `stepKey` of action that must be executed next. +`after`|string|optional| `stepKey` of the preceding action. + +### assertEqualsIgnoringCase + +See [assertEqualsIgnoringCase docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertEqualsIgnoringCase). + +Attribute|Type|Use|Description +---|---|---|--- +`message`|string|optional|Text of informational message about a cause of failure. +`stepKey`|string|required| A unique identifier of the text step. +`before`|string|optional| `stepKey` of action that must be executed next. +`after`|string|optional| `stepKey` of the preceding action. + ### assertFalse See [assertFalse docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertFalse). @@ -367,6 +400,17 @@ Attribute|Type|Use|Description See [assertNotEquals docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertNotEquals). +Attribute|Type|Use|Description +---|---|---|--- +`message`|string|optional|Text of informational message about a cause of failure. +`stepKey`|string|required| A unique identifier of the text step. +`before`|string|optional| `stepKey` of action that must be executed next. +`after`|string|optional| `stepKey` of the preceding action. + +### assertNotEqualsWithDelta + +See [assertNotEqualsWithDelta docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertNotEqualsWithDelta). + Attribute|Type|Use|Description ---|---|---|--- `delta`|string|optional| @@ -375,6 +419,28 @@ Attribute|Type|Use|Description `before`|string|optional| `stepKey` of action that must be executed next. `after`|string|optional| `stepKey` of the preceding action. +### assertNotEqualsCanonicalizing + +See [assertNotEqualsCanonicalizing docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertNotEqualsCanonicalizing). + +Attribute|Type|Use|Description +---|---|---|--- +`message`|string|optional|Text of informational message about a cause of failure. +`stepKey`|string|required| A unique identifier of the text step. +`before`|string|optional| `stepKey` of action that must be executed next. +`after`|string|optional| `stepKey` of the preceding action. + +### assertNotEqualsIgnoringCase + +See [assertNotEqualsIgnoringCase docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertNotEqualsIgnoringCase). + +Attribute|Type|Use|Description +---|---|---|--- +`message`|string|optional|Text of informational message about a cause of failure. +`stepKey`|string|required| A unique identifier of the text step. +`before`|string|optional| `stepKey` of action that must be executed next. +`after`|string|optional| `stepKey` of the preceding action. + ### assertNotInstanceOf See [assertNotInstanceOf docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertNotInstanceOf). From 44fad378048b17c617ca10732bb38891bbe80177 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Fri, 17 Apr 2020 14:44:44 -0500 Subject: [PATCH 339/888] MQE-2077: [PHPUnit 9] Remove assertArraySubset, assertInternalType, assertNotInternalType --- .../verification/Resources/AssertTest.txt | 10 ----- .../TestModule/Test/AssertTest.xml | 40 ------------------- docs/test/assertions.md | 23 ----------- etc/di.xml | 2 +- .../Test/etc/Actions/assertActions.xsd | 2 - .../Util/TestGenerator.php | 11 ----- 6 files changed, 1 insertion(+), 87 deletions(-) diff --git a/dev/tests/verification/Resources/AssertTest.txt b/dev/tests/verification/Resources/AssertTest.txt index 7697b7baf..53a017188 100644 --- a/dev/tests/verification/Resources/AssertTest.txt +++ b/dev/tests/verification/Resources/AssertTest.txt @@ -43,7 +43,6 @@ class AssertTestCest $I->comment("asserts without variable replacement"); $I->assertArrayHasKey("apple", ['orange' => 2, 'apple' => 1], "pass"); // stepKey: assertArrayHasKey $I->assertArrayNotHasKey("kiwi", ['orange' => 2, 'apple' => 1], "pass"); // stepKey: assertArrayNotHasKey - $I->assertArraySubset([1, 2], [1, 2, 3, 5], "pass"); // stepKey: assertArraySubset $I->assertContains("ab", ['item1' => 'a', 'item2' => 'ab'], "pass"); // stepKey: assertContains $I->assertStringContainsString("apple", "apple", "pass"); // stepKey: assertStringContainsString $I->assertStringContainsStringIgnoringCase("Banana", "banana", "pass"); // stepKey: assertStringContainsStringIgnoringCase @@ -58,9 +57,6 @@ class AssertTestCest $I->assertGreaterOrEquals(2, 5, "pass"); // stepKey: assertGreaterOrEquals $I->assertGreaterThan(2, 5, "pass"); // stepKey: assertGreaterthan $I->assertGreaterThanOrEqual(2, 5, "pass"); // stepKey: assertGreaterThanOrEqual - $I->assertInternalType("string", "xyz", "pass"); // stepKey: assertInternalType1 - $I->assertInternalType("int", 21, "pass"); // stepKey: assertInternalType2 - $I->assertInternalType("string", $text, "pass"); // stepKey: assertInternalType3 $I->assertLessOrEquals(5, 2, "pass"); // stepKey: assertLessOrEquals $I->assertLessThan(5, 2, "pass"); // stepKey: assertLessThan $I->assertLessThanOrEqual(5, 2, "pass"); // stepKey: assertLessThanOrEquals @@ -83,7 +79,6 @@ class AssertTestCest $I->comment("asserts backward compatible"); $I->assertArrayHasKey("apple", ['orange' => 2, 'apple' => 1], "pass"); // stepKey: assertArrayHasKeyBackwardCompatible $I->assertArrayNotHasKey("kiwi", ['orange' => 2, 'apple' => 1], "pass"); // stepKey: assertArrayNotHasKeyBackwardCompatible - $I->assertArraySubset([1, 2], [1, 2, 3, 5], "pass"); // stepKey: assertArraySubsetBackwardCompatible $I->assertContains("ab", ['item1' => 'a', 'item2' => 'ab'], "pass"); // stepKey: assertContainsBackwardCompatible $I->assertCount(2, ['a', 'b'], "pass"); // stepKey: assertCountBackwardCompatible $I->assertEmpty([], "pass"); // stepKey: assertEmptyBackwardCompatible @@ -95,9 +90,6 @@ class AssertTestCest $I->assertGreaterOrEquals(2, 5, "pass"); // stepKey: assertGreaterOrEqualsBackwardCompatible $I->assertGreaterThan(2, 5, "pass"); // stepKey: assertGreaterThanBackwardCompatible $I->assertGreaterThanOrEqual(2, 5, "pass"); // stepKey: assertGreaterThanOrEqualBackwardCompatible - $I->assertInternalType("string", "xyz", "pass"); // stepKey: assertInternalType1BackwardCompatible - $I->assertInternalType("int", 21, "pass"); // stepKey: assertInternalType2BackwardCompatible - $I->assertInternalType("string", $text, "pass"); // stepKey: assertInternalType3BackwardCompatible $I->assertLessOrEquals(5, 2, "pass"); // stepKey: assertLessOrEqualBackwardCompatibles $I->assertLessThan(5, 2, "pass"); // stepKey: assertLessThanBackwardCompatible $I->assertLessThanOrEqual(5, 2, "pass"); // stepKey: assertLessThanOrEqualBackwardCompatible @@ -129,8 +121,6 @@ class AssertTestCest $I->assertEquals($I->retrieveEntityField('createData1', 'lastname', 'test'), $I->retrieveEntityField('createData1', 'lastname', 'test'), "pass"); // stepKey: assert5 $I->comment("array type that use created data"); $I->comment("array type that use created data"); - $I->assertArraySubset([$I->retrieveEntityField('createData1', 'lastname', 'test'), $I->retrieveEntityField('createData1', 'firstname', 'test')], [$I->retrieveEntityField('createData1', 'lastname', 'test'), $I->retrieveEntityField('createData1', 'firstname', 'test'), "1"], "pass"); // stepKey: assert9 - $I->assertArraySubset([$I->retrieveEntityField('createData2', 'firstname', 'test'), $I->retrieveEntityField('createData2', 'lastname', 'test')], [$I->retrieveEntityField('createData2', 'firstname', 'test'), $I->retrieveEntityField('createData2', 'lastname', 'test'), "1"], "pass"); // stepKey: assert10 $I->assertArrayHasKey("lastname", ['lastname' => $I->retrieveEntityField('createData1', 'lastname', 'test'), 'firstname' => $I->retrieveEntityField('createData1', 'firstname', 'test')], "pass"); // stepKey: assert3 $I->assertArrayHasKey("lastname", ['lastname' => $I->retrieveEntityField('createData2', 'lastname', 'test'), 'firstname' => $I->retrieveEntityField('createData2', 'firstname', 'test')], "pass"); // stepKey: assert4 $I->comment("this section can only be generated and cannot run"); diff --git a/dev/tests/verification/TestModule/Test/AssertTest.xml b/dev/tests/verification/TestModule/Test/AssertTest.xml index fd81c9bea..f54290402 100644 --- a/dev/tests/verification/TestModule/Test/AssertTest.xml +++ b/dev/tests/verification/TestModule/Test/AssertTest.xml @@ -31,10 +31,6 @@ <expectedResult type="string">kiwi</expectedResult> <actualResult type="const">['orange' => 2, 'apple' => 1]</actualResult> </assertArrayNotHasKey> - <assertArraySubset stepKey="assertArraySubset" message="pass"> - <expectedResult type="const">[1, 2]</expectedResult> - <actualResult type="const">[1, 2, 3, 5]</actualResult> - </assertArraySubset> <assertContains stepKey="assertContains" message="pass"> <expectedResult type="string">ab</expectedResult> <actualResult type="const">['item1' => 'a', 'item2' => 'ab']</actualResult> @@ -87,18 +83,6 @@ <expectedResult type="int">2</expectedResult> <actualResult type="int">5</actualResult> </assertGreaterThanOrEqual> - <assertInternalType stepKey="assertInternalType1" message="pass"> - <expectedResult type="string">string</expectedResult> - <actualResult type="string">xyz</actualResult> - </assertInternalType> - <assertInternalType stepKey="assertInternalType2" message="pass"> - <expectedResult type="string">int</expectedResult> - <actualResult type="int">21</actualResult> - </assertInternalType> - <assertInternalType stepKey="assertInternalType3" message="pass"> - <expectedResult type="string">string</expectedResult> - <actualResult type="variable">text</actualResult> - </assertInternalType> <assertLessOrEquals stepKey="assertLessOrEquals" message="pass"> <expectedResult type="int">5</expectedResult> <actualResult type="int">2</actualResult> @@ -177,10 +161,6 @@ <expectedResult type="string">kiwi</expectedResult> <actualResult type="const">['orange' => 2, 'apple' => 1]</actualResult> </assertArrayNotHasKey> - <assertArraySubset stepKey="assertArraySubsetBackwardCompatible" message="pass"> - <actualResult type="const">[1, 2, 3, 5]</actualResult> - <expectedResult type="const">[1, 2]</expectedResult> - </assertArraySubset> <assertContains stepKey="assertContainsBackwardCompatible" message="pass"> <expectedResult type="string">ab</expectedResult> <actualResult type="const">['item1' => 'a', 'item2' => 'ab']</actualResult> @@ -221,18 +201,6 @@ <actualResult type="int">5</actualResult> <expectedResult type="int">2</expectedResult> </assertGreaterThanOrEqual> - <assertInternalType stepKey="assertInternalType1BackwardCompatible" message="pass"> - <actualResult type="string">xyz</actualResult> - <expectedResult type="string">string</expectedResult> - </assertInternalType> - <assertInternalType stepKey="assertInternalType2BackwardCompatible" message="pass"> - <actualResult type="int">21</actualResult> - <expectedResult type="string">int</expectedResult> - </assertInternalType> - <assertInternalType stepKey="assertInternalType3BackwardCompatible" message="pass"> - <actualResult type="variable">$text</actualResult> - <expectedResult type="string">string</expectedResult> - </assertInternalType> <assertLessOrEquals stepKey="assertLessOrEqualBackwardCompatibles" message="pass"> <actualResult type="int">2</actualResult> <expectedResult type="int">5</expectedResult> @@ -338,14 +306,6 @@ <!-- array type that use created data --> <comment stepKey="c3" userInput="array type that use created data"/> - <assertArraySubset stepKey="assert9" message="pass"> - <expectedResult type="array">[$$createData1.lastname$$, $$createData1.firstname$$]</expectedResult> - <actualResult type="array">[$$createData1.lastname$$, $$createData1.firstname$$, 1]</actualResult> - </assertArraySubset> - <assertArraySubset stepKey="assert10" message="pass"> - <expectedResult type="array">[$createData2.firstname$, $createData2.lastname$]</expectedResult> - <actualResult type="array">[$createData2.firstname$, $createData2.lastname$, 1]</actualResult> - </assertArraySubset> <assertArrayHasKey stepKey="assert3" message="pass"> <expectedResult type="string">lastname</expectedResult> <actualResult type="array">['lastname' => $$createData1.lastname$$, 'firstname' => $$createData1.firstname$$]</actualResult> diff --git a/docs/test/assertions.md b/docs/test/assertions.md index 8577c85c3..e422f7265 100644 --- a/docs/test/assertions.md +++ b/docs/test/assertions.md @@ -108,18 +108,6 @@ Attribute|Type|Use|Description `before`|string|optional| `stepKey` of action that must be executed next. `after`|string|optional| `stepKey` of the preceding action. -### assertArraySubset - -See [assertArraySubset docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertArraySubset). - -Attribute|Type|Use|Description ----|---|---|--- -`strict`|boolean|optional| -`message`|string|optional|Text of informational message about a cause of failure. -`stepKey`|string|required| A unique identifier of the text step. -`before`|string|optional| `stepKey` of action that must be executed next. -`after`|string|optional| `stepKey` of the preceding action. - ### assertContains See [assertContains docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertContains). @@ -264,17 +252,6 @@ Attribute|Type|Use|Description `before`|string|optional| `stepKey` of action that must be executed next. `after`|string|optional| `stepKey` of the preceding action. -### assertInternalType - -See [assertInternalType docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertInternalType). - -Attribute|Type|Use|Description ----|---|---|--- -`message`|string|optional|Text of informational message about a cause of failure. -`stepKey`|string|required| A unique identifier of the text step. -`before`|string|optional| `stepKey` of action that must be executed next. -`after`|string|optional| `stepKey` of the preceding action. - ### assertIsEmpty See [assertIsEmpty docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertIsEmpty). diff --git a/etc/di.xml b/etc/di.xml index 9b0c53af1..96a3d0712 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -8,7 +8,7 @@ <!-- Entity value gets replaced in Dom.php before reading $xml --> <!DOCTYPE config [ - <!ENTITY commonTestActions "acceptPopup|actionGroup|amOnPage|amOnUrl|amOnSubdomain|appendField|assertArrayIsSortasserted|assertArraySubset|assertElementContainsAttribute|attachFile|cancelPopup|checkOption|clearField|click|clickWithLeftButton|clickWithRightButton|closeAdminNotification|closeTab|comment|conditionalClick|createData|deleteData|updateData|getData|dontSee|dontSeeJsError|dontSeeCheckboxIsChecked|dontSeeCookie|dontSeeCurrentUrlEquals|dontSeeCurrentUrlMatches|dontSeeElement|dontSeeElementInDOM|dontSeeInCurrentUrl|dontSeeInField|dontSeeInFormFields|dontSeeInPageSource|dontSeeInSource|dontSeeInTitle|dontSeeLink|dontSeeOptionIsSelected|doubleClick|dragAndDrop|entity|executeJS|fillField|formatMoney|generateDate|grabAttributeFrom|grabCookie|grabFromCurrentUrl|grabMultiple|grabPageSource|grabTextFrom|grabValueFrom|loadSessionSnapshot|loginAsAdmin|magentoCLI|magentoCron|makeScreenshot|maximizeWindow|moveBack|moveForward|moveMouseOver|mSetLocale|mResetLocale|openNewTab|pause|parseFloat|pressKey|reloadPage|resetCookie|submitForm|resizeWindow|saveSessionSnapshot|scrollTo|scrollToTopOfPage|searchAndMultiSelectOption|see|seeCheckboxIsChecked|seeCookie|seeCurrentUrlEquals|seeCurrentUrlMatches|seeElement|seeElementInDOM|seeInCurrentUrl|seeInField|seeInFormFields|seeInPageSource|seeInPopup|seeInSource|seeInTitle|seeLink|seeNumberOfElements|seeOptionIsSelected|selectOption|setCookie|submitForm|switchToIFrame|switchToNextTab|switchToPreviousTab|switchToWindow|typeInPopup|uncheckOption|unselectOption|wait|waitForAjaxLoad|waitForElement|waitForElementChange|waitForElementNotVisible|waitForElementVisible|waitForPwaElementNotVisible|waitForPwaElementVisible|waitForJS|waitForLoadingMaskToDisappear|waitForPageLoad|waitForText|assertArrayHasKey|assertArrayNotHasKey|assertArraySubset|assertContains|assertStringContainsString|assertStringContainsStringIgnoringCase|assertCount|assertEmpty|assertEquals|assertFalse|assertFileExists|assertFileNotExists|assertGreaterOrEquals|assertGreaterThan|assertGreaterThanOrEqual|assertInstanceOf|assertInternalType|assertIsEmpty|assertLessOrEquals|assertLessThan|assertLessThanOrEqual|assertNotContains|assertStringNotContainsString|assertStringNotContainsStringIgnoringCase|assertNotEmpty|assertNotEquals|assertNotInstanceOf|assertNotNull|assertNotRegExp|assertNotSame|assertNull|assertRegExp|assertSame|assertStringStartsNotWith|assertStringStartsWith|assertTrue|expectException|fail|dontSeeFullUrlEquals|dontSee|dontSeeFullUrlMatches|dontSeeInFullUrl|seeFullUrlEquals|seeFullUrlMatches|seeInFullUrl|grabFromFullUrl|helper"> + <!ENTITY commonTestActions "acceptPopup|actionGroup|amOnPage|amOnUrl|amOnSubdomain|appendField|assertArrayIsSortasserted|assertElementContainsAttribute|attachFile|cancelPopup|checkOption|clearField|click|clickWithLeftButton|clickWithRightButton|closeAdminNotification|closeTab|comment|conditionalClick|createData|deleteData|updateData|getData|dontSee|dontSeeJsError|dontSeeCheckboxIsChecked|dontSeeCookie|dontSeeCurrentUrlEquals|dontSeeCurrentUrlMatches|dontSeeElement|dontSeeElementInDOM|dontSeeInCurrentUrl|dontSeeInField|dontSeeInFormFields|dontSeeInPageSource|dontSeeInSource|dontSeeInTitle|dontSeeLink|dontSeeOptionIsSelected|doubleClick|dragAndDrop|entity|executeJS|fillField|formatMoney|generateDate|grabAttributeFrom|grabCookie|grabFromCurrentUrl|grabMultiple|grabPageSource|grabTextFrom|grabValueFrom|loadSessionSnapshot|loginAsAdmin|magentoCLI|magentoCron|makeScreenshot|maximizeWindow|moveBack|moveForward|moveMouseOver|mSetLocale|mResetLocale|openNewTab|pause|parseFloat|pressKey|reloadPage|resetCookie|submitForm|resizeWindow|saveSessionSnapshot|scrollTo|scrollToTopOfPage|searchAndMultiSelectOption|see|seeCheckboxIsChecked|seeCookie|seeCurrentUrlEquals|seeCurrentUrlMatches|seeElement|seeElementInDOM|seeInCurrentUrl|seeInField|seeInFormFields|seeInPageSource|seeInPopup|seeInSource|seeInTitle|seeLink|seeNumberOfElements|seeOptionIsSelected|selectOption|setCookie|submitForm|switchToIFrame|switchToNextTab|switchToPreviousTab|switchToWindow|typeInPopup|uncheckOption|unselectOption|wait|waitForAjaxLoad|waitForElement|waitForElementChange|waitForElementNotVisible|waitForElementVisible|waitForPwaElementNotVisible|waitForPwaElementVisible|waitForJS|waitForLoadingMaskToDisappear|waitForPageLoad|waitForText|assertArrayHasKey|assertArrayNotHasKey|assertContains|assertStringContainsString|assertStringContainsStringIgnoringCase|assertCount|assertEmpty|assertEquals|assertFalse|assertFileExists|assertFileNotExists|assertGreaterOrEquals|assertGreaterThan|assertGreaterThanOrEqual|assertInstanceOf|assertIsEmpty|assertLessOrEquals|assertLessThan|assertLessThanOrEqual|assertNotContains|assertStringNotContainsString|assertStringNotContainsStringIgnoringCase|assertNotEmpty|assertNotEquals|assertNotInstanceOf|assertNotNull|assertNotRegExp|assertNotSame|assertNull|assertRegExp|assertSame|assertStringStartsNotWith|assertStringStartsWith|assertTrue|expectException|fail|dontSeeFullUrlEquals|dontSee|dontSeeFullUrlMatches|dontSeeInFullUrl|seeFullUrlEquals|seeFullUrlMatches|seeInFullUrl|grabFromFullUrl|helper"> ]> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../src/Magento/FunctionalTestingFramework/ObjectManager/etc/config.xsd"> diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/assertActions.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/assertActions.xsd index 694429a30..5c327f795 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/assertActions.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/assertActions.xsd @@ -14,7 +14,6 @@ <xs:element type="assertElementContainsAttributeType" name="assertElementContainsAttribute" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertArrayHasKeyType" name="assertArrayHasKey" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertArrayNotHasKeyType" name="assertArrayNotHasKey" minOccurs="0" maxOccurs="unbounded"/> - <xs:element type="assertArraySubsetType" name="assertArraySubset" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertContainsType" name="assertContains" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertStringContainsStringType" name="assertStringContainsString" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertStringContainsStringIgnoringCaseType" name="assertStringContainsStringIgnoringCase" minOccurs="0" maxOccurs="unbounded"/> @@ -28,7 +27,6 @@ <xs:element type="assertGreaterThanType" name="assertGreaterThan" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertGreaterThanOrEqualType" name="assertGreaterThanOrEqual" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertInstanceOfType" name="assertInstanceOf" minOccurs="0" maxOccurs="unbounded"/> - <xs:element type="assertInternalTypeType" name="assertInternalType" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertIsEmptyType" name="assertIsEmpty" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertLessOrEqualsType" name="assertLessOrEquals" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertLessThanType" name="assertLessThan" minOccurs="0" maxOccurs="unbounded"/> diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index be4c38e02..7e0404457 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1276,7 +1276,6 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato case "assertGreaterOrEquals": case "assertGreaterThan": case "assertGreaterThanOrEqual": - case "assertInternalType": case "assertLessOrEquals": case "assertLessThan": case "assertLessThanOrEqual": @@ -1338,16 +1337,6 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $assertMessage ); break; - case "assertArraySubset": - $testSteps .= $this->wrapFunctionCall( - $actor, - $actionObject, - $assertExpected, - $assertActual, - $assertIsStrict, - $assertMessage - ); - break; case "fail": $testSteps .= $this->wrapFunctionCall( $actor, From a07bf6b64a1514ef72bb4091224bd8df621d75a9 Mon Sep 17 00:00:00 2001 From: Ajith <ajithkumar.maragathavel@ziffity.com> Date: Sun, 19 Apr 2020 14:57:43 +0530 Subject: [PATCH 340/888] command added to modifiy the web server rewrites config --- docs/getting-started.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/getting-started.md b/docs/getting-started.md index 89d228df9..903a77372 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -117,6 +117,18 @@ The MFTF does not support executing CLI commands if your web server points to `< If the Nginx Web server is used on your development environment, then **Use Web Server Rewrites** setting in **Stores** > Settings > **Configuration** > **General** > **Web** > **Search Engine Optimization** must be set to **Yes**. +or via command line: + +```bash +bin/magento config:set web/seo/use_rewrites 1 +``` + +Clean the cache after changing the configuration values: + +```bash +bin/magento cache:clean config full_page +``` + To be able to run Magento command line commands in tests, add the following location block to the Nginx configuration file in the Magento root directory: ```conf From 4b8581fc74ecb326c7b256bda91fea49b052dac5 Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Mon, 20 Apr 2020 13:28:20 -0500 Subject: [PATCH 341/888] grammar --- docs/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index 11882084e..d2ce5e1a5 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -301,7 +301,7 @@ CREDENTIAL_AWS_SECRETS_MANAGER_PROFILE=default ### VERBOSE_ARTIFACTS -Determines if passed tests should still have all their Allure artifacts. These artifacts include `.txt` attachments for things like `dontSee` actions and `createData` actions. +Determines if passed tests should still have all their Allure artifacts. These artifacts include `.txt` attachments for `dontSee` actions and `createData` actions. If enabled, all tests will have all of their normal Allure artifacts. From e9b96a3109a83f2990b57f1bc440bc27745607ee Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Tue, 21 Apr 2020 12:15:24 -0500 Subject: [PATCH 342/888] =?UTF-8?q?MQE-2080:=20[PHPUnit=209]=20Suite=20fai?= =?UTF-8?q?lures=20on=20builds=20w/=20extns=20(PageBuilder,=E2=80=A6=20(#6?= =?UTF-8?q?80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * MQE-2080: [PHPUnit 9] Suite failures on builds w/ extns (PageBuilder, MSI) * MQE-2080: [PHPUnit 9] Suite failures on builds w/ extns (PageBuilder, MSI) fixing unit tests * MQE-2080: [PHPUnit 9] Suite failures on builds w/ extns (PageBuilder, MSI) Updated comment block * MQE-2080: [PHPUnit 9] Suite failures on builds w/ extns (PageBuilder, MSI) --- dev/tests/phpunit.xml | 2 +- .../Util/Sorter/ParallelGroupSorterTest.php | 4 ++-- dev/tests/verification/Tests/SuiteGenerationTest.php | 8 ++++---- .../Allure/Adapter/MagentoAllureAdapter.php | 1 + .../Util/Sorter/ParallelGroupSorter.php | 6 +++--- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/dev/tests/phpunit.xml b/dev/tests/phpunit.xml index 9648ab3fd..1014ec7c3 100644 --- a/dev/tests/phpunit.xml +++ b/dev/tests/phpunit.xml @@ -7,7 +7,7 @@ <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/6.3/phpunit.xsd" + xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.1/phpunit.xsd" convertNoticesToExceptions="false" bootstrap="_bootstrap.php" backupGlobals="false"> diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Sorter/ParallelGroupSorterTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Sorter/ParallelGroupSorterTest.php index 997bf0c3e..48966fbaa 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Sorter/ParallelGroupSorterTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Sorter/ParallelGroupSorterTest.php @@ -101,8 +101,8 @@ public function testSortWithSuites() $this->assertCount(5, $actualResult); $expectedResults = [ - 1 => ['mockSuite1_0'], - 2 => ['mockSuite1_1'], + 1 => ['mockSuite1_0_G'], + 2 => ['mockSuite1_1_G'], 3 => ['test3'], 4 => ['test2','test5', 'test4'], 5 => ['test1'], diff --git a/dev/tests/verification/Tests/SuiteGenerationTest.php b/dev/tests/verification/Tests/SuiteGenerationTest.php index 926287aad..4a8371692 100644 --- a/dev/tests/verification/Tests/SuiteGenerationTest.php +++ b/dev/tests/verification/Tests/SuiteGenerationTest.php @@ -118,10 +118,10 @@ public function testSuiteGenerationParallel() $groupName = 'functionalSuite1'; $expectedGroups = [ - 'functionalSuite1_0', - 'functionalSuite1_1', - 'functionalSuite1_2', - 'functionalSuite1_3' + 'functionalSuite1_0_G', + 'functionalSuite1_1_G', + 'functionalSuite1_2_G', + 'functionalSuite1_3_G' ]; $expectedContents = [ diff --git a/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php b/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php index ae3b07ef0..e1732b6dc 100644 --- a/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php +++ b/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php @@ -121,6 +121,7 @@ private function sanitizeGroupName($group) // if we can't find this group in the generated suites we have to assume that the group was split for generation $groupNameSplit = explode("_", $group); array_pop($groupNameSplit); + array_pop($groupNameSplit); $originalName = implode("_", $groupNameSplit); // confirm our original name is one of the existing suite names otherwise just return the original group name diff --git a/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php b/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php index 8f4cac8a2..fa30837cb 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php +++ b/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php @@ -232,7 +232,7 @@ private function getSuiteToSize($suiteNamesToTests) * * E.g. * Input {suitename = 'sample', tests = ['test1' => 100,'test2' => 150, 'test3' => 300], linelimit = 275} - * Result { ['sample_01' => ['test3' => 300], 'sample_02' => ['test2' => 150, 'test1' => 100]] } + * Result { ['sample_01_G' => ['test3' => 300], 'sample_02_G' => ['test2' => 150, 'test1' => 100]] } * * @param string $suiteName * @param array $tests @@ -252,8 +252,8 @@ private function splitTestSuite($suiteName, $tests, $maxTime) } $group = $this->createTestGroup($maxTime, $test, $size, $availableTests); - $splitSuites["{$suiteName}_${splitCount}"] = $group; - $this->addSuiteToConfig($suiteName, "{$suiteName}_${splitCount}", $group); + $splitSuites["{$suiteName}_${splitCount}_G"] = $group; + $this->addSuiteToConfig($suiteName, "{$suiteName}_${splitCount}_G", $group); $availableTests = array_diff_key($availableTests, $group); $splitCount++; From 849e5de5cb24ac00e3bf5d154d9d3f3c2ae06b49 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 21 Apr 2020 10:40:51 -0500 Subject: [PATCH 343/888] MQE-2027: MFTF PHP Compatibility Update (PHP 7.4) --- .travis.yml | 1 + composer.json | 28 +- composer.lock | 408 +++++++++--------- .../Commenting/FunctionCommentSniff.php | 4 +- .../Util/Validation/NameValidationUtil.php | 4 +- 5 files changed, 227 insertions(+), 218 deletions(-) diff --git a/.travis.yml b/.travis.yml index bc0d6a5db..b4dfd3717 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ language: php php: - 7.3 + - 7.4 services: - docker before_install: diff --git a/composer.json b/composer.json index 1e5cebdce..19c08b6c0 100755 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ "sort-packages": true }, "require": { - "php": "^7.3", + "php": "~7.3.0||~7.4.0", "ext-curl": "*", "ext-dom": "*", "ext-json": "*", @@ -20,35 +20,32 @@ "codeception/module-asserts": "^1.1", "codeception/module-sequence": "^1.0", "codeception/module-webdriver": "^1.0", - "composer/composer": "^1.6", + "composer/composer": "^1.9", "csharpru/vault-php": "~3.5.3", "csharpru/vault-php-guzzle6-transport": "^2.0", - "monolog/monolog": "^1.0", + "monolog/monolog": "^1.17", "mustache/mustache": "~2.5", "php-webdriver/webdriver": "^1.8.0", "symfony/console": "^4.4", - "symfony/finder": "^4.4", + "symfony/finder": "^4.4||^5.0", "symfony/mime": "^5.0", "symfony/process": "^4.4", "vlucas/phpdotenv": "^2.4" }, "require-dev": { - "squizlabs/php_codesniffer": "~3.2", - "sebastian/phpcpd": "~4.0||~5.0", "brainmaestro/composer-git-hooks": "^2.3.1", - "doctrine/cache": "<1.7.0", - "codeception/aspect-mock": "^3.0", - "goaop/framework": "2.2.0", "codacy/coverage": "^1.4", - "phpmd/phpmd": "^2.6.0", + "codeception/aspect-mock": "^3.0", + "doctrine/cache": "<1.7.0", + "goaop/framework": "~2.3.4", + "php-coveralls/php-coveralls": "^1.0", + "phpmd/phpmd": "^2.8.0", "phpunit/phpunit": "~9.0.0", "rregeer/phpunit-coverage-check": "^0.1.4", - "php-coveralls/php-coveralls": "^1.0", + "sebastian/phpcpd": "~5.0.0", + "squizlabs/php_codesniffer": "~3.5.4", "symfony/stopwatch": "~3.4.6" }, - "suggest": { - "epfremme/swagger-php": "^2.0" - }, "replace": { "facebook/webdriver": "^1.7.1" }, @@ -56,7 +53,8 @@ "files": ["src/Magento/FunctionalTestingFramework/_bootstrap.php"], "psr-4": { "Magento\\FunctionalTestingFramework\\": "src/Magento/FunctionalTestingFramework", - "MFTF\\": "dev/tests/functional/tests/MFTF" + "MFTF\\": "dev/tests/functional/tests/MFTF", + "Magento\\": "../magento5/app/code/Magento/" } }, "autoload-dev": { diff --git a/composer.lock b/composer.lock index 22e562cef..b88f217f5 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "727146c7b29909e5d60e4c7f3ed5f268", + "content-hash": "aff9cb54455b486036efa97f1fcb14bd", "packages": [ { "name": "allure-framework/allure-codeception", @@ -112,16 +112,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.133.44", + "version": "3.135.1", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "00df425deebdde3f3bebfde446a4250695dc47e4" + "reference": "59587a4f3fc88b36ce7f2e1a102bfcd7a816b27c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/00df425deebdde3f3bebfde446a4250695dc47e4", - "reference": "00df425deebdde3f3bebfde446a4250695dc47e4", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/59587a4f3fc88b36ce7f2e1a102bfcd7a816b27c", + "reference": "59587a4f3fc88b36ce7f2e1a102bfcd7a816b27c", "shasum": "" }, "require": { @@ -192,7 +192,7 @@ "s3", "sdk" ], - "time": "2020-03-25T18:15:47+00:00" + "time": "2020-04-21T18:14:29+00:00" }, { "name": "behat/gherkin", @@ -433,16 +433,16 @@ }, { "name": "codeception/lib-asserts", - "version": "1.2.0", + "version": "1.12.0", "source": { "type": "git", "url": "https://github.com/Codeception/lib-asserts.git", - "reference": "74bfe433af24e2f75c6386b9d843ec69029f4337" + "reference": "acd0dc8b394595a74b58dcc889f72569ff7d8e71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/lib-asserts/zipball/74bfe433af24e2f75c6386b9d843ec69029f4337", - "reference": "74bfe433af24e2f75c6386b9d843ec69029f4337", + "url": "https://api.github.com/repos/Codeception/lib-asserts/zipball/acd0dc8b394595a74b58dcc889f72569ff7d8e71", + "reference": "acd0dc8b394595a74b58dcc889f72569ff7d8e71", "shasum": "" }, "require": { @@ -474,25 +474,25 @@ "keywords": [ "codeception" ], - "time": "2020-02-07T17:47:55+00:00" + "time": "2020-04-17T18:20:46+00:00" }, { "name": "codeception/module-asserts", - "version": "1.1.1", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/Codeception/module-asserts.git", - "reference": "87c83ca3ccfbc0d79f5effb57e1f82eeaab0cb3e" + "reference": "79f13d05b63f2fceba4d0e78044bab668c9b2a6b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/module-asserts/zipball/87c83ca3ccfbc0d79f5effb57e1f82eeaab0cb3e", - "reference": "87c83ca3ccfbc0d79f5effb57e1f82eeaab0cb3e", + "url": "https://api.github.com/repos/Codeception/module-asserts/zipball/79f13d05b63f2fceba4d0e78044bab668c9b2a6b", + "reference": "79f13d05b63f2fceba4d0e78044bab668c9b2a6b", "shasum": "" }, "require": { "codeception/codeception": "*@dev", - "codeception/lib-asserts": "^1.0.0", + "codeception/lib-asserts": "^1.12.0", "php": ">=5.6.0 <8.0" }, "conflict": { @@ -526,7 +526,7 @@ "asserts", "codeception" ], - "time": "2019-11-13T17:32:27+00:00" + "time": "2020-04-20T07:26:11+00:00" }, { "name": "codeception/module-sequence", @@ -573,16 +573,16 @@ }, { "name": "codeception/module-webdriver", - "version": "1.0.6", + "version": "1.0.7", "source": { "type": "git", "url": "https://github.com/Codeception/module-webdriver.git", - "reference": "9ee54108860859b120ed4a22e50f37d33aa3a518" + "reference": "f05c5c25e39d10fbfb2d508779e1537df019ff9b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/module-webdriver/zipball/9ee54108860859b120ed4a22e50f37d33aa3a518", - "reference": "9ee54108860859b120ed4a22e50f37d33aa3a518", + "url": "https://api.github.com/repos/Codeception/module-webdriver/zipball/f05c5c25e39d10fbfb2d508779e1537df019ff9b", + "reference": "f05c5c25e39d10fbfb2d508779e1537df019ff9b", "shasum": "" }, "require": { @@ -624,20 +624,20 @@ "browser-testing", "codeception" ], - "time": "2020-03-23T17:08:27+00:00" + "time": "2020-04-01T10:18:18+00:00" }, { "name": "codeception/phpunit-wrapper", - "version": "9.0.1", + "version": "9.0.2", "source": { "type": "git", "url": "https://github.com/Codeception/phpunit-wrapper.git", - "reference": "cf5954ca7cbe9ac6eddd3c9e9ce866c27ec8b906" + "reference": "eb27243d8edde68593bf8d9ef5e9074734777931" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/phpunit-wrapper/zipball/cf5954ca7cbe9ac6eddd3c9e9ce866c27ec8b906", - "reference": "cf5954ca7cbe9ac6eddd3c9e9ce866c27ec8b906", + "url": "https://api.github.com/repos/Codeception/phpunit-wrapper/zipball/eb27243d8edde68593bf8d9ef5e9074734777931", + "reference": "eb27243d8edde68593bf8d9ef5e9074734777931", "shasum": "" }, "require": { @@ -668,7 +668,7 @@ } ], "description": "PHPUnit classes used by Codeception", - "time": "2020-03-20T07:44:37+00:00" + "time": "2020-04-17T18:16:31+00:00" }, { "name": "codeception/stub", @@ -702,16 +702,16 @@ }, { "name": "composer/ca-bundle", - "version": "1.2.6", + "version": "1.2.7", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "47fe531de31fca4a1b997f87308e7d7804348f7e" + "reference": "95c63ab2117a72f48f5a55da9740a3273d45b7fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/47fe531de31fca4a1b997f87308e7d7804348f7e", - "reference": "47fe531de31fca4a1b997f87308e7d7804348f7e", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/95c63ab2117a72f48f5a55da9740a3273d45b7fd", + "reference": "95c63ab2117a72f48f5a55da9740a3273d45b7fd", "shasum": "" }, "require": { @@ -754,20 +754,20 @@ "ssl", "tls" ], - "time": "2020-01-13T10:02:55+00:00" + "time": "2020-04-08T08:27:21+00:00" }, { "name": "composer/composer", - "version": "1.10.1", + "version": "1.10.5", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "b912a45da3e2b22f5cb5a23e441b697a295ba011" + "reference": "7a4d5b6aa30d2118af27c04f5e897b57156ccfa9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/b912a45da3e2b22f5cb5a23e441b697a295ba011", - "reference": "b912a45da3e2b22f5cb5a23e441b697a295ba011", + "url": "https://api.github.com/repos/composer/composer/zipball/7a4d5b6aa30d2118af27c04f5e897b57156ccfa9", + "reference": "7a4d5b6aa30d2118af27c04f5e897b57156ccfa9", "shasum": "" }, "require": { @@ -834,7 +834,7 @@ "dependency", "package" ], - "time": "2020-03-13T19:34:27+00:00" + "time": "2020-04-10T09:44:22+00:00" }, { "name": "composer/semver", @@ -1089,20 +1089,21 @@ }, { "name": "doctrine/annotations", - "version": "v1.8.0", + "version": "1.10.2", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "904dca4eb10715b92569fbcd79e201d5c349b6bc" + "reference": "b9d758e831c70751155c698c2f7df4665314a1cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/904dca4eb10715b92569fbcd79e201d5c349b6bc", - "reference": "904dca4eb10715b92569fbcd79e201d5c349b6bc", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/b9d758e831c70751155c698c2f7df4665314a1cb", + "reference": "b9d758e831c70751155c698c2f7df4665314a1cb", "shasum": "" }, "require": { "doctrine/lexer": "1.*", + "ext-tokenizer": "*", "php": "^7.1" }, "require-dev": { @@ -1112,7 +1113,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7.x-dev" + "dev-master": "1.9.x-dev" } }, "autoload": { @@ -1153,7 +1154,7 @@ "docblock", "parser" ], - "time": "2019-10-01T18:55:10+00:00" + "time": "2020-04-20T09:18:32+00:00" }, { "name": "doctrine/cache", @@ -1412,23 +1413,24 @@ }, { "name": "guzzlehttp/guzzle", - "version": "6.5.2", + "version": "6.5.3", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "43ece0e75098b7ecd8d13918293029e555a50f82" + "reference": "aab4ebd862aa7d04f01a4b51849d657db56d882e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/43ece0e75098b7ecd8d13918293029e555a50f82", - "reference": "43ece0e75098b7ecd8d13918293029e555a50f82", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/aab4ebd862aa7d04f01a4b51849d657db56d882e", + "reference": "aab4ebd862aa7d04f01a4b51849d657db56d882e", "shasum": "" }, "require": { "ext-json": "*", "guzzlehttp/promises": "^1.0", "guzzlehttp/psr7": "^1.6.1", - "php": ">=5.5" + "php": ">=5.5", + "symfony/polyfill-intl-idn": "^1.11" }, "require-dev": { "ext-curl": "*", @@ -1436,7 +1438,6 @@ "psr/log": "^1.1" }, "suggest": { - "ext-intl": "Required for Internationalized Domain Name (IDN) support", "psr/log": "Required for using the Log middleware" }, "type": "library", @@ -1475,7 +1476,7 @@ "rest", "web service" ], - "time": "2019-12-23T11:57:10+00:00" + "time": "2020-04-18T10:38:46+00:00" }, { "name": "guzzlehttp/promises", @@ -1841,16 +1842,16 @@ }, { "name": "league/flysystem", - "version": "1.0.66", + "version": "1.0.67", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "021569195e15f8209b1c4bebb78bd66aa4f08c21" + "reference": "5b1f36c75c4bdde981294c2a0ebdb437ee6f275e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/021569195e15f8209b1c4bebb78bd66aa4f08c21", - "reference": "021569195e15f8209b1c4bebb78bd66aa4f08c21", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/5b1f36c75c4bdde981294c2a0ebdb437ee6f275e", + "reference": "5b1f36c75c4bdde981294c2a0ebdb437ee6f275e", "shasum": "" }, "require": { @@ -1921,7 +1922,7 @@ "sftp", "storage" ], - "time": "2020-03-17T18:58:12+00:00" + "time": "2020-04-16T13:21:26+00:00" }, { "name": "monolog/monolog", @@ -2747,16 +2748,16 @@ }, { "name": "phpunit/php-file-iterator", - "version": "3.0.0", + "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "354d4a5faa7449a377a18b94a2026ca3415e3d7a" + "reference": "4ac5b3e13df14829daa60a2eb4fdd2f2b7d33cf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/354d4a5faa7449a377a18b94a2026ca3415e3d7a", - "reference": "354d4a5faa7449a377a18b94a2026ca3415e3d7a", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/4ac5b3e13df14829daa60a2eb4fdd2f2b7d33cf4", + "reference": "4ac5b3e13df14829daa60a2eb4fdd2f2b7d33cf4", "shasum": "" }, "require": { @@ -2793,7 +2794,7 @@ "filesystem", "iterator" ], - "time": "2020-02-07T06:05:22+00:00" + "time": "2020-04-18T05:02:12+00:00" }, { "name": "phpunit/php-invoker", @@ -2896,16 +2897,16 @@ }, { "name": "phpunit/php-timer", - "version": "3.0.0", + "version": "3.1.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "4118013a4d0f97356eae8e7fb2f6c6472575d1df" + "reference": "dc9368fae6ef2ffa57eba80a7410bcef81df6258" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/4118013a4d0f97356eae8e7fb2f6c6472575d1df", - "reference": "4118013a4d0f97356eae8e7fb2f6c6472575d1df", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/dc9368fae6ef2ffa57eba80a7410bcef81df6258", + "reference": "dc9368fae6ef2ffa57eba80a7410bcef81df6258", "shasum": "" }, "require": { @@ -2917,7 +2918,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.1-dev" } }, "autoload": { @@ -2941,7 +2942,7 @@ "keywords": [ "timer" ], - "time": "2020-02-07T06:08:11+00:00" + "time": "2020-04-20T06:00:37+00:00" }, { "name": "phpunit/php-token-stream", @@ -3612,16 +3613,16 @@ }, { "name": "sebastian/environment", - "version": "5.0.2", + "version": "5.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "c39c1db0a5cffc98173f3de5a17d489d1043fd7b" + "reference": "c753f04d68cd489b6973cf9b4e505e191af3b05c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/c39c1db0a5cffc98173f3de5a17d489d1043fd7b", - "reference": "c39c1db0a5cffc98173f3de5a17d489d1043fd7b", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/c753f04d68cd489b6973cf9b4e505e191af3b05c", + "reference": "c753f04d68cd489b6973cf9b4e505e191af3b05c", "shasum": "" }, "require": { @@ -3661,7 +3662,7 @@ "environment", "hhvm" ], - "time": "2020-03-31T12:14:15+00:00" + "time": "2020-04-14T13:36:52+00:00" }, { "name": "sebastian/exporter", @@ -4234,16 +4235,16 @@ }, { "name": "symfony/css-selector", - "version": "v5.0.5", + "version": "v5.0.7", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "a0b51ba9938ccc206d9284de7eb527c2d4550b44" + "reference": "5f8d5271303dad260692ba73dfa21777d38e124e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/a0b51ba9938ccc206d9284de7eb527c2d4550b44", - "reference": "a0b51ba9938ccc206d9284de7eb527c2d4550b44", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/5f8d5271303dad260692ba73dfa21777d38e124e", + "reference": "5f8d5271303dad260692ba73dfa21777d38e124e", "shasum": "" }, "require": { @@ -4283,20 +4284,20 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "time": "2020-02-04T09:41:09+00:00" + "time": "2020-03-27T16:56:45+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "4ad8e149799d3128621a3a1f70e92b9897a8930d" + "reference": "abc8e3618bfdb55e44c8c6a00abd333f831bbfed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/4ad8e149799d3128621a3a1f70e92b9897a8930d", - "reference": "4ad8e149799d3128621a3a1f70e92b9897a8930d", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/abc8e3618bfdb55e44c8c6a00abd333f831bbfed", + "reference": "abc8e3618bfdb55e44c8c6a00abd333f831bbfed", "shasum": "" }, "require": { @@ -4353,7 +4354,7 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2020-02-04T09:32:40+00:00" + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -4415,16 +4416,16 @@ }, { "name": "symfony/filesystem", - "version": "v5.0.5", + "version": "v5.0.7", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "3afadc0f57cd74f86379d073e694b0f2cda2a88c" + "reference": "ca3b87dd09fff9b771731637f5379965fbfab420" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/3afadc0f57cd74f86379d073e694b0f2cda2a88c", - "reference": "3afadc0f57cd74f86379d073e694b0f2cda2a88c", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/ca3b87dd09fff9b771731637f5379965fbfab420", + "reference": "ca3b87dd09fff9b771731637f5379965fbfab420", "shasum": "" }, "require": { @@ -4461,29 +4462,29 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2020-01-21T08:40:24+00:00" + "time": "2020-03-27T16:56:45+00:00" }, { "name": "symfony/finder", - "version": "v4.4.5", + "version": "v5.0.7", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "ea69c129aed9fdeca781d4b77eb20b62cf5d5357" + "reference": "600a52c29afc0d1caa74acbec8d3095ca7e9910d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/ea69c129aed9fdeca781d4b77eb20b62cf5d5357", - "reference": "ea69c129aed9fdeca781d4b77eb20b62cf5d5357", + "url": "https://api.github.com/repos/symfony/finder/zipball/600a52c29afc0d1caa74acbec8d3095ca7e9910d", + "reference": "600a52c29afc0d1caa74acbec8d3095ca7e9910d", "shasum": "" }, "require": { - "php": "^7.1.3" + "php": "^7.2.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.4-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -4510,20 +4511,20 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2020-02-14T07:42:58+00:00" + "time": "2020-03-27T16:56:45+00:00" }, { "name": "symfony/http-foundation", - "version": "v5.0.5", + "version": "v5.0.7", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "6f9c2ba72f4295d7ce6cf9f79dbb18036291d335" + "reference": "26fb006a2c7b6cdd23d52157b05f8414ffa417b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/6f9c2ba72f4295d7ce6cf9f79dbb18036291d335", - "reference": "6f9c2ba72f4295d7ce6cf9f79dbb18036291d335", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/26fb006a2c7b6cdd23d52157b05f8414ffa417b6", + "reference": "26fb006a2c7b6cdd23d52157b05f8414ffa417b6", "shasum": "" }, "require": { @@ -4565,20 +4566,20 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2020-02-14T07:43:07+00:00" + "time": "2020-03-30T14:14:32+00:00" }, { "name": "symfony/mime", - "version": "v5.0.5", + "version": "v5.0.7", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "9b3e5b5e58c56bbd76628c952d2b78556d305f3c" + "reference": "481b7d6da88922fb1e0d86a943987722b08f3955" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/9b3e5b5e58c56bbd76628c952d2b78556d305f3c", - "reference": "9b3e5b5e58c56bbd76628c952d2b78556d305f3c", + "url": "https://api.github.com/repos/symfony/mime/zipball/481b7d6da88922fb1e0d86a943987722b08f3955", + "reference": "481b7d6da88922fb1e0d86a943987722b08f3955", "shasum": "" }, "require": { @@ -4627,20 +4628,20 @@ "mime", "mime-type" ], - "time": "2020-02-04T09:41:09+00:00" + "time": "2020-03-27T16:56:45+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.14.0", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "fbdeaec0df06cf3d51c93de80c7eb76e271f5a38" + "reference": "4719fa9c18b0464d399f1a63bf624b42b6fa8d14" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/fbdeaec0df06cf3d51c93de80c7eb76e271f5a38", - "reference": "fbdeaec0df06cf3d51c93de80c7eb76e271f5a38", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/4719fa9c18b0464d399f1a63bf624b42b6fa8d14", + "reference": "4719fa9c18b0464d399f1a63bf624b42b6fa8d14", "shasum": "" }, "require": { @@ -4652,7 +4653,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.14-dev" + "dev-master": "1.15-dev" } }, "autoload": { @@ -4685,20 +4686,20 @@ "polyfill", "portable" ], - "time": "2020-01-13T11:15:53+00:00" + "time": "2020-02-27T09:26:54+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.14.0", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "6842f1a39cf7d580655688069a03dd7cd83d244a" + "reference": "47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/6842f1a39cf7d580655688069a03dd7cd83d244a", - "reference": "6842f1a39cf7d580655688069a03dd7cd83d244a", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf", + "reference": "47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf", "shasum": "" }, "require": { @@ -4712,7 +4713,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.14-dev" + "dev-master": "1.15-dev" } }, "autoload": { @@ -4747,20 +4748,20 @@ "portable", "shim" ], - "time": "2020-01-17T12:01:36+00:00" + "time": "2020-03-09T19:04:49+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.14.0", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "34094cfa9abe1f0f14f48f490772db7a775559f2" + "reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/34094cfa9abe1f0f14f48f490772db7a775559f2", - "reference": "34094cfa9abe1f0f14f48f490772db7a775559f2", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/81ffd3a9c6d707be22e3012b827de1c9775fc5ac", + "reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac", "shasum": "" }, "require": { @@ -4772,7 +4773,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.14-dev" + "dev-master": "1.15-dev" } }, "autoload": { @@ -4806,20 +4807,20 @@ "portable", "shim" ], - "time": "2020-01-13T11:15:53+00:00" + "time": "2020-03-09T19:04:49+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.14.0", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "46ecacf4751dd0dc81e4f6bf01dbf9da1dc1dadf" + "reference": "37b0976c78b94856543260ce09b460a7bc852747" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/46ecacf4751dd0dc81e4f6bf01dbf9da1dc1dadf", - "reference": "46ecacf4751dd0dc81e4f6bf01dbf9da1dc1dadf", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/37b0976c78b94856543260ce09b460a7bc852747", + "reference": "37b0976c78b94856543260ce09b460a7bc852747", "shasum": "" }, "require": { @@ -4828,7 +4829,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.14-dev" + "dev-master": "1.15-dev" } }, "autoload": { @@ -4861,20 +4862,20 @@ "portable", "shim" ], - "time": "2020-01-13T11:15:53+00:00" + "time": "2020-02-27T09:26:54+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.14.0", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "5e66a0fa1070bf46bec4bea7962d285108edd675" + "reference": "0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/5e66a0fa1070bf46bec4bea7962d285108edd675", - "reference": "5e66a0fa1070bf46bec4bea7962d285108edd675", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7", + "reference": "0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7", "shasum": "" }, "require": { @@ -4883,7 +4884,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.14-dev" + "dev-master": "1.15-dev" } }, "autoload": { @@ -4919,20 +4920,20 @@ "portable", "shim" ], - "time": "2020-01-13T11:15:53+00:00" + "time": "2020-02-27T09:26:54+00:00" }, { "name": "symfony/process", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "bf9166bac906c9e69fb7a11d94875e7ced97bcd7" + "reference": "3e40e87a20eaf83a1db825e1fa5097ae89042db3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/bf9166bac906c9e69fb7a11d94875e7ced97bcd7", - "reference": "bf9166bac906c9e69fb7a11d94875e7ced97bcd7", + "url": "https://api.github.com/repos/symfony/process/zipball/3e40e87a20eaf83a1db825e1fa5097ae89042db3", + "reference": "3e40e87a20eaf83a1db825e1fa5097ae89042db3", "shasum": "" }, "require": { @@ -4968,7 +4969,7 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2020-02-07T20:06:44+00:00" + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/service-contracts", @@ -5030,16 +5031,16 @@ }, { "name": "symfony/yaml", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "94d005c176db2080e98825d98e01e8b311a97a88" + "reference": "ef166890d821518106da3560086bfcbeb4fadfec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/94d005c176db2080e98825d98e01e8b311a97a88", - "reference": "94d005c176db2080e98825d98e01e8b311a97a88", + "url": "https://api.github.com/repos/symfony/yaml/zipball/ef166890d821518106da3560086bfcbeb4fadfec", + "reference": "ef166890d821518106da3560086bfcbeb4fadfec", "shasum": "" }, "require": { @@ -5085,7 +5086,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2020-02-03T10:46:43+00:00" + "time": "2020-03-30T11:41:10+00:00" }, { "name": "theseer/tokenizer", @@ -5129,16 +5130,16 @@ }, { "name": "vlucas/phpdotenv", - "version": "v2.6.1", + "version": "v2.6.3", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "2a7dcf7e3e02dc5e701004e51a6f304b713107d5" + "reference": "df4c4d08a639be4ef5d6d1322868f9e477553679" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/2a7dcf7e3e02dc5e701004e51a6f304b713107d5", - "reference": "2a7dcf7e3e02dc5e701004e51a6f304b713107d5", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/df4c4d08a639be4ef5d6d1322868f9e477553679", + "reference": "df4c4d08a639be4ef5d6d1322868f9e477553679", "shasum": "" }, "require": { @@ -5146,8 +5147,14 @@ "symfony/polyfill-ctype": "^1.9" }, "require-dev": { + "ext-filter": "*", + "ext-pcre": "*", "phpunit/phpunit": "^4.8.35 || ^5.0" }, + "suggest": { + "ext-filter": "Required to use the boolean validator.", + "ext-pcre": "Required to use most of the library." + }, "type": "library", "extra": { "branch-alias": { @@ -5176,20 +5183,20 @@ "env", "environment" ], - "time": "2019-01-29T11:11:52+00:00" + "time": "2020-04-12T15:11:38+00:00" }, { "name": "webmozart/assert", - "version": "1.7.0", + "version": "1.8.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "aed98a490f9a8f78468232db345ab9cf606cf598" + "reference": "ab2cb0b3b559010b75981b1bdce728da3ee90ad6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/aed98a490f9a8f78468232db345ab9cf606cf598", - "reference": "aed98a490f9a8f78468232db345ab9cf606cf598", + "url": "https://api.github.com/repos/webmozart/assert/zipball/ab2cb0b3b559010b75981b1bdce728da3ee90ad6", + "reference": "ab2cb0b3b559010b75981b1bdce728da3ee90ad6", "shasum": "" }, "require": { @@ -5197,7 +5204,7 @@ "symfony/polyfill-ctype": "^1.8" }, "conflict": { - "vimeo/psalm": "<3.6.0" + "vimeo/psalm": "<3.9.1" }, "require-dev": { "phpunit/phpunit": "^4.8.36 || ^7.5.13" @@ -5224,7 +5231,7 @@ "check", "validate" ], - "time": "2020-02-14T12:15:55+00:00" + "time": "2020-04-18T12:12:48+00:00" }, { "name": "weew/helpers-array", @@ -5491,24 +5498,25 @@ }, { "name": "goaop/framework", - "version": "2.2.0", + "version": "2.3.4", "source": { "type": "git", "url": "https://github.com/goaop/framework.git", - "reference": "152abbffffcba72d2d159b892deb40b0829d0f28" + "reference": "f980f249c55637acba0d5fdcfd2b5182c419f3d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/goaop/framework/zipball/152abbffffcba72d2d159b892deb40b0829d0f28", - "reference": "152abbffffcba72d2d159b892deb40b0829d0f28", + "url": "https://api.github.com/repos/goaop/framework/zipball/f980f249c55637acba0d5fdcfd2b5182c419f3d1", + "reference": "f980f249c55637acba0d5fdcfd2b5182c419f3d1", "shasum": "" }, "require": { "doctrine/annotations": "^1.2.3", "doctrine/cache": "^1.5", - "goaop/parser-reflection": "~1.4", + "goaop/parser-reflection": "~2.0", "jakubledl/dissect": "~1.0", - "php": ">=5.6.0" + "php": "~7.0", + "symfony/finder": "^3.4|^4.2|^5.0" }, "require-dev": { "adlawson/vfs": "^0.12", @@ -5516,7 +5524,8 @@ "phpunit/phpunit": "^5.7", "symfony/console": "^2.7|^3.0", "symfony/filesystem": "^3.3", - "symfony/process": "^3.3" + "symfony/process": "^3.3", + "webmozart/glob": "^4.1" }, "suggest": { "symfony/console": "Enables the usage of the command-line tool." @@ -5553,25 +5562,25 @@ "library", "php" ], - "time": "2018-01-05T23:07:51+00:00" + "time": "2020-04-06T09:46:21+00:00" }, { "name": "goaop/parser-reflection", - "version": "1.4.1", + "version": "2.1.1", "source": { "type": "git", "url": "https://github.com/goaop/parser-reflection.git", - "reference": "d9c1dcc7ce4a5284fe3530e011faf9c9c10e1166" + "reference": "e9628006b321c8a62a8ad22085bc61eec0c21558" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/goaop/parser-reflection/zipball/d9c1dcc7ce4a5284fe3530e011faf9c9c10e1166", - "reference": "d9c1dcc7ce4a5284fe3530e011faf9c9c10e1166", + "url": "https://api.github.com/repos/goaop/parser-reflection/zipball/e9628006b321c8a62a8ad22085bc61eec0c21558", + "reference": "e9628006b321c8a62a8ad22085bc61eec0c21558", "shasum": "" }, "require": { - "nikic/php-parser": "^1.2|^2.0|^3.0", - "php": ">=5.6.0" + "nikic/php-parser": "^4.0", + "php": ">=7.1" }, "require-dev": { "phpunit/phpunit": "~4.0" @@ -5579,7 +5588,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-master": "2.x-dev" } }, "autoload": { @@ -5604,7 +5613,7 @@ } ], "description": "Provides reflection information, based on raw source", - "time": "2018-03-19T15:57:41+00:00" + "time": "2020-02-21T19:52:39+00:00" }, { "name": "guzzle/guzzle", @@ -5756,24 +5765,25 @@ }, { "name": "nikic/php-parser", - "version": "v3.1.5", + "version": "v4.4.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "bb87e28e7d7b8d9a7fda231d37457c9210faf6ce" + "reference": "bd43ec7152eaaab3bd8c6d0aa95ceeb1df8ee120" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/bb87e28e7d7b8d9a7fda231d37457c9210faf6ce", - "reference": "bb87e28e7d7b8d9a7fda231d37457c9210faf6ce", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/bd43ec7152eaaab3bd8c6d0aa95ceeb1df8ee120", + "reference": "bd43ec7152eaaab3bd8c6d0aa95ceeb1df8ee120", "shasum": "" }, "require": { "ext-tokenizer": "*", - "php": ">=5.5" + "php": ">=7.0" }, "require-dev": { - "phpunit/phpunit": "~4.0|~5.0" + "ircmaxell/php-yacc": "0.0.5", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0" }, "bin": [ "bin/php-parse" @@ -5781,7 +5791,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "4.3-dev" } }, "autoload": { @@ -5803,7 +5813,7 @@ "parser", "php" ], - "time": "2018-02-28T20:30:58+00:00" + "time": "2020-04-10T16:34:50+00:00" }, { "name": "pdepend/pdepend", @@ -6124,16 +6134,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.5.4", + "version": "3.5.5", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "dceec07328401de6211037abbb18bda423677e26" + "reference": "73e2e7f57d958e7228fce50dc0c61f58f017f9f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/dceec07328401de6211037abbb18bda423677e26", - "reference": "dceec07328401de6211037abbb18bda423677e26", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/73e2e7f57d958e7228fce50dc0c61f58f017f9f6", + "reference": "73e2e7f57d958e7228fce50dc0c61f58f017f9f6", "shasum": "" }, "require": { @@ -6171,20 +6181,20 @@ "phpcs", "standards" ], - "time": "2020-01-30T22:20:29+00:00" + "time": "2020-04-17T01:09:41+00:00" }, { "name": "symfony/config", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "cbfef5ae91ccd3b06621c18d58cd355c68c87ae9" + "reference": "3f4a3de1af498ed0ea653d4dc2317794144e6ca4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/cbfef5ae91ccd3b06621c18d58cd355c68c87ae9", - "reference": "cbfef5ae91ccd3b06621c18d58cd355c68c87ae9", + "url": "https://api.github.com/repos/symfony/config/zipball/3f4a3de1af498ed0ea653d4dc2317794144e6ca4", + "reference": "3f4a3de1af498ed0ea653d4dc2317794144e6ca4", "shasum": "" }, "require": { @@ -6235,20 +6245,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2020-02-04T09:32:40+00:00" + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/dependency-injection", - "version": "v4.4.5", + "version": "v4.4.7", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "ebb2e882e8c9e2eb990aa61ddcd389848466e342" + "reference": "755b18859be26b90f4bf63753432d3387458bf31" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/ebb2e882e8c9e2eb990aa61ddcd389848466e342", - "reference": "ebb2e882e8c9e2eb990aa61ddcd389848466e342", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/755b18859be26b90f4bf63753432d3387458bf31", + "reference": "755b18859be26b90f4bf63753432d3387458bf31", "shasum": "" }, "require": { @@ -6308,20 +6318,20 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2020-02-29T09:50:10+00:00" + "time": "2020-03-30T10:09:30+00:00" }, { "name": "symfony/stopwatch", - "version": "v3.4.38", + "version": "v3.4.39", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "e2d954156d4817c9a5c79f519a71516693a4a9c8" + "reference": "a7a98f40dcc382a332c3729a6d04b298ffbb8f1f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/e2d954156d4817c9a5c79f519a71516693a4a9c8", - "reference": "e2d954156d4817c9a5c79f519a71516693a4a9c8", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/a7a98f40dcc382a332c3729a6d04b298ffbb8f1f", + "reference": "a7a98f40dcc382a332c3729a6d04b298ffbb8f1f", "shasum": "" }, "require": { @@ -6357,7 +6367,7 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", - "time": "2020-01-01T11:03:25+00:00" + "time": "2020-03-15T09:38:08+00:00" }, { "name": "theseer/fdomdocument", @@ -6406,7 +6416,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^7.3", + "php": "~7.3.0||~7.4.0", "ext-curl": "*", "ext-dom": "*", "ext-json": "*", diff --git a/dev/tests/static/Magento/Sniffs/Commenting/FunctionCommentSniff.php b/dev/tests/static/Magento/Sniffs/Commenting/FunctionCommentSniff.php index 5050d5f03..8985f2407 100644 --- a/dev/tests/static/Magento/Sniffs/Commenting/FunctionCommentSniff.php +++ b/dev/tests/static/Magento/Sniffs/Commenting/FunctionCommentSniff.php @@ -214,7 +214,7 @@ protected function processThrows(File $phpcsFile, $stackPtr, $commentStart) } // Starts with a capital letter and ends with a fullstop. - $firstChar = $comment{0}; + $firstChar = $comment[0]; if (strtoupper($firstChar) !== $firstChar) { $error = '@throws tag comment must start with a capital letter'; $phpcsFile->addError($error, ($tag + 2), 'ThrowsNotCapital'); @@ -437,7 +437,7 @@ protected function processParams(File $phpcsFile, $stackPtr, $commentStart) }//end if }//end foreach - $suggestedType = implode($suggestedTypeNames, '|'); + $suggestedType = implode('|', $suggestedTypeNames); if ($param['type'] !== $suggestedType) { $error = 'Expected "%s" but found "%s" for parameter type'; $data = array( diff --git a/src/Magento/FunctionalTestingFramework/Util/Validation/NameValidationUtil.php b/src/Magento/FunctionalTestingFramework/Util/Validation/NameValidationUtil.php index 0112af14e..eb8d615a2 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Validation/NameValidationUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/Validation/NameValidationUtil.php @@ -89,7 +89,7 @@ public static function validateName($name, $type) */ public function validatePascalCase($str, $type, $filename = null) { - if (!ctype_upper($str[0])) { + if (!is_string($str) || !ctype_upper($str[0])) { $message = "The {$type} {$str} should be PascalCase with an uppercase first letter."; if ($filename !== null) { @@ -117,7 +117,7 @@ public function validatePascalCase($str, $type, $filename = null) */ public function validateCamelCase($str, $type, $filename = null) { - if (!ctype_lower($str[0])) { + if (!is_string($str) || !ctype_lower($str[0])) { $message = "The {$type} {$str} should be camelCase with a lowercase first letter."; if ($filename !== null) { From 76be5a742045c6080677c8f5fe2a3a44712982ca Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Tue, 21 Apr 2020 17:17:59 -0500 Subject: [PATCH 344/888] MQE-1704: MFTF Compatibility with PHPUnit 9 (#681) --- composer.json | 4 +- composer.lock | 330 +++++++++++++++++++++++++++++++++++++------------- 2 files changed, 250 insertions(+), 84 deletions(-) diff --git a/composer.json b/composer.json index 1e5cebdce..33daf0ad5 100755 --- a/composer.json +++ b/composer.json @@ -34,14 +34,14 @@ }, "require-dev": { "squizlabs/php_codesniffer": "~3.2", - "sebastian/phpcpd": "~4.0||~5.0", + "sebastian/phpcpd": "~5.0", "brainmaestro/composer-git-hooks": "^2.3.1", "doctrine/cache": "<1.7.0", "codeception/aspect-mock": "^3.0", "goaop/framework": "2.2.0", "codacy/coverage": "^1.4", "phpmd/phpmd": "^2.6.0", - "phpunit/phpunit": "~9.0.0", + "phpunit/phpunit": "^9", "rregeer/phpunit-coverage-check": "^0.1.4", "php-coveralls/php-coveralls": "^1.0", "symfony/stopwatch": "~3.4.6" diff --git a/composer.lock b/composer.lock index 22e562cef..8078d2686 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "727146c7b29909e5d60e4c7f3ed5f268", + "content-hash": "9beabb43fcd8d6adec18f81144726c75", "packages": [ { "name": "allure-framework/allure-codeception", @@ -112,16 +112,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.133.44", + "version": "3.133.38", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "00df425deebdde3f3bebfde446a4250695dc47e4" + "reference": "5ec9442162d83f94918bc17136a2b674a04784e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/00df425deebdde3f3bebfde446a4250695dc47e4", - "reference": "00df425deebdde3f3bebfde446a4250695dc47e4", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/5ec9442162d83f94918bc17136a2b674a04784e5", + "reference": "5ec9442162d83f94918bc17136a2b674a04784e5", "shasum": "" }, "require": { @@ -192,7 +192,7 @@ "s3", "sdk" ], - "time": "2020-03-25T18:15:47+00:00" + "time": "2020-03-17T18:16:01+00:00" }, { "name": "behat/gherkin", @@ -433,16 +433,16 @@ }, { "name": "codeception/lib-asserts", - "version": "1.2.0", + "version": "1.12.0", "source": { "type": "git", "url": "https://github.com/Codeception/lib-asserts.git", - "reference": "74bfe433af24e2f75c6386b9d843ec69029f4337" + "reference": "acd0dc8b394595a74b58dcc889f72569ff7d8e71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/lib-asserts/zipball/74bfe433af24e2f75c6386b9d843ec69029f4337", - "reference": "74bfe433af24e2f75c6386b9d843ec69029f4337", + "url": "https://api.github.com/repos/Codeception/lib-asserts/zipball/acd0dc8b394595a74b58dcc889f72569ff7d8e71", + "reference": "acd0dc8b394595a74b58dcc889f72569ff7d8e71", "shasum": "" }, "require": { @@ -474,25 +474,25 @@ "keywords": [ "codeception" ], - "time": "2020-02-07T17:47:55+00:00" + "time": "2020-04-17T18:20:46+00:00" }, { "name": "codeception/module-asserts", - "version": "1.1.1", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/Codeception/module-asserts.git", - "reference": "87c83ca3ccfbc0d79f5effb57e1f82eeaab0cb3e" + "reference": "79f13d05b63f2fceba4d0e78044bab668c9b2a6b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/module-asserts/zipball/87c83ca3ccfbc0d79f5effb57e1f82eeaab0cb3e", - "reference": "87c83ca3ccfbc0d79f5effb57e1f82eeaab0cb3e", + "url": "https://api.github.com/repos/Codeception/module-asserts/zipball/79f13d05b63f2fceba4d0e78044bab668c9b2a6b", + "reference": "79f13d05b63f2fceba4d0e78044bab668c9b2a6b", "shasum": "" }, "require": { "codeception/codeception": "*@dev", - "codeception/lib-asserts": "^1.0.0", + "codeception/lib-asserts": "^1.12.0", "php": ">=5.6.0 <8.0" }, "conflict": { @@ -526,7 +526,7 @@ "asserts", "codeception" ], - "time": "2019-11-13T17:32:27+00:00" + "time": "2020-04-20T07:26:11+00:00" }, { "name": "codeception/module-sequence", @@ -573,16 +573,16 @@ }, { "name": "codeception/module-webdriver", - "version": "1.0.6", + "version": "1.0.7", "source": { "type": "git", "url": "https://github.com/Codeception/module-webdriver.git", - "reference": "9ee54108860859b120ed4a22e50f37d33aa3a518" + "reference": "f05c5c25e39d10fbfb2d508779e1537df019ff9b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/module-webdriver/zipball/9ee54108860859b120ed4a22e50f37d33aa3a518", - "reference": "9ee54108860859b120ed4a22e50f37d33aa3a518", + "url": "https://api.github.com/repos/Codeception/module-webdriver/zipball/f05c5c25e39d10fbfb2d508779e1537df019ff9b", + "reference": "f05c5c25e39d10fbfb2d508779e1537df019ff9b", "shasum": "" }, "require": { @@ -624,20 +624,20 @@ "browser-testing", "codeception" ], - "time": "2020-03-23T17:08:27+00:00" + "time": "2020-04-01T10:18:18+00:00" }, { "name": "codeception/phpunit-wrapper", - "version": "9.0.1", + "version": "9.0.2", "source": { "type": "git", "url": "https://github.com/Codeception/phpunit-wrapper.git", - "reference": "cf5954ca7cbe9ac6eddd3c9e9ce866c27ec8b906" + "reference": "eb27243d8edde68593bf8d9ef5e9074734777931" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/phpunit-wrapper/zipball/cf5954ca7cbe9ac6eddd3c9e9ce866c27ec8b906", - "reference": "cf5954ca7cbe9ac6eddd3c9e9ce866c27ec8b906", + "url": "https://api.github.com/repos/Codeception/phpunit-wrapper/zipball/eb27243d8edde68593bf8d9ef5e9074734777931", + "reference": "eb27243d8edde68593bf8d9ef5e9074734777931", "shasum": "" }, "require": { @@ -668,7 +668,7 @@ } ], "description": "PHPUnit classes used by Codeception", - "time": "2020-03-20T07:44:37+00:00" + "time": "2020-04-17T18:16:31+00:00" }, { "name": "codeception/stub", @@ -2565,20 +2565,20 @@ }, { "name": "phpoption/phpoption", - "version": "1.7.3", + "version": "1.7.2", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "4acfd6a4b33a509d8c88f50e5222f734b6aeebae" + "reference": "77f7c4d2e65413aff5b5a8cc8b3caf7a28d81959" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/4acfd6a4b33a509d8c88f50e5222f734b6aeebae", - "reference": "4acfd6a4b33a509d8c88f50e5222f734b6aeebae", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/77f7c4d2e65413aff5b5a8cc8b3caf7a28d81959", + "reference": "77f7c4d2e65413aff5b5a8cc8b3caf7a28d81959", "shasum": "" }, "require": { - "php": "^5.5.9 || ^7.0 || ^8.0" + "php": "^5.5.9 || ^7.0" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.3", @@ -2616,7 +2616,7 @@ "php", "type" ], - "time": "2020-03-21T18:07:53+00:00" + "time": "2019-12-15T19:35:24+00:00" }, { "name": "phpspec/prophecy", @@ -2747,16 +2747,16 @@ }, { "name": "phpunit/php-file-iterator", - "version": "3.0.0", + "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "354d4a5faa7449a377a18b94a2026ca3415e3d7a" + "reference": "4ac5b3e13df14829daa60a2eb4fdd2f2b7d33cf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/354d4a5faa7449a377a18b94a2026ca3415e3d7a", - "reference": "354d4a5faa7449a377a18b94a2026ca3415e3d7a", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/4ac5b3e13df14829daa60a2eb4fdd2f2b7d33cf4", + "reference": "4ac5b3e13df14829daa60a2eb4fdd2f2b7d33cf4", "shasum": "" }, "require": { @@ -2793,7 +2793,7 @@ "filesystem", "iterator" ], - "time": "2020-02-07T06:05:22+00:00" + "time": "2020-04-18T05:02:12+00:00" }, { "name": "phpunit/php-invoker", @@ -2896,16 +2896,16 @@ }, { "name": "phpunit/php-timer", - "version": "3.0.0", + "version": "3.1.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "4118013a4d0f97356eae8e7fb2f6c6472575d1df" + "reference": "dc9368fae6ef2ffa57eba80a7410bcef81df6258" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/4118013a4d0f97356eae8e7fb2f6c6472575d1df", - "reference": "4118013a4d0f97356eae8e7fb2f6c6472575d1df", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/dc9368fae6ef2ffa57eba80a7410bcef81df6258", + "reference": "dc9368fae6ef2ffa57eba80a7410bcef81df6258", "shasum": "" }, "require": { @@ -2917,7 +2917,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.1-dev" } }, "autoload": { @@ -2941,7 +2941,7 @@ "keywords": [ "timer" ], - "time": "2020-02-07T06:08:11+00:00" + "time": "2020-04-20T06:00:37+00:00" }, { "name": "phpunit/php-token-stream", @@ -2994,16 +2994,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.0.2", + "version": "9.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "c0ecbfb898ab8b24d8a59a23520f7b2a73e27b5b" + "reference": "d99d4e69c98c18d5c5f033c68c623880536f37be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c0ecbfb898ab8b24d8a59a23520f7b2a73e27b5b", - "reference": "c0ecbfb898ab8b24d8a59a23520f7b2a73e27b5b", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d99d4e69c98c18d5c5f033c68c623880536f37be", + "reference": "d99d4e69c98c18d5c5f033c68c623880536f37be", "shasum": "" }, "require": { @@ -3023,7 +3023,8 @@ "phpunit/php-file-iterator": "^3.0", "phpunit/php-invoker": "^3.0", "phpunit/php-text-template": "^2.0", - "phpunit/php-timer": "^3.0", + "phpunit/php-timer": "^3.1.4", + "sebastian/code-unit": "^1.0", "sebastian/comparator": "^4.0", "sebastian/diff": "^4.0", "sebastian/environment": "^5.0.1", @@ -3035,7 +3036,8 @@ "sebastian/version": "^3.0" }, "require-dev": { - "ext-pdo": "*" + "ext-pdo": "*", + "phpspec/prophecy-phpunit": "^2.0" }, "suggest": { "ext-soap": "*", @@ -3047,7 +3049,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.0-dev" + "dev-master": "9.1-dev" } }, "autoload": { @@ -3076,7 +3078,7 @@ "testing", "xunit" ], - "time": "2020-03-31T08:57:51+00:00" + "time": "2020-04-20T06:24:01+00:00" }, { "name": "psr/cache", @@ -3225,16 +3227,16 @@ }, { "name": "psr/log", - "version": "1.1.3", + "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc" + "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc", - "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc", + "url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801", + "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801", "shasum": "" }, "require": { @@ -3268,7 +3270,7 @@ "psr", "psr-3" ], - "time": "2020-03-23T09:12:05+00:00" + "time": "2019-11-01T11:05:21+00:00" }, { "name": "psr/simple-cache", @@ -3445,6 +3447,52 @@ ], "time": "2020-02-21T04:36:14+00:00" }, + { + "name": "sebastian/code-unit", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "8d8f09bd47c75159921e6e84fdef146343962866" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/8d8f09bd47c75159921e6e84fdef146343962866", + "reference": "8d8f09bd47c75159921e6e84fdef146343962866", + "shasum": "" + }, + "require": { + "php": "^7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "time": "2020-03-30T11:59:20+00:00" + }, { "name": "sebastian/code-unit-reverse-lookup", "version": "2.0.0", @@ -3612,16 +3660,16 @@ }, { "name": "sebastian/environment", - "version": "5.0.2", + "version": "5.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "c39c1db0a5cffc98173f3de5a17d489d1043fd7b" + "reference": "c753f04d68cd489b6973cf9b4e505e191af3b05c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/c39c1db0a5cffc98173f3de5a17d489d1043fd7b", - "reference": "c39c1db0a5cffc98173f3de5a17d489d1043fd7b", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/c753f04d68cd489b6973cf9b4e505e191af3b05c", + "reference": "c753f04d68cd489b6973cf9b4e505e191af3b05c", "shasum": "" }, "require": { @@ -3661,7 +3709,7 @@ "environment", "hhvm" ], - "time": "2020-03-31T12:14:15+00:00" + "time": "2020-04-14T13:36:52+00:00" }, { "name": "sebastian/exporter", @@ -4158,16 +4206,16 @@ }, { "name": "symfony/console", - "version": "v4.4.7", + "version": "v4.4.5", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "10bb3ee3c97308869d53b3e3d03f6ac23ff985f7" + "reference": "4fa15ae7be74e53f6ec8c83ed403b97e23b665e9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/10bb3ee3c97308869d53b3e3d03f6ac23ff985f7", - "reference": "10bb3ee3c97308869d53b3e3d03f6ac23ff985f7", + "url": "https://api.github.com/repos/symfony/console/zipball/4fa15ae7be74e53f6ec8c83ed403b97e23b665e9", + "reference": "4fa15ae7be74e53f6ec8c83ed403b97e23b665e9", "shasum": "" }, "require": { @@ -4230,29 +4278,29 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2020-03-30T11:41:10+00:00" + "time": "2020-02-24T13:10:00+00:00" }, { "name": "symfony/css-selector", - "version": "v5.0.5", + "version": "v4.4.5", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "a0b51ba9938ccc206d9284de7eb527c2d4550b44" + "reference": "d0a6dd288fa8848dcc3d1f58b94de6a7cc5d2d22" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/a0b51ba9938ccc206d9284de7eb527c2d4550b44", - "reference": "a0b51ba9938ccc206d9284de7eb527c2d4550b44", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/d0a6dd288fa8848dcc3d1f58b94de6a7cc5d2d22", + "reference": "d0a6dd288fa8848dcc3d1f58b94de6a7cc5d2d22", "shasum": "" }, "require": { - "php": "^7.2.5" + "php": "^7.1.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -4283,7 +4331,7 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "time": "2020-02-04T09:41:09+00:00" + "time": "2020-02-04T09:01:01+00:00" }, { "name": "symfony/event-dispatcher", @@ -5427,22 +5475,20 @@ }, { "name": "gitonomy/gitlib", - "version": "v1.2.1", + "version": "v1.2.0", "source": { "type": "git", "url": "https://github.com/gitonomy/gitlib.git", - "reference": "718ca021c67f3ea8f6a5fa5d231ec49675068868" + "reference": "a0bea921266ad1c9626d712e7f8687dcc08ca528" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/gitonomy/gitlib/zipball/718ca021c67f3ea8f6a5fa5d231ec49675068868", - "reference": "718ca021c67f3ea8f6a5fa5d231ec49675068868", + "url": "https://api.github.com/repos/gitonomy/gitlib/zipball/a0bea921266ad1c9626d712e7f8687dcc08ca528", + "reference": "a0bea921266ad1c9626d712e7f8687dcc08ca528", "shasum": "" }, "require": { - "ext-pcre": "*", "php": "^5.6 || ^7.0", - "symfony/polyfill-mbstring": "^1.7", "symfony/process": "^3.4|^4.0|^5.0" }, "require-dev": { @@ -5450,7 +5496,6 @@ "psr/log": "^1.0" }, "suggest": { - "ext-fileinfo": "Required to determine the mimetype of a blob", "psr/log": "Required to use loggers for reporting of execution" }, "type": "library", @@ -5487,7 +5532,8 @@ } ], "description": "Library for accessing git", - "time": "2020-03-23T12:43:44+00:00" + "homepage": "http://gitonomy.com", + "time": "2019-12-08T12:42:25+00:00" }, { "name": "goaop/framework", @@ -6173,6 +6219,65 @@ ], "time": "2020-01-30T22:20:29+00:00" }, + { + "name": "symfony/browser-kit", + "version": "v4.4.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/browser-kit.git", + "reference": "090ce406505149d6852a7c03b0346dec3b8cf612" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/090ce406505149d6852a7c03b0346dec3b8cf612", + "reference": "090ce406505149d6852a7c03b0346dec3b8cf612", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/dom-crawler": "^3.4|^4.0|^5.0" + }, + "require-dev": { + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/http-client": "^4.3|^5.0", + "symfony/mime": "^4.3|^5.0", + "symfony/process": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\BrowserKit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony BrowserKit Component", + "homepage": "https://symfony.com", + "time": "2020-02-23T10:00:59+00:00" + }, { "name": "symfony/config", "version": "v4.4.5", @@ -6310,6 +6415,67 @@ "homepage": "https://symfony.com", "time": "2020-02-29T09:50:10+00:00" }, + { + "name": "symfony/dom-crawler", + "version": "v4.4.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "11dcf08f12f29981bf770f097a5d64d65bce5929" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/11dcf08f12f29981bf770f097a5d64d65bce5929", + "reference": "11dcf08f12f29981bf770f097a5d64d65bce5929", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "masterminds/html5": "<2.6" + }, + "require-dev": { + "masterminds/html5": "^2.6", + "symfony/css-selector": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/css-selector": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\DomCrawler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony DomCrawler Component", + "homepage": "https://symfony.com", + "time": "2020-02-29T10:05:28+00:00" + }, { "name": "symfony/stopwatch", "version": "v3.4.38", From cd17978fd55f4b6809e1466fb4af054dd9270093 Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Wed, 22 Apr 2020 14:06:06 -0500 Subject: [PATCH 345/888] MQE-2094: Test failure re-run error for extn builds (#682) * MQE-2094: Test failure re-run error for extn builds fixed group name * MQE-2094: Test failure re-run error for extn builds * MQE-2094: Test failure re-run error for extn builds --- .../Console/RunTestFailedCommand.php | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php index 5f0596a7f..c6a2d0b76 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php @@ -165,11 +165,7 @@ private function getFailedTestList() if ($suiteName == self::DEFAULT_TEST_GROUP) { array_push($failedTestDetails['tests'], $testName); } else { - // Trim potential suite_parallel_0 to suite_parallel - $suiteNameArray = explode("_", $suiteName); - if (is_numeric(array_pop($suiteNameArray))) { - $suiteName = implode("_", $suiteNameArray); - } + $suiteName = $this->sanitizeSuiteName($suiteName); $failedTestDetails['suites'] = array_merge_recursive( $failedTestDetails['suites'], [$suiteName => [$testName]] @@ -191,6 +187,23 @@ private function getFailedTestList() return $testConfigurationJson; } + /** + * Trim potential suite_parallel_0_G to suite_parallel + * + * @param string $suiteName + * @return string + */ + private function sanitizeSuiteName($suiteName) + { + $suiteNameArray = explode("_", $suiteName); + if (array_pop($suiteNameArray) == 'G') { + if (is_numeric(array_pop($suiteNameArray))) { + $suiteName = implode("_", $suiteNameArray); + } + } + return $suiteName; + } + /** * Returns an array of run commands read from the manifest file created post generation * From 54004ba8506aa93d5bd6f7047a9a0f90f7ad4568 Mon Sep 17 00:00:00 2001 From: Ajith <ajithkumar.maragathavel@ziffity.com> Date: Thu, 23 Apr 2020 00:47:13 +0530 Subject: [PATCH 346/888] Renamed sample test name with the correct one --- docs/getting-started.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 89d228df9..8f30601af 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -241,10 +241,10 @@ See more commands in [`codecept`][]. #### Run a simple test {#run-test} -To clean up the previously generated tests, and then generate and run a single test `AdminLoginTest`, run: +To clean up the previously generated tests, and then generate and run a single test `AdminLoginSuccessfulTest`, run: ```bash -vendor/bin/mftf run:test AdminLoginTest --remove +vendor/bin/mftf run:test AdminLoginSuccessfulTest --remove ``` See more commands in [`mftf`][]. @@ -319,7 +319,7 @@ composer remove magento/magento2-functional-testing-framework --dev -d <path to Generate and run a single test that will check your logging to the Magento Admin functionality: ```bash -bin/mftf run:test AdminLoginTest +bin/mftf run:test AdminLoginSuccessfulTest ``` You can find the generated test at `dev/tests/functional/tests/MFTF/_generated/default/`. From b66506c231406655d633f01015dc329cf56c6ebc Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 22 Apr 2020 16:34:32 -0500 Subject: [PATCH 347/888] MQE-2027: MFTF PHP Compatibility Update (PHP 7.4) - changed formatMoney to formatCurrency --- bin/functional | 3 +- composer.json | 4 +- composer.lock | 15 +++--- .../MFTF/DevDocs/Test/FormatCurrencyTest.xml | 52 +++++++++++++++++++ .../ActionGroupWithStepKeyReferences.txt | 2 +- ...nGroupWithStepKeyReferencesActionGroup.xml | 2 +- .../ActionGroup/XmlDuplicateActionGroup.xml | 4 +- .../XmlDuplicateTest/XmlDuplicateTest.xml | 12 ++--- docs/test/actions.md | 9 ++-- etc/di.xml | 2 +- .../Module/MagentoWebDriver.php | 25 +++++---- .../Test/Objects/ActionGroupObject.php | 2 +- .../Test/etc/Actions/customActions.xsd | 37 +++++++------ .../Util/TestGenerator.php | 39 ++++++++++++-- 14 files changed, 154 insertions(+), 54 deletions(-) create mode 100644 dev/tests/functional/tests/MFTF/DevDocs/Test/FormatCurrencyTest.xml diff --git a/bin/functional b/bin/functional index 99377337e..97501e018 100755 --- a/bin/functional +++ b/bin/functional @@ -4,7 +4,8 @@ set -e echo "===============================" -echo " EXECUTE DevDocsTest " +echo " EXECUTE Functional Tests " echo "===============================" bin/mftf build:project bin/mftf run:test DevDocsTest -f +bin/mftf run:test FormatCurrencyTest -f \ No newline at end of file diff --git a/composer.json b/composer.json index 19c08b6c0..2bd6c222b 100755 --- a/composer.json +++ b/composer.json @@ -14,6 +14,7 @@ "ext-dom": "*", "ext-json": "*", "ext-openssl": "*", + "ext-intl": "*", "allure-framework/allure-codeception": "~1.4.0", "aws/aws-sdk-php": "^3.132", "codeception/codeception": "~4.1.4", @@ -53,8 +54,7 @@ "files": ["src/Magento/FunctionalTestingFramework/_bootstrap.php"], "psr-4": { "Magento\\FunctionalTestingFramework\\": "src/Magento/FunctionalTestingFramework", - "MFTF\\": "dev/tests/functional/tests/MFTF", - "Magento\\": "../magento5/app/code/Magento/" + "MFTF\\": "dev/tests/functional/tests/MFTF" } }, "autoload-dev": { diff --git a/composer.lock b/composer.lock index b88f217f5..5b53f0b7f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "aff9cb54455b486036efa97f1fcb14bd", + "content-hash": "25cf03eee8281f6787f72fb9f497da74", "packages": [ { "name": "allure-framework/allure-codeception", @@ -112,16 +112,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.135.1", + "version": "3.135.2", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "59587a4f3fc88b36ce7f2e1a102bfcd7a816b27c" + "reference": "1810725052836683d0cfd2907d515173058e710e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/59587a4f3fc88b36ce7f2e1a102bfcd7a816b27c", - "reference": "59587a4f3fc88b36ce7f2e1a102bfcd7a816b27c", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/1810725052836683d0cfd2907d515173058e710e", + "reference": "1810725052836683d0cfd2907d515173058e710e", "shasum": "" }, "require": { @@ -192,7 +192,7 @@ "s3", "sdk" ], - "time": "2020-04-21T18:14:29+00:00" + "time": "2020-04-22T18:11:15+00:00" }, { "name": "behat/gherkin", @@ -6420,7 +6420,8 @@ "ext-curl": "*", "ext-dom": "*", "ext-json": "*", - "ext-openssl": "*" + "ext-openssl": "*", + "ext-intl": "*" }, "platform-dev": [] } diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Test/FormatCurrencyTest.xml b/dev/tests/functional/tests/MFTF/DevDocs/Test/FormatCurrencyTest.xml new file mode 100644 index 000000000..ab3d36c4e --- /dev/null +++ b/dev/tests/functional/tests/MFTF/DevDocs/Test/FormatCurrencyTest.xml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="FormatCurrencyTest"> + <comment userInput="formatCurrency uses NumberFormatter::formatCurrency(), see https://www.php.net/manual/en/numberformatter.formatcurrency.php" stepKey="comment"/> + <formatCurrency userInput="1234.56789000" locale="de_DE" currency="EUR" stepKey="eurInDE"/> + <assertEquals stepKey="assertEurInDE"> + <expectedResult type="string">1.234,57 €</expectedResult> + <actualResult type="variable">$eurInDE</actualResult> + </assertEquals> + <formatCurrency userInput="+1234" locale="de_DE" currency="EUR" stepKey="eurInDEPos"/> + <assertEquals stepKey="assertEurInDEPos"> + <expectedResult type="string">1.234,00 €</expectedResult> + <actualResult type="variable">$eurInDEPos</actualResult> + </assertEquals> + <formatCurrency userInput="-1234.56" locale="de_DE" currency="EUR" stepKey="eurInDENeg"/> + <assertEquals stepKey="assertEurInDENeg"> + <expectedResult type="string">-1.234,56 €</expectedResult> + <actualResult type="variable">$eurInDENeg</actualResult> + </assertEquals> + + <formatCurrency userInput="1234.56789000" locale="de_DE" currency="USD" stepKey="usdInDE"/> + <assertEquals stepKey="assertUsdInDE"> + <expectedResult type="string">1.234,57 $</expectedResult> + <actualResult type="variable">$usdInDE</actualResult> + </assertEquals> + <formatCurrency userInput="+1234" locale="de_DE" currency="USD" stepKey="usdInDEPos"/> + <assertEquals stepKey="assertUsdInDEPos"> + <expectedResult type="string">1.234,00 $</expectedResult> + <actualResult type="variable">$usdInDEPos</actualResult> + </assertEquals> + <formatCurrency userInput="-1234.56" locale="de_DE" currency="USD" stepKey="usdInDENeg"/> + <assertEquals stepKey="assertUsdInDENeg"> + <expectedResult type="string">-1.234,56 $</expectedResult> + <actualResult type="variable">$usdInDENeg</actualResult> + </assertEquals> + + <executeJS function="return 10.5;" stepKey="variable"/> + <formatCurrency userInput="$variable" locale="de_DE" currency="EUR" stepKey="usingVariable"/> + <assertEquals stepKey="assertUsingVariable"> + <expectedResult type="string">10,50 €</expectedResult> + <actualResult type="variable">$usingVariable</actualResult> + </assertEquals> + </test> +</tests> diff --git a/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt b/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt index d623839d3..7d8fae946 100644 --- a/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt +++ b/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt @@ -42,7 +42,7 @@ class ActionGroupWithStepKeyReferencesCest $date->setTimezone(new \DateTimeZone("America/Los_Angeles")); $action5ActionGroup = $date->format("H:i:s"); - $action6ActionGroup = $I->formatMoney($action6ActionGroup); // stepKey: action6ActionGroup + $action6ActionGroup = $I->formatCurrency($action6ActionGroup, "en_CA", "USD"); // stepKey: action6ActionGroup $I->deleteEntity("{$action7ActionGroupActionGroup}", "test"); // stepKey: action7ActionGroup $I->getEntity("action8ActionGroup", "test", "{$action8}", [], null); // stepKey: action8ActionGroup $I->updateEntity("1", "test", "{$action9}",[]); // stepKey: action9ActionGroup diff --git a/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionActionGroupWithStepKeyReferencesActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionActionGroupWithStepKeyReferencesActionGroup.xml index 8d36773e8..516c2895b 100644 --- a/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionActionGroupWithStepKeyReferencesActionGroup.xml +++ b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionActionGroupWithStepKeyReferencesActionGroup.xml @@ -18,7 +18,7 @@ <executeJS function="{$action3}" stepKey="action3"/> <magentoCLI command="{$action4}" arguments=""stuffHere"" stepKey="action4"/> <generateDate date="{$action5}" format="H:i:s" stepKey="action5"/> - <formatMoney userInput="{$action6}" stepKey="action6"/> + <formatCurrency userInput="{$action6}" locale="en_CA" currency="USD" stepKey="action6"/> <deleteData createDataKey="{$action7}" stepKey="action7"/> <getData entity="{$action8}" stepKey="action8"/> <updateData entity="{$action9}" stepKey="action9" createDataKey="1"/> diff --git a/dev/tests/verification/TestModule/ActionGroup/XmlDuplicateActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/XmlDuplicateActionGroup.xml index 464322f27..6eefdaf51 100644 --- a/dev/tests/verification/TestModule/ActionGroup/XmlDuplicateActionGroup.xml +++ b/dev/tests/verification/TestModule/ActionGroup/XmlDuplicateActionGroup.xml @@ -82,8 +82,8 @@ <executeJS function="1" stepKey="execJS2"/> <fillField stepKey="fill1"/> <fillField stepKey="fill21"/> - <formatMoney stepKey="frmtmoney1"/> - <formatMoney stepKey="frmtmoney12"/> + <formatCurrency userInput="1234.567890" locale="de_DE" currency="EUR" stepKey="frmtmoney1"/> + <formatCurrency userInput="1234.567890" locale="de_DE" currency="USD" stepKey="frmtmoney12"/> <getData entity="1" stepKey="getdata1"/> <getData entity="1" stepKey="getdata12"/> <grabAttributeFrom selector="1" stepKey="grabattribute1"/> diff --git a/dev/tests/verification/TestModule/Test/XmlDuplicateTest/XmlDuplicateTest.xml b/dev/tests/verification/TestModule/Test/XmlDuplicateTest/XmlDuplicateTest.xml index 905a04779..b24bac3b5 100644 --- a/dev/tests/verification/TestModule/Test/XmlDuplicateTest/XmlDuplicateTest.xml +++ b/dev/tests/verification/TestModule/Test/XmlDuplicateTest/XmlDuplicateTest.xml @@ -85,8 +85,8 @@ <executeJS function="1" stepKey="execJS2"/> <fillField stepKey="fill1"/> <fillField stepKey="fill21"/> - <formatMoney stepKey="frmtmoney1"/> - <formatMoney stepKey="frmtmoney12"/> + <formatCurrency userInput="1234.567890" locale="de_DE" currency="EUR" stepKey="frmtmoney1"/> + <formatCurrency userInput="1234.567890" locale="en_US" currency="EUR" stepKey="frmtmoney12"/> <getData entity="1" stepKey="getdata1"/> <getData entity="1" stepKey="getdata12"/> <grabAttributeFrom selector="1" stepKey="grabattribute1"/> @@ -297,8 +297,8 @@ <executeJS function="1" stepKey="execJS2"/> <fillField stepKey="fill1"/> <fillField stepKey="fill21"/> - <formatMoney stepKey="frmtmoney1"/> - <formatMoney stepKey="frmtmoney12"/> + <formatCurrency userInput="1234.567890" locale="de_DE" currency="EUR" stepKey="frmtmoney1"/> + <formatCurrency userInput="1234.567890" locale="en_US" currency="EUR" stepKey="frmtmoney12"/> <getData entity="1" stepKey="getdata1"/> <getData entity="1" stepKey="getdata12"/> <grabAttributeFrom selector="1" stepKey="grabattribute1"/> @@ -508,8 +508,8 @@ <executeJS function="1" stepKey="execJS2"/> <fillField stepKey="fill1"/> <fillField stepKey="fill21"/> - <formatMoney stepKey="frmtmoney1"/> - <formatMoney stepKey="frmtmoney12"/> + <formatCurrency userInput="1234.567890" locale="de_DE" currency="EUR" stepKey="frmtmoney1"/> + <formatCurrency userInput="1234.567890" locale="en_US" currency="EUR" stepKey="frmtmoney12"/> <getData entity="1" stepKey="getdata1"/> <getData entity="1" stepKey="getdata12"/> <grabAttributeFrom selector="1" stepKey="grabattribute1"/> diff --git a/docs/test/actions.md b/docs/test/actions.md index a403b0942..49e0c6afe 100644 --- a/docs/test/actions.md +++ b/docs/test/actions.md @@ -1012,12 +1012,15 @@ Attribute|Type|Use|Description <fillField userInput="Sample text" selector="input#myfield" stepKey="fillField"/> ``` -### formatMoney +### formatCurrency +Format input to specified currency according to the locale specified. Returns formatted string for test use. +Use NumberFormatter::formatCurrency(), see https://www.php.net/manual/en/numberformatter.formatcurrency.php Attribute|Type|Use|Description ---|---|---|--- -`userInput`|string|optional| Value for the money form field. -`locale`|string|optional| The PHP locale value for the store. +`userInput`|string|required| Number to be formatted. +`locale`|string|required| The locale to format to. +`currency`|string|required| The 3-letter ISO 4217 currency code indicating the currency to use. `stepKey`|string|required| A unique identifier of the action. `before`|string|optional| `stepKey` of action that must be executed next. `after`|string|optional| `stepKey` of preceding action. diff --git a/etc/di.xml b/etc/di.xml index b8cc9e7a2..f6a89fcb0 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -8,7 +8,7 @@ <!-- Entity value gets replaced in Dom.php before reading $xml --> <!DOCTYPE config [ - <!ENTITY commonTestActions "acceptPopup|actionGroup|amOnPage|amOnUrl|amOnSubdomain|appendField|assertArrayIsSortasserted|assertElementContainsAttribute|attachFile|cancelPopup|checkOption|clearField|click|clickWithLeftButton|clickWithRightButton|closeAdminNotification|closeTab|comment|conditionalClick|createData|deleteData|updateData|getData|dontSee|dontSeeJsError|dontSeeCheckboxIsChecked|dontSeeCookie|dontSeeCurrentUrlEquals|dontSeeCurrentUrlMatches|dontSeeElement|dontSeeElementInDOM|dontSeeInCurrentUrl|dontSeeInField|dontSeeInFormFields|dontSeeInPageSource|dontSeeInSource|dontSeeInTitle|dontSeeLink|dontSeeOptionIsSelected|doubleClick|dragAndDrop|entity|executeJS|fillField|formatMoney|generateDate|grabAttributeFrom|grabCookie|grabFromCurrentUrl|grabMultiple|grabPageSource|grabTextFrom|grabValueFrom|loadSessionSnapshot|loginAsAdmin|magentoCLI|magentoCron|makeScreenshot|maximizeWindow|moveBack|moveForward|moveMouseOver|mSetLocale|mResetLocale|openNewTab|pause|parseFloat|pressKey|reloadPage|resetCookie|submitForm|resizeWindow|saveSessionSnapshot|scrollTo|scrollToTopOfPage|searchAndMultiSelectOption|see|seeCheckboxIsChecked|seeCookie|seeCurrentUrlEquals|seeCurrentUrlMatches|seeElement|seeElementInDOM|seeInCurrentUrl|seeInField|seeInFormFields|seeInPageSource|seeInPopup|seeInSource|seeInTitle|seeLink|seeNumberOfElements|seeOptionIsSelected|selectOption|setCookie|submitForm|switchToIFrame|switchToNextTab|switchToPreviousTab|switchToWindow|typeInPopup|uncheckOption|unselectOption|wait|waitForAjaxLoad|waitForElement|waitForElementChange|waitForElementNotVisible|waitForElementVisible|waitForPwaElementNotVisible|waitForPwaElementVisible|waitForJS|waitForLoadingMaskToDisappear|waitForPageLoad|waitForText|assertArrayHasKey|assertArrayNotHasKey|assertContains|assertStringContainsString|assertStringContainsStringIgnoringCase|assertCount|assertEmpty|assertEquals|assertFalse|assertFileExists|assertFileNotExists|assertGreaterOrEquals|assertGreaterThan|assertGreaterThanOrEqual|assertInstanceOf|assertIsEmpty|assertLessOrEquals|assertLessThan|assertLessThanOrEqual|assertNotContains|assertStringNotContainsString|assertStringNotContainsStringIgnoringCase|assertNotEmpty|assertNotEquals|assertNotInstanceOf|assertNotNull|assertNotRegExp|assertNotSame|assertNull|assertRegExp|assertSame|assertStringStartsNotWith|assertStringStartsWith|assertTrue|expectException|fail|dontSeeFullUrlEquals|dontSee|dontSeeFullUrlMatches|dontSeeInFullUrl|seeFullUrlEquals|seeFullUrlMatches|seeInFullUrl|grabFromFullUrl|helper|assertEqualsWithDelta|assertEqualsCanonicalizing|assertEqualsIgnoringCase|assertNotEqualsWithDelta|assertNotEqualsCanonicalizing|assertNotEqualsIgnoringCase"> + <!ENTITY commonTestActions "acceptPopup|actionGroup|amOnPage|amOnUrl|amOnSubdomain|appendField|assertArrayIsSortasserted|assertElementContainsAttribute|attachFile|cancelPopup|checkOption|clearField|click|clickWithLeftButton|clickWithRightButton|closeAdminNotification|closeTab|comment|conditionalClick|createData|deleteData|updateData|getData|dontSee|dontSeeJsError|dontSeeCheckboxIsChecked|dontSeeCookie|dontSeeCurrentUrlEquals|dontSeeCurrentUrlMatches|dontSeeElement|dontSeeElementInDOM|dontSeeInCurrentUrl|dontSeeInField|dontSeeInFormFields|dontSeeInPageSource|dontSeeInSource|dontSeeInTitle|dontSeeLink|dontSeeOptionIsSelected|doubleClick|dragAndDrop|entity|executeJS|fillField|formatCurrency|generateDate|grabAttributeFrom|grabCookie|grabFromCurrentUrl|grabMultiple|grabPageSource|grabTextFrom|grabValueFrom|loadSessionSnapshot|loginAsAdmin|magentoCLI|magentoCron|makeScreenshot|maximizeWindow|moveBack|moveForward|moveMouseOver|mSetLocale|mResetLocale|openNewTab|pause|parseFloat|pressKey|reloadPage|resetCookie|submitForm|resizeWindow|saveSessionSnapshot|scrollTo|scrollToTopOfPage|searchAndMultiSelectOption|see|seeCheckboxIsChecked|seeCookie|seeCurrentUrlEquals|seeCurrentUrlMatches|seeElement|seeElementInDOM|seeInCurrentUrl|seeInField|seeInFormFields|seeInPageSource|seeInPopup|seeInSource|seeInTitle|seeLink|seeNumberOfElements|seeOptionIsSelected|selectOption|setCookie|submitForm|switchToIFrame|switchToNextTab|switchToPreviousTab|switchToWindow|typeInPopup|uncheckOption|unselectOption|wait|waitForAjaxLoad|waitForElement|waitForElementChange|waitForElementNotVisible|waitForElementVisible|waitForPwaElementNotVisible|waitForPwaElementVisible|waitForJS|waitForLoadingMaskToDisappear|waitForPageLoad|waitForText|assertArrayHasKey|assertArrayNotHasKey|assertContains|assertStringContainsString|assertStringContainsStringIgnoringCase|assertCount|assertEmpty|assertEquals|assertFalse|assertFileExists|assertFileNotExists|assertGreaterOrEquals|assertGreaterThan|assertGreaterThanOrEqual|assertInstanceOf|assertIsEmpty|assertLessOrEquals|assertLessThan|assertLessThanOrEqual|assertNotContains|assertStringNotContainsString|assertStringNotContainsStringIgnoringCase|assertNotEmpty|assertNotEquals|assertNotInstanceOf|assertNotNull|assertNotRegExp|assertNotSame|assertNull|assertRegExp|assertSame|assertStringStartsNotWith|assertStringStartsWith|assertTrue|expectException|fail|dontSeeFullUrlEquals|dontSee|dontSeeFullUrlMatches|dontSeeInFullUrl|seeFullUrlEquals|seeFullUrlMatches|seeInFullUrl|grabFromFullUrl|helper|assertEqualsWithDelta|assertEqualsCanonicalizing|assertEqualsIgnoringCase|assertNotEqualsWithDelta|assertNotEqualsCanonicalizing|assertNotEqualsIgnoringCase"> ]> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../src/Magento/FunctionalTestingFramework/ObjectManager/etc/config.xsd"> diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 4ff1dc271..936b0a0da 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -452,19 +452,26 @@ public function waitForLoadingMaskToDisappear($timeout = null) } /** - * @param float $money + * Format input to specified currency in locale specified + * @link https://php.net/manual/en/numberformatter.formatcurrency.php + * + * @param float $value * @param string $locale - * @return array + * @param string $currency + * @return string + * @throws TestFrameworkException */ - public function formatMoney(float $money, $locale = 'en_US.UTF-8') + public function formatCurrency(float $value, $locale, $currency) { - $this->mSetLocale(LC_MONETARY, $locale); - $money = money_format('%.2n', $money); - $this->mResetLocale(); - $prefix = substr($money, 0, 1); - $number = substr($money, 1); + $formatter = \NumberFormatter::create($locale, \NumberFormatter::CURRENCY); + if ($formatter && !empty($formatter)) { + $result = $formatter->formatCurrency($value, $currency); + if ($result) { + return $result; + } + } - return ['prefix' => $prefix, 'number' => $number]; + throw new TestFrameworkException('Invalid attributes used in formatCurrency.'); } /** diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php index a8027764b..4298465b8 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php @@ -24,7 +24,7 @@ class ActionGroupObject "executeJS", "magentoCLI", "generateDate", - "formatMoney", + "formatCurrency", "deleteData", "getData", "updateData", diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd index fbb21456f..6d60110ca 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd @@ -17,7 +17,7 @@ <xs:element type="closeAdminNotificationType" name="closeAdminNotification" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="searchAndMultiSelectOptionType" name="searchAndMultiSelectOption" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="selectMultipleOptionsType" name="selectMultipleOptions" minOccurs="0" maxOccurs="unbounded"/> - <xs:element type="formatMoneyType" name="formatMoney" minOccurs="0" maxOccurs="unbounded"/> + <xs:element type="formatCurrencyType" name="formatCurrency" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="parseFloatType" name="parseFloat" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="mSetLocaleType" name="mSetLocale" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="mResetLocaleType" name="mResetLocale" minOccurs="0" maxOccurs="unbounded"/> @@ -178,25 +178,29 @@ <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> - <xs:complexType name="formatMoneyType"> + <xs:complexType name="formatCurrencyType"> <xs:annotation> <xs:documentation> - Formats given input to given locale. Returns formatted string for test use. + Format input to specified currency according to the locale specified. Returns formatted string for test use. + Use NumberFormatter::formatCurrency(), see https://www.php.net/manual/en/numberformatter.formatcurrency.php </xs:documentation> </xs:annotation> - <xs:simpleContent> - <xs:extension base="xs:string"> - <xs:attribute ref="userInput"/> - <xs:attribute type="xs:string" name="locale"> - <xs:annotation> - <xs:documentation> - Locale to format given input. Defaults to 'en_US.UTF-8' if nothing is given. - </xs:documentation> - </xs:annotation> - </xs:attribute> - <xs:attributeGroup ref="commonActionAttributes"/> - </xs:extension> - </xs:simpleContent> + <xs:attribute type="xs:string" name="userInput" use="required"/> + <xs:attribute type="xs:string" name="locale" use="required"> + <xs:annotation> + <xs:documentation> + Locale in which the input would be formatted (e.g. en_US). + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute type="xs:string" name="currency" use="required"> + <xs:annotation> + <xs:documentation> + The 3-letter ISO 4217 currency code indicating the currency to use. + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attributeGroup ref="commonActionAttributes"/> </xs:complexType> <xs:complexType name="parseFloatType"> @@ -316,7 +320,6 @@ </xs:simpleContent> </xs:complexType> - <xs:complexType name="arrayType"> <xs:simpleContent> <xs:extension base="xs:string"> diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index aa24a28e4..82022d613 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -610,6 +610,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $function = null; $time = null; $locale = null; + $currency = null; $username = null; $password = null; $width = null; @@ -654,7 +655,11 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $sortOrder = $customActionAttributes['sortOrder']; } - if (isset($customActionAttributes['userInput']) && isset($customActionAttributes['url'])) { + if (isset($customActionAttributes['userInput']) + && isset($customActionAttributes['locale']) + && isset($customActionAttributes['currency'])) { + $input = $this->parseUserInput($customActionAttributes['userInput']); + } elseif (isset($customActionAttributes['userInput']) && isset($customActionAttributes['url'])) { $input = $this->addUniquenessFunctionCall($customActionAttributes['userInput']); $url = $this->addUniquenessFunctionCall($customActionAttributes['url']); } elseif (isset($customActionAttributes['userInput'])) { @@ -772,6 +777,10 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $locale = $this->wrapWithDoubleQuotes($customActionAttributes['locale']); } + if (isset($customActionAttributes['currency'])) { + $currency = $this->wrapWithDoubleQuotes($customActionAttributes['currency']); + } + if (isset($customActionAttributes['username'])) { $username = $this->wrapWithDoubleQuotes($customActionAttributes['username']); } @@ -1162,13 +1171,14 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $selector ); break; - case "formatMoney": + case "formatCurrency": $testSteps .= $this->wrapFunctionCallWithReturnValue( $stepKey, $actor, $actionObject, $input, - $locale + $locale, + $currency ); break; case "mSetLocale": @@ -2277,4 +2287,27 @@ private function hasDecimalPoint(string $outStr) { return strpos($outStr, localeconv()['decimal_point']) !== false; } + + /** + * Parse userInput for formatCurrency action + * + * @param string $userInput + * @return string + */ + private function parseUserInput($userInput) + { + $floatPattern = '/^\s*([+-]?[0-9]*\.?[0-9]+)\s*$/'; + preg_match($floatPattern, $userInput, $float); + if (isset($float[1])) { + return $float[1]; + } + + $intPattern = '/^\s*([+-]?[0-9]+)\s*$/'; + preg_match($intPattern, $userInput, $int); + if (isset($int[1])) { + return $int[1]; + } + + return $this->addUniquenessFunctionCall($userInput); + } } From 3ad161bb7a5ba315ef0dd5c69b5de74e8217d67f Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 23 Apr 2020 14:20:18 -0500 Subject: [PATCH 348/888] MQE-2027: MFTF PHP Compatibility Update (PHP 7.4) - changed formatMoney to formatCurrency --- composer.json | 4 +- composer.lock | 76 +++++++++++++++---- .../Util/TestGenerator.php | 2 +- 3 files changed, 65 insertions(+), 17 deletions(-) diff --git a/composer.json b/composer.json index 2bd6c222b..9860b8746 100755 --- a/composer.json +++ b/composer.json @@ -28,7 +28,7 @@ "mustache/mustache": "~2.5", "php-webdriver/webdriver": "^1.8.0", "symfony/console": "^4.4", - "symfony/finder": "^4.4||^5.0", + "symfony/finder": "^5.0", "symfony/mime": "^5.0", "symfony/process": "^4.4", "vlucas/phpdotenv": "^2.4" @@ -41,7 +41,7 @@ "goaop/framework": "~2.3.4", "php-coveralls/php-coveralls": "^1.0", "phpmd/phpmd": "^2.8.0", - "phpunit/phpunit": "~9.0.0", + "phpunit/phpunit": "^9.0", "rregeer/phpunit-coverage-check": "^0.1.4", "sebastian/phpcpd": "~5.0.0", "squizlabs/php_codesniffer": "~3.5.4", diff --git a/composer.lock b/composer.lock index 5b53f0b7f..1ccde9c5f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "25cf03eee8281f6787f72fb9f497da74", + "content-hash": "48a6beb57b4139c5fa16954b8d83579f", "packages": [ { "name": "allure-framework/allure-codeception", @@ -112,16 +112,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.135.2", + "version": "3.135.3", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "1810725052836683d0cfd2907d515173058e710e" + "reference": "0f6f6e8f4a44193908e18b8c7b8530b02f5bc428" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/1810725052836683d0cfd2907d515173058e710e", - "reference": "1810725052836683d0cfd2907d515173058e710e", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/0f6f6e8f4a44193908e18b8c7b8530b02f5bc428", + "reference": "0f6f6e8f4a44193908e18b8c7b8530b02f5bc428", "shasum": "" }, "require": { @@ -192,7 +192,7 @@ "s3", "sdk" ], - "time": "2020-04-22T18:11:15+00:00" + "time": "2020-04-23T18:18:24+00:00" }, { "name": "behat/gherkin", @@ -2995,16 +2995,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.0.2", + "version": "9.1.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "c0ecbfb898ab8b24d8a59a23520f7b2a73e27b5b" + "reference": "a74780472172957a65cb5999a597e8c0878cf39c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c0ecbfb898ab8b24d8a59a23520f7b2a73e27b5b", - "reference": "c0ecbfb898ab8b24d8a59a23520f7b2a73e27b5b", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a74780472172957a65cb5999a597e8c0878cf39c", + "reference": "a74780472172957a65cb5999a597e8c0878cf39c", "shasum": "" }, "require": { @@ -3024,7 +3024,8 @@ "phpunit/php-file-iterator": "^3.0", "phpunit/php-invoker": "^3.0", "phpunit/php-text-template": "^2.0", - "phpunit/php-timer": "^3.0", + "phpunit/php-timer": "^3.1.4", + "sebastian/code-unit": "^1.0", "sebastian/comparator": "^4.0", "sebastian/diff": "^4.0", "sebastian/environment": "^5.0.1", @@ -3036,7 +3037,8 @@ "sebastian/version": "^3.0" }, "require-dev": { - "ext-pdo": "*" + "ext-pdo": "*", + "phpspec/prophecy-phpunit": "^2.0" }, "suggest": { "ext-soap": "*", @@ -3048,7 +3050,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.0-dev" + "dev-master": "9.1-dev" } }, "autoload": { @@ -3077,7 +3079,7 @@ "testing", "xunit" ], - "time": "2020-03-31T08:57:51+00:00" + "time": "2020-04-23T04:42:05+00:00" }, { "name": "psr/cache", @@ -3446,6 +3448,52 @@ ], "time": "2020-02-21T04:36:14+00:00" }, + { + "name": "sebastian/code-unit", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "8d8f09bd47c75159921e6e84fdef146343962866" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/8d8f09bd47c75159921e6e84fdef146343962866", + "reference": "8d8f09bd47c75159921e6e84fdef146343962866", + "shasum": "" + }, + "require": { + "php": "^7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "time": "2020-03-30T11:59:20+00:00" + }, { "name": "sebastian/code-unit-reverse-lookup", "version": "2.0.0", diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 82022d613..010e63689 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -2289,7 +2289,7 @@ private function hasDecimalPoint(string $outStr) } /** - * Parse userInput for formatCurrency action + * Parse action attribute `userInput` * * @param string $userInput * @return string From a7fda0ad211698d5ce5db0efde2e4a95af83706c Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Thu, 23 Apr 2020 15:41:52 -0500 Subject: [PATCH 349/888] MQE-2094: Test failure re-run error for extn builds (#685) --- .../Allure/Adapter/MagentoAllureAdapter.php | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php b/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php index e1732b6dc..09a72dbb5 100644 --- a/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php +++ b/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php @@ -259,8 +259,11 @@ public function testError(FailEvent $failEvent) */ public function testEnd(TestEvent $testEvent) { + $test = $this->getLifecycle()->getTestCaseStorage()->get(); + // update testClass label to consolidate re-try reporting + $this->formatAllureTestClassName($test); // Peek top of testCaseStorage to check of failure - $testFailed = $this->getLifecycle()->getTestCaseStorage()->get()->getFailure(); + $testFailed = $test->getFailure(); // Pops top of stepStorage, need to add it back in after processing $rootStep = $this->getLifecycle()->getStepStorage()->pollLast(); $formattedSteps = []; @@ -402,4 +405,43 @@ private function removeAttachments($step, $testFailed) } } } + + /** + * Format testClass label to consolidate re-try reporting for groups split for parallel execution + * @param TestCase $test + * @return void + */ + private function formatAllureTestClassName($test) + { + if ($this->getGroup() !== null) { + foreach ($test->getLabels() as $name => $label) { + if ($label->getName() == 'testClass') { + $originalTestClass = $this->sanitizeTestClassLabel($label->getValue()); + call_user_func(\Closure::bind( + function () use ($label, $originalTestClass) { + $label->value = $originalTestClass; + }, + null, + $label + )); + break; + } + } + } + } + + /** + * Function which sanitizes testClass label for split group runs + * @param string $testClass + * @return string + */ + private function sanitizeTestClassLabel($testClass) + { + $originalTestClass = $testClass; + $originalGroupName = $this->sanitizeGroupName($this->getGroup()); + if ($originalGroupName !== $this->getGroup()) { + $originalTestClass = str_replace($this->getGroup(), $originalGroupName, $testClass); + } + return $originalTestClass; + } } From 67afbb002ec7994784eb93d3b5c561c464f859d1 Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Fri, 24 Apr 2020 09:30:48 -0500 Subject: [PATCH 350/888] Grammar --- docs/getting-started.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 903a77372..51dabe4b5 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -117,13 +117,13 @@ The MFTF does not support executing CLI commands if your web server points to `< If the Nginx Web server is used on your development environment, then **Use Web Server Rewrites** setting in **Stores** > Settings > **Configuration** > **General** > **Web** > **Search Engine Optimization** must be set to **Yes**. -or via command line: +Or via command line: ```bash bin/magento config:set web/seo/use_rewrites 1 ``` -Clean the cache after changing the configuration values: +You must clean the cache after changing the configuration values: ```bash bin/magento cache:clean config full_page From e6932220bf930fce1f7868a0375d3337eee66b5c Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Fri, 24 Apr 2020 10:00:11 -0500 Subject: [PATCH 351/888] MQE-2027: MFTF PHP Compatibility Update (PHP 7.4) - changed formatMoney to formatCurrency --- composer.json | 2 +- composer.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 9860b8746..ebfcced1e 100755 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ "sort-packages": true }, "require": { - "php": "~7.3.0||~7.4.0", + "php": "^7.3", "ext-curl": "*", "ext-dom": "*", "ext-json": "*", diff --git a/composer.lock b/composer.lock index 1ccde9c5f..c64efd79d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "48a6beb57b4139c5fa16954b8d83579f", + "content-hash": "ebf4f970c3bb0b9d3c3c9ff1611da2f2", "packages": [ { "name": "allure-framework/allure-codeception", @@ -6464,7 +6464,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "~7.3.0||~7.4.0", + "php": "^7.3", "ext-curl": "*", "ext-dom": "*", "ext-json": "*", From 9229669083ec2486730bc0764a875eee475709ee Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Mon, 27 Apr 2020 12:44:18 -0500 Subject: [PATCH 352/888] MQE-2104: Allure attachments don't appear in report for VERBOSE_ARTIFACTS=true for passing tests - Fixed comparison to string. --- .../Allure/Adapter/MagentoAllureAdapter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php b/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php index 09a72dbb5..7d7a7bd44 100644 --- a/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php +++ b/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php @@ -398,7 +398,7 @@ private function retrieveStepKey($stepLine) private function removeAttachments($step, $testFailed) { //Remove Attachments if verbose flag is not true AND test did not fail - if (getenv('VERBOSE_ARTIFACTS') !== true && $testFailed === null) { + if (getenv('VERBOSE_ARTIFACTS') !== "true" && $testFailed === null) { foreach ($step->getAttachments() as $index => $attachment) { $step->removeAttachment($index); unlink(Provider::getOutputDirectory() . DIRECTORY_SEPARATOR . $attachment->getSource()); From 01324d15878c25fc1b83c72a95754d48b7ef3a3f Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Tue, 28 Apr 2020 11:52:09 -0500 Subject: [PATCH 353/888] MQE-2097: CHANGELOG.MD and Composer version bump (#687) * MQE-1957: Entity Deprecation Reference - Static Check Documentation * MQE-2097: CHANGELOG.MD and Composer version bump Updated changelog * linting * Linting and grammar * MQE-2097: CHANGELOG.MD and Composer version bump doc updates and minor fixes Co-authored-by: Donald Booth <dobooth@adobe.com> --- CHANGELOG.md | 32 ++++++++++++++++++++++++++++++++ docs/commands/mftf.md | 19 ++++++++++++++++--- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3edf84411..217ab72bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,39 @@ Magento Functional Testing Framework Changelog ================================================ +3.0.0 RC2 +--------- + +### Enhancements + +* Maintainability + * Added support for PHP 7.4. + * Removed support for PHP 7.2. + * Added support for PHPUnit 9. + * Improved assertion actions to support PHPUnit 9 changes. [See assertions page for details](./docs/test/assertions.md) + * Added new actions: `assertEqualsWithDelta`, `assertNotEqualsWithDelta`, `assertEqualsCanonicalizing`, `assertNotEqualsCanonicalizing`, `assertEqualsIgnoringCase`, `assertNotEqualsIgnoringCase`. + * Added new actions: `assertStringContainsString`, `assertStringNotContainsString`, `assertStringContainsStringIgnoringCase`, `assertStringNotContainsStringIgnoringCase` for string haystacks. + * Removed actions: `assertInternalType`, `assertNotInternalType`, `assertArraySubset`. + * Removed delta option from `assertEquals` and `assertNotEquals`. + * Removed action `pauseExecution` and added `pause`. [See actions page for details](./docs/test/actions.md#pause) + * Removed action `formatMoney` and added `formatCurrency`. [See actions page for details](./docs/test/actions.md#formatcurrency) + * Added new static check that checks and reports references to deprecated test entities. +* Bumped dependencies to support PHP/PHPUnit upgrade. + +* Traceability + * Introduced new `.env` configuration `VERBOSE_ARTIFACTS` to toggle saving attachments in Allure. [See configuration page for details](./docs/configuration.md) + +### Fixes + +* Fixed issue of resolving arguments of type `entity` in action groups within a custom helper. +* Fixed reporting issue in output file for `testDependencies` static check. +* Fixed a bug in `actionGroupArguments` static check when action group filename is missing `ActionGroup`. +* Fixed issue of running suites under root `_suite` directory in Standalone MFTF. + 3.0.0 RC1 --------- ### Enhancements + * Customizability * Introduced MFTF helpers `<helper>` to create custom actions outside of MFTF. * Removed deprecated actions `<executeSelenium>` and `<performOn>`. @@ -23,11 +53,13 @@ Magento Functional Testing Framework Changelog * Bumped dependencies to latest possible versions. ### Fixes + * Throw exception during generation when leaving out .url for `amOnPage`. * `request_timeout` and `connection_timeout` added to functional.suite.yml.dist. * Fixed `ModuleResolver` to resolve test modules moved out of deprecated path. ### Upgrade Instructions + * Run `bin/mftf reset --hard` to remove old generated configurations. * Run `bin/mftf build:project` to generate new configurations. * Run `bin/mftf upgrade:tests`. [See command page for details](./docs/commands/mftf.md#upgradetests). diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 5b62e9c24..a4d77ad7a 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -464,18 +464,31 @@ To run specific static check scripts ```bash vendor/bin/mftf static-checks testDependencies ``` + ```bash vendor/bin/mftf static-checks actionGroupArguments ``` + +```bash +vendor/bin/mftf static-checks deprecatedEntityUsage +``` + +```bash +vendor/bin/mftf static-checks deprecatedEntityUsage -p path/to/mftf/test/module +``` + ```bash vendor/bin/mftf static-checks testDependencies actionGroupArguments ``` #### Existing static checks -* Test Dependency: Checks that test dependencies do not violate Magento module's composer dependencies. -* Action Group Unused Arguments: Checks that action groups do not have unused arguments. - +| Argument | Description | +|-----------------------|-----------------------------------------------------------------------------------------------------------| +|`testDependencies` | Checks that test dependencies do not violate Magento module's composer dependencies.| +|`actionGroupArguments` | Checks that action groups do not have unused arguments.| +|`deprecatedEntityUsage`| Checks that deprecated test entities are not being referenced.| + ### `upgrade:tests` When the path argument is specified, this `upgrade` command applies all the major version MFTF upgrade scripts to a `Test Module` in the given path. From 1225f25f380182cfb1cb73dd3cabbb72fc5f5bee Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Tue, 28 Apr 2020 13:49:36 -0500 Subject: [PATCH 354/888] MQE-2097: CHANGELOG.MD and Composer version bump (#689) added github PR --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 217ab72bb..c8b6a20e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,10 @@ Magento Functional Testing Framework Changelog * Fixed a bug in `actionGroupArguments` static check when action group filename is missing `ActionGroup`. * Fixed issue of running suites under root `_suite` directory in Standalone MFTF. +### GitHub Issues/Pull Requests + +* [#567](https://github.com/magento/magento2-functional-testing-framework/pull/567) -- log attachments for failed requests. + 3.0.0 RC1 --------- From d35455e9b8de4ef2a3d7b5dddd4702065b003462 Mon Sep 17 00:00:00 2001 From: Ajith <ajithkumar.maragathavel@ziffity.com> Date: Wed, 29 Apr 2020 23:09:28 +0530 Subject: [PATCH 355/888] Branch name changed --- docs/getting-started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 89d228df9..0c543042f 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -44,7 +44,7 @@ cd magento2/ ``` ```bash -git checkout 2.3-develop +git checkout 2.4-develop ``` Install the Magento application. From 8b39c1514e1af1a6e6de771bcb2e189e7ea8b471 Mon Sep 17 00:00:00 2001 From: Ajith <ajithkumar.maragathavel@ziffity.com> Date: Thu, 30 Apr 2020 00:56:06 +0530 Subject: [PATCH 356/888] Data entity document improvement --- docs/data.md | 56 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/docs/data.md b/docs/data.md index fa4c90dcf..6d4dc3756 100644 --- a/docs/data.md +++ b/docs/data.md @@ -7,6 +7,8 @@ The following diagram shows the XML structure of an MFTF data object: <!-- {% raw %} --> +The MFTF `<data>` entities are stored in the following directory <module_dir>/Test/Mftf/Data/ + ## Supply data to test by reference to a data entity Test steps requiring `<data>` input in an action, like filling a field with a string, may reference an attribute from a data entity: @@ -20,6 +22,20 @@ In this example: * `SimpleSubCategory` is an entity name. * `name` is a `<data>` key of the entity. The corresponding value will be assigned to `userInput` as a result. +The following is the usage of `<data>` entity in the `Magento/Customer/Test/Mftf/Test/AdminCustomersAllCustomersNavigateMenuTest.xml` test: + +```xml +<actionGroup ref="AdminNavigateMenuActionGroup" stepKey="navigateToAllCustomerPage"> + <argument name="menuUiId" value="{{AdminMenuCustomers.dataUiId}}"/> + <argument name="submenuUiId" value="{{AdminMenuCustomersAllCustomers.dataUiId}}"/> +</actionGroup> +``` + +In the above example: + +* `AdminMenuCustomers` is an entity name. +* `dataUiId` is a `<data>` key of the entity. + ### Environmental data ```xml @@ -32,6 +48,12 @@ In this example: * `MAGENTO_ADMIN_USERNAME` is a name of an environment variable. The corresponding value will be assigned to `userInput` as a result. +The following is the usage of `_ENV` in the `Magento/Braintree/Test/Mftf/ActionGroup/AdminDeleteRoleActionGroup.xml` action group: + +```xml +<fillField stepKey="TypeCurrentPassword" selector="{{AdminDeleteRoleSection.current_pass}}" userInput="{{_ENV.MAGENTO_ADMIN_PASSWORD}}"/> +``` + ### Sensitive data ```xml @@ -47,6 +69,14 @@ In this example: Learn more in [Credentials][]. +The following is the usage of `_CREDS` in the `Magento/Braintree/Test/Mftf/Data/BraintreeData.xml` data entity: + +```xml +<entity name="MerchantId" type="merchant_id"> + <data key="value">{{_CREDS.magento/braintree_enabled_fraud_merchant_id}}</data> +</entity> +``` + ## Persist a data entity as a prerequisite of a test {#persist-data} A test can specify an entity to be persisted (created in the database) so that the test actions could operate on the existing known data. @@ -63,6 +93,14 @@ In this example: * `email` is a data key of the entity. The corresponding value will be assigned to `userInput` as a result. +The following is the usage of the persistant data in `Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithCountryUSATest.xml` test: + +```xml +<actionGroup ref="AdminFilterCustomerByEmail" stepKey="filterTheCustomerByEmail"> + <argument name="email" value="$$createCustomer.email$$"/> +</actionGroup> +``` + <div class="bs-callout bs-callout-info"> As of MFTF 2.3.6, you no longer need to differentiate between scopes (a test, a hook, or a suite) for persisted data when referencing it in tests. </div> @@ -107,7 +145,7 @@ userInput="We'll email you an order confirmation with details and tracking info. ## Format -The format of `<data>` is: +The format of `<data>` entity is: ```xml <?xml version="1.0" encoding="UTF-8"?> @@ -135,7 +173,7 @@ The following conventions apply to MFTF `<data>`: ## Example -Example (`.../Catalog/Data/CategoryData.xml` file): +Example (`Magento/Catalog/Test/Mftf/Data/CategoryData.xml` file): ```xml <?xml version="1.0" encoding="UTF-8"?> @@ -205,7 +243,7 @@ You can also call data from the xml definition of a `data` tag directly: Attributes|Type|Use|Description ---|---|---|--- -`name`|string|optional|Name of the `<entity>`. +`name`|string|optional|Name of the `<entity>`. Camel case is used for the entity name. `type`|string|optional|Node containing the exact name of `<entity>` type. Used later to find specific Persistence Layer Model class. `type` in `<data>` can be whatever the user wants; There are no constraints. It is important when persisting data, depending on the `type` given, as it will try to match a metadata definition with the operation being done. Example: A `myCustomer` entity with `type="customer"`, calling `<createData entity="myCustomer"/>`, will try to find a metadata entry with the following attributes: `<operation dataType="customer" type="create">`. `deprecated`|string|optional|Used to warn about the future deprecation of the data entity. String will appear in Allure reports and console output at runtime. @@ -220,6 +258,12 @@ Attributes|Type|Use|Description `key`|string|optional|Key attribute of data/value pair. `unique`|enum: `"prefix"`, `"suffix"`|optional|Add suite or test wide unique sequence as "prefix" or "suffix" to the data value if specified. +Example: + +```xml +<data key="name" unique="suffix">simpleCategory</data> +``` + ### var {#var-tag} `<var>` is an element that can be used to grab a key value from another entity. For example, when creating a customer with the `<createData>` action, the server responds with the auto-incremented ID of that customer. Use `<var>` to access that ID and use it in another data entity. @@ -231,6 +275,12 @@ Attributes|Type|Use|Description `entityKey`|string|optional|Key attribute of the referenced entity from which to get a value. `unique`|--|--|*This attribute hasn't been implemented yet.* +Example: + +``` +<var key="parent_id" entityType="category" entityKey="id" /> +``` + ### requiredEntity {#requiredentity-tag} `<requiredEntity>` is an element that specifies the parent/child relationship between complex types. From ec3f086c475c44baa747c1bf8d31609e76b013d9 Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Thu, 30 Apr 2020 14:42:12 -0500 Subject: [PATCH 357/888] MQE-2034: Document Custom Helper functionality --- docs/custom-helpers.md | 125 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 docs/custom-helpers.md diff --git a/docs/custom-helpers.md b/docs/custom-helpers.md new file mode 100644 index 000000000..a83249b2e --- /dev/null +++ b/docs/custom-helpers.md @@ -0,0 +1,125 @@ +# Custom Helpers + +<div class="bs-callout bs-callout-warning" markdown="1"> +Due to complexity, you should only write new Custom Helpers as a last resort after trying to implement your test using built-in actions. +</div> + +Custom Helpers allow test writers to write custom test actions to solve for advanced requirements beyond what MFTF offers out of the box. + +In MFTF version 3.0.0, we removed the following test actions: + +* `<executeInSelenium>` +* `<performOn>` + +These actions were removed because they allowed custom PHP code to be written inline inside of XML files. This code was difficult to read. It had no proper syntax highlighting and no linting. It was difficult to maintain, troubleshoot, and modify. + +However, sometimes custom logic beyond what MFTF offers is necessary so we have provided an alternative solution: the `<helper>` action. + +## Example + +Custom Helpers are implemented in PHP files that must be placed in this directory: +``` +<ModuleName>/Test/Mftf/Helper +``` + +Let's take a look at one. This Custom Helper selects text on the page by this approach: + +1. Move to a very specific X,Y starting position +2. Click and hold the mouse button down +3. Move to another specific X,Y position +4. Release the mouse button + +This functionality is used to select text on the page and cannot be accomplished using built-in test actions. + +### PHP File + +```php +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\PageBuilder\Test\Mftf\Helper; + +use Magento\FunctionalTestingFramework\Helper\Helper; + +/** + * Class SelectText provides an ability to select needed text. + */ +class SelectText extends Helper +{ + /** + * Select needed text. + * + * @param string $context + * @param int $startX + * @param int $startY + * @param int $endX + * @param int $endY + * @return void + */ + public function selectText(string $context, int $startX, int $startY, int $endX, int $endY) + { + try { + /** @var \Magento\FunctionalTestingFramework\Module\MagentoWebDriver $webDriver */ + $webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); + + $contextElement = $webDriver->webDriver->findElement(\Facebook\WebDriver\WebDriverBy::xpath($context)); + $actions = new \Facebook\WebDriver\Interactions\WebDriverActions($webDriver->webDriver); + $actions->moveToElement($contextElement, $startX, $startY) + ->clickAndHold() + ->moveToElement($contextElement, $endX, $endY) + ->release() + ->perform(); + } catch (\Exception $e) { + $this->fail($e->getMessage()); + } + } +} +``` + +### Notes About The PHP File + +The following details are important about the file above: +1. The `namespace` must match the file location like `namespace Magento\PageBuilder\Test\Mftf\Helper;` +2. The class must `extends Helper` and have the corresponding `use` statement to match +3. You can get access to the WebDriver object via `$this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver')` +4. You can implement multiple related methods in the same class. + +You should follow the same patterns in any Custom Helpers that you write yourself. But you can implement any logic or iteration that you need to solve for your use case. + +### Referencing In A Test + +Once you have implemented something like the above PHP file. You can then reference it in a test like this: + +```xml +<helper class="\Magento\PageBuilder\Test\Mftf\Helper\SelectText" method="selectText" stepKey="selectHeadingTextInTinyMCE"> + <argument name="context">//div[contains(@class, 'inline-wysiwyg')]//h2</argument> + <argument name="startX">{{TinyMCEPartialHeadingSelection.startX}}</argument> + <argument name="startY">{{TinyMCEPartialHeadingSelection.startY}}</argument> + <argument name="endX">{{TinyMCEPartialHeadingSelection.endX}}</argument> + <argument name="endY">{{TinyMCEPartialHeadingSelection.endY}}</argument> +</helper> +``` + +### Notes About The XML + +1. Specify an argument value for every argument that matches our PHP implementation. This allows us to pass other test data to the Custom Helper. +2. The `class` attribute matches the namespace we specified in the PHP file +3. You can specify the method from the class via the `method` attribute +4. If the function has a return value, it will be assigned to the stepKey variable. In this case `$selectHeadingTextInTinyMCE` would hold the return value. + +## Key Takeaways + +Custom Helpers allow you to solve for complex use cases such as conditional logic, iteration, or complex WebDriver usage. + +With access to the WebDriver object, you have a lot of flexibility available to you. See the [Codeception WebDriver](https://github.com/Codeception/module-webdriver/blob/master/src/Codeception/Module/WebDriver.php) for technical details and functionality available for use. + +A Custom Helper is written in a PHP file and then referenced in test XML like other actions. + +Due to complexity, you should only use these as a last resort after trying to implement your test using built-in actions. + +## References + +[Codeception WebDriver source code](https://github.com/Codeception/module-webdriver/blob/master/src/Codeception/Module/WebDriver.php) - Reference for using the WebDriver Object From 04bc005bb8bb9e1674caebaff9e36e539b01f94b Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Thu, 30 Apr 2020 14:48:37 -0500 Subject: [PATCH 358/888] MQE-2034: Document Custom Helper functionality --- docs/custom-helpers.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/custom-helpers.md b/docs/custom-helpers.md index a83249b2e..a38be1e8d 100644 --- a/docs/custom-helpers.md +++ b/docs/custom-helpers.md @@ -86,6 +86,7 @@ The following details are important about the file above: 2. The class must `extends Helper` and have the corresponding `use` statement to match 3. You can get access to the WebDriver object via `$this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver')` 4. You can implement multiple related methods in the same class. +5. Specify the correct function argument types to match the types of the values you want to pass in. In this case we specified `string $context, int $startX, int $startY, int $endX, int $endY` so in the XML we will match these types. You should follow the same patterns in any Custom Helpers that you write yourself. But you can implement any logic or iteration that you need to solve for your use case. @@ -109,6 +110,7 @@ Once you have implemented something like the above PHP file. You can then refere 2. The `class` attribute matches the namespace we specified in the PHP file 3. You can specify the method from the class via the `method` attribute 4. If the function has a return value, it will be assigned to the stepKey variable. In this case `$selectHeadingTextInTinyMCE` would hold the return value. +5. The types of argument values must match the PHP implementation's expected types. ## Key Takeaways From 9f710db73fe8462a96392c0b338c710dd4403633 Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Fri, 1 May 2020 12:24:36 -0500 Subject: [PATCH 359/888] Grammar and formatting --- docs/custom-helpers.md | 64 ++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/docs/custom-helpers.md b/docs/custom-helpers.md index a38be1e8d..950bccfa7 100644 --- a/docs/custom-helpers.md +++ b/docs/custom-helpers.md @@ -1,15 +1,15 @@ # Custom Helpers -<div class="bs-callout bs-callout-warning" markdown="1"> -Due to complexity, you should only write new Custom Helpers as a last resort after trying to implement your test using built-in actions. +<div class="bs-callout-warning"> +Due to complexity, you should only write new custom helpers as a last resort, after trying to implement your test using built-in actions. </div> -Custom Helpers allow test writers to write custom test actions to solve for advanced requirements beyond what MFTF offers out of the box. +Custom Helpers allow test writers to write custom test actions to solve advanced requirements beyond what MFTF offers out of the box. -In MFTF version 3.0.0, we removed the following test actions: +In MFTF version 3.0.0, the following test actions were removed: -* `<executeInSelenium>` -* `<performOn>` +* `<executeInSelenium>` +* `<performOn>` These actions were removed because they allowed custom PHP code to be written inline inside of XML files. This code was difficult to read. It had no proper syntax highlighting and no linting. It was difficult to maintain, troubleshoot, and modify. @@ -17,17 +17,18 @@ However, sometimes custom logic beyond what MFTF offers is necessary so we have ## Example -Custom Helpers are implemented in PHP files that must be placed in this directory: -``` +Custom helpers are implemented in PHP files that must be placed in this directory: + +```text <ModuleName>/Test/Mftf/Helper ``` -Let's take a look at one. This Custom Helper selects text on the page by this approach: +This custom helper selects text on the page with this approach: -1. Move to a very specific X,Y starting position -2. Click and hold the mouse button down -3. Move to another specific X,Y position -4. Release the mouse button +1. Move to a very specific X,Y starting position. +1. Click and hold the mouse button down. +1. Move to another specific X,Y position. +1. Release the mouse button. This functionality is used to select text on the page and cannot be accomplished using built-in test actions. @@ -79,20 +80,21 @@ class SelectText extends Helper } ``` -### Notes About The PHP File +### Notes about this PHP file + +The following details are important about the above file: -The following details are important about the file above: -1. The `namespace` must match the file location like `namespace Magento\PageBuilder\Test\Mftf\Helper;` -2. The class must `extends Helper` and have the corresponding `use` statement to match -3. You can get access to the WebDriver object via `$this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver')` -4. You can implement multiple related methods in the same class. -5. Specify the correct function argument types to match the types of the values you want to pass in. In this case we specified `string $context, int $startX, int $startY, int $endX, int $endY` so in the XML we will match these types. +1. The `namespace` must match the file location: `namespace Magento\PageBuilder\Test\Mftf\Helper;` +2. The class must `extends Helper` and have the corresponding `use` statement to match. +3. You may access the WebDriver object via `$this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver')`. +4. You may implement multiple related methods within the same class. +5. Specify the correct function argument types to match the type of values you want to pass in. In this case, we specified `string $context, int $startX, int $startY, int $endX, int $endY`. In the XML we will match these types. -You should follow the same patterns in any Custom Helpers that you write yourself. But you can implement any logic or iteration that you need to solve for your use case. +You should follow the same patterns in any custom helpers that you write yourself, but you may implement any logic or iteration that you need to solve for your use case. -### Referencing In A Test +### Referencing in a test -Once you have implemented something like the above PHP file. You can then reference it in a test like this: +Once you have implemented something like the above PHP file, reference it in a test: ```xml <helper class="\Magento\PageBuilder\Test\Mftf\Helper\SelectText" method="selectText" stepKey="selectHeadingTextInTinyMCE"> @@ -104,23 +106,23 @@ Once you have implemented something like the above PHP file. You can then refere </helper> ``` -### Notes About The XML +### Notes about the XML 1. Specify an argument value for every argument that matches our PHP implementation. This allows us to pass other test data to the Custom Helper. -2. The `class` attribute matches the namespace we specified in the PHP file -3. You can specify the method from the class via the `method` attribute -4. If the function has a return value, it will be assigned to the stepKey variable. In this case `$selectHeadingTextInTinyMCE` would hold the return value. +2. The `class` attribute matches the namespace specified in the PHP file. +3. Specify the method from the class via the `method` attribute. +4. If the function has a return value, it will be assigned to the `stepKey` variable. In this case, `$selectHeadingTextInTinyMCE` holds the return value. 5. The types of argument values must match the PHP implementation's expected types. -## Key Takeaways +## Key takeaways -Custom Helpers allow you to solve for complex use cases such as conditional logic, iteration, or complex WebDriver usage. +Custom helpers allow you to solve complex use cases such as conditional logic, iteration, or complex WebDriver usage. With access to the WebDriver object, you have a lot of flexibility available to you. See the [Codeception WebDriver](https://github.com/Codeception/module-webdriver/blob/master/src/Codeception/Module/WebDriver.php) for technical details and functionality available for use. -A Custom Helper is written in a PHP file and then referenced in test XML like other actions. +A custom helper is written in a PHP file and then referenced in test XML, like other actions. -Due to complexity, you should only use these as a last resort after trying to implement your test using built-in actions. +You should only use these as a last resort after trying to implement your test using built-in actions. ## References From c57f3694dbae6e7592349a43c1857ecabaa02e10 Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Fri, 1 May 2020 12:25:36 -0500 Subject: [PATCH 360/888] Formatting --- docs/custom-helpers.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/custom-helpers.md b/docs/custom-helpers.md index 950bccfa7..bf1ebc572 100644 --- a/docs/custom-helpers.md +++ b/docs/custom-helpers.md @@ -109,10 +109,10 @@ Once you have implemented something like the above PHP file, reference it in a t ### Notes about the XML 1. Specify an argument value for every argument that matches our PHP implementation. This allows us to pass other test data to the Custom Helper. -2. The `class` attribute matches the namespace specified in the PHP file. -3. Specify the method from the class via the `method` attribute. -4. If the function has a return value, it will be assigned to the `stepKey` variable. In this case, `$selectHeadingTextInTinyMCE` holds the return value. -5. The types of argument values must match the PHP implementation's expected types. +1. The `class` attribute matches the namespace specified in the PHP file. +1. Specify the method from the class via the `method` attribute. +1. If the function has a return value, it will be assigned to the `stepKey` variable. In this case, `$selectHeadingTextInTinyMCE` holds the return value. +1. The types of argument values must match the PHP implementation's expected types. ## Key takeaways From f13ba03f5f1435a007bf57a641144ff9b9a9844e Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 28 Apr 2020 17:07:38 -0500 Subject: [PATCH 361/888] MQE-2082: MFTF compatibility with 2fa --- composer.json | 3 +- composer.lock | 333 +++++++++++++++++- .../Allure/AllureHelperTest.php | 2 +- .../Composer/ComposerInstallTest.php | 4 +- .../Composer/ComposerPackageTest.php | 4 +- .../Config/Reader/FilesystemTest.php | 2 +- .../Console/BaseGenerateCommandTest.php | 2 +- .../Handlers/DataObjectHandlerTest.php | 2 +- .../OperationDefinitionObjectHandlerTest.php | 2 +- .../Handlers/PersistedObjectHandlerTest.php | 2 +- .../AwsSecretsManagerStorageTest.php | 2 +- .../SecretStorage/FileStorageTest.php | 2 +- .../Objects/EntityDataObjectTest.php | 2 +- .../OperationDataArrayResolverTest.php | 2 +- .../Util/DataExtensionUtilTest.php | 8 +- .../Extension/BrowserLogUtilTest.php | 2 +- .../Page/Handlers/PageObjectHandlerTest.php | 2 +- .../Handlers/SectionObjectHandlerTest.php | 2 +- .../Page/Objects/ElementObjectTest.php | 2 +- .../Page/Objects/PageObjectTest.php | 2 +- .../Page/Objects/SectionObjectTest.php | 2 +- .../Suite/Handlers/SuiteObjectHandlerTest.php | 4 +- .../Suite/SuiteGeneratorTest.php | 4 +- .../Test/Config/ActionGroupDomTest.php | 4 +- .../Test/Config/DomTest.php | 4 +- .../Handlers/ActionGroupObjectHandlerTest.php | 4 +- .../Test/Handlers/TestObjectHandlerTest.php | 4 +- .../Test/Objects/ActionGroupObjectTest.php | 2 +- .../Test/Objects/ActionObjectTest.php | 2 +- .../Util/ActionGroupObjectExtractorTest.php | 2 +- .../Test/Util/ActionMergeUtilTest.php | 3 +- .../Test/Util/ActionObjectExtractorTest.php | 2 +- .../Util/ActionMergeUtilTest.php | 4 +- .../Util/ComposerModuleResolverTest.php | 4 +- .../Util/ModulePathExtractorTest.php | 4 +- .../Util/ModuleResolverTest.php | 4 +- .../Util/Path/FilePathFormatterTest.php | 4 +- .../Util/Path/UrlFormatterTest.php | 4 +- .../Util/Sorter/ParallelGroupSorterTest.php | 4 +- .../Util/TestGeneratorTest.php | 4 +- .../DuplicateNodeValidationUtilTest.php | 6 +- .../Validation/NameValidationUtilTest.php | 4 +- dev/tests/unit/Util/MagentoTestCase.php | 2 +- etc/config/.credentials.example | 3 +- etc/di.xml | 2 +- .../Console/DoctorCommand.php | 5 +- .../Persist/Curl/AbstractExecutor.php | 34 -- .../DataGenerator/Persist/CurlHandler.php | 18 +- .../AdminFormExecutor.php} | 56 +-- .../DataTransport/Auth/Tfa.php | 97 +++++ .../DataTransport/Auth/Tfa/OTP.php | 61 ++++ .../DataTransport/Auth/WebApiAuth.php | 108 ++++++ .../FrontendFormExecutor.php} | 17 +- .../Protocol/CurlInterface.php | 2 +- .../Protocol/CurlTransport.php | 2 +- .../WebApiExecutor.php} | 108 ++---- .../WebApiNoAuthExecutor.php} | 4 +- .../Module/MagentoWebDriver.php | 29 +- .../Test/Objects/ActionGroupObject.php | 3 +- .../Test/etc/Actions/customActions.xsd | 14 + .../Util/MftfGlobals.php | 160 +++++++++ .../Util/ModuleResolver.php | 81 +---- .../Util/Path/UrlFormatter.php | 2 +- .../Util/TestGenerator.php | 11 +- 64 files changed, 936 insertions(+), 344 deletions(-) delete mode 100644 src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/AbstractExecutor.php rename src/Magento/FunctionalTestingFramework/{DataGenerator/Persist/Curl/AdminExecutor.php => DataTransport/AdminFormExecutor.php} (76%) create mode 100644 src/Magento/FunctionalTestingFramework/DataTransport/Auth/Tfa.php create mode 100644 src/Magento/FunctionalTestingFramework/DataTransport/Auth/Tfa/OTP.php create mode 100644 src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php rename src/Magento/FunctionalTestingFramework/{DataGenerator/Persist/Curl/FrontendExecutor.php => DataTransport/FrontendFormExecutor.php} (90%) rename src/Magento/FunctionalTestingFramework/{Util => DataTransport}/Protocol/CurlInterface.php (94%) rename src/Magento/FunctionalTestingFramework/{Util => DataTransport}/Protocol/CurlTransport.php (99%) rename src/Magento/FunctionalTestingFramework/{DataGenerator/Persist/Curl/WebapiExecutor.php => DataTransport/WebApiExecutor.php} (51%) rename src/Magento/FunctionalTestingFramework/{DataGenerator/Persist/Curl/WebapiNoAuthExecutor.php => DataTransport/WebApiNoAuthExecutor.php} (74%) create mode 100644 src/Magento/FunctionalTestingFramework/Util/MftfGlobals.php diff --git a/composer.json b/composer.json index ebfcced1e..541b75966 100755 --- a/composer.json +++ b/composer.json @@ -12,9 +12,9 @@ "php": "^7.3", "ext-curl": "*", "ext-dom": "*", + "ext-intl": "*", "ext-json": "*", "ext-openssl": "*", - "ext-intl": "*", "allure-framework/allure-codeception": "~1.4.0", "aws/aws-sdk-php": "^3.132", "codeception/codeception": "~4.1.4", @@ -27,6 +27,7 @@ "monolog/monolog": "^1.17", "mustache/mustache": "~2.5", "php-webdriver/webdriver": "^1.8.0", + "spomky-labs/otphp": "^10.0", "symfony/console": "^4.4", "symfony/finder": "^5.0", "symfony/mime": "^5.0", diff --git a/composer.lock b/composer.lock index c64efd79d..39dc222bd 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ebf4f970c3bb0b9d3c3c9ff1611da2f2", + "content-hash": "bebbc11e36de2f68821cbeebeafe04ad", "packages": [ { "name": "allure-framework/allure-codeception", @@ -194,6 +194,68 @@ ], "time": "2020-04-23T18:18:24+00:00" }, + { + "name": "beberlei/assert", + "version": "v3.2.7", + "source": { + "type": "git", + "url": "https://github.com/beberlei/assert.git", + "reference": "d63a6943fc4fd1a2aedb65994e3548715105abcf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/beberlei/assert/zipball/d63a6943fc4fd1a2aedb65994e3548715105abcf", + "reference": "d63a6943fc4fd1a2aedb65994e3548715105abcf", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "ext-mbstring": "*", + "ext-simplexml": "*", + "php": "^7" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "*", + "phpstan/phpstan-shim": "*", + "phpunit/phpunit": ">=6.0.0 <8" + }, + "suggest": { + "ext-intl": "Needed to allow Assertion::count(), Assertion::isCountable(), Assertion::minCount(), and Assertion::maxCount() to operate on ResourceBundles" + }, + "type": "library", + "autoload": { + "psr-4": { + "Assert\\": "lib/Assert" + }, + "files": [ + "lib/Assert/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de", + "role": "Lead Developer" + }, + { + "name": "Richard Quadling", + "email": "rquadling@gmail.com", + "role": "Collaborator" + } + ], + "description": "Thin assertion library for input validation in business models.", + "keywords": [ + "assert", + "assertion", + "validation" + ], + "time": "2019-12-19T17:51:41+00:00" + }, { "name": "behat/gherkin", "version": "v4.6.2", @@ -2153,6 +2215,68 @@ ], "time": "2020-01-17T21:11:47+00:00" }, + { + "name": "paragonie/constant_time_encoding", + "version": "v2.3.0", + "source": { + "type": "git", + "url": "https://github.com/paragonie/constant_time_encoding.git", + "reference": "47a1cedd2e4d52688eb8c96469c05ebc8fd28fa2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/47a1cedd2e4d52688eb8c96469c05ebc8fd28fa2", + "reference": "47a1cedd2e4d52688eb8c96469c05ebc8fd28fa2", + "shasum": "" + }, + "require": { + "php": "^7|^8" + }, + "require-dev": { + "phpunit/phpunit": "^6|^7", + "vimeo/psalm": "^1|^2|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "ParagonIE\\ConstantTime\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com", + "role": "Maintainer" + }, + { + "name": "Steve 'Sc00bz' Thomas", + "email": "steve@tobtu.com", + "homepage": "https://www.tobtu.com", + "role": "Original Developer" + } + ], + "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", + "keywords": [ + "base16", + "base32", + "base32_decode", + "base32_encode", + "base64", + "base64_decode", + "base64_encode", + "bin2hex", + "encoding", + "hex", + "hex2bin", + "rfc4648" + ], + "time": "2019-11-06T19:20:29+00:00" + }, { "name": "paragonie/random_compat", "version": "v9.99.99", @@ -4205,6 +4329,77 @@ ], "time": "2020-02-14T15:25:33+00:00" }, + { + "name": "spomky-labs/otphp", + "version": "v10.0.1", + "source": { + "type": "git", + "url": "https://github.com/Spomky-Labs/otphp.git", + "reference": "f44cce5a9db4b8da410215d992110482c931232f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Spomky-Labs/otphp/zipball/f44cce5a9db4b8da410215d992110482c931232f", + "reference": "f44cce5a9db4b8da410215d992110482c931232f", + "shasum": "" + }, + "require": { + "beberlei/assert": "^3.0", + "ext-mbstring": "*", + "paragonie/constant_time_encoding": "^2.0", + "php": "^7.2|^8.0", + "thecodingmachine/safe": "^0.1.14|^1.0" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.0", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-beberlei-assert": "^0.12", + "phpstan/phpstan-deprecation-rules": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpstan/phpstan-strict-rules": "^0.12", + "phpunit/phpunit": "^8.0", + "thecodingmachine/phpstan-safe-rule": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "v10.0": "10.0.x-dev", + "v9.0": "9.0.x-dev", + "v8.3": "8.3.x-dev" + } + }, + "autoload": { + "psr-4": { + "OTPHP\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky" + }, + { + "name": "All contributors", + "homepage": "https://github.com/Spomky-Labs/otphp/contributors" + } + ], + "description": "A PHP library for generating one time passwords according to RFC 4226 (HOTP Algorithm) and the RFC 6238 (TOTP Algorithm) and compatible with Google Authenticator", + "homepage": "https://github.com/Spomky-Labs/otphp", + "keywords": [ + "FreeOTP", + "RFC 4226", + "RFC 6238", + "google authenticator", + "hotp", + "otp", + "totp" + ], + "time": "2020-01-28T09:24:19+00:00" + }, { "name": "symfony/console", "version": "v4.4.7", @@ -5136,6 +5331,138 @@ "homepage": "https://symfony.com", "time": "2020-03-30T11:41:10+00:00" }, + { + "name": "thecodingmachine/safe", + "version": "v1.1", + "source": { + "type": "git", + "url": "https://github.com/thecodingmachine/safe.git", + "reference": "f440677bad66c0ef42fa3f875bf05718028af5d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/f440677bad66c0ef42fa3f875bf05718028af5d3", + "reference": "f440677bad66c0ef42fa3f875bf05718028af5d3", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "require-dev": { + "phpstan/phpstan": "^0.12", + "squizlabs/php_codesniffer": "^3.2", + "thecodingmachine/phpstan-strict-rules": "^0.12" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.1-dev" + } + }, + "autoload": { + "psr-4": { + "Safe\\": [ + "lib/", + "generated/" + ] + }, + "files": [ + "generated/apache.php", + "generated/apc.php", + "generated/apcu.php", + "generated/array.php", + "generated/bzip2.php", + "generated/classobj.php", + "generated/com.php", + "generated/cubrid.php", + "generated/curl.php", + "generated/datetime.php", + "generated/dir.php", + "generated/eio.php", + "generated/errorfunc.php", + "generated/exec.php", + "generated/fileinfo.php", + "generated/filesystem.php", + "generated/filter.php", + "generated/fpm.php", + "generated/ftp.php", + "generated/funchand.php", + "generated/gmp.php", + "generated/gnupg.php", + "generated/hash.php", + "generated/ibase.php", + "generated/ibmDb2.php", + "generated/iconv.php", + "generated/image.php", + "generated/imap.php", + "generated/info.php", + "generated/ingres-ii.php", + "generated/inotify.php", + "generated/json.php", + "generated/ldap.php", + "generated/libevent.php", + "generated/libxml.php", + "generated/lzf.php", + "generated/mailparse.php", + "generated/mbstring.php", + "generated/misc.php", + "generated/msql.php", + "generated/mssql.php", + "generated/mysql.php", + "generated/mysqli.php", + "generated/mysqlndMs.php", + "generated/mysqlndQc.php", + "generated/network.php", + "generated/oci8.php", + "generated/opcache.php", + "generated/openssl.php", + "generated/outcontrol.php", + "generated/password.php", + "generated/pcntl.php", + "generated/pcre.php", + "generated/pdf.php", + "generated/pgsql.php", + "generated/posix.php", + "generated/ps.php", + "generated/pspell.php", + "generated/readline.php", + "generated/rrd.php", + "generated/sem.php", + "generated/session.php", + "generated/shmop.php", + "generated/simplexml.php", + "generated/sockets.php", + "generated/sodium.php", + "generated/solr.php", + "generated/spl.php", + "generated/sqlsrv.php", + "generated/ssdeep.php", + "generated/ssh2.php", + "generated/stats.php", + "generated/stream.php", + "generated/strings.php", + "generated/swoole.php", + "generated/uodbc.php", + "generated/uopz.php", + "generated/url.php", + "generated/var.php", + "generated/xdiff.php", + "generated/xml.php", + "generated/xmlrpc.php", + "generated/yaml.php", + "generated/yaz.php", + "generated/zip.php", + "generated/zlib.php", + "lib/special_cases.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHP core functions that throw exceptions instead of returning FALSE on error", + "time": "2020-03-24T13:59:42+00:00" + }, { "name": "theseer/tokenizer", "version": "1.1.3", @@ -6467,9 +6794,9 @@ "php": "^7.3", "ext-curl": "*", "ext-dom": "*", + "ext-intl": "*", "ext-json": "*", - "ext-openssl": "*", - "ext-intl": "*" + "ext-openssl": "*" }, "platform-dev": [] } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php index f0041e074..b009af5ff 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php @@ -3,7 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Tests\unit\Magento\FunctionalTestingFramework\Allure; +namespace tests\unit\Magento\FunctionalTestFramework\Allure; use Magento\FunctionalTestingFramework\Allure\AllureHelper; use Magento\FunctionalTestingFramework\Allure\Event\AddUniqueAttachmentEvent; diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerInstallTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerInstallTest.php index 445e615a9..9b8327bd4 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerInstallTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerInstallTest.php @@ -4,10 +4,10 @@ * See COPYING.txt for license details. */ -namespace tests\unit\Magento\FunctionalTestFramework\Test\Util; +namespace tests\unit\Magento\FunctionalTestFramework\Composer; use Magento\FunctionalTestingFramework\Composer\ComposerInstall; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; class ComposerInstallTest extends MagentoTestCase { diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerPackageTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerPackageTest.php index dfe691651..7620f9c1c 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerPackageTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerPackageTest.php @@ -4,10 +4,10 @@ * See COPYING.txt for license details. */ -namespace tests\unit\Magento\FunctionalTestFramework\Test\Util; +namespace tests\unit\Magento\FunctionalTestFramework\Composer; use Magento\FunctionalTestingFramework\Composer\ComposerPackage; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; use Composer\Package\RootPackage; class ComposerPackageTest extends MagentoTestCase diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Config/Reader/FilesystemTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Config/Reader/FilesystemTest.php index e12ccbe5c..f91f071f0 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Config/Reader/FilesystemTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Config/Reader/FilesystemTest.php @@ -3,7 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Tests\unit\Magento\FunctionalTestFramework\Test\Config\Reader; +namespace tests\unit\Magento\FunctionalTestFramework\Config\Reader; use Magento\FunctionalTestingFramework\Config\FileResolver\Module; use Magento\FunctionalTestingFramework\Config\Reader\Filesystem; diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php index c57dfe471..d2a58c0ff 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php @@ -3,7 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Tests\unit\Magento\FunctionalTestingFramework\Console; +namespace tests\unit\Magento\FunctionalTestFramework\Console; use AspectMock\Test as AspectMock; use PHPUnit\Framework\TestCase; diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php index d55f35247..c9ec92ba8 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php @@ -12,7 +12,7 @@ use Magento\FunctionalTestingFramework\DataGenerator\Parsers\DataProfileSchemaParser; use Magento\FunctionalTestingFramework\ObjectManager; use Magento\FunctionalTestingFramework\ObjectManagerFactory; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; /** * Class DataObjectHandlerTest diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php index b54980314..9ca10c7f2 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php @@ -13,7 +13,7 @@ use Magento\FunctionalTestingFramework\ObjectManagerFactory; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\OperationDefinitionObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Parsers\OperationDefinitionParser; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; /** * Class OperationDefinitionObjectHandlerTest diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php index 0e3367a70..870e75dcd 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php @@ -15,7 +15,7 @@ use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\ObjectManager; use Magento\FunctionalTestingFramework\ObjectManagerFactory; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; use tests\unit\Util\TestLoggingUtil; /** diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/AwsSecretsManagerStorageTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/AwsSecretsManagerStorageTest.php index e1f4e4879..3112529c2 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/AwsSecretsManagerStorageTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/AwsSecretsManagerStorageTest.php @@ -9,7 +9,7 @@ use Aws\SecretsManager\SecretsManagerClient; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\SecretStorage\AwsSecretsManagerStorage; use Aws\Result; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; use ReflectionClass; class AwsSecretsManagerStorageTest extends MagentoTestCase diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/FileStorageTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/FileStorageTest.php index 7e5824c8e..62cb9798e 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/FileStorageTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/FileStorageTest.php @@ -7,7 +7,7 @@ namespace tests\unit\Magento\FunctionalTestFramework\DataGenerator\Handlers\SecretStorage; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\SecretStorage\FileStorage; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; use AspectMock\Test as AspectMock; class FileStorageTest extends MagentoTestCase diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Objects/EntityDataObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Objects/EntityDataObjectTest.php index ef7dfac9b..3fc2aaacb 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Objects/EntityDataObjectTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Objects/EntityDataObjectTest.php @@ -6,7 +6,7 @@ namespace Magento\FunctionalTestingFramework\DataGenerator\Objects; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use tests\unit\Util\TestLoggingUtil; diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php index 1e77c8158..3596edd98 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php @@ -10,7 +10,7 @@ use Magento\FunctionalTestingFramework\DataGenerator\Handlers\OperationDefinitionObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Persist\OperationDataArrayResolver; use Magento\FunctionalTestingFramework\Util\Iterator\AbstractIterator; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; use tests\unit\Util\EntityDataObjectBuilder; use tests\unit\Util\OperationDefinitionBuilder; use tests\unit\Util\OperationElementBuilder; diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Util/DataExtensionUtilTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Util/DataExtensionUtilTest.php index b921229e0..3b79ffec3 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Util/DataExtensionUtilTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Util/DataExtensionUtilTest.php @@ -4,19 +4,19 @@ * See COPYING.txt for license details. */ -namespace Magento\FunctionalTestingFramework\DataGenerator\Objects; +namespace tests\unit\Magento\FunctionalTestFramework\DataGenerator\Util; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Parsers\DataProfileSchemaParser; use Magento\FunctionalTestingFramework\ObjectManager\ObjectManager; use Magento\FunctionalTestingFramework\ObjectManagerFactory; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; use AspectMock\Test as AspectMock; /** - * Class EntityDataObjectTest + * Class DataExtensionUtilTest */ -class EntityDataExtensionTest extends MagentoTestCase +class DataExtensionUtilTest extends MagentoTestCase { /** * Before method functionality diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Extension/BrowserLogUtilTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Extension/BrowserLogUtilTest.php index 32cac698e..45d14ae99 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Extension/BrowserLogUtilTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Extension/BrowserLogUtilTest.php @@ -6,7 +6,7 @@ namespace tests\unit\Magento\FunctionalTestFramework\Extension; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; use Magento\FunctionalTestingFramework\Extension\BrowserLogUtil; class BrowserLogUtilTest extends MagentoTestCase diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/PageObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/PageObjectHandlerTest.php index 28ffcd9e1..1a0ba5fc2 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/PageObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/PageObjectHandlerTest.php @@ -11,7 +11,7 @@ use Magento\FunctionalTestingFramework\ObjectManagerFactory; use Magento\FunctionalTestingFramework\Page\Handlers\PageObjectHandler; use Magento\FunctionalTestingFramework\XmlParser\PageParser; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; class PageObjectHandlerTest extends MagentoTestCase { diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/SectionObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/SectionObjectHandlerTest.php index 4a939dbad..b8bcf3dfb 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/SectionObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/SectionObjectHandlerTest.php @@ -11,7 +11,7 @@ use Magento\FunctionalTestingFramework\ObjectManagerFactory; use Magento\FunctionalTestingFramework\Page\Handlers\SectionObjectHandler; use Magento\FunctionalTestingFramework\XmlParser\SectionParser; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; class SectionObjectHandlerTest extends MagentoTestCase { diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/ElementObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/ElementObjectTest.php index 02fb0f465..eacafbc68 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/ElementObjectTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/ElementObjectTest.php @@ -8,7 +8,7 @@ use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Page\Objects\ElementObject; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; /** * Class ElementObjectTest diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/PageObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/PageObjectTest.php index 7f8053e77..29ec5366d 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/PageObjectTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/PageObjectTest.php @@ -7,7 +7,7 @@ namespace tests\unit\Magento\FunctionalTestFramework\Page\Objects; use Magento\FunctionalTestingFramework\Page\Objects\PageObject; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; /** * Class PageObjectTest diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/SectionObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/SectionObjectTest.php index 5ed1f557f..4305c0101 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/SectionObjectTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/SectionObjectTest.php @@ -8,7 +8,7 @@ use Magento\FunctionalTestingFramework\Page\Objects\ElementObject; use Magento\FunctionalTestingFramework\Page\Objects\SectionObject; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; /** * Class SectionObjectTest diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/Handlers/SuiteObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/Handlers/SuiteObjectHandlerTest.php index c065b1fbf..6f337b05c 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/Handlers/SuiteObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/Handlers/SuiteObjectHandlerTest.php @@ -3,7 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Tests\unit\Magento\FunctionalTestFramework\Suite\Handlers; +namespace tests\unit\Magento\FunctionalTestFramework\Suite\Handlers; use AspectMock\Test as AspectMock; use Magento\FunctionalTestingFramework\ObjectManager\ObjectManager; @@ -12,7 +12,7 @@ use Magento\FunctionalTestingFramework\Suite\Parsers\SuiteDataParser; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; use Magento\FunctionalTestingFramework\Test\Parsers\TestDataParser; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; use tests\unit\Util\SuiteDataArrayBuilder; use tests\unit\Util\TestDataArrayBuilder; use tests\unit\Util\MockModuleResolverBuilder; diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php index d3bf71f5f..8ac8fae37 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php @@ -3,7 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Tests\unit\Magento\FunctionalTestFramework\Suite; +namespace tests\unit\Magento\FunctionalTestFramework\Suite; use AspectMock\Test as AspectMock; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; @@ -17,7 +17,7 @@ use Magento\FunctionalTestingFramework\Test\Util\TestObjectExtractor; use Magento\FunctionalTestingFramework\Test\Parsers\TestDataParser; use Magento\FunctionalTestingFramework\Util\Manifest\DefaultTestManifest; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; use Magento\FunctionalTestingFramework\Util\Manifest\TestManifestFactory; use tests\unit\Util\SuiteDataArrayBuilder; use tests\unit\Util\TestDataArrayBuilder; diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Config/ActionGroupDomTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Config/ActionGroupDomTest.php index 767d06628..cf29b62b5 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Config/ActionGroupDomTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Config/ActionGroupDomTest.php @@ -3,12 +3,12 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Tests\unit\Magento\FunctionalTestFramework\Test\Config; +namespace tests\unit\Magento\FunctionalTestFramework\Test\Config; use Magento\FunctionalTestingFramework\Exceptions\Collector\ExceptionCollector; use Magento\FunctionalTestingFramework\Config\Dom\ValidationException; use Magento\FunctionalTestingFramework\Test\Config\ActionGroupDom; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; class ActionGroupDomTest extends MagentoTestCase { diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Config/DomTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Config/DomTest.php index 719c629d4..5601dce10 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Config/DomTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Config/DomTest.php @@ -3,12 +3,12 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Tests\unit\Magento\FunctionalTestFramework\Test\Config; +namespace tests\unit\Magento\FunctionalTestFramework\Test\Config; use Magento\FunctionalTestingFramework\Exceptions\Collector\ExceptionCollector; use Magento\FunctionalTestingFramework\Config\Dom\ValidationException; use Magento\FunctionalTestingFramework\Test\Config\ActionGroupDom; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; class DomTest extends MagentoTestCase { diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/ActionGroupObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/ActionGroupObjectHandlerTest.php index 4a7c6101e..deb08d783 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/ActionGroupObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/ActionGroupObjectHandlerTest.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Tests\unit\Magento\FunctionalTestFramework\Test\Handlers; +namespace tests\unit\Magento\FunctionalTestFramework\Test\Handlers; use AspectMock\Test as AspectMock; @@ -12,7 +12,7 @@ use Magento\FunctionalTestingFramework\ObjectManager; use Magento\FunctionalTestingFramework\ObjectManagerFactory; use Magento\FunctionalTestingFramework\Test\Handlers\ActionGroupObjectHandler; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; use tests\unit\Util\ActionGroupArrayBuilder; use Magento\FunctionalTestingFramework\Test\Parsers\ActionGroupDataParser; diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php index 7dededc1a..4db2f21a4 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Tests\unit\Magento\FunctionalTestFramework\Test\Handlers; +namespace tests\unit\Magento\FunctionalTestFramework\Test\Handlers; use AspectMock\Test as AspectMock; @@ -16,7 +16,7 @@ use Magento\FunctionalTestingFramework\Test\Objects\TestObject; use Magento\FunctionalTestingFramework\Test\Parsers\TestDataParser; use Magento\FunctionalTestingFramework\Test\Util\TestObjectExtractor; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; use tests\unit\Util\TestDataArrayBuilder; use tests\unit\Util\MockModuleResolverBuilder; diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionGroupObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionGroupObjectTest.php index db32de3b7..4424989f8 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionGroupObjectTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionGroupObjectTest.php @@ -15,7 +15,7 @@ use Magento\FunctionalTestingFramework\Test\Objects\ActionGroupObject; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Magento\FunctionalTestingFramework\Test\Objects\ArgumentObject; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; use tests\unit\Util\ActionGroupObjectBuilder; use tests\unit\Util\EntityDataObjectBuilder; use tests\unit\Util\TestLoggingUtil; diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php index 42830ce9f..8bf71d542 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php @@ -17,7 +17,7 @@ use Magento\FunctionalTestingFramework\Page\Objects\SectionObject; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use tests\unit\Util\TestLoggingUtil; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; /** * Class ActionObjectTest diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionGroupObjectExtractorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionGroupObjectExtractorTest.php index 2d399cfb1..2c9e171d5 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionGroupObjectExtractorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionGroupObjectExtractorTest.php @@ -6,7 +6,7 @@ namespace tests\unit\Magento\FunctionalTestFramework\Test\Util; use Magento\FunctionalTestingFramework\Test\Util\ActionGroupObjectExtractor; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; use tests\unit\Util\TestLoggingUtil; class ActionGroupObjectExtractorTest extends MagentoTestCase diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php index 7996837ff..8c55210a4 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php @@ -13,8 +13,7 @@ use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Magento\FunctionalTestingFramework\Test\Util\ActionMergeUtil; use Magento\FunctionalTestingFramework\Test\Util\ActionObjectExtractor; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; -use tests\unit\Util\DataObjectHandlerReflectionUtil; +use tests\unit\Util\MagentoTestCase; use tests\unit\Util\TestLoggingUtil; class ActionMergeUtilTest extends MagentoTestCase diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionObjectExtractorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionObjectExtractorTest.php index 5f30f8422..6f464b41e 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionObjectExtractorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionObjectExtractorTest.php @@ -7,7 +7,7 @@ use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Magento\FunctionalTestingFramework\Test\Util\ActionObjectExtractor; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; use tests\unit\Util\TestLoggingUtil; class ActionObjectExtractorTest extends MagentoTestCase diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ActionMergeUtilTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ActionMergeUtilTest.php index 913b106a7..864149b2f 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ActionMergeUtilTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ActionMergeUtilTest.php @@ -4,11 +4,11 @@ * See COPYING.txt for license details. */ -namespace Tests\unit\Magento\FunctionalTestFramework\Test\Handlers; +namespace tests\unit\Magento\FunctionalTestFramework\Util; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Magento\FunctionalTestingFramework\Test\Util\ActionMergeUtil; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; class ActionMergeUtilTest extends MagentoTestCase { diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ComposerModuleResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ComposerModuleResolverTest.php index 3173730b3..cec5f097e 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ComposerModuleResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ComposerModuleResolverTest.php @@ -4,11 +4,11 @@ * See COPYING.txt for license details. */ -namespace tests\unit\Magento\FunctionalTestFramework\Test\Util; +namespace tests\unit\Magento\FunctionalTestFramework\Util; use ReflectionClass; use Magento\FunctionalTestingFramework\Util\ComposerModuleResolver; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; class ComposerModuleResolverTest extends MagentoTestCase { diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModulePathExtractorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModulePathExtractorTest.php index 05bc99b89..3f2ba1962 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModulePathExtractorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModulePathExtractorTest.php @@ -4,10 +4,10 @@ * See COPYING.txt for license details. */ -namespace tests\unit\Magento\FunctionalTestFramework\Test\Util; +namespace tests\unit\Magento\FunctionalTestFramework\Util; use Magento\FunctionalTestingFramework\Util\ModulePathExtractor; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; use tests\unit\Util\MockModuleResolverBuilder; class ModulePathExtractorTest extends MagentoTestCase diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php index 694f6c190..81b162981 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace tests\unit\Magento\FunctionalTestFramework\Test\Util; +namespace tests\unit\Magento\FunctionalTestFramework\Util; use AspectMock\Proxy\Verifier; use AspectMock\Test as AspectMock; @@ -15,7 +15,7 @@ use Magento\FunctionalTestingFramework\ObjectManagerFactory; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; use Magento\FunctionalTestingFramework\Util\ModuleResolver; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; use PHPUnit\Runner\Exception; use tests\unit\Util\TestLoggingUtil; diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/FilePathFormatterTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/FilePathFormatterTest.php index bac14113d..1bad633e2 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/FilePathFormatterTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/FilePathFormatterTest.php @@ -3,10 +3,10 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Tests\unit\Magento\FunctionalTestFramework\Util\Path; +namespace tests\unit\Magento\FunctionalTestFramework\Util\Path; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; class FilePathFormatterTest extends MagentoTestCase diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/UrlFormatterTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/UrlFormatterTest.php index c66c9558c..48fc9f337 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/UrlFormatterTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/UrlFormatterTest.php @@ -3,9 +3,9 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Tests\unit\Magento\FunctionalTestFramework\Util\Path; +namespace tests\unit\Magento\FunctionalTestFramework\Util\Path; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Sorter/ParallelGroupSorterTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Sorter/ParallelGroupSorterTest.php index 48966fbaa..0b274f87e 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Sorter/ParallelGroupSorterTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Sorter/ParallelGroupSorterTest.php @@ -3,7 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Tests\unit\Magento\FunctionalTestFramework\Util\Sorter; +namespace tests\unit\Magento\FunctionalTestFramework\Util\Sorter; use AspectMock\Test as AspectMock; use Magento\FunctionalTestingFramework\Suite\Handlers\SuiteObjectHandler; @@ -11,7 +11,7 @@ use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; use Magento\FunctionalTestingFramework\Util\Sorter\ParallelGroupSorter; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; class ParallelGroupSorterTest extends MagentoTestCase { diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php index 9eefbd94a..46bc6e346 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Tests\unit\Magento\FunctionalTestFramework\Test\Handlers; +namespace tests\unit\Magento\FunctionalTestFramework\Util; use AspectMock\Test as AspectMock; @@ -12,7 +12,7 @@ use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Magento\FunctionalTestingFramework\Test\Objects\TestHookObject; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; use Magento\FunctionalTestingFramework\Util\TestGenerator; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Validation/DuplicateNodeValidationUtilTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Validation/DuplicateNodeValidationUtilTest.php index 5dba1cb8b..db117c6b6 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Validation/DuplicateNodeValidationUtilTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Validation/DuplicateNodeValidationUtilTest.php @@ -4,13 +4,11 @@ * See COPYING.txt for license details. */ -namespace tests\unit\Magento\FunctionalTestFramework\Test\Util; +namespace tests\unit\Magento\FunctionalTestFramework\Util\Validation; use Magento\FunctionalTestingFramework\Exceptions\Collector\ExceptionCollector; -use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Util\Validation\DuplicateNodeValidationUtil; -use Magento\FunctionalTestingFramework\Util\Validation\NameValidationUtil; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; class DuplicateNodeValidationUtilTest extends MagentoTestCase { diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Validation/NameValidationUtilTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Validation/NameValidationUtilTest.php index 28d75b1ad..e9854be40 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Validation/NameValidationUtilTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Validation/NameValidationUtilTest.php @@ -4,11 +4,11 @@ * See COPYING.txt for license details. */ -namespace tests\unit\Magento\FunctionalTestFramework\Test\Util; +namespace tests\unit\Magento\FunctionalTestFramework\Util\Validation; use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Util\Validation\NameValidationUtil; -use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use tests\unit\Util\MagentoTestCase; class NameValidationUtilTest extends MagentoTestCase { diff --git a/dev/tests/unit/Util/MagentoTestCase.php b/dev/tests/unit/Util/MagentoTestCase.php index 9d3a0a6f4..7760acfc6 100644 --- a/dev/tests/unit/Util/MagentoTestCase.php +++ b/dev/tests/unit/Util/MagentoTestCase.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Magento\FunctionalTestingFramework\Util; +namespace tests\unit\Util; use AspectMock\Test as AspectMock; use PHPUnit\Framework\TestCase; diff --git a/etc/config/.credentials.example b/etc/config/.credentials.example index 429e9d19f..25400bd63 100644 --- a/etc/config/.credentials.example +++ b/etc/config/.credentials.example @@ -1,3 +1,5 @@ +magento/tfa/OTP_SHARED_SECRET + #magento/carriers_fedex_account= #magento/carriers_fedex_meter_number= #magento/carriers_fedex_key= @@ -72,4 +74,3 @@ #magento/payment_paypal_alternative_payment_methods_express_checkout_us_express_checkout_required_express_checkout_required_express_checkout_api_password= #magento/payment_paypal_alternative_payment_methods_express_checkout_us_express_checkout_required_express_checkout_required_express_checkout_api_signature= -#magento/fraud_protection_signifyd_api_key= \ No newline at end of file diff --git a/etc/di.xml b/etc/di.xml index f6a89fcb0..27dfc61c8 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -8,7 +8,7 @@ <!-- Entity value gets replaced in Dom.php before reading $xml --> <!DOCTYPE config [ - <!ENTITY commonTestActions "acceptPopup|actionGroup|amOnPage|amOnUrl|amOnSubdomain|appendField|assertArrayIsSortasserted|assertElementContainsAttribute|attachFile|cancelPopup|checkOption|clearField|click|clickWithLeftButton|clickWithRightButton|closeAdminNotification|closeTab|comment|conditionalClick|createData|deleteData|updateData|getData|dontSee|dontSeeJsError|dontSeeCheckboxIsChecked|dontSeeCookie|dontSeeCurrentUrlEquals|dontSeeCurrentUrlMatches|dontSeeElement|dontSeeElementInDOM|dontSeeInCurrentUrl|dontSeeInField|dontSeeInFormFields|dontSeeInPageSource|dontSeeInSource|dontSeeInTitle|dontSeeLink|dontSeeOptionIsSelected|doubleClick|dragAndDrop|entity|executeJS|fillField|formatCurrency|generateDate|grabAttributeFrom|grabCookie|grabFromCurrentUrl|grabMultiple|grabPageSource|grabTextFrom|grabValueFrom|loadSessionSnapshot|loginAsAdmin|magentoCLI|magentoCron|makeScreenshot|maximizeWindow|moveBack|moveForward|moveMouseOver|mSetLocale|mResetLocale|openNewTab|pause|parseFloat|pressKey|reloadPage|resetCookie|submitForm|resizeWindow|saveSessionSnapshot|scrollTo|scrollToTopOfPage|searchAndMultiSelectOption|see|seeCheckboxIsChecked|seeCookie|seeCurrentUrlEquals|seeCurrentUrlMatches|seeElement|seeElementInDOM|seeInCurrentUrl|seeInField|seeInFormFields|seeInPageSource|seeInPopup|seeInSource|seeInTitle|seeLink|seeNumberOfElements|seeOptionIsSelected|selectOption|setCookie|submitForm|switchToIFrame|switchToNextTab|switchToPreviousTab|switchToWindow|typeInPopup|uncheckOption|unselectOption|wait|waitForAjaxLoad|waitForElement|waitForElementChange|waitForElementNotVisible|waitForElementVisible|waitForPwaElementNotVisible|waitForPwaElementVisible|waitForJS|waitForLoadingMaskToDisappear|waitForPageLoad|waitForText|assertArrayHasKey|assertArrayNotHasKey|assertContains|assertStringContainsString|assertStringContainsStringIgnoringCase|assertCount|assertEmpty|assertEquals|assertFalse|assertFileExists|assertFileNotExists|assertGreaterOrEquals|assertGreaterThan|assertGreaterThanOrEqual|assertInstanceOf|assertIsEmpty|assertLessOrEquals|assertLessThan|assertLessThanOrEqual|assertNotContains|assertStringNotContainsString|assertStringNotContainsStringIgnoringCase|assertNotEmpty|assertNotEquals|assertNotInstanceOf|assertNotNull|assertNotRegExp|assertNotSame|assertNull|assertRegExp|assertSame|assertStringStartsNotWith|assertStringStartsWith|assertTrue|expectException|fail|dontSeeFullUrlEquals|dontSee|dontSeeFullUrlMatches|dontSeeInFullUrl|seeFullUrlEquals|seeFullUrlMatches|seeInFullUrl|grabFromFullUrl|helper|assertEqualsWithDelta|assertEqualsCanonicalizing|assertEqualsIgnoringCase|assertNotEqualsWithDelta|assertNotEqualsCanonicalizing|assertNotEqualsIgnoringCase"> + <!ENTITY commonTestActions "acceptPopup|actionGroup|amOnPage|amOnUrl|amOnSubdomain|appendField|assertArrayIsSortasserted|assertElementContainsAttribute|attachFile|cancelPopup|checkOption|clearField|click|clickWithLeftButton|clickWithRightButton|closeAdminNotification|closeTab|comment|conditionalClick|createData|deleteData|updateData|getData|dontSee|dontSeeJsError|dontSeeCheckboxIsChecked|dontSeeCookie|dontSeeCurrentUrlEquals|dontSeeCurrentUrlMatches|dontSeeElement|dontSeeElementInDOM|dontSeeInCurrentUrl|dontSeeInField|dontSeeInFormFields|dontSeeInPageSource|dontSeeInSource|dontSeeInTitle|dontSeeLink|dontSeeOptionIsSelected|doubleClick|dragAndDrop|entity|executeJS|fillField|formatCurrency|generateDate|getOTP|grabAttributeFrom|grabCookie|grabFromCurrentUrl|grabMultiple|grabPageSource|grabTextFrom|grabValueFrom|loadSessionSnapshot|loginAsAdmin|magentoCLI|magentoCron|makeScreenshot|maximizeWindow|moveBack|moveForward|moveMouseOver|mSetLocale|mResetLocale|openNewTab|pause|parseFloat|pressKey|reloadPage|resetCookie|submitForm|resizeWindow|saveSessionSnapshot|scrollTo|scrollToTopOfPage|searchAndMultiSelectOption|see|seeCheckboxIsChecked|seeCookie|seeCurrentUrlEquals|seeCurrentUrlMatches|seeElement|seeElementInDOM|seeInCurrentUrl|seeInField|seeInFormFields|seeInPageSource|seeInPopup|seeInSource|seeInTitle|seeLink|seeNumberOfElements|seeOptionIsSelected|selectOption|setCookie|submitForm|switchToIFrame|switchToNextTab|switchToPreviousTab|switchToWindow|typeInPopup|uncheckOption|unselectOption|wait|waitForAjaxLoad|waitForElement|waitForElementChange|waitForElementNotVisible|waitForElementVisible|waitForPwaElementNotVisible|waitForPwaElementVisible|waitForJS|waitForLoadingMaskToDisappear|waitForPageLoad|waitForText|assertArrayHasKey|assertArrayNotHasKey|assertContains|assertStringContainsString|assertStringContainsStringIgnoringCase|assertCount|assertEmpty|assertEquals|assertFalse|assertFileExists|assertFileNotExists|assertGreaterOrEquals|assertGreaterThan|assertGreaterThanOrEqual|assertInstanceOf|assertIsEmpty|assertLessOrEquals|assertLessThan|assertLessThanOrEqual|assertNotContains|assertStringNotContainsString|assertStringNotContainsStringIgnoringCase|assertNotEmpty|assertNotEquals|assertNotInstanceOf|assertNotNull|assertNotRegExp|assertNotSame|assertNull|assertRegExp|assertSame|assertStringStartsNotWith|assertStringStartsWith|assertTrue|expectException|fail|dontSeeFullUrlEquals|dontSee|dontSeeFullUrlMatches|dontSeeInFullUrl|seeFullUrlEquals|seeFullUrlMatches|seeInFullUrl|grabFromFullUrl|helper|assertEqualsWithDelta|assertEqualsCanonicalizing|assertEqualsIgnoringCase|assertNotEqualsWithDelta|assertNotEqualsCanonicalizing|assertNotEqualsIgnoringCase"> ]> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../src/Magento/FunctionalTestingFramework/ObjectManager/etc/config.xsd"> diff --git a/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php b/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php index 6fc9afa55..aa0c81d57 100644 --- a/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php @@ -8,7 +8,7 @@ namespace Magento\FunctionalTestingFramework\Console; use Codeception\Configuration; -use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; +use Magento\FunctionalTestingFramework\DataTransport\Auth\WebApiAuth; use Symfony\Component\EventDispatcher\EventDispatcher; use Codeception\SuiteManager; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; @@ -16,7 +16,6 @@ use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -use Magento\FunctionalTestingFramework\Util\ModuleResolver; use Magento\FunctionalTestingFramework\Module\MagentoWebDriver; use Magento\FunctionalTestingFramework\Module\MagentoWebDriverDoctor; use Symfony\Component\Console\Style\SymfonyStyle; @@ -125,7 +124,7 @@ private function checkAuthenticationToMagentoAdmin() $result = false; try { $this->ioStyle->text("Requesting API token for admin user through cURL ..."); - ModuleResolver::getInstance()->getAdminToken(); + WebApiAuth::getAdminToken(); $this->ioStyle->success('Successful'); $result = true; } catch (TestFrameworkException $e) { diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/AbstractExecutor.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/AbstractExecutor.php deleted file mode 100644 index e27da3718..000000000 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/AbstractExecutor.php +++ /dev/null @@ -1,34 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\FunctionalTestingFramework\DataGenerator\Persist\Curl; - -use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; -use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; -use Magento\FunctionalTestingFramework\Util\Protocol\CurlInterface; - -/** - * Abstract Curl executor. - */ -abstract class AbstractExecutor implements CurlInterface -{ - /** - * Returns Magento base URL. Used as a fallback for other services (eg. WebApi, Backend) - * - * @var string - */ - protected static $baseUrl = null; - - /** - * Returns base URL for Magento instance - * @return string - * @throws TestFrameworkException - */ - public function getBaseUrl(): string - { - return UrlFormatter::format(getenv('MAGENTO_BASE_URL')); - } -} diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php index efdc17ab9..362d25e75 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php @@ -6,15 +6,15 @@ namespace Magento\FunctionalTestingFramework\DataGenerator\Persist; use Magento\FunctionalTestingFramework\Allure\AllureHelper; -use Magento\FunctionalTestingFramework\DataGenerator\Persist\Curl\AdminExecutor; -use Magento\FunctionalTestingFramework\DataGenerator\Persist\Curl\FrontendExecutor; -use Magento\FunctionalTestingFramework\DataGenerator\Persist\Curl\WebapiExecutor; -use Magento\FunctionalTestingFramework\DataGenerator\Persist\Curl\WebapiNoAuthExecutor; +use Magento\FunctionalTestingFramework\DataTransport\AdminFormExecutor; +use Magento\FunctionalTestingFramework\DataTransport\FrontendFormExecutor; +use Magento\FunctionalTestingFramework\DataTransport\WebApiExecutor; +use Magento\FunctionalTestingFramework\DataTransport\WebApiNoAuthExecutor; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\OperationDefinitionObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; use Magento\FunctionalTestingFramework\DataGenerator\Objects\OperationDefinitionObject; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; -use Magento\FunctionalTestingFramework\Util\Protocol\CurlInterface; +use Magento\FunctionalTestingFramework\DataTransport\Protocol\CurlInterface; /** * Class CurlHandler @@ -138,17 +138,17 @@ public function executeRequest($dependentEntities) if (($contentType === 'application/json') && ($authorization === 'adminOauth')) { $this->isJson = true; - $executor = new WebapiExecutor($this->storeCode); + $executor = new WebApiExecutor($this->storeCode); } elseif ($authorization === 'adminFormKey') { - $executor = new AdminExecutor($this->operationDefinition->removeUrlBackend()); + $executor = new AdminFormExecutor($this->operationDefinition->removeUrlBackend()); } elseif ($authorization === 'customerFormKey') { - $executor = new FrontendExecutor( + $executor = new FrontendFormExecutor( $this->requestData['customer_email'], $this->requestData['customer_password'] ); } elseif ($authorization === 'anonymous') { $this->isJson = true; - $executor = new WebapiNoAuthExecutor($this->storeCode); + $executor = new WebApiNoAuthExecutor($this->storeCode); } if (!$executor) { diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/AdminExecutor.php b/src/Magento/FunctionalTestingFramework/DataTransport/AdminFormExecutor.php similarity index 76% rename from src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/AdminExecutor.php rename to src/Magento/FunctionalTestingFramework/DataTransport/AdminFormExecutor.php index 86b3b742f..cf8977036 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/AdminExecutor.php +++ b/src/Magento/FunctionalTestingFramework/DataTransport/AdminFormExecutor.php @@ -4,17 +4,19 @@ * See COPYING.txt for license details. */ -namespace Magento\FunctionalTestingFramework\DataGenerator\Persist\Curl; +namespace Magento\FunctionalTestingFramework\DataTransport; -use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; -use Magento\FunctionalTestingFramework\Util\Protocol\CurlInterface; -use Magento\FunctionalTestingFramework\Util\Protocol\CurlTransport; +use Magento\FunctionalTestingFramework\Util\MftfGlobals; +use Magento\FunctionalTestingFramework\DataTransport\Protocol\CurlInterface; +use Magento\FunctionalTestingFramework\DataTransport\Protocol\CurlTransport; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\DataTransport\Auth\Tfa\OTP; +use Magento\FunctionalTestingFramework\DataTransport\Auth\Tfa; /** * Curl executor for requests to Admin. */ -class AdminExecutor extends AbstractExecutor implements CurlInterface +class AdminFormExecutor implements CurlInterface { /** * Curl transport protocol. @@ -57,25 +59,6 @@ public function __construct($removeBackend) $this->authorize(); } - /** - * Returns base URL for Magento backend instance - * @return string - * @throws TestFrameworkException - */ - public function getBaseUrl(): string - { - $backendHost = getenv('MAGENTO_BACKEND_BASE_URL') - ? - UrlFormatter::format(getenv('MAGENTO_BACKEND_BASE_URL')) - : - parent::getBaseUrl(); - return empty(getenv('MAGENTO_BACKEND_NAME')) - ? - $backendHost - : - $backendHost . getenv('MAGENTO_BACKEND_NAME') . '/'; - } - /** * Authorize admin on backend. * @@ -85,11 +68,11 @@ public function getBaseUrl(): string private function authorize() { // Perform GET to backend url so form_key is set - $this->transport->write($this->getBaseUrl(), [], CurlInterface::GET); + $this->transport->write(MftfGlobals::getBackendBaseUrl(), [], CurlInterface::GET); $this->read(); // Authenticate admin user - $authUrl = $this->getBaseUrl() . 'admin/auth/login/'; + $authUrl = MftfGlobals::getBackendBaseUrl() . 'admin/auth/login/'; $data = [ 'login[username]' => getenv('MAGENTO_ADMIN_USERNAME'), 'login[password]' => getenv('MAGENTO_ADMIN_PASSWORD'), @@ -97,9 +80,25 @@ private function authorize() ]; $this->transport->write($authUrl, $data, CurlInterface::POST); $response = $this->read(); + if (strpos($response, 'login-form')) { throw new TestFrameworkException('Admin user authentication failed!'); } + + // Get OTP + if (Tfa::isEnabled()) { + $authUrl = MftfGlobals::getBackendBaseUrl() . 'tfa/google/authpost/?isAjax=true'; + $data = [ + 'tfa_code' => OTP::getOTP(), + 'form_key' => $this->formKey, + ]; + $this->transport->write($authUrl, $data, CurlInterface::POST); + $response = json_decode($this->read()); + + if (!$response->success) { + throw new TestFrameworkException('Admin user 2FA authentication failed!'); + } + } } /** @@ -128,10 +127,11 @@ private function setFormKey() public function write($url, $data = [], $method = CurlInterface::POST, $headers = []) { $url = ltrim($url, "/"); - $apiUrl = $this->getBaseUrl() . $url; + $apiUrl = MftfGlobals::getBackendBaseUrl() . $url; if ($this->removeBackend) { - $apiUrl = parent::getBaseUrl() . $url; + //TODO + //Cannot find usage. Do we need this? } if ($this->formKey) { diff --git a/src/Magento/FunctionalTestingFramework/DataTransport/Auth/Tfa.php b/src/Magento/FunctionalTestingFramework/DataTransport/Auth/Tfa.php new file mode 100644 index 000000000..fcecfac58 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/DataTransport/Auth/Tfa.php @@ -0,0 +1,97 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\FunctionalTestingFramework\DataTransport\Auth; + +use Magento\FunctionalTestingFramework\Util\MftfGlobals; +use Magento\FunctionalTestingFramework\DataTransport\Protocol\CurlInterface; +use Magento\FunctionalTestingFramework\DataTransport\Protocol\CurlTransport; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; + +/** + * Class Tfa (i.e. 2FA) + */ +class Tfa +{ + const WEB_API_AUTH_GOOGLE = 'V1/tfa/provider/google/authenticate'; + const ADMIN_FORM_AUTH_GOOGLE = 'tfa/google/authpost/?isAjax=true'; + const TFA_SCHEMA = 'schema?services=twoFactorAuthAdminTokenServiceV1'; + + /** Rest request headers + * + * @var string[] + */ + private static $headers = [ + 'Accept: application/json', + 'Content-Type: application/json', + ]; + + /** + * 2FA provider web API authentication endpoints + * + * @var string[] + */ + private static $providerWebApiAuthEndpoints = [ + 'google' => self::WEB_API_AUTH_GOOGLE, + ]; + + /** + * 2FA provider admin form authentication endpoints + * + * @var string[] + */ + private static $providerAdminFormAuthEndpoints = [ + 'google' => self::ADMIN_FORM_AUTH_GOOGLE, + ]; + + /** + * Check if 2FA is enabled for Magento instance under test + * + * @return boolean + * @throws TestFrameworkException + */ + public static function isEnabled() + { + $schemaUrl = MftfGlobals::getWebApiBaseUrl() . self::TFA_SCHEMA; + $transport = new CurlTransport(); + try { + $transport->write($schemaUrl, [], CurlInterface::GET, self::$headers); + $response = $transport->read(); + $transport->close(); + $schema = json_decode($response, true); + if (isset($schema['definitions'], $schema['paths'])) { + return true; + } + } catch (TestFrameworkException $e) { + $transport->close(); + } + return false; + } + + /** + * Return provider's 2FA web API authentication endpoint + * + * @param string $name + * @return string|null + */ + public static function getProviderWebApiAuthEndpoint($name) + { + // Currently only support Google Authenticator + return self::$providerWebApiAuthEndpoints[$name] ?? null; + } + + /** + * Return 2FA provider's admin form authentication endpoint + * + * @param string $name + * @return string|null + */ + public static function getProviderAdminFormEndpoint($name) + { + // Currently only support Google Authenticator + return self::$providerAdminFormAuthEndpoints[$name] ?? null; + } +} diff --git a/src/Magento/FunctionalTestingFramework/DataTransport/Auth/Tfa/OTP.php b/src/Magento/FunctionalTestingFramework/DataTransport/Auth/Tfa/OTP.php new file mode 100644 index 000000000..a44218b58 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/DataTransport/Auth/Tfa/OTP.php @@ -0,0 +1,61 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\FunctionalTestingFramework\DataTransport\Auth\Tfa; + +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use OTPHP\TOTP; +use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; + +/** + * Class OTP + */ +class OTP +{ + const OTP_SHARED_SECRET_PATH = 'magento/tfa/OTP_SHARED_SECRET'; + + /** + * TOTP object + * + * @var TOTP + */ + private static $totp = null; + + /** + * Return OTP for custom secret `OTP_SHARED_SECRET` defined in env + * + * @return string + * @throws TestFrameworkException + */ + public static function getOTP() + { + return self::create()->now(); + } + + /** + * Create TOTP object + * + * @return TOTP + * @throws TestFrameworkException + */ + private static function create() + { + if (self::$totp === null) { + try { + // Get shared secret from Credential storage + $encryptedSecret = CredentialStore::getInstance()->getSecret(self::OTP_SHARED_SECRET_PATH); + $secret = CredentialStore::getInstance()->decryptSecretValue($encryptedSecret); + } catch (TestFrameworkException $e) { + throw new TestFrameworkException('Unable to get OTP' . PHP_EOL . $e->getMessage()); + } + + self::$totp = TOTP::create($secret); + self::$totp->setIssuer('MFTF'); + self::$totp->setLabel('MFTF Testing'); + } + return self::$totp; + } +} diff --git a/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php b/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php new file mode 100644 index 000000000..566d2b348 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php @@ -0,0 +1,108 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\FunctionalTestingFramework\DataTransport\Auth; + +use Magento\FunctionalTestingFramework\Util\MftfGlobals; +use Magento\FunctionalTestingFramework\DataTransport\Protocol\CurlInterface; +use Magento\FunctionalTestingFramework\DataTransport\Protocol\CurlTransport; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\DataTransport\Auth\Tfa\OTP; + +/** + * Class WebApiAuth + */ +class WebApiAuth +{ + const PATH_ADMIN_AUTH = 'V1/integration/admin/token'; + + /** Rest request headers + * + * @var string[] + */ + private static $headers = [ + 'Accept: application/json', + 'Content-Type: application/json', + ]; + + /** + * Tokens for admin users + * + * @var string[] + */ + private static $adminAuthTokens = []; + + /** + * Return the API token for an admin user + * Use MAGENTO_ADMIN_USERNAME and MAGENTO_ADMIN_PASSWORD when $username and/or $password is/are omitted + * + * @param string $username + * @param string $password + * @return string + * @throws TestFrameworkException + */ + public static function getAdminToken($username = null, $password = null) + { + $login = $username ?? getenv('MAGENTO_ADMIN_USERNAME'); + $password = $password ?? getenv('MAGENTO_ADMIN_PASSWORD'); + if (!$login || !$password) { + $message = 'Cannot retrieve API token without credentials. Please fill out .env.'; + $context = [ + 'MAGENTO_BASE_URL' => getenv('MAGENTO_BASE_URL'), + 'MAGENTO_BACKEND_BASE_URL' => getenv('MAGENTO_BACKEND_BASE_URL'), + 'MAGENTO_ADMIN_USERNAME' => getenv('MAGENTO_ADMIN_USERNAME'), + 'MAGENTO_ADMIN_PASSWORD' => getenv('MAGENTO_ADMIN_PASSWORD'), + ]; + throw new TestFrameworkException($message, $context); + } + + if (isset(self::$adminAuthTokens[$login])) { + return self::$adminAuthTokens[$login]; + } + + $authUrl = MftfGlobals::getWebApiBaseUrl() . self::PATH_ADMIN_AUTH; + + $data = [ + 'username' => $login, + 'password' => $password + ]; + + if (Tfa::isEnabled()) { + $authUrl = MftfGlobals::getWebApiBaseUrl() . Tfa::getProviderWebApiAuthEndpoint('google'); + $data['otp'] = OTP::getOTP(); + } + + $transport = new CurlTransport(); + $transport->write( + $authUrl, + json_encode($data, JSON_PRETTY_PRINT), + CurlInterface::POST, + self::$headers + ); + + try { + $response = $transport->read(); + $transport->close(); + $token = json_decode($response); + if ($token !== null) { + self::$adminAuthTokens[$login] = $token; + return $token; + } + $errMessage = "Invalid response: {$response}"; + } catch (TestFrameworkException $e) { + $transport->close(); + $errMessage = $e->getMessage(); + } + + $message = 'Cannot retrieve API token with credentials. Please check the following credentials'; + $message .= Tfa::isEnabled() ? ' and 2FA settings:' : ':' . PHP_EOL; + $message .= "username: {$login}" . PHP_EOL; + $message .= "password: {$password}" . PHP_EOL; + $message .= $errMessage; + $context = ['url' => $authUrl]; + throw new TestFrameworkException($message, $context); + } +} diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/FrontendExecutor.php b/src/Magento/FunctionalTestingFramework/DataTransport/FrontendFormExecutor.php similarity index 90% rename from src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/FrontendExecutor.php rename to src/Magento/FunctionalTestingFramework/DataTransport/FrontendFormExecutor.php index 799cd6d5c..0cf69ec94 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/FrontendExecutor.php +++ b/src/Magento/FunctionalTestingFramework/DataTransport/FrontendFormExecutor.php @@ -4,16 +4,17 @@ * See COPYING.txt for license details. */ -namespace Magento\FunctionalTestingFramework\DataGenerator\Persist\Curl; +namespace Magento\FunctionalTestingFramework\DataTransport; -use Magento\FunctionalTestingFramework\Util\Protocol\CurlInterface; -use Magento\FunctionalTestingFramework\Util\Protocol\CurlTransport; +use Magento\FunctionalTestingFramework\Util\MftfGlobals; +use Magento\FunctionalTestingFramework\DataTransport\Protocol\CurlInterface; +use Magento\FunctionalTestingFramework\DataTransport\Protocol\CurlTransport; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; /** * Curl executor for requests to Frontend. */ -class FrontendExecutor extends AbstractExecutor implements CurlInterface +class FrontendFormExecutor implements CurlInterface { /** * Curl transport protocol. @@ -58,7 +59,7 @@ class FrontendExecutor extends AbstractExecutor implements CurlInterface private $customerPassword; /** - * FrontendExecutor constructor. + * FrontendFormExecutor constructor. * * @param string $customerEmail * @param string $customerPassWord @@ -81,11 +82,11 @@ public function __construct($customerEmail, $customerPassWord) */ private function authorize() { - $url = $this->getBaseUrl() . 'customer/account/login/'; + $url = MftfGlobals::getBaseUrl() . 'customer/account/login/'; $this->transport->write($url, [], CurlInterface::GET); $this->read(); - $url = $this->getBaseUrl() . 'customer/account/loginPost/'; + $url = MftfGlobals::getBaseUrl() . 'customer/account/loginPost/'; $data = [ 'login[username]' => $this->customerEmail, 'login[password]' => $this->customerPassword, @@ -143,7 +144,7 @@ public function write($url, $data = [], $method = CurlInterface::POST, $headers if (isset($data['customer_password'])) { unset($data['customer_password']); } - $apiUrl = $this->getBaseUrl() . $url; + $apiUrl = MftfGlobals::getBaseUrl() . $url; if ($this->formKey) { $data['form_key'] = $this->formKey; } else { diff --git a/src/Magento/FunctionalTestingFramework/Util/Protocol/CurlInterface.php b/src/Magento/FunctionalTestingFramework/DataTransport/Protocol/CurlInterface.php similarity index 94% rename from src/Magento/FunctionalTestingFramework/Util/Protocol/CurlInterface.php rename to src/Magento/FunctionalTestingFramework/DataTransport/Protocol/CurlInterface.php index a2d6bc344..d15dbb18b 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Protocol/CurlInterface.php +++ b/src/Magento/FunctionalTestingFramework/DataTransport/Protocol/CurlInterface.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Magento\FunctionalTestingFramework\Util\Protocol; +namespace Magento\FunctionalTestingFramework\DataTransport\Protocol; /** * Curl protocol interface. diff --git a/src/Magento/FunctionalTestingFramework/Util/Protocol/CurlTransport.php b/src/Magento/FunctionalTestingFramework/DataTransport/Protocol/CurlTransport.php similarity index 99% rename from src/Magento/FunctionalTestingFramework/Util/Protocol/CurlTransport.php rename to src/Magento/FunctionalTestingFramework/DataTransport/Protocol/CurlTransport.php index 16c716e22..a34bad6ce 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Protocol/CurlTransport.php +++ b/src/Magento/FunctionalTestingFramework/DataTransport/Protocol/CurlTransport.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Magento\FunctionalTestingFramework\Util\Protocol; +namespace Magento\FunctionalTestingFramework\DataTransport\Protocol; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/WebapiExecutor.php b/src/Magento/FunctionalTestingFramework/DataTransport/WebApiExecutor.php similarity index 51% rename from src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/WebapiExecutor.php rename to src/Magento/FunctionalTestingFramework/DataTransport/WebApiExecutor.php index 494ce8f97..4c6682438 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/WebapiExecutor.php +++ b/src/Magento/FunctionalTestingFramework/DataTransport/WebApiExecutor.php @@ -4,29 +4,30 @@ * See COPYING.txt for license details. */ -namespace Magento\FunctionalTestingFramework\DataGenerator\Persist\Curl; +namespace Magento\FunctionalTestingFramework\DataTransport; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; -use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; -use Magento\FunctionalTestingFramework\Util\Protocol\CurlInterface; -use Magento\FunctionalTestingFramework\Util\Protocol\CurlTransport; +use Magento\FunctionalTestingFramework\Util\MftfGlobals; +use Magento\FunctionalTestingFramework\DataTransport\Protocol\CurlInterface; +use Magento\FunctionalTestingFramework\DataTransport\Protocol\CurlTransport; +use Magento\FunctionalTestingFramework\DataTransport\Auth\WebApiAuth; /** * Curl executor for Magento Web Api requests. */ -class WebapiExecutor extends AbstractExecutor implements CurlInterface +class WebApiExecutor implements CurlInterface { /** - * Curl transport protocol. + * Curl transport protocol * * @var CurlTransport */ private $transport; /** - * Api headers. + * Rest request headers * - * @var array + * @var string[] */ private $headers = [ 'Accept: application/json', @@ -34,33 +35,14 @@ class WebapiExecutor extends AbstractExecutor implements CurlInterface ]; /** - * Response data. - * - * @var string - */ - private $response; - - /** - * Admin authentication url. - */ - const ADMIN_AUTH_URL = '/V1/integration/admin/token'; - - /** - * Store code in api request. + * Store code in API request * * @var string */ private $storeCode; /** - * Admin user auth token. - * - * @var string - */ - private $authToken; - - /** - * WebapiExecutor Constructor. + * WebApiExecutor Constructor * * @param string $storeCode * @throws TestFrameworkException @@ -68,59 +50,22 @@ class WebapiExecutor extends AbstractExecutor implements CurlInterface public function __construct($storeCode = null) { $this->storeCode = $storeCode; - $this->authToken = null; $this->transport = new CurlTransport(); $this->authorize(); } /** - * Returns base URL for Magento Web API instance - * @return string - * @throws TestFrameworkException - */ - public function getBaseUrl(): string - { - $webapiHost = getenv('MAGENTO_RESTAPI_SERVER_HOST'); - $webapiPort = getenv("MAGENTO_RESTAPI_SERVER_PORT"); - $webapiProtocol = getenv("MAGENTO_RESTAPI_SERVER_PROTOCOL"); - - if ($webapiHost && $webapiProtocol) { - $baseUrl = UrlFormatter::format( - sprintf('%s://%s', $webapiProtocol, $webapiHost), - false - ); - } elseif ($webapiHost) { - $baseUrl = UrlFormatter::format(sprintf('%s', $webapiProtocol, $webapiHost), false); - } - - if (!isset($baseUrl)) { - $baseUrl = rtrim(parent::getBaseUrl(), '/'); - } - - if ($webapiPort) { - $baseUrl .= ':' . $webapiPort; - } - - return $baseUrl . '/'; - } - - /** - * Acquire and store the authorization token needed for REST requests. + * Acquire and store the authorization token needed for REST requests * * @return void * @throws TestFrameworkException */ protected function authorize() { - $authUrl = $this->getFormattedUrl(self::ADMIN_AUTH_URL); - $authCreds = [ - 'username' => getenv('MAGENTO_ADMIN_USERNAME'), - 'password' => getenv('MAGENTO_ADMIN_PASSWORD') - ]; - - $this->transport->write($authUrl, json_encode($authCreds), CurlInterface::POST, $this->headers); - $this->authToken = str_replace('"', "", $this->read()); - $this->headers = array_merge(['Authorization: Bearer ' . $this->authToken], $this->headers); + $this->headers = array_merge( + ['Authorization: Bearer ' . WebApiAuth::getAdminToken()], + $this->headers + ); } /** @@ -154,8 +99,7 @@ public function write($url, $data = [], $method = CurlInterface::POST, $headers */ public function read($successRegex = null, $returnRegex = null, $returnIndex = null) { - $this->response = $this->transport->read(); - return $this->response; + return $this->transport->read(); } /** @@ -181,29 +125,19 @@ public function close() } /** - * Builds and returns URL for request, appending storeCode if needed. + * Builds and returns URL for request, appending storeCode if needed + * * @param string $resource * @return string * @throws TestFrameworkException */ - public function getFormattedUrl($resource) + protected function getFormattedUrl($resource) { - $urlResult = $this->getBaseUrl() . 'rest/'; + $urlResult = MftfGlobals::getWebApiBaseUrl(); if ($this->storeCode != null) { $urlResult .= $this->storeCode . '/'; } $urlResult .= trim($resource, '/'); return $urlResult; } - - /** - * Return admin auth token. - * - * @return string - * @throws TestFrameworkException - */ - public function getAuthToken() - { - return $this->authToken; - } } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/WebapiNoAuthExecutor.php b/src/Magento/FunctionalTestingFramework/DataTransport/WebApiNoAuthExecutor.php similarity index 74% rename from src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/WebapiNoAuthExecutor.php rename to src/Magento/FunctionalTestingFramework/DataTransport/WebApiNoAuthExecutor.php index c54bc60b9..066c676f2 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/WebapiNoAuthExecutor.php +++ b/src/Magento/FunctionalTestingFramework/DataTransport/WebApiNoAuthExecutor.php @@ -4,12 +4,12 @@ * See COPYING.txt for license details. */ -namespace Magento\FunctionalTestingFramework\DataGenerator\Persist\Curl; +namespace Magento\FunctionalTestingFramework\DataTransport; /** * Curl executor for Magento Web Api requests that do not require authorization. */ -class WebapiNoAuthExecutor extends WebapiExecutor +class WebApiNoAuthExecutor extends WebApiExecutor { /** * No authorization is needed and just return. diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 936b0a0da..5ee26cf92 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -15,18 +15,17 @@ use Codeception\Exception\ModuleConfigException; use Codeception\Exception\ModuleException; use Codeception\Util\Uri; +use Magento\FunctionalTestingFramework\DataTransport\WebApiExecutor; +use Magento\FunctionalTestingFramework\DataTransport\Auth\WebApiAuth; +use Magento\FunctionalTestingFramework\DataTransport\Auth\Tfa\OTP; +use Magento\FunctionalTestingFramework\DataTransport\Protocol\CurlInterface; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; -use Magento\FunctionalTestingFramework\DataGenerator\Persist\Curl\WebapiExecutor; use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; -use Magento\FunctionalTestingFramework\Util\Protocol\CurlInterface; use Magento\FunctionalTestingFramework\Util\ConfigSanitizerUtil; use Yandex\Allure\Adapter\AllureException; -use Magento\FunctionalTestingFramework\Util\Protocol\CurlTransport; +use Magento\FunctionalTestingFramework\DataTransport\Protocol\CurlTransport; use Yandex\Allure\Adapter\Support\AttachmentSupport; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; -use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; -use Facebook\WebDriver\Remote\RemoteWebDriver; -use Facebook\WebDriver\Exception\WebDriverCurlException; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; /** @@ -49,6 +48,7 @@ * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) * @SuppressWarnings(PHPMD.ExcessivePublicCount) + * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) */ class MagentoWebDriver extends WebDriver { @@ -551,12 +551,11 @@ public function magentoCLI($command, $timeout = null, $arguments = null) false ); - $restExecutor = new WebapiExecutor(); $executor = new CurlTransport(); $executor->write( $apiURL, [ - 'token' => $restExecutor->getAuthToken(), + 'token' => WebApiAuth::getAdminToken(), getenv('MAGENTO_CLI_COMMAND_PARAMETER') => $command, 'arguments' => $arguments, 'timeout' => $timeout, @@ -565,7 +564,6 @@ public function magentoCLI($command, $timeout = null, $arguments = null) [] ); $response = $executor->read(); - $restExecutor->close(); $executor->close(); return $response; @@ -653,7 +651,7 @@ private function getCronWait(array $cronGroups = [], int $cronInterval = self::M */ public function deleteEntityByUrl($url) { - $executor = new WebapiExecutor(null); + $executor = new WebApiExecutor(null); $executor->write($url, [], CurlInterface::DELETE, []); $response = $executor->read(); $executor->close(); @@ -944,6 +942,17 @@ public function makeScreenshot($name = null) AllureHelper::addAttachmentToCurrentStep($screenName, 'Screenshot'); } + /** + * Return OTP based on a shared secret + * + * @return string + * @throws TestFrameworkException + */ + public function getOTP() + { + return OTP::getOTP(); + } + /** * Create an entity * TODO: move this function to MagentoActionProxies after MQE-1904 diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php index 4298465b8..74aa414a8 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php @@ -35,7 +35,8 @@ class ActionGroupObject "grabMultiple", "grabPageSource", "grabTextFrom", - "grabValueFrom" + "grabValueFrom", + "getOTP" ]; /** diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd index 6d60110ca..2aad30c75 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd @@ -25,6 +25,7 @@ <xs:element type="clearFieldType" name="clearField" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="assertArrayIsSortedType" name="assertArrayIsSorted" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="generateDateType" name="generateDate" minOccurs="0" maxOccurs="unbounded"/> + <xs:element type="getOTPType" name="getOTP" minOccurs="0" maxOccurs="unbounded"/> </xs:choice> </xs:group> @@ -320,6 +321,19 @@ </xs:simpleContent> </xs:complexType> + <xs:complexType name="getOTPType"> + <xs:annotation> + <xs:documentation> + Generates TOTP by a shared secret. Use https://github.com/Spomky-Labs/otphp + </xs:documentation> + </xs:annotation> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attributeGroup ref="commonActionAttributes"/> + </xs:extension> + </xs:simpleContent> + </xs:complexType> + <xs:complexType name="arrayType"> <xs:simpleContent> <xs:extension base="xs:string"> diff --git a/src/Magento/FunctionalTestingFramework/Util/MftfGlobals.php b/src/Magento/FunctionalTestingFramework/Util/MftfGlobals.php new file mode 100644 index 000000000..d59df5c11 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/MftfGlobals.php @@ -0,0 +1,160 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\FunctionalTestingFramework\Util; + +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; + +/** + * MFTF Globals + */ +class MftfGlobals +{ + /** + * Magento Base URL + * + * @var string null + */ + private static $baseUrl = null; + + /** + * Magento Backend Base URL + * + * @var string null + */ + private static $backendBaseUrl = null; + + /** + * Magento Web API Base URL + * + * @var string null + */ + private static $webApiBaseUrl = null; + + /** + * Returns Magento Base URL + * + * @param boolean $withTrailingSeparator + * @return string + * @throws TestFrameworkException + */ + public static function getBaseUrl($withTrailingSeparator = true) + { + if (!self::$baseUrl) { + try { + $url = getenv('MAGENTO_BASE_URL'); + if ($url) { + self::$baseUrl = UrlFormatter::format($url, false); + } + } catch (TestFrameworkException $e) { + } + } + + if (self::$baseUrl) { + return UrlFormatter::format(self::$baseUrl, $withTrailingSeparator); + } + + throw new TestFrameworkException( + 'Unable to retrieve Magento Base URL. Please check .env and set:' + . PHP_EOL + . '"MAGENTO_BASE_URL"' + ); + } + + /** + * Return Magento Backend Base URL + * + * @param boolean $withTrailingSeparator + * @return string + * @throws TestFrameworkException + */ + public static function getBackendBaseUrl($withTrailingSeparator = true) + { + if (!self::$backendBaseUrl) { + try { + $bUrl = getenv('MAGENTO_BACKEND_BASE_URL'); + if ($bUrl) { + self::$backendBaseUrl = UrlFormatter::format($bUrl, false); + } else { + $baseUrl = getenv('MAGENTO_BASE_URL'); + $backendName = getenv('MAGENTO_BACKEND_NAME'); + if ($baseUrl && $backendName) { + self::$backendBaseUrl = UrlFormatter::format( + UrlFormatter::format($baseUrl) . $backendName, + false + ); + } + } + } catch (TestFrameworkException $e) { + } + } + + if (self::$backendBaseUrl) { + return UrlFormatter::format(self::$backendBaseUrl, $withTrailingSeparator); + } + + throw new TestFrameworkException( + 'Unable to retrieve Magento Backend Base URL. Please check .env and set either:' + . PHP_EOL + . '"MAGENTO_BASE_URL" and "MAGENTO_BACKEND_NAME"' + . PHP_EOL + . 'or' + . PHP_EOL + . '"MAGENTO_BACKEND_BASE_URL"' + ); + } + + /** + * Return Web API Base URL + * + * @param boolean $withTrailingSeparator + * @return string + * @throws TestFrameworkException + */ + public static function getWebApiBaseUrl($withTrailingSeparator = true) + { + if (!self::$webApiBaseUrl) { + try { + $webapiHost = getenv('MAGENTO_RESTAPI_SERVER_HOST'); + $webapiPort = getenv("MAGENTO_RESTAPI_SERVER_PORT"); + $webapiProtocol = getenv("MAGENTO_RESTAPI_SERVER_PROTOCOL"); + + if ($webapiHost && $webapiProtocol) { + $baseUrl = UrlFormatter::format( + sprintf('%s://%s', $webapiProtocol, $webapiHost), + false + ); + } elseif ($webapiHost) { + $baseUrl = UrlFormatter::format($webapiHost, false); + } + + if (!isset($baseUrl)) { + $baseUrl = MftfGlobals::getBaseUrl(false); + } + + if ($webapiPort) { + $baseUrl .= ':' . $webapiPort; + } + + self::$webApiBaseUrl = $baseUrl . '/rest'; + } catch (TestFrameworkException $e) { + } + } + if (self::$webApiBaseUrl) { + return UrlFormatter::format(self::$webApiBaseUrl, $withTrailingSeparator); + } + throw new TestFrameworkException( + 'Unable to retrieve Magento Web API Base URL. Please check .env and set either:' + . PHP_EOL + . '"MAGENTO_BASE_URL"' + . PHP_EOL + . 'or' + . PHP_EOL + . '"MAGENTO_RESTAPI_SERVER_HOST"' + ); + } +} diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index b24e77d9c..c16b309ef 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -11,7 +11,7 @@ use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; -use Symfony\Component\HttpFoundation\Response; +use Magento\FunctionalTestingFramework\DataTransport\Auth\WebApiAuth; use \Magento\FunctionalTestingFramework\Util\ModuleResolver\AlphabeticSequenceSorter; use \Magento\FunctionalTestingFramework\Util\ModuleResolver\SequenceSorterInterface; @@ -200,7 +200,7 @@ public function getEnabledModules() $this->printMagentoVersionInfo(); } - $token = $this->getAdminToken(); + $token = WebApiAuth::getAdminToken(); $url = UrlFormatter::format(getenv('MAGENTO_BASE_URL')) . $this->moduleUrl; @@ -685,66 +685,6 @@ private function printMagentoVersionInfo() ); } - /** - * Get the API token for admin. - * - * @return string|boolean - */ - public function getAdminToken() - { - $login = $_ENV['MAGENTO_ADMIN_USERNAME'] ?? null; - $password = $_ENV['MAGENTO_ADMIN_PASSWORD'] ?? null; - if (!$login || !$password || !$this->getBackendUrl()) { - $message = "Cannot retrieve API token without credentials and base url, please fill out .env."; - $context = [ - "MAGENTO_BASE_URL" => getenv("MAGENTO_BASE_URL"), - "MAGENTO_BACKEND_BASE_URL" => getenv("MAGENTO_BACKEND_BASE_URL"), - "MAGENTO_ADMIN_USERNAME" => getenv("MAGENTO_ADMIN_USERNAME"), - "MAGENTO_ADMIN_PASSWORD" => getenv("MAGENTO_ADMIN_PASSWORD"), - ]; - throw new TestFrameworkException($message, $context); - } - - $url = $this->getBackendUrl() . $this->adminTokenUrl; - $data = [ - 'username' => $login, - 'password' => $password - ]; - $headers = [ - 'Content-Type: application/json', - ]; - - $ch = curl_init($url); - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); - curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); - - $response = curl_exec($ch); - $responseCode = curl_getinfo($ch)['http_code']; - - if ($responseCode !== 200) { - if ($responseCode == 0) { - $details = "Could not find Magento Backend Instance at MAGENTO_BACKEND_BASE_URL or MAGENTO_BASE_URL"; - } else { - $details = $responseCode . " " . Response::$statusTexts[$responseCode]; - } - - $message = "Could not retrieve API token from Magento Instance ({$details})"; - $context = [ - "tokenUrl" => $url, - "responseCode" => $responseCode, - "MAGENTO_ADMIN_USERNAME" => getenv("MAGENTO_ADMIN_USERNAME"), - "MAGENTO_ADMIN_PASSWORD" => getenv("MAGENTO_ADMIN_PASSWORD"), - ]; - throw new TestFrameworkException($message, $context); - } - - return json_decode($response); - } - /** * A wrapping method for any custom logic which needs to be applied to the module list * @@ -867,23 +807,6 @@ private function getRegisteredModuleList() return []; } - /** - * Returns custom Backend URL if set, fallback to Magento Base URL - * @return string|null - */ - private function getBackendUrl() - { - try { - if (getenv('MAGENTO_BACKEND_BASE_URL')) { - return UrlFormatter::format(getenv('MAGENTO_BACKEND_BASE_URL')); - } else { - return UrlFormatter::format(getenv('MAGENTO_BASE_URL')); - } - } catch (TestFrameworkException $e) { - return null; - } - } - /** * Find vendor and module name from path * diff --git a/src/Magento/FunctionalTestingFramework/Util/Path/UrlFormatter.php b/src/Magento/FunctionalTestingFramework/Util/Path/UrlFormatter.php index 2ff1e430b..c7b60b6ab 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Path/UrlFormatter.php +++ b/src/Magento/FunctionalTestingFramework/Util/Path/UrlFormatter.php @@ -11,7 +11,7 @@ class UrlFormatter implements FormatterInterface { /** - * Return formatted url path from input string, or false on error + * Return formatted url path from input string * * @param string $url * @param boolean $withTrailingSeparator diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 010e63689..8253a75ba 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1090,6 +1090,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato break; case "selectOption": case "unselectOption": + case "seeNumberOfElements": $testSteps .= $this->wrapFunctionCall( $actor, $actionObject, @@ -1205,6 +1206,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato ); break; case "grabPageSource": + case "getOTP": $testSteps .= $this->wrapFunctionCallWithReturnValue( $stepKey, $actor, @@ -1254,15 +1256,6 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato case "seeOptionIsSelected": $testSteps .= $this->wrapFunctionCall($actor, $actionObject, $selector, $input); break; - case "seeNumberOfElements": - $testSteps .= $this->wrapFunctionCall( - $actor, - $actionObject, - $selector, - $input, - $parameterArray - ); - break; case "seeInPageSource": case "dontSeeInPageSource": case "seeInSource": From 7eb31cecb4dae4a0578ea53adba700f0f76cb573 Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Fri, 1 May 2020 15:02:20 -0500 Subject: [PATCH 362/888] MQE-537: Remove useless classes from framework --- .../Config/Reader/Filesystem.php | 81 - .../Step/Backend/AdminStep.php | 2316 ----------------- 2 files changed, 2397 deletions(-) delete mode 100644 src/Magento/FunctionalTestingFramework/DataGenerator/Config/Reader/Filesystem.php delete mode 100644 src/Magento/FunctionalTestingFramework/Step/Backend/AdminStep.php diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Config/Reader/Filesystem.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Config/Reader/Filesystem.php deleted file mode 100644 index 4f21fabea..000000000 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Config/Reader/Filesystem.php +++ /dev/null @@ -1,81 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\FunctionalTestingFramework\DataGenerator\Config\Reader; - -/** - * Filesystem configuration loader. Loads configuration from XML files, split by scopes. - */ -class Filesystem extends \Magento\FunctionalTestingFramework\Config\Reader\Filesystem -{ - /** - * An array of paths which do have a key for merging but instead are value based nodes which can only be appended - * - * @var array - */ - private $mergeablePaths; - - /** - * Constructor - * - * @param \Magento\FunctionalTestingFramework\Config\FileResolverInterface $fileResolver - * @param \Magento\FunctionalTestingFramework\Config\ConverterInterface $converter - * @param \Magento\FunctionalTestingFramework\Config\SchemaLocatorInterface $schemaLocator - * @param \Magento\FunctionalTestingFramework\Config\ValidationStateInterface $validationState - * @param string $fileName - * @param array $idAttributes - * @param array $mergeablePaths - * @param string $domDocumentClass - * @param string $defaultScope - */ - public function __construct( - \Magento\FunctionalTestingFramework\Config\FileResolverInterface $fileResolver, - \Magento\FunctionalTestingFramework\Config\ConverterInterface $converter, - \Magento\FunctionalTestingFramework\Config\SchemaLocatorInterface $schemaLocator, - \Magento\FunctionalTestingFramework\Config\ValidationStateInterface $validationState, - $fileName, - $idAttributes = [], - $mergeablePaths = [], - $domDocumentClass = \Magento\FunctionalTestingFramework\Config\Dom::class, - $defaultScope = 'global' - ) { - $this->fileResolver = $fileResolver; - $this->converter = $converter; - $this->fileName = $fileName; - $this->idAttributes = array_replace($this->idAttributes, $idAttributes); - $this->mergeablePaths = $mergeablePaths; - $this->validationState = $validationState; - $this->schemaFile = $schemaLocator->getSchema(); - $this->perFileSchema = $schemaLocator->getPerFileSchema() && $validationState->isValidationRequired() - ? $schemaLocator->getPerFileSchema() : null; - $this->domDocumentClass = $domDocumentClass; - $this->defaultScope = $defaultScope; - } - - /** - * Return newly created instance of a config merger. Overridden to include new arg in mergerClass. - * - * @param string $mergerClass - * @param string $initialContents - * @return \Magento\FunctionalTestingFramework\Config\Dom - * @throws \UnexpectedValueException - */ - protected function createConfigMerger($mergerClass, $initialContents) - { - $result = new $mergerClass( - $initialContents, - $this->idAttributes, - $this->mergeablePaths, - null, - $this->perFileSchema - ); - if (!$result instanceof \Magento\FunctionalTestingFramework\Config\Dom) { - throw new \UnexpectedValueException( - "Instance of the DOM config merger is expected, got {$mergerClass} instead." - ); - } - return $result; - } -} diff --git a/src/Magento/FunctionalTestingFramework/Step/Backend/AdminStep.php b/src/Magento/FunctionalTestingFramework/Step/Backend/AdminStep.php deleted file mode 100644 index 5ae74a076..000000000 --- a/src/Magento/FunctionalTestingFramework/Step/Backend/AdminStep.php +++ /dev/null @@ -1,2316 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\FunctionalTestingFramework\Step\Backend; - -require_once __DIR__ . '/../../Helper/AdminUrlList.php'; - -/** - * Class AdminStep - * @SuppressWarnings(PHPMD) - * @codingStandardsIgnoreFile - */ -class AdminStep extends \Magento\FunctionalTestingFramework\AcceptanceTester -{ - public static $adminPageTitle = '.page-title'; - - public function openNewTabGoToVerify($url) - { - $I = $this; - $I->openNewTab(); - $I->amOnPage($url); - $I->waitForPageLoad(); - $I->seeInCurrentUrl($url); - } - - public function closeNewTab() - { - $I = $this; - $I->closeTab(); - } - - // Key Admin Pages - public function goToRandomAdminPage() - { - $I = $this; - - $admin_url_list = array( - "/admin/admin/dashboard/", - "/admin/sales/order/", - "/admin/sales/invoice/", - "/admin/sales/shipment/", - "/admin/sales/creditmemo/", - "/admin/paypal/billing_agreement/", - "/admin/sales/transactions/", - "/admin/catalog/product/", - "/admin/catalog/category/", - "/admin/customer/index/", - "/admin/customer/online/", - "/admin/catalog_rule/promo_catalog/", - "/admin/sales_rule/promo_quote/", - "/admin/admin/email_template/", - "/admin/newsletter/template/", - "/admin/newsletter/queue/", - "/admin/newsletter/subscriber/", - "/admin/admin/url_rewrite/index/", - "/admin/search/term/index/", - "/admin/search/synonyms/index/", - "/admin/admin/sitemap/", - "/admin/review/product/index/", - "/admin/cms/page/", - "/admin/cms/block/", - "/admin/admin/widget_instance/", - "/admin/theme/design_config/", - "/admin/admin/system_design_theme/", - "/admin/admin/system_design/", - "/admin/reports/report_shopcart/product/", - "/admin/search/term/report/", - "/admin/reports/report_shopcart/abandoned/", - "/admin/newsletter/problem/", - "/admin/reports/report_review/customer/", - "/admin/reports/report_review/product/", - "/admin/reports/report_sales/sales/", - "/admin/reports/report_sales/tax/", - "/admin/reports/report_sales/invoiced/", - "/admin/reports/report_sales/shipping/", - "/admin/reports/report_sales/refunded/", - "/admin/reports/report_sales/coupons/", - "/admin/paypal/paypal_reports/", - "/admin/braintree/report/", - "/admin/reports/report_customer/totals/", - "/admin/reports/report_customer/orders/", - "/admin/reports/report_customer/accounts/", - "/admin/reports/report_product/viewed/", - "/admin/reports/report_sales/bestsellers/", - "/admin/reports/report_product/lowstock/", - "/admin/reports/report_product/sold/", - "/admin/reports/report_product/downloads/", - "/admin/reports/report_statistics/", - "/admin/admin/system_store/", - "/admin/admin/system_config/", - "/admin/checkout/agreement/", - "/admin/sales/order_status/", - "/admin/tax/rule/", - "/admin/tax/rate/", - "/admin/admin/system_currency/", - "/admin/admin/system_currencysymbol/", - "/admin/catalog/product_attribute/", - "/admin/catalog/product_set/", - "/admin/review/rating/", - "/admin/customer/group/", - "/admin/admin/import/", - "/admin/admin/export/", - "/admin/tax/rate/importExport/", - "/admin/admin/history/", - "/admin/admin/integration/", - "/admin/admin/cache/", - "/admin/backup/index/", - "/admin/indexer/indexer/list/", - "/admin/admin/user/", - "/admin/admin/locks/", - "/admin/admin/user_role/", - "/admin/admin/notification/", - "/admin/admin/system_variable/", - "/admin/admin/crypt_key/" - ); - - $random_admin_url = array_rand($admin_url_list, 1); - - $I->amOnPage($admin_url_list[$random_admin_url]); - $I->waitForPageLoad(); - - return $admin_url_list[$random_admin_url]; - } - - public function goToTheAdminLoginPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminLoginPage); - $I->waitForPageLoad(); - } - - public function goToTheAdminLogoutPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminLogoutPage); - } - - // Sales - public function goToTheAdminOrdersGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminOrdersGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminOrderForIdPage($orderId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminOrderByIdPage . $orderId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddOrderPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddOrderPage); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddOrderForCustomerIdPage($customerId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddOrderForCustomerIdPage . $customerId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminInvoicesGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminInvoicesGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddInvoiceForOrderIdPage($orderId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddInvoiceForOrderIdPage . $orderId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminShipmentsGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminShipmentsGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminShipmentForIdPage($shipmentId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminShipmentForIdPage . $shipmentId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminCreditMemosGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCreditMemosGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminCreditMemoForIdPage($creditMemoId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCreditMemoForIdPage . $creditMemoId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminBillingAgreementsGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminBillingAgreementsGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminTransactionsGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminTransactionsGrid); - $I->waitForPageLoad(); - } - - // Products - public function goToTheAdminCatalogPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCatalogGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminProductForIdPage($productId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminProductForIdPage . $productId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddSimpleProductPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddSimpleProductPage); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddConfigurableProductPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddConfigurableProductPage); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddGroupedProductPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddGroupedProductPage); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddVirtualProductPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddVirtualProductPage); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddBundledProductPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddBundleProductPage); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddDownloadableProductPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddDownloadableProductPage); - $I->waitForPageLoad(); - } - - public function goToTheAdminCategoriesPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCategoriesPage); - $I->waitForPageLoad(); - } - - public function goToTheAdminCategoryForIdPage($categoryId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCategoryForIdPage . $categoryId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddRootCategoryForStoreIdPage($storeId) - { - $I = $this; - $I->amOnPage(('/admin/catalog/category/add/store/' . $storeId . '/parent/1')); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddSubCategoryForStoreIdPage($storeId) - { - $I = $this; - $I->amOnPage(('/admin/catalog/category/add/store/' . $storeId . '/parent/2')); - $I->waitForPageLoad(); - } - - // Customers - public function goToTheAdminAllCustomersGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAllCustomersGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminCustomersNowOnlineGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCustomersNowOnlineGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminCustomerForIdPage($customerId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCustomerForCustomerIdPage . $customerId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddCustomerPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddCustomerPage); - $I->waitForPageLoad(); - } - - // Marketing - public function goToTheAdminCatalogPriceRuleGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCatalogPriceRuleGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminCatalogPriceRuleForIdPage($catalogPriceRuleId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCatalogPriceRuleForIdPage . $catalogPriceRuleId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddCatalogPriceRulePage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddCatalogPriceRulePage); - $I->waitForPageLoad(); - } - - public function goToTheAdminCartPriceRulesGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCartPriceRulesGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminCartPriceRuleForIdPage($cartPriceRuleId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCartPriceRuleForIdPage . $cartPriceRuleId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddCartPriceRulePage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddCartPriceRulePage); - $I->waitForPageLoad(); - } - - public function goToTheAdminEmailTemplatesGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminEmailTemplatesGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminEmailTemplateForIdPage($emailTemplateId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminEmailTemplateForIdPage . $emailTemplateId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddEmailTemplatePage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddEmailTemplatePage); - $I->waitForPageLoad(); - } - - public function goToTheAdminNewsletterTemplateGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminNewsletterTemplateGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminNewsletterTemplateByIdPage($newsletterTemplateId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminNewsletterTemplateForIdPage . $newsletterTemplateId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddNewsletterTemplatePage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddNewsletterTemplatePage); - $I->waitForPageLoad(); - } - - public function goToTheAdminNewsletterQueueGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminNewsletterQueueGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminNewsletterSubscribersGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminNewsletterSubscribersGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminURLRewritesGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminURLRewritesGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminURLRewriteForId($urlRewriteId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminURLRewriteForIdPage . $urlRewriteId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddURLRewritePage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddURLRewritePage); - $I->waitForPageLoad(); - } - - public function goToTheAdminSearchTermsGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminSearchTermsGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminSearchTermForIdPage($searchTermId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminSearchTermForIdPage . $searchTermId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddSearchTermPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddSearchTermPage); - $I->waitForPageLoad(); - } - - public function goToTheAdminSearchSynonymsGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminSearchSynonymsGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminSearchSynonymGroupByIdPage($searchSynonymId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminSearchSynonymGroupForIdPage . $searchSynonymId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddSearchSynonymGroupPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddSearchSynonymGroupPage); - $I->waitForPageLoad(); - } - - public function goToTheAdminSiteMapGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminSiteMapGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminSiteMapForIdPage($siteMapId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminSiteMapForIdPage . $siteMapId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddSiteMapPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddSiteMapPage); - $I->waitForPageLoad(); - } - - public function goToTheAdminReviewsGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminReviewsGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminReviewForIdPage($reviewId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminReviewByIdPage . $reviewId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddReviewPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddReviewPage); - $I->waitForPageLoad(); - } - - // Content - public function goToTheAdminPagesGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminPagesGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminPageForIdPage($pageId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminPageForIdPage . $pageId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddPagePage() - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddPagePage)); - $I->waitForPageLoad(); - } - - public function goToTheAdminBlocksGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminBlocksGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminBlockForIdPage($blockId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminBlockForIdPage . $blockId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddBlockPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddBlockPage); - $I->waitForPageLoad(); - } - - public function goToTheAdminWidgetsGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminWidgetsGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddWidgetPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddWidgetPage); - $I->waitForPageLoad(); - } - - public function goToTheAdminDesignConfigurationGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminDesignConfigurationGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminThemesGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminThemesGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminThemeByIdPage($themeId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminThemeByIdPage . $themeId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminStoreContentScheduleGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminStoreContentScheduleGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminStoreContentScheduleForIdPage($storeContentScheduleId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminStoreContentScheduleForIdPage . $storeContentScheduleId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddStoreDesignChangePage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddStoreDesignChangePage); - $I->waitForPageLoad(); - } - - // Reports - public function goToTheAdminProductsInCartGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminProductsInCartGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminSearchTermsReportGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminSearchTermsReportGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminAbandonedCartsGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAbandonedCartsGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminNewsletterProblemsReportGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminNewsletterProblemsReportGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminCustomerReviewsReportGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCustomerReviewsReportGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminProductReviewsReportGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminProductReviewsReportGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminProductReviewsForProductIdPage($productId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminProductReviewsForProductIdPage . $productId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminProductReviewIdForProductIdPage($productReviewId, $productId) - { - $I = $this; - $I->amOnPage(('/admin/review/product/edit/id/' . $productReviewId . '/productId/' . $productId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminOrdersReportGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminOrdersReportGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminTaxReportGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminTaxReportGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminInvoiceReportGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminInvoiceReportGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminShippingReportGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminShippingReportGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminRefundsReportGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminRefundsReportGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminCouponsReportGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCouponsReportGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminPayPalSettlementReportsGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminPayPalSettlementReportsGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminBraintreeSettlementReportGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminBraintreeSettlementReportGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminOrderTotalReportGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminOrderTotalReportGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminOrderCountReportGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminOrderCountReportGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminNewAccountsReportGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminNewAccountsReportGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminProductViewsReportGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminProductViewsReportGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminBestsellersReportGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminBestsellersReportGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminLowStockReportGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminLowStockReportGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminOrderedProductsReportGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminOrderedProductsReportGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminDownloadsReportGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminDownloadsReportGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminRefreshStatisticsGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminRefreshStatisticsGrid); - $I->waitForPageLoad(); - } - - // Stores - public function goToTheAdminAllStoresGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAllStoresGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminCreateStoreViewPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCreateStoreViewPage); - $I->waitForPageLoad(); - } - - public function goToTheAdminCreateStorePage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCreateStorePage); - $I->waitForPageLoad(); - } - - public function goToTheAdminCreateWebsitePage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCreateWebsitePage); - $I->waitForPageLoad(); - } - - public function goToTheAdminWebsiteForIdPage($websiteId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminWebsiteByIdPage . $websiteId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminStoreViewForIdPage($storeViewId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminStoreViewByIdPage . $storeViewId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminStoreForIdPage($storeId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminStoreByIdPage . $storeId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminConfigurationGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminConfigurationGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminTermsAndConditionsGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminTermsAndConditionsGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminTermsAndConditionForIdPage($termsAndConditionsId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminTermsAndConditionByIdPage . $termsAndConditionsId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddNewTermsAndConditionsPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddNewTermsAndConditionPage); - $I->waitForPageLoad(); - } - - public function goToTheAdminOrderStatusGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminOrderStatusGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddOrderStatusPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddOrderStatusPage); - $I->waitForPageLoad(); - } - - public function goToTheAdminTaxRulesGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminTaxRulesGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminTaxRuleForIdPage($taxRuleId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminTaxRuleByIdPage . $taxRuleId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddTaxRulePage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddTaxRulePage); - $I->waitForPageLoad(); - } - - public function goToTheAdminTaxZonesAndRatesGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminTaxZonesAndRatesGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminTaxZoneAndRateForIdPage($taxZoneAndRateId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminTaxZoneAndRateByIdPage . $taxZoneAndRateId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddTaxZoneAndRatePage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddTaxZoneAndRatePage); - $I->waitForPageLoad(); - } - - public function goToTheAdminCurrencyRatesPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCurrencyRatesPage); - $I->waitForPageLoad(); - } - - public function goToTheAdminCurrencySymbolsPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCurrencySymbolsPage); - $I->waitForPageLoad(); - } - - public function goToTheAdminProductAttributesGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminProductAttributesGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminProductAttributeForIdPage($productAttributeId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminProductAttributeForIdPage . $productAttributeId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddProductAttributePage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddProductAttributePage); - $I->waitForPageLoad(); - } - - public function goToTheAdminAttributeSetGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAttributeSetsGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminAttributeSetByIdPage($attributeSetId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAttributeSetByIdPage . $attributeSetId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddAttributeSetPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddAttributeSetPage); - $I->waitForPageLoad(); - } - - public function goToTheAdminRatingGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminRatingsGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminRatingForIdPage($ratingId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminRatingForIdPage . $ratingId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddRatingPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddRatingPage); - $I->waitForPageLoad(); - } - - public function goToTheAdminCustomerGroupsGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCustomerGroupsGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminCustomerGroupForIdPage($customerGroupId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCustomerGroupByIdPage . $customerGroupId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddCustomerGroupPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddCustomerGroupPage); - $I->waitForPageLoad(); - } - - // System - public function goToTheAdminImportPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminImportPage); - $I->waitForPageLoad(); - } - - public function goToTheAdminExportPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminExportPage); - $I->waitForPageLoad(); - } - - public function goToTheAdminImportAndExportTaxRatesPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminImportAndExportTaxRatesPage); - $I->waitForPageLoad(); - } - - public function goToTheAdminImportHistoryGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminImportHistoryGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminIntegrationsGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminIntegrationsGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminIntegrationForIdPage($integrationId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminIntegrationByIdPage . $integrationId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddIntegrationPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddIntegrationPage); - $I->waitForPageLoad(); - } - - public function goToTheAdminCacheManagementGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCacheManagementGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminBackupsGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminBackupsGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminIndexManagementGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminIndexManagementGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminWebSetupWizardPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminWebSetupWizardPage); - $I->waitForPageLoad(); - } - - public function goToTheAdminAllUsersGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAllUsersGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminUserForIdPage($userId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminUserByIdPage . $userId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddUserPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddNewUserPage); - $I->waitForPageLoad(); - } - - public function goToTheAdminLockedUsersGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminLockedUsersGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminUserRolesGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminUserRolesGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminUserRoleForIdPage($userRoleId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminUserRoleByIdPage . $userRoleId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddUserRolePage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddUserRolePage); - $I->waitForPageLoad(); - } - - public function goToTheAdminNotificationsGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminNotificationsGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminCustomVariablesGrid() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCustomVariablesGrid); - $I->waitForPageLoad(); - } - - public function goToTheAdminCustomVariableForId($customVariableId) - { - $I = $this; - $I->amOnPage((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCustomVariableByIdPage . $customVariableId)); - $I->waitForPageLoad(); - } - - public function goToTheAdminAddCustomVariablePage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddCustomVariablePage); - $I->waitForPageLoad(); - } - - public function goToTheAdminEncryptionKeyPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminEncryptionKeyPage); - $I->waitForPageLoad(); - } - - public function goToTheAdminFindPartnersAndExtensionsPage() - { - $I = $this; - $I->amOnPage(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminFindPartnersAndExtensions); - $I->waitForPageLoad(); - } - - // Key Admin Pages - public function shouldBeOnTheAdminLoginPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminLoginPage); - } - - public function shouldBeOnTheAdminDashboardPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminDashboardPage); - $I->see('Dashboard', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminForgotYourPasswordPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminForgotYourPasswordPage); - } - - // Sales - public function shouldBeOnTheAdminOrdersGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminOrdersGrid); - $I->see('Orders', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminOrderForIdPage($orderId) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminOrderByIdPage . $orderId)); - $I->see($orderId, self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddOrderPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddOrderPage); - $I->see('Create New Order', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddOrderForCustomerIdPage($customerId) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddOrderForCustomerIdPage . $customerId)); - $I->see('Create New Order', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminInvoicesGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminInvoicesGrid); - $I->see('Invoices', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddInvoiceForOrderIdPage($orderId) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddInvoiceForOrderIdPage . $orderId)); - $I->see('New Invoice', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminShipmentsGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminShipmentsGrid); - $I->see('Shipments', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminShipmentForIdPage($shipmentId) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminShipmentForIdPage . $shipmentId)); - $I->see('New Shipment'); - } - - public function shouldBeOnTheAdminCreditMemosGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCreditMemosGrid); - $I->see('Credit Memos', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminCreditMemoForIdPage($creditMemoId) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCreditMemoForIdPage . $creditMemoId)); - $I->see('View Memo', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminBillingAgreementsGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminBillingAgreementsGrid); - $I->see('Billing Agreements', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminTransactionsGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminTransactionsGrid); - $I->see('Transactions', self::$adminPageTitle); - } - - // Products - public function shouldBeOnTheAdminCatalogGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCatalogGrid); - $I->see('Catalog', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminProductForIdPage($productId, $productName) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminProductForIdPage . $productId)); - $I->see($productName, self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddSimpleProductPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddSimpleProductPage); - $I->see('New Product', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddConfigurableProductPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddConfigurableProductPage); - $I->see('New Product', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddGroupedProductPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddGroupedProductPage); - $I->see('New Product', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddVirtualProductPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddVirtualProductPage); - $I->see('New Product', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddBundledProductPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddBundleProductPage); - $I->see('New Product', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddDownloadableProductPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddDownloadableProductPage); - $I->see('New Product', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminCategoriesPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCategoriesPage); - $I->see('Default Category', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminCategoryForIdPage($categoryId, $categoryName) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCategoryForIdPage . $categoryId)); - $I->see($categoryName, self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddRootCategoryForStoreIdPage($storeId) - { - $I = $this; - $I->seeInCurrentUrl(('/admin/catalog/category/add/store/' . $storeId . '/parent/1')); - $I->see('New Category', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddSubCategoryForStoreIdPage($storeId) - { - $I = $this; - $I->seeInCurrentUrl(('/admin/catalog/category/add/store/' . $storeId . '/parent/2')); - $I->see('New Category', self::$adminPageTitle); - } - - // Customers - public function shouldBeOnTheAdminAllCustomersGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAllCustomersGrid); - $I->see('Customers', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminCustomersNowOnlineGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCustomersNowOnlineGrid); - $I->see('Customers Now Online', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminCustomerForIdPage($customerId, $customerName) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCustomerForCustomerIdPage . $customerId)); - $I->see($customerName, self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddCustomerPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddCustomerPage); - $I->see('New Customer', self::$adminPageTitle); - } - - // Marketing - public function shouldBeOnTheAdminCatalogPriceRuleGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCatalogPriceRuleGrid); - $I->see('Catalog Price Rule', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminCatalogPriceRuleForIdPage($catalogPriceRuleId, $catalogPriceRuleName) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCatalogPriceRuleForIdPage . $catalogPriceRuleId)); - $I->see($catalogPriceRuleName, self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddCatalogPriceRulePage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddCatalogPriceRulePage); - $I->see('New Catalog Price Rule', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminCartPriceRulesGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCartPriceRulesGrid); - $I->see('Cart Price Rules', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminCartPriceRuleForIdPage($cartPriceRuleId, $cartPriceRuleName) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCartPriceRuleForIdPage . $cartPriceRuleId)); - $I->see($cartPriceRuleName, self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddCartPriceRulePage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddCartPriceRulePage); - $I->see('New Cart Price Rule', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminEmailTemplatesGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminEmailTemplatesGrid); - $I->see('Email Templates', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminEmailTemplateForIdPage($emailTemplateId, $templateName) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminEmailTemplateForIdPage . $emailTemplateId)); - $I->see($templateName, self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddEmailTemplatePage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddEmailTemplatePage); - $I->see('New Template', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminNewsletterTemplateGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminNewsletterTemplateGrid); - $I->see('Newsletter Templates', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminNewsletterTemplateByIdPage($newsletterTemplateId, $templateName) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminNewsletterTemplateForIdPage . $newsletterTemplateId)); - $I->see($templateName, self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddNewsletterTemplatePage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddNewsletterTemplatePage); - $I->see('New Template', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminNewsletterQueueGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminNewsletterQueueGrid); - $I->see('Newsletter Queue', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminNewsletterSubscribersGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminNewsletterSubscribersGrid); - $I->see('Newsletter Subscribers', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminURLRewritesGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminURLRewritesGrid); - $I->see('URL Rewrites', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminURLRewriteForId($urlRewriteId) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminURLRewriteForIdPage . $urlRewriteId)); - $I->see('Edit URL Rewrite for a', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddURLRewritePage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddURLRewritePage); - $I->see('Add New URL Rewrite', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminSearchTermsGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminSearchTermsGrid); - $I->see('Search Terms', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminSearchTermForIdPage($searchTermId, $searchQuery) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminSearchTermForIdPage . $searchTermId)); - $I->see($searchQuery, self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddSearchTermPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddSearchTermPage); - $I->see('New Search', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminSearchSynonymsGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminSearchSynonymsGrid); - $I->see('Search Synonyms', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminSearchSynonymGroupByIdPage($searchSynonymId, $synonyms) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminSearchSynonymGroupForIdPage . $searchSynonymId)); - $I->see($synonyms, self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddSearchSynonymGroupPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddSearchSynonymGroupPage); - $I->see('New Synonym Group', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminSiteMapGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminSiteMapGrid); - $I->see('Site Map', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminSiteMapForIdPage($siteMapId, $fileName) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminSiteMapForIdPage . $siteMapId)); - $I->see($fileName, self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddSiteMapPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddSiteMapPage); - $I->see('New Site Map', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminReviewsGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminReviewsGrid); - $I->see('Reviews', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminReviewForIdPage($reviewId) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminReviewByIdPage . $reviewId)); - $I->see('Edit Review', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddReviewPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddReviewPage); - $I->see('New Review', self::$adminPageTitle); - } - - // Content - public function shouldBeOnTheAdminPagesGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminPagesGrid); - $I->see('Pages', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminPageForIdPage($pageId, $pageTitle) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminPageForIdPage . $pageId)); - $I->see($pageTitle, self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddPagePage() - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddPagePage)); - $I->see('New Page', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminBlocksGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminBlocksGrid); - $I->see('Blocks', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminBlockForIdPage($blockId, $blockTitle) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminBlockForIdPage . $blockId)); - $I->see($blockTitle, self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddBlockPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddBlockPage); - $I->see('New Block', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminWidgetsGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminWidgetsGrid); - $I->see('Widgets', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddWidgetPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddWidgetPage); - $I->see('Widgets', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminDesignConfigurationGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminDesignConfigurationGrid); - $I->see('Design Configuration', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminThemesGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminThemesGrid); - $I->see('Themes', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminThemeByIdPage($themeId, $themeTitle) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminThemeByIdPage . $themeId)); - $I->see($themeTitle); - } - - public function shouldBeOnTheAdminStoreContentScheduleGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminStoreContentScheduleGrid); - $I->see('Store Design Schedule', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminStoreContentScheduleForIdPage($storeContentScheduleId) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminStoreContentScheduleForIdPage . $storeContentScheduleId)); - $I->see('Edit Store Design Change', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddStoreDesignChangePage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddStoreDesignChangePage); - $I->see('New Store Design Change'); - } - - // Reports - public function shouldBeOnTheAdminProductsInCartGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminProductsInCartGrid); - $I->see('Products in Carts', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminSearchTermsReportGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminSearchTermsReportGrid); - $I->see('Search Terms Report', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAbandonedCartsGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAbandonedCartsGrid); - $I->see('Abandoned Carts', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminNewsletterProblemsReportGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminNewsletterProblemsReportGrid); - $I->see('Newsletter Problems Report', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminCustomerReviewsReportGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCustomerReviewsReportGrid); - $I->see('Customer Reviews Report', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminProductReviewsReportGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminProductReviewsReportGrid); - $I->see('Product Reviews Report', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminProductReviewsForProductIdPage($productId) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminProductReviewsForProductIdPage . $productId)); - $I->see('Reviews', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminProductReviewIdForProductIdPage($productReviewId, $productId) - { - $I = $this; - $I->seeInCurrentUrl(('/admin/review/product/edit/id/' . $productReviewId . '/productId/' . $productId)); - $I->see('Edit Review', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminOrdersReportGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminOrdersReportGrid); - $I->see('Orders Report', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminTaxReportGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminTaxReportGrid); - $I->see('Tax Report', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminInvoiceReportGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminInvoiceReportGrid); - $I->see('Invoice Report', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminShippingReportGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminShippingReportGrid); - $I->see('Shipping Report', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminRefundsReportGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminRefundsReportGrid); - $I->see('Refunds Report', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminCouponsReportGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCouponsReportGrid); - $I->see('Coupons Report', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminPayPalSettlementReportsGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminPayPalSettlementReportsGrid); - $I->see('PayPal Settlement Reports', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminBraintreeSettlementReportGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminBraintreeSettlementReportGrid); - $I->see('Braintree Settlement Report', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminOrderTotalReportGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminOrderTotalReportGrid); - $I->see('Order Total Report', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminOrderCountReportGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminOrderCountReportGrid); - $I->see('Order Count Report', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminNewAccountsReportGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminNewAccountsReportGrid); - $I->see('New Accounts Report', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminProductViewsReportGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminProductViewsReportGrid); - $I->see('Product Views Report', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminBestsellersReportGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminBestsellersReportGrid); - $I->see('Bestsellers Report', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminLowStockReportGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminLowStockReportGrid); - $I->see('Low Stock Report', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminOrderedProductsGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminOrderedProductsReportGrid); - $I->see('Ordered Products Report', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminDownloadsReportGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminDownloadsReportGrid); - $I->see('Downloads Report', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminRefreshStatisticsGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminRefreshStatisticsGrid); - $I->see('Refresh Statistics', self::$adminPageTitle); - } - - // Stores - public function shouldBeOnTheAdminAllStoresGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAllStoresGrid); - $I->see('Stores', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminCreateStoreViewPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCreateStoreViewPage); - $I->see('Stores', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminCreateStorePage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCreateStorePage); - $I->see('Stores', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminCreateWebsitePage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCreateWebsitePage); - $I->see('Stores'); - } - - public function shouldBeOnTheAdminWebsiteForIdPage($websiteId) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminWebsiteByIdPage . $websiteId)); - } - - public function shouldBeOnTheAdminStoreViewForIdPage($storeViewId) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminStoreViewByIdPage . $storeViewId)); - } - - public function shouldBeOnTheAdminStoreForIdPage($storeId) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminStoreByIdPage . $storeId)); - } - - public function shouldBeOnTheAdminConfigurationGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminConfigurationGrid); - $I->see('Configuration', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminTermsAndConditionsGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminTermsAndConditionsGrid); - $I->see('Terms and Conditions', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminTermsAndConditionForIdPage($termsAndConditionsId, $conditionName) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminTermsAndConditionByIdPage . $termsAndConditionsId)); - $I->see($conditionName, self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddNewTermsAndConditionsPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddNewTermsAndConditionPage); - $I->see('New Condition', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminOrderStatusGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminOrderStatusGrid); - $I->see('Order Status', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddOrderStatusPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddOrderStatusPage); - $I->see('Create New Order Status', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminTaxRulesGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminTaxRulesGrid); - $I->see('Tax Rules', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminTaxRuleForIdPage($taxRuleId, $taxRuleName) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminTaxRuleByIdPage . $taxRuleId)); - $I->see($taxRuleName, self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddTaxRulePage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddTaxRulePage); - $I->see('New Tax Rule', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminTaxZonesAndRatesGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminTaxZonesAndRatesGrid); - $I->see('Tax Zones and Rates', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminTaxZoneAndRateForIdPage($taxZoneAndRateId, $taxIdentifier) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminTaxZoneAndRateByIdPage . $taxZoneAndRateId)); - $I->see($taxIdentifier, self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddTaxZoneAndRatePage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddTaxZoneAndRatePage); - $I->see('New Tax Rate', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminCurrencyRatesPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCurrencyRatesPage); - $I->see('Currency Rates', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminCurrencySymbolsPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCurrencySymbolsPage); - $I->see('Currency Symbols', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminProductAttributesGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminProductAttributesGrid); - $I->see('Product Attributes', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminProductAttributeForIdPage($productAttributeId, $productAttributeDefaultLabel) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminProductAttributeForIdPage . $productAttributeId)); - $I->see($productAttributeDefaultLabel, self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddProductAttributePage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddProductAttributePage); - $I->see('New Product Attribute', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAttributeSetsGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAttributeSetsGrid); - $I->see('Attribute Sets', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAttributeSetByIdPage($attributeSetId, $attributeSetName) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAttributeSetByIdPage . $attributeSetId)); - $I->see($attributeSetName, self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddAttributeSetPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddAttributeSetPage); - $I->see('New Attribute Set', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminRatingsGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminRatingsGrid); - $I->see('Ratings', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminRatingForIdPage($ratingId, $ratingDefaultValue) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminRatingForIdPage . $ratingId)); - $I->see($ratingDefaultValue, self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddRatingPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddRatingPage); - $I->see('New Rating', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminCustomerGroupsGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCustomerGroupsGrid); - $I->see('Customer Groups', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminCustomerGroupForIdPage($customerGroupId, $customerGroupName) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCustomerGroupByIdPage . $customerGroupId)); - $I->see($customerGroupName, self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddCustomerGroupPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddCustomerGroupPage); - $I->see('New Customer Group', self::$adminPageTitle); - } - - // System - public function shouldBeOnTheAdminImportPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminImportPage); - $I->see('Import', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminExportPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminExportPage); - $I->see('Export', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminImportAndExportTaxRatesPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminImportAndExportTaxRatesPage); - $I->see('Import and Export Tax Rates', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminImportHistoryGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminImportHistoryGrid); - $I->see('Import History', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminIntegrationsGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminIntegrationsGrid); - $I->see('Integrations', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminIntegrationForIdPage($integrationId, $integrationName) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminIntegrationByIdPage . $integrationId)); - $I->see('Edit', self::$adminPageTitle); - $I->see($integrationName, self::$adminPageTitle); - $I->see('Integration', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddIntegrationPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddIntegrationPage); - $I->see('New Integration', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminCacheManagementGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCacheManagementGrid); - $I->see('Cache Management', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminBackupsGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminBackupsGrid); - $I->see('Backups', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminIndexManagementGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminIndexManagementGrid); - $I->see('Index Management', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminWebSetupWizardPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminWebSetupWizardPage); - $I->see('Setup Wizard', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAllUsersGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAllUsersGrid); - $I->see('Users', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminUserForIdPage($userId, $userFirstAndLastName) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminUserByIdPage . $userId)); - $I->see($userFirstAndLastName, self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddUserPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddNewUserPage); - $I->see('New User', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminLockedUsersGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminLockedUsersGrid); - $I->see('Locked Users', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminUserRolesGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminUserRolesGrid); - $I->see('Roles', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminUserRoleForIdPage($userRoleId, $userRoleName) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminUserRoleByIdPage . $userRoleId)); - $I->see($userRoleName, self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddUserRolePage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddUserRolePage); - $I->see('New Role', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminNotificationsGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminNotificationsGrid); - $I->see('Notifications', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminCustomVariablesGrid() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCustomVariablesGrid); - $I->see('Custom Variables', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminCustomVariableForId($customVariableId, $customVariableCode) - { - $I = $this; - $I->seeInCurrentUrl((\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminCustomVariableByIdPage . $customVariableId)); - $I->see($customVariableCode, self::$adminPageTitle); - } - - public function shouldBeOnTheAdminAddCustomVariablePage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminAddCustomVariablePage); - $I->see('New Custom Variable', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminEncryptionKeyPage() - { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminEncryptionKeyPage); - $I->see('Encryption Key', self::$adminPageTitle); - } - - public function shouldBeOnTheAdminFindPartnersAndExtensionsPage() { - $I = $this; - $I->seeInCurrentUrl(\Magento\FunctionalTestingFramework\Helper\AdminUrlList::$adminFindPartnersAndExtensions); - $I->see('Magento Marketplace', self::$adminPageTitle); - } -} From c0b7f3d676e2a7ca8af11acf1dd35c72428e8224 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 4 May 2020 11:51:47 -0500 Subject: [PATCH 363/888] MQE-2082: MFTF compatibility with 2fa --- .../FunctionalTestingFramework/DataTransport/Auth/Tfa/OTP.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/DataTransport/Auth/Tfa/OTP.php b/src/Magento/FunctionalTestingFramework/DataTransport/Auth/Tfa/OTP.php index a44218b58..dcd6715c9 100644 --- a/src/Magento/FunctionalTestingFramework/DataTransport/Auth/Tfa/OTP.php +++ b/src/Magento/FunctionalTestingFramework/DataTransport/Auth/Tfa/OTP.php @@ -25,7 +25,7 @@ class OTP private static $totp = null; /** - * Return OTP for custom secret `OTP_SHARED_SECRET` defined in env + * Return OTP for custom secret stored in `magento/tfa/OTP_SHARED_SECRET` * * @return string * @throws TestFrameworkException From 7432b524e964842058cf160545eae94e447bc3ef Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 4 May 2020 12:41:05 -0500 Subject: [PATCH 364/888] MQE-2082: MFTF compatibility with 2fa --- .../DataTransport/AdminFormExecutor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/DataTransport/AdminFormExecutor.php b/src/Magento/FunctionalTestingFramework/DataTransport/AdminFormExecutor.php index cf8977036..5639ee8d7 100644 --- a/src/Magento/FunctionalTestingFramework/DataTransport/AdminFormExecutor.php +++ b/src/Magento/FunctionalTestingFramework/DataTransport/AdminFormExecutor.php @@ -87,7 +87,7 @@ private function authorize() // Get OTP if (Tfa::isEnabled()) { - $authUrl = MftfGlobals::getBackendBaseUrl() . 'tfa/google/authpost/?isAjax=true'; + $authUrl = MftfGlobals::getBackendBaseUrl() . Tfa::getProviderAdminFormEndpoint('google'); $data = [ 'tfa_code' => OTP::getOTP(), 'form_key' => $this->formKey, From 93b45d6b60ebef427bcaa43ea11c012d344c561a Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 4 May 2020 12:51:22 -0500 Subject: [PATCH 365/888] MQE-2082: MFTF compatibility with 2fa --- .../DataTransport/Auth/Tfa.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Magento/FunctionalTestingFramework/DataTransport/Auth/Tfa.php b/src/Magento/FunctionalTestingFramework/DataTransport/Auth/Tfa.php index fcecfac58..04f1971b7 100644 --- a/src/Magento/FunctionalTestingFramework/DataTransport/Auth/Tfa.php +++ b/src/Magento/FunctionalTestingFramework/DataTransport/Auth/Tfa.php @@ -20,6 +20,13 @@ class Tfa const ADMIN_FORM_AUTH_GOOGLE = 'tfa/google/authpost/?isAjax=true'; const TFA_SCHEMA = 'schema?services=twoFactorAuthAdminTokenServiceV1'; + /** + * If 2FA is enabled + * + * @var boolean|null + */ + private static $tfaEnabled = null; + /** Rest request headers * * @var string[] @@ -55,6 +62,10 @@ class Tfa */ public static function isEnabled() { + if (self::$tfaEnabled !== null) { + return self::$tfaEnabled; + } + $schemaUrl = MftfGlobals::getWebApiBaseUrl() . self::TFA_SCHEMA; $transport = new CurlTransport(); try { From 164d969bc28cc1fc55eeb2d78b09faf5349cf2f6 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Wed, 6 May 2020 10:07:45 -0500 Subject: [PATCH 366/888] MQE-2047: Static Check Options - added ruleset reading functionality to static-checks command - added example staticRuleset.json to framework. --- .../Console/StaticChecksCommand.php | 29 +++++++++++++++++-- staticRuleset.json | 5 ++++ 2 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 staticRuleset.json diff --git a/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php b/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php index c8242c8b1..df3b3da24 100644 --- a/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php @@ -22,6 +22,13 @@ class StaticChecksCommand extends Command { + /** + * Associative array containing static ruleset properties. + * + * @var array + */ + private $ruleSet; + /** * Pool of all existing static check objects * @@ -81,6 +88,7 @@ protected function configure() protected function execute(InputInterface $input, OutputInterface $output) { $this->ioStyle = new SymfonyStyle($input, $output); + $this->parseRulesetJson(); try { $this->validateInput($input); } catch (InvalidArgumentException $e) { @@ -133,8 +141,10 @@ private function validateInput(InputInterface $input) $this->staticCheckObjects = []; $requiredChecksNames = $input->getArgument('names'); $invalidCheckNames = []; - // Found user required static check script(s) to run, - // If no static check name is supplied, run all static check scripts + // Build list of static check names to run. + if (empty($requiredChecksNames) && isset($this->ruleSet['tests'])) { + $requiredChecksNames = $this->ruleSet['tests']; + } if (empty($requiredChecksNames)) { $this->staticCheckObjects = $this->allStaticCheckObjects; } else { @@ -164,4 +174,19 @@ private function validateInput(InputInterface $input) ); } } + + /** + * Parses and sets local ruleSet. If not found, simply returns and lets script continue. + * @return void; + */ + private function parseRulesetJson() + { + $pathToRuleset = FW_BP . DIRECTORY_SEPARATOR . "staticRuleset.json"; + if ($pathToRuleset === null) { + $this->ioStyle->text("No ruleset under $pathToRuleset" . PHP_EOL); + return; + } + $this->ioStyle->text("Using ruleset under $pathToRuleset" . PHP_EOL); + $this->ruleSet = json_decode(file_get_contents($pathToRuleset), true); + } } diff --git a/staticRuleset.json b/staticRuleset.json new file mode 100644 index 000000000..b65d8b83d --- /dev/null +++ b/staticRuleset.json @@ -0,0 +1,5 @@ +{ + "tests": [ + "actionGroupArguments" + ] +} From c2a53cf5bff9bff83070beb7a26631b5d9d70548 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Wed, 6 May 2020 11:39:22 -0500 Subject: [PATCH 367/888] MQE-2047: Static Check Options - Fixed project root --- .../FunctionalTestingFramework/Console/StaticChecksCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php b/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php index df3b3da24..d76404cf0 100644 --- a/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php @@ -181,7 +181,7 @@ private function validateInput(InputInterface $input) */ private function parseRulesetJson() { - $pathToRuleset = FW_BP . DIRECTORY_SEPARATOR . "staticRuleset.json"; + $pathToRuleset = PROJECT_ROOT . DIRECTORY_SEPARATOR . "staticRuleset.json"; if ($pathToRuleset === null) { $this->ioStyle->text("No ruleset under $pathToRuleset" . PHP_EOL); return; From 52360a732464f2539a4a20a45076180e86be02cf Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Wed, 6 May 2020 12:35:51 -0500 Subject: [PATCH 368/888] MQE-2047: Static Check Options -Fixed to use TESTS_BP, should be good now. --- staticRuleset.json => dev/staticRuleset.json | 0 .../FunctionalTestingFramework/Console/StaticChecksCommand.php | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename staticRuleset.json => dev/staticRuleset.json (100%) diff --git a/staticRuleset.json b/dev/staticRuleset.json similarity index 100% rename from staticRuleset.json rename to dev/staticRuleset.json diff --git a/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php b/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php index d76404cf0..1d33102e6 100644 --- a/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php @@ -181,7 +181,7 @@ private function validateInput(InputInterface $input) */ private function parseRulesetJson() { - $pathToRuleset = PROJECT_ROOT . DIRECTORY_SEPARATOR . "staticRuleset.json"; + $pathToRuleset = TESTS_BP . DIRECTORY_SEPARATOR . "staticRuleset.json"; if ($pathToRuleset === null) { $this->ioStyle->text("No ruleset under $pathToRuleset" . PHP_EOL); return; From 86e644a1387cc3a48cef1a81a31ff6e9003f42fa Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Thu, 7 May 2020 09:12:30 -0500 Subject: [PATCH 369/888] MQE-942: MFTF Annotation Static Check --- .../StaticCheck/AnnotationsCheck.php | 218 ++++++++++++++++++ .../StaticCheck/StaticChecksList.php | 1 + .../Test/Handlers/TestObjectHandler.php | 14 +- .../Test/Util/AnnotationExtractor.php | 10 +- .../Test/Util/TestObjectExtractor.php | 5 +- 5 files changed, 237 insertions(+), 11 deletions(-) create mode 100644 src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php new file mode 100644 index 000000000..0c8c92bf7 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php @@ -0,0 +1,218 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\FunctionalTestingFramework\StaticCheck; + +use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; +use Magento\FunctionalTestingFramework\Util\Script\ScriptUtil; +use Symfony\Component\Console\Input\InputInterface; +use Exception; + +/** + * Class AnnotationsCheck + * @package Magento\FunctionalTestingFramework\StaticCheck + */ +class AnnotationsCheck implements StaticCheckInterface +{ + const ERROR_LOG_FILENAME = 'mftf-annotations-static-check'; + const ERROR_LOG_MESSAGE = 'MFTF Annotations Static Check'; + + /** + * Array containing all errors found after running the execute() function. + * @var array + */ + private $errors = []; + + /** + * String representing the output summary found after running the execute() function. + * @var string + */ + private $output; + + /** + * Array containing + * key = Story appended to Title + * value = test names that have that pair + * @var array + */ + private $storiesTitlePairs = []; + + /** + * Array containing + * key = testCaseId appended to Title + * value = test names that have that pair + * @var array + */ + private $testCaseIdTitlePairs = []; + + /** + * Validates test annotations + * + * @param InputInterface $input + * @return void + * @throws Exception + */ + public function execute(InputInterface $input) + { + // Set MFTF to the UNIT_TEST_PHASE to mute the default DEPRECATION warnings from the TestObjectHandler. + MftfApplicationConfig::create( + true, + MftfApplicationConfig::UNIT_TEST_PHASE, + false, + MftfApplicationConfig::LEVEL_DEFAULT, + true + ); + $allTests = TestObjectHandler::getInstance(false)->getAllObjects(); + + foreach ($allTests as $test) { + $this->validateRequiredAnnotations($test); + $this->aggregateStoriesTitlePairs($test); + $this->aggregateTestCaseIdTitlePairs($test); + } + + $this->validateStoriesTitlePairs(); + $this->validateTestCaseIdTitlePairs(); + + $scriptUtil = new ScriptUtil(); + $this->output = $scriptUtil->printErrorsToFile( + $this->errors, + self::ERROR_LOG_FILENAME, + self::ERROR_LOG_MESSAGE + ); + } + + /** + * Return array containing all errors found after running the execute() function. + * @return array + */ + public function getErrors() + { + return $this->errors; + } + + /** + * Return string of a short human readable result of the check. For example: "No Dependency errors found." + * @return string + */ + public function getOutput() + { + return $this->output; + } + + /** + * Validates that the test has the following annotations: + * stories + * title + * description + * severity + * + * @param $test + */ + private function validateRequiredAnnotations($test) + { + $annotations = $test->getAnnotations(); + $missing = []; + + $stories = $annotations['stories'] ?? null; + if ($stories === null) { + $missing[] = "stories"; + } + + $title = $annotations['title'] ?? null; + if ($title === null) { + $missing[] = "title"; + } + + $description = $annotations['description']['main'] ?? null; + if ($description === null) { + $missing[] = "description"; + } + + $severity = $annotations['severity'] ?? null; + if ($severity === null) { + $missing[] = "severity"; + } + + $allMissing = join(", ", $missing); + if (strlen($allMissing) > 0) { + $this->errors[][] = "Test {$test->getName()} is missing the required annotations: " . $allMissing; + } + } + + /** + * Add the key = "stories appended to title", value = test name, to the class variable. + * + * @param $test + */ + private function aggregateStoriesTitlePairs($test) + { + $annotations = $test->getAnnotations(); + $stories = $annotations['stories'][0] ?? null; + $title = $this->getTestTitleWithoutPrefix($test); + if ($stories !== null && $title !== null) { + $this->storiesTitlePairs[$stories . $title][] = $test->getName(); + } + } + + /** + * Add the key = "testCaseId appended to title", value = test name, to the class variable. + * + * @param $test + */ + private function aggregateTestCaseIdTitlePairs($test) + { + $annotations = $test->getAnnotations(); + $testCaseId = $annotations['testCaseId'][0] ?? null; + $title = $this->getTestTitleWithoutPrefix($test); + if ($testCaseId !== null && $title !== null) { + $this->testCaseIdTitlePairs[$testCaseId . $title][] = $test->getName(); + } + } + + /** + * Strip away the testCaseId prefix that was automatically added to the test title + * so that way we have just the raw title from the XML file. + * + * @param $test + * @return string|null + */ + private function getTestTitleWithoutPrefix($test) + { + $annotations = $test->getAnnotations(); + $title = $annotations['title'][0] ?? null; + if ($title === null) { + return null; + } else { + $testCaseId = $annotations['testCaseId'][0] ?? "[NO TESTCASEID]"; + return substr($title, strlen($testCaseId . ": ")); + } + } + + /** + * Adds an error if any story+title pairs are used by more than one test. + */ + private function validateStoriesTitlePairs() + { + foreach ($this->storiesTitlePairs as $pair) { + if (sizeof($pair) > 1) { + $this->errors[][] = "Stories + title combination must be unique: " . join(", ", $pair); + } + } + } + + /** + * Adds an error if any testCaseId+title pairs are used by more than one test. + */ + private function validateTestCaseIdTitlePairs() + { + foreach ($this->testCaseIdTitlePairs as $pair) { + if (sizeof($pair) > 1) { + $this->errors[][] = "testCaseId + title combination must be unique: " . join(", ", $pair); + } + } + } +} diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php b/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php index 063b36f14..4b4b9b4c0 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php @@ -33,6 +33,7 @@ public function __construct(array $checks = []) 'testDependencies' => new TestDependencyCheck(), 'actionGroupArguments' => new ActionGroupArgumentsCheck(), self::DEPRECATED_ENTITY_USAGE_CHECK_NAME => new DeprecatedEntityUsageCheck(), + 'annotations' => new AnnotationsCheck() ] + $checks; } diff --git a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php index 109237a77..6ad9762af 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php @@ -53,11 +53,11 @@ class TestObjectHandler implements ObjectHandlerInterface * @return TestObjectHandler * @throws XmlException */ - public static function getInstance() + public static function getInstance($validateAnnotations = true) { if (!self::$testObjectHandler) { self::$testObjectHandler = new TestObjectHandler(); - self::$testObjectHandler->initTestData(); + self::$testObjectHandler->initTestData($validateAnnotations); } return self::$testObjectHandler; @@ -129,7 +129,7 @@ public function getTestsByGroup($groupName) * @SuppressWarnings(PHPMD.UnusedPrivateMethod) * @throws XmlException */ - private function initTestData() + private function initTestData($validateAnnotations = true) { $testDataParser = ObjectManagerFactory::getObjectManager()->create(TestDataParser::class); $parsedTestArray = $testDataParser->readTestData(); @@ -150,15 +150,17 @@ private function initTestData() continue; } try { - $this->tests[$testName] = $testObjectExtractor->extractTestData($testData); + $this->tests[$testName] = $testObjectExtractor->extractTestData($testData, $validateAnnotations); } catch (XmlException $exception) { $exceptionCollector->addError(self::class, $exception->getMessage()); } } $exceptionCollector->throwException(); $testNameValidator->summarize(NameValidationUtil::TEST_NAME); - $testObjectExtractor->getAnnotationExtractor()->validateStoryTitleUniqueness(); - $testObjectExtractor->getAnnotationExtractor()->validateTestCaseIdTitleUniqueness(); + if ($validateAnnotations) { + $testObjectExtractor->getAnnotationExtractor()->validateStoryTitleUniqueness(); + $testObjectExtractor->getAnnotationExtractor()->validateTestCaseIdTitleUniqueness(); + } } /** diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php index 1859f3195..249356abc 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php @@ -60,7 +60,7 @@ public function __construct() * @return array * @throws XmlException */ - public function extractAnnotations($testAnnotations, $filename) + public function extractAnnotations($testAnnotations, $filename, $validateAnnotations = true) { $annotationObjects = []; $annotations = $this->stripDescriptorTags($testAnnotations, self::NODE_NAME); @@ -82,7 +82,9 @@ public function extractAnnotations($testAnnotations, $filename) if ($annotationKey == "skip") { $annotationData = $annotationData['issueId']; - $this->validateSkippedIssues($annotationData, $filename); + if ($validateAnnotations) { + $this->validateSkippedIssues($annotationData, $filename); + } } foreach ($annotationData as $annotationValue) { @@ -100,7 +102,9 @@ public function extractAnnotations($testAnnotations, $filename) } $this->addTestCaseIdToTitle($annotationObjects, $filename); - $this->validateMissingAnnotations($annotationObjects, $filename); + if ($validateAnnotations) { + $this->validateMissingAnnotations($annotationObjects, $filename); + } $this->addStoryTitleToMap($annotationObjects, $filename); return $annotationObjects; diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php index 18a034807..e7afa0960 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php @@ -87,7 +87,7 @@ public function getAnnotationExtractor() * @return TestObject * @throws \Exception */ - public function extractTestData($testData) + public function extractTestData($testData, $validateAnnotations = true) { // validate the test name for blacklisted char (will cause allure report issues) MQE-483 NameValidationUtil::validateName($testData[self::NAME], "Test"); @@ -117,7 +117,8 @@ public function extractTestData($testData) $testAnnotations = $this->annotationExtractor->extractAnnotations( $testData[self::TEST_ANNOTATIONS] ?? [], - $testData[self::NAME] + $testData[self::NAME], + $validateAnnotations ); //Override features with module name if present, populates it otherwise From 488327ee4bfcac4b16bdd56ef2fdd39af72f27f9 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Thu, 7 May 2020 09:29:23 -0500 Subject: [PATCH 370/888] MQE-2047: Static Check Options - Added docs - Fixed static check errors --- docs/commands/mftf.md | 28 ++++++++++++- .../Console/StaticChecksCommand.php | 40 ++++++++++++------- 2 files changed, 51 insertions(+), 17 deletions(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index a4d77ad7a..5ea4d6dcc 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -430,8 +430,11 @@ The example parameters are taken from the `etc/config/.env.example` file. ### `static-checks` -Runs all or specific MFTF static-checks on the test codebase that MFTF is currently attached to. -If no script name argument is specified, all existing static check scripts will run. +Runs all or specific MFTF static-checks on the test codebase that MFTF is currently attached to. +Behavior for determining what tests to runs is as follows: +* If test names are specified, runs only those tests +* If no test names are specified, run tests according to `staticRuleset.json` +* If no `staticRuleset.json` is found, run all tests. #### Usage @@ -489,6 +492,27 @@ vendor/bin/mftf static-checks testDependencies actionGroupArguments |`actionGroupArguments` | Checks that action groups do not have unused arguments.| |`deprecatedEntityUsage`| Checks that deprecated test entities are not being referenced.| +#### Defining ruleset + +The `static-checks` command will look for a `staticRuleset.json` file under either: +* `dev/tests/acceptance/staticRuleset.json` if embedded with Magento2 +* `dev/staticRuleset.json` if standalone + +This file works as a default configuration to easily allow for integration of `static-checks` in a CI environment. + +Currently, the ruleset only defines the tests to run. Here is an example of the expected format: + +```json +{ + "tests": [ + "actionGroupArguments", + "anotherTest" + ] +} + +``` + + ### `upgrade:tests` When the path argument is specified, this `upgrade` command applies all the major version MFTF upgrade scripts to a `Test Module` in the given path. diff --git a/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php b/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php index 1d33102e6..934ff14a6 100644 --- a/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php @@ -140,7 +140,6 @@ private function validateInput(InputInterface $input) { $this->staticCheckObjects = []; $requiredChecksNames = $input->getArgument('names'); - $invalidCheckNames = []; // Build list of static check names to run. if (empty($requiredChecksNames) && isset($this->ruleSet['tests'])) { $requiredChecksNames = $this->ruleSet['tests']; @@ -148,20 +147,7 @@ private function validateInput(InputInterface $input) if (empty($requiredChecksNames)) { $this->staticCheckObjects = $this->allStaticCheckObjects; } else { - for ($index = 0; $index < count($requiredChecksNames); $index++) { - if (in_array($requiredChecksNames[$index], array_keys($this->allStaticCheckObjects))) { - $this->staticCheckObjects[$requiredChecksNames[$index]] = - $this->allStaticCheckObjects[$requiredChecksNames[$index]]; - } else { - $invalidCheckNames[] = $requiredChecksNames[$index]; - } - } - } - - if (!empty($invalidCheckNames)) { - throw new InvalidArgumentException( - 'Invalid static check script(s): ' . implode(', ', $invalidCheckNames) . '.' - ); + $this->validateTestNames($requiredChecksNames); } if ($input->getOption('path')) { @@ -175,6 +161,30 @@ private function validateInput(InputInterface $input) } } + /** + * Validates that all passed in static-check names match an existing static check + * @param string[] $requiredChecksNames + * @return void + */ + private function validateTestNames($requiredChecksNames) + { + $invalidCheckNames = []; + for ($index = 0; $index < count($requiredChecksNames); $index++) { + if (in_array($requiredChecksNames[$index], array_keys($this->allStaticCheckObjects))) { + $this->staticCheckObjects[$requiredChecksNames[$index]] = + $this->allStaticCheckObjects[$requiredChecksNames[$index]]; + } else { + $invalidCheckNames[] = $requiredChecksNames[$index]; + } + } + + if (!empty($invalidCheckNames)) { + throw new InvalidArgumentException( + 'Invalid static check script(s): ' . implode(', ', $invalidCheckNames) . '.' + ); + } + } + /** * Parses and sets local ruleSet. If not found, simply returns and lets script continue. * @return void; From 2167a37f8ac934f023ae644241d032f9a1c393f2 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Thu, 7 May 2020 09:43:38 -0500 Subject: [PATCH 371/888] MQE-2047: Static Check Options - Added proper static checks to sample file. --- dev/staticRuleset.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dev/staticRuleset.json b/dev/staticRuleset.json index b65d8b83d..98041c3d8 100644 --- a/dev/staticRuleset.json +++ b/dev/staticRuleset.json @@ -1,5 +1,6 @@ { "tests": [ - "actionGroupArguments" + "actionGroupArguments", + "deprecatedEntityUsage" ] -} +} \ No newline at end of file From 2a0a9e992321200b8838ed650650a77281674dff Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Thu, 7 May 2020 10:11:54 -0500 Subject: [PATCH 372/888] MQE-942: MFTF Annotation Static Check --- .../StaticCheck/AnnotationsCheck.php | 16 ++++++++++++---- .../Test/Util/ActionGroupAnnotationExtractor.php | 7 ++++--- .../Test/Util/AnnotationExtractor.php | 1 + 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php index 0c8c92bf7..49cc692d3 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php @@ -8,6 +8,7 @@ use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; +use Magento\FunctionalTestingFramework\Test\Objects\TestObject; use Magento\FunctionalTestingFramework\Util\Script\ScriptUtil; use Symfony\Component\Console\Input\InputInterface; use Exception; @@ -110,7 +111,8 @@ public function getOutput() * description * severity * - * @param $test + * @param TestObject $test + * @return void */ private function validateRequiredAnnotations($test) { @@ -146,7 +148,8 @@ private function validateRequiredAnnotations($test) /** * Add the key = "stories appended to title", value = test name, to the class variable. * - * @param $test + * @param TestObject $test + * @return void */ private function aggregateStoriesTitlePairs($test) { @@ -161,7 +164,8 @@ private function aggregateStoriesTitlePairs($test) /** * Add the key = "testCaseId appended to title", value = test name, to the class variable. * - * @param $test + * @param TestObject $test + * @return void */ private function aggregateTestCaseIdTitlePairs($test) { @@ -177,7 +181,7 @@ private function aggregateTestCaseIdTitlePairs($test) * Strip away the testCaseId prefix that was automatically added to the test title * so that way we have just the raw title from the XML file. * - * @param $test + * @param TestObject $test * @return string|null */ private function getTestTitleWithoutPrefix($test) @@ -194,6 +198,8 @@ private function getTestTitleWithoutPrefix($test) /** * Adds an error if any story+title pairs are used by more than one test. + * + * @return void */ private function validateStoriesTitlePairs() { @@ -206,6 +212,8 @@ private function validateStoriesTitlePairs() /** * Adds an error if any testCaseId+title pairs are used by more than one test. + * + * @return void */ private function validateTestCaseIdTitlePairs() { diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/ActionGroupAnnotationExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/ActionGroupAnnotationExtractor.php index 65f0f41b0..7f35ee302 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/ActionGroupAnnotationExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/ActionGroupAnnotationExtractor.php @@ -17,12 +17,13 @@ class ActionGroupAnnotationExtractor extends AnnotationExtractor * This method trims away irrelevant tags and returns annotations used in the array passed. The annotations * can be found in both Tests and their child element tests. * - * @param array $testAnnotations - * @param string $filename + * @param array $testAnnotations + * @param string $filename + * @param boolean $validateAnnotations * @return array * @throws \Exception */ - public function extractAnnotations($testAnnotations, $filename) + public function extractAnnotations($testAnnotations, $filename, $validateAnnotations = true) { $annotationObjects = []; $annotations = $this->stripDescriptorTags($testAnnotations, parent::NODE_NAME); diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php index 249356abc..5699f6727 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php @@ -59,6 +59,7 @@ public function __construct() * @param string $filename * @return array * @throws XmlException + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function extractAnnotations($testAnnotations, $filename, $validateAnnotations = true) { From 1de7456703280a83afd3a774798a1b5cc99186bf Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Fri, 8 May 2020 09:01:26 -0500 Subject: [PATCH 373/888] MQE-2045: Upgrade script to remove unused arguments (#696) * MQE-2045: Upgrade script to remove unused arguments * MQE-2045: Upgrade script to remove unused arguments Fixed static checks, extracted some code into methods * MQE-2045: Upgrade script to remove unused arguments Fixed static checks * MQE-2045: Upgrade script to remove unused arguments Fixed static checks * MQE-2045: Upgrade script to remove unused arguments --- .../StaticCheck/ActionGroupArgumentsCheck.php | 72 +++++++++++-------- .../Upgrade/RemoveUnusedArguments.php | 65 +++++++++++++++++ .../Upgrade/UpgradeScriptList.php | 1 + 3 files changed, 110 insertions(+), 28 deletions(-) create mode 100644 src/Magento/FunctionalTestingFramework/Upgrade/RemoveUnusedArguments.php diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php index 881ee69ab..e6afded68 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php @@ -12,6 +12,8 @@ use Symfony\Component\Finder\Finder; use Exception; use Magento\FunctionalTestingFramework\Util\Script\ScriptUtil; +use Symfony\Component\Finder\SplFileInfo; +use DOMElement; /** * Class ActionGroupArgumentsCheck @@ -19,10 +21,7 @@ */ class ActionGroupArgumentsCheck implements StaticCheckInterface { - const ACTIONGROUP_XML_REGEX_PATTERN = '/<actionGroup\sname=(?: (?!<\/actionGroup>).)*/mxs'; - const ACTIONGROUP_ARGUMENT_REGEX_PATTERN = '/<argument[^\/>]*name="([^"\']*)/mxs'; const ACTIONGROUP_NAME_REGEX_PATTERN = '/<actionGroup name=["\']([^\'"]*)/'; - const ERROR_LOG_FILENAME = 'mftf-arguments-checks'; const ERROR_LOG_MESSAGE = 'MFTF Action Group Unused Arguments Check'; @@ -97,45 +96,62 @@ public function getOutput() private function findErrorsInFileSet($files) { $actionGroupErrors = []; + /** @var SplFileInfo $filePath */ foreach ($files as $filePath) { - $contents = file_get_contents($filePath); - preg_match_all(self::ACTIONGROUP_XML_REGEX_PATTERN, $contents, $actionGroups); - $actionGroupToArguments = $this->buildUnusedArgumentList($actionGroups[0]); - $actionGroupErrors += $this->setErrorOutput($actionGroupToArguments, $filePath); + $actionGroupToArguments = []; + $contents = $filePath->getContents(); + /** @var DOMElement $actionGroup */ + $actionGroup = $this->getActionGroupDomElement($contents); + $arguments = $this->extractActionGroupArguments($actionGroup); + $unusedArguments = $this->findUnusedArguments($arguments, $contents); + if (!empty($unusedArguments)) { + $actionGroupToArguments[$actionGroup->getAttribute('name')] = $unusedArguments; + $actionGroupErrors += $this->setErrorOutput($actionGroupToArguments, $filePath); + } } return $actionGroupErrors; } /** - * Builds array of action group => unused arguments - * @param array $actionGroups - * @return array $actionGroupToArguments + * Extract actionGroup DomElement from xml file + * @param string $contents + * @return \DOMElement */ - private function buildUnusedArgumentList($actionGroups) + public function getActionGroupDomElement($contents) { - $actionGroupToArguments = []; + $domDocument = new \DOMDocument(); + $domDocument->loadXML($contents); + return $domDocument->getElementsByTagName('actionGroup')[0]; + } - foreach ($actionGroups as $actionGroupXml) { - preg_match(self::ACTIONGROUP_NAME_REGEX_PATTERN, $actionGroupXml, $actionGroupName); - $unusedArguments = $this->findUnusedArguments($actionGroupXml); - if (!empty($unusedArguments)) { - $actionGroupToArguments[$actionGroupName[1]] = $unusedArguments; + /** + * Get list of action group arguments declared in an action group + * @param \DOMElement $actionGroup + * @return array $arguments + */ + public function extractActionGroupArguments($actionGroup) + { + $arguments = []; + $argumentsNodes = $actionGroup->getElementsByTagName('arguments'); + if ($argumentsNodes->length > 0) { + $argumentNodes = $argumentsNodes[0]->getElementsByTagName('argument'); + foreach ($argumentNodes as $argumentNode) { + $arguments[] = $argumentNode->getAttribute('name'); } } - return $actionGroupToArguments; + return $arguments; } /** * Returns unused arguments in an action group - * @param string $actionGroupXml + * @param array $arguments + * @param string $contents * @return array */ - private function findUnusedArguments($actionGroupXml) + public function findUnusedArguments($arguments, $contents) { $unusedArguments = []; - - preg_match_all(self::ACTIONGROUP_ARGUMENT_REGEX_PATTERN, $actionGroupXml, $arguments); - preg_match(self::ACTIONGROUP_NAME_REGEX_PATTERN, $actionGroupXml, $actionGroupName); + preg_match(self::ACTIONGROUP_NAME_REGEX_PATTERN, $contents, $actionGroupName); $validActionGroup = false; try { $actionGroup = ActionGroupObjectHandler::getInstance()->getObject($actionGroupName[1]); @@ -149,18 +165,18 @@ private function findUnusedArguments($actionGroupXml) return $unusedArguments; } - foreach ($arguments[1] as $argument) { + foreach ($arguments as $argument) { //pattern to match all argument references $patterns = [ '(\{{2}' . $argument . '(\.[a-zA-Z0-9_\[\]\(\).,\'\/ ]+)?}{2})', '([(,\s\'$$]' . $argument . '(\.[a-zA-Z0-9_$\[\]]+)?[),\s\'])' ]; // matches entity references - if (preg_match($patterns[0], $actionGroupXml)) { + if (preg_match($patterns[0], $contents)) { continue; } //matches parametrized references - if (preg_match($patterns[1], $actionGroupXml)) { + if (preg_match($patterns[1], $contents)) { continue; } //for extending action groups, exclude arguments that are also defined in parent action group @@ -196,8 +212,8 @@ private function isParentActionGroupArgument($argument, $actionGroup) /** * Builds and returns error output for violating references * - * @param array $actionGroupToArguments - * @param string $path + * @param array $actionGroupToArguments + * @param SplFileInfo $path * @return mixed */ private function setErrorOutput($actionGroupToArguments, $path) diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/RemoveUnusedArguments.php b/src/Magento/FunctionalTestingFramework/Upgrade/RemoveUnusedArguments.php new file mode 100644 index 000000000..ced1042ad --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Upgrade/RemoveUnusedArguments.php @@ -0,0 +1,65 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\FunctionalTestingFramework\Upgrade; + +use Magento\FunctionalTestingFramework\StaticCheck\ActionGroupArgumentsCheck; +use Magento\FunctionalTestingFramework\Util\Script\ScriptUtil; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Filesystem\Filesystem; +use DOMElement; + +/** + * Class RenameMetadataFiles + * @package Magento\FunctionalTestingFramework\Upgrade + */ +class RemoveUnusedArguments implements UpgradeInterface +{ + const ARGUMENTS_BLOCK_REGEX_PATTERN = "/\s*<arguments.*\/arguments>/s"; + + /** + * Updates all actionGroup xml files + * + * @param InputInterface $input + * @param OutputInterface $output + * @return string + */ + public function execute(InputInterface $input, OutputInterface $output) + { + $scriptUtil = new ScriptUtil(); + $testPaths[] = $input->getArgument('path'); + if (empty($testPaths[0])) { + $testPaths = $scriptUtil->getAllModulePaths(); + } + $xmlFiles = $scriptUtil->getModuleXmlFilesByScope($testPaths, 'ActionGroup'); + $actionGroupsUpdated = 0; + $fileSystem = new Filesystem(); + foreach ($xmlFiles as $file) { + $contents = $file->getContents(); + $argumentsCheck = new ActionGroupArgumentsCheck(); + /** @var DOMElement $actionGroup */ + $actionGroup = $argumentsCheck->getActionGroupDomElement($contents); + $allArguments = $argumentsCheck->extractActionGroupArguments($actionGroup); + $unusedArguments = $argumentsCheck->findUnusedArguments($allArguments, $contents); + if (empty($unusedArguments)) { + continue; + } + //Remove <arguments> block if all arguments are unused + if (empty(array_diff($allArguments, $unusedArguments))) { + $contents = preg_replace(self::ARGUMENTS_BLOCK_REGEX_PATTERN, '', $contents); + } else { + foreach ($unusedArguments as $argument) { + $argumentRegexPattern = "/\s*<argument.*name\s*=\s*\"".$argument."\".*\/>/"; + $contents = preg_replace($argumentRegexPattern, '', $contents); + } + } + $fileSystem->dumpFile($file->getRealPath(), $contents); + $actionGroupsUpdated++; + } + return "Removed unused action group arguments from {$actionGroupsUpdated} file(s)."; + } +} diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/UpgradeScriptList.php b/src/Magento/FunctionalTestingFramework/Upgrade/UpgradeScriptList.php index 6293b589b..cf2aabe2d 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/UpgradeScriptList.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/UpgradeScriptList.php @@ -28,6 +28,7 @@ class UpgradeScriptList implements UpgradeScriptListInterface public function __construct(array $scripts = []) { $this->scripts = [ + 'removeUnusedArguments' => new RemoveUnusedArguments(), 'upgradeTestSchema' => new UpdateTestSchemaPaths(), 'upgradeAssertionSchema' => new UpdateAssertionSchema(), 'renameMetadataFiles' => new RenameMetadataFiles(), From 7b3aca15c6444f887d5875b45632292999994d51 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Mon, 11 May 2020 09:21:01 -0500 Subject: [PATCH 374/888] MQE-2047: Static Check Options - CR Fixes --- dev/staticRuleset.json | 6 ------ .../Console/StaticChecksCommand.php | 8 ++++---- 2 files changed, 4 insertions(+), 10 deletions(-) delete mode 100644 dev/staticRuleset.json diff --git a/dev/staticRuleset.json b/dev/staticRuleset.json deleted file mode 100644 index 98041c3d8..000000000 --- a/dev/staticRuleset.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "tests": [ - "actionGroupArguments", - "deprecatedEntityUsage" - ] -} \ No newline at end of file diff --git a/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php b/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php index 934ff14a6..792f65ff1 100644 --- a/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php @@ -88,7 +88,6 @@ protected function configure() protected function execute(InputInterface $input, OutputInterface $output) { $this->ioStyle = new SymfonyStyle($input, $output); - $this->parseRulesetJson(); try { $this->validateInput($input); } catch (InvalidArgumentException $e) { @@ -141,8 +140,9 @@ private function validateInput(InputInterface $input) $this->staticCheckObjects = []; $requiredChecksNames = $input->getArgument('names'); // Build list of static check names to run. - if (empty($requiredChecksNames) && isset($this->ruleSet['tests'])) { - $requiredChecksNames = $this->ruleSet['tests']; + if (empty($requiredChecksNames)) { + $this->parseRulesetJson(); + $requiredChecksNames = $this->ruleSet['tests'] ?? null; } if (empty($requiredChecksNames)) { $this->staticCheckObjects = $this->allStaticCheckObjects; @@ -192,7 +192,7 @@ private function validateTestNames($requiredChecksNames) private function parseRulesetJson() { $pathToRuleset = TESTS_BP . DIRECTORY_SEPARATOR . "staticRuleset.json"; - if ($pathToRuleset === null) { + if (!file_exists($pathToRuleset)) { $this->ioStyle->text("No ruleset under $pathToRuleset" . PHP_EOL); return; } From 37d16ccf9a672e78e254494f0fe64118f3e61395 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Mon, 11 May 2020 11:27:56 -0500 Subject: [PATCH 375/888] MQE-2047: Static Check Options - CR Fixes --- .../Console/StaticChecksCommand.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php b/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php index 792f65ff1..fe07dbaaf 100644 --- a/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php @@ -191,7 +191,12 @@ private function validateTestNames($requiredChecksNames) */ private function parseRulesetJson() { - $pathToRuleset = TESTS_BP . DIRECTORY_SEPARATOR . "staticRuleset.json"; + $pathAddition = "/dev/tests/acceptance/"; + // MFTF is both NOT attached and no MAGENTO_BP defined in .env + if (MAGENTO_BP === FW_BP) { + $pathAddition = "/dev/"; + } + $pathToRuleset = MAGENTO_BP . $pathAddition . "staticRuleset.json"; if (!file_exists($pathToRuleset)) { $this->ioStyle->text("No ruleset under $pathToRuleset" . PHP_EOL); return; From a7964e84dfabcfd20a154ee1d514503079620ab0 Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Mon, 11 May 2020 14:57:00 -0500 Subject: [PATCH 376/888] Grammar and formatting --- docs/commands/mftf.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 5ea4d6dcc..55b488e52 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -431,10 +431,11 @@ The example parameters are taken from the `etc/config/.env.example` file. ### `static-checks` Runs all or specific MFTF static-checks on the test codebase that MFTF is currently attached to. -Behavior for determining what tests to runs is as follows: -* If test names are specified, runs only those tests -* If no test names are specified, run tests according to `staticRuleset.json` -* If no `staticRuleset.json` is found, run all tests. +Behavior for determining what tests to run is as follows: + +* If test names are specified, only those tests are run. +* If no test names are specified, tests are run according to `staticRuleset.json`. +* If no `staticRuleset.json` is found, all tests are run. #### Usage @@ -495,11 +496,11 @@ vendor/bin/mftf static-checks testDependencies actionGroupArguments #### Defining ruleset The `static-checks` command will look for a `staticRuleset.json` file under either: -* `dev/tests/acceptance/staticRuleset.json` if embedded with Magento2 -* `dev/staticRuleset.json` if standalone -This file works as a default configuration to easily allow for integration of `static-checks` in a CI environment. +* `dev/tests/acceptance/staticRuleset.json`, if embedded with Magento2 +* `dev/staticRuleset.json`, if standalone +This file works as the default configuration to easily allow for the integration of `static-checks` in a CI environment. Currently, the ruleset only defines the tests to run. Here is an example of the expected format: ```json @@ -509,10 +510,8 @@ Currently, the ruleset only defines the tests to run. Here is an example of the "anotherTest" ] } +``` -``` - - ### `upgrade:tests` When the path argument is specified, this `upgrade` command applies all the major version MFTF upgrade scripts to a `Test Module` in the given path. From c0423df1288ee65209e1cd7800e5e568ea5b96e2 Mon Sep 17 00:00:00 2001 From: Ajith <ajithkumar.maragathavel@ziffity.com> Date: Tue, 12 May 2020 14:37:37 +0530 Subject: [PATCH 377/888] Minor changes in the document --- docs/data.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/data.md b/docs/data.md index 6d4dc3756..31aa1ac97 100644 --- a/docs/data.md +++ b/docs/data.md @@ -22,7 +22,7 @@ In this example: * `SimpleSubCategory` is an entity name. * `name` is a `<data>` key of the entity. The corresponding value will be assigned to `userInput` as a result. -The following is the usage of `<data>` entity in the `Magento/Customer/Test/Mftf/Test/AdminCustomersAllCustomersNavigateMenuTest.xml` test: +The following is an example of the usage of `<data>` entity in the `Magento/Customer/Test/Mftf/Test/AdminCustomersAllCustomersNavigateMenuTest.xml` test: ```xml <actionGroup ref="AdminNavigateMenuActionGroup" stepKey="navigateToAllCustomerPage"> @@ -48,7 +48,7 @@ In this example: * `MAGENTO_ADMIN_USERNAME` is a name of an environment variable. The corresponding value will be assigned to `userInput` as a result. -The following is the usage of `_ENV` in the `Magento/Braintree/Test/Mftf/ActionGroup/AdminDeleteRoleActionGroup.xml` action group: +The following is an example of the usage of `_ENV` in the `Magento/Braintree/Test/Mftf/ActionGroup/AdminDeleteRoleActionGroup.xml` action group: ```xml <fillField stepKey="TypeCurrentPassword" selector="{{AdminDeleteRoleSection.current_pass}}" userInput="{{_ENV.MAGENTO_ADMIN_PASSWORD}}"/> @@ -69,7 +69,7 @@ In this example: Learn more in [Credentials][]. -The following is the usage of `_CREDS` in the `Magento/Braintree/Test/Mftf/Data/BraintreeData.xml` data entity: +The following is an example of the usage of `_CREDS` in the `Magento/Braintree/Test/Mftf/Data/BraintreeData.xml` data entity: ```xml <entity name="MerchantId" type="merchant_id"> @@ -93,7 +93,7 @@ In this example: * `email` is a data key of the entity. The corresponding value will be assigned to `userInput` as a result. -The following is the usage of the persistant data in `Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithCountryUSATest.xml` test: +The following is an example of the usage of the persistant data in `Magento/Customer/Test/Mftf/Test/AdminCreateCustomerWithCountryUSATest.xml` test: ```xml <actionGroup ref="AdminFilterCustomerByEmail" stepKey="filterTheCustomerByEmail"> @@ -145,7 +145,7 @@ userInput="We'll email you an order confirmation with details and tracking info. ## Format -The format of `<data>` entity is: +The format of the `<data>` entity is: ```xml <?xml version="1.0" encoding="UTF-8"?> @@ -243,7 +243,7 @@ You can also call data from the xml definition of a `data` tag directly: Attributes|Type|Use|Description ---|---|---|--- -`name`|string|optional|Name of the `<entity>`. Camel case is used for the entity name. +`name`|string|optional|Name of the `<entity>`. Use camel case for entity names. `type`|string|optional|Node containing the exact name of `<entity>` type. Used later to find specific Persistence Layer Model class. `type` in `<data>` can be whatever the user wants; There are no constraints. It is important when persisting data, depending on the `type` given, as it will try to match a metadata definition with the operation being done. Example: A `myCustomer` entity with `type="customer"`, calling `<createData entity="myCustomer"/>`, will try to find a metadata entry with the following attributes: `<operation dataType="customer" type="create">`. `deprecated`|string|optional|Used to warn about the future deprecation of the data entity. String will appear in Allure reports and console output at runtime. @@ -277,7 +277,7 @@ Attributes|Type|Use|Description Example: -``` +```xml <var key="parent_id" entityType="category" entityKey="id" /> ``` From 5b6185c0f98a1b27f1b4d0a59e0663189634b74d Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Tue, 12 May 2020 10:23:11 -0500 Subject: [PATCH 378/888] MQE-942: MFTF Annotation Static Check --- .../Test/Util/AnnotationExtractor.php | 5 +++-- .../Test/Util/TestObjectExtractor.php | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php index 5699f6727..031215abb 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php @@ -55,8 +55,9 @@ public function __construct() * This method trims away irrelevant tags and returns annotations used in the array passed. The annotations * can be found in both Tests and their child element tests. * - * @param array $testAnnotations - * @param string $filename + * @param array $testAnnotations + * @param string $filename + * @param boolean $validateAnnotations * @return array * @throws XmlException * @SuppressWarnings(PHPMD.CyclomaticComplexity) diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php index e7afa0960..cfe417dc9 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php @@ -83,7 +83,8 @@ public function getAnnotationExtractor() * This method takes and array of test data and strips away irrelevant tags. The data is converted into an array of * TestObjects. * - * @param array $testData + * @param array $testData + * @param boolean $validateAnnotations * @return TestObject * @throws \Exception */ From 5eb4a9d1dc78f7ea2934c7b538687edd47966120 Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Tue, 12 May 2020 11:14:45 -0500 Subject: [PATCH 379/888] MQE-942: MFTF Annotation Static Check --- .gitignore | 1 + .../StaticCheck/AnnotationsCheck.php | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/.gitignore b/.gitignore index d6ad9e81c..1ad606e97 100755 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ dev/tests/mftf.log dev/tests/docs/* dev/tests/_output dev/tests/functional.suite.yml +mftf-annotations-static-check.txt diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php index 49cc692d3..86cbec2db 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php @@ -71,6 +71,7 @@ public function execute(InputInterface $input) foreach ($allTests as $test) { $this->validateRequiredAnnotations($test); + $this->validateSkipIssueId($test); $this->aggregateStoriesTitlePairs($test); $this->aggregateTestCaseIdTitlePairs($test); } @@ -145,6 +146,25 @@ private function validateRequiredAnnotations($test) } } + /** + * Validates that if the test is skipped, that it has an issueId value. + * + * @param TestObject $test + * @return void + */ + private function validateSkipIssueId($test) + { + $annotations = $test->getAnnotations(); + + $skip = $annotations['skip'] ?? null; + if ($skip !== null) { + $issueId = $skip[0] ?? null; + if ($issueId === null || strlen($issueId) == 0) { + $this->errors[][] = "Test {$test->getName()} is skipped but the issueId is empty."; + } + } + } + /** * Add the key = "stories appended to title", value = test name, to the class variable. * From bd5054f82f708b381b8fd09a9fbd3d6d844f6ef7 Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Tue, 12 May 2020 13:38:04 -0500 Subject: [PATCH 380/888] MQE-942: MFTF Annotation Static Check --- docs/commands/mftf.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 55b488e52..b71e45148 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -477,6 +477,10 @@ vendor/bin/mftf static-checks actionGroupArguments vendor/bin/mftf static-checks deprecatedEntityUsage ``` +```bash +vendor/bin/mftf static-checks annotations +``` + ```bash vendor/bin/mftf static-checks deprecatedEntityUsage -p path/to/mftf/test/module ``` @@ -492,6 +496,7 @@ vendor/bin/mftf static-checks testDependencies actionGroupArguments |`testDependencies` | Checks that test dependencies do not violate Magento module's composer dependencies.| |`actionGroupArguments` | Checks that action groups do not have unused arguments.| |`deprecatedEntityUsage`| Checks that deprecated test entities are not being referenced.| +|`annotations`| Checks various details of test annotations, such as missing annotations or duplicate annotations.| #### Defining ruleset From 05a620f6852ac72584bf90ed120c5c692f308fe3 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 12 May 2020 15:40:30 -0500 Subject: [PATCH 381/888] MQE-2082: MFTF compatibility with 2fa --- dev/tests/verification/Resources/BasicFunctionalTest.txt | 1 + .../TestModule/Test/BasicFunctionalTest/BasicFunctionalTest.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/dev/tests/verification/Resources/BasicFunctionalTest.txt b/dev/tests/verification/Resources/BasicFunctionalTest.txt index d07d333a2..2a67888f6 100644 --- a/dev/tests/verification/Resources/BasicFunctionalTest.txt +++ b/dev/tests/verification/Resources/BasicFunctionalTest.txt @@ -112,6 +112,7 @@ class BasicFunctionalTestCest $date->setTimezone(new \DateTimeZone("UTC")); $generateDateKey2 = $date->format("H:i:s"); + $getOtp = $I->getOTP(); // stepKey: getOtp $grabAttributeFromKey1 = $I->grabAttributeFrom(".functionalTestSelector", "someInput"); // stepKey: grabAttributeFromKey1 $grabCookieKey1 = $I->grabCookie("grabCookieInput", ['domain' => 'www.google.com']); // stepKey: grabCookieKey1 $grabFromCurrentUrlKey1 = $I->grabFromCurrentUrl("/grabCurrentUrl"); // stepKey: grabFromCurrentUrlKey1 diff --git a/dev/tests/verification/TestModule/Test/BasicFunctionalTest/BasicFunctionalTest.xml b/dev/tests/verification/TestModule/Test/BasicFunctionalTest/BasicFunctionalTest.xml index 63c4857a0..81a43ca12 100644 --- a/dev/tests/verification/TestModule/Test/BasicFunctionalTest/BasicFunctionalTest.xml +++ b/dev/tests/verification/TestModule/Test/BasicFunctionalTest/BasicFunctionalTest.xml @@ -68,6 +68,7 @@ <fillField selector=".functionalTestSelector" userInput="0" stepKey="fillFieldKey2" /> <generateDate date="Now" format="H:i:s" stepKey="generateDateKey"/> <generateDate date="Now" format="H:i:s" stepKey="generateDateKey2" timezone="UTC"/> + <getOTP stepKey="getOtp"/> <grabAttributeFrom selector=".functionalTestSelector" userInput="someInput" stepKey="grabAttributeFromKey1" /> <grabCookie userInput="grabCookieInput" parameterArray="['domain' => 'www.google.com']" stepKey="grabCookieKey1" /> <grabFromCurrentUrl regex="/grabCurrentUrl" stepKey="grabFromCurrentUrlKey1" /> From 4343cc96007758993b9767eb7aa6c2a090907402 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 12 May 2020 16:58:13 -0500 Subject: [PATCH 382/888] MQE-2122: MFTF 2FA documentation --- docs/configure-2fa.md | 46 +++++++++++++++++++++++++++++++++++++++++ docs/getting-started.md | 4 ++++ docs/test/actions.md | 20 ++++++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 docs/configure-2fa.md diff --git a/docs/configure-2fa.md b/docs/configure-2fa.md new file mode 100644 index 000000000..16d63c4dd --- /dev/null +++ b/docs/configure-2fa.md @@ -0,0 +1,46 @@ +# MFTF Configuration for Magento with Two-Factor Authentication (2FA) + +## Configure Magento {#config-magento-2fa} + +To prepare Magento for MFTF testing when 2FA is enabled, set the following configurations through Magento CLI + +### Select `Google Authenticator` as Magento 2FA provider + +```bash +bin/magento config:set twofactorauth/general/force_providers google +``` + +### Set OTP window to `60` seconds + +```bash +bin/magento config:set twofactorauth/google/otp_window 60 +``` + +### Set a base32 encoded `secret` for `Google Authenticator` to generate OTP for the default admin user that you set for `MAGENTO_ADMIN_USERNAME` in .env. + +```bash +bin/magento security:tfa:google:set-secret <MAGENTO_ADMIN_USERNAME> <OTP_SHARED_SECRET> +``` + +## Configure MFTF {#config-mftf-2fa} + +Save the same base32 encoded `secret` in MFTF Credential Storages, e.g. `.credentials` file, `HashiCorp Vault` or `AWS Secrets Manager`. +More details [here](../credentials.md). + +The path of the `secret` should be: + +```conf +magento/tfa/OTP_SHARED_SECRET +``` + +## GetOTP {#getOTP} + +One-time password (OTP) is required when an admin user logs in to Magento Admin page. +Use action `getOTP` [Reference](../test/actions.md#getotp) to generate the code and use it for the `Authenticator code` text field in 2FA - Google Auth page. + +Note: +You will need to set the `secret` for any non default admin users first before using `getOTP`. For example + +```xml +<magentoCLI command="security:tfa:google:set-secret admin2 {{_CREDS.magento/tfa/OTP_SHARED_SECRET}}" stepKey="setSecret"/> +``` diff --git a/docs/getting-started.md b/docs/getting-started.md index 89d228df9..36ef03836 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -109,6 +109,9 @@ Clean the cache after changing the configuration values: bin/magento cache:clean config full_page ``` +### Testing with Magento Two-Factor Authentication (2FA) extension {#2fa} +If Magento under test has [Magento Two-Factor Authentication (2FA) extension][] installed and enabled, additional configures are needed to run MFTF tests. Learn more in [Configure MFTF for Magento with Two-Factor Authentication (2FA)](../configure-2fa.md). + ### Webserver configuration {#web-server-configuration} The MFTF does not support executing CLI commands if your web server points to `<MAGE_ROOT_DIR>/pub` directory as recommended in the [Installation Guide][Installation Guide docroot]. For the MFTF to execute the CLI commands, the web server must point to the Magento root directory. @@ -357,3 +360,4 @@ allure serve dev/tests/_output/allure-results/ [test suite]: suite.html [Find your MFTF version]: introduction.html#find-your-mftf-version [Installation Guide docroot]: https://devdocs.magento.com/guides/v2.3/install-gde/tutorials/change-docroot-to-pub.html +[Magento Two-Factor Authentication (2FA) extension]: https://devdocs.magento.com/guides/v2.3/security/two-factor-authentication.html \ No newline at end of file diff --git a/docs/test/actions.md b/docs/test/actions.md index 49e0c6afe..939f345df 100644 --- a/docs/test/actions.md +++ b/docs/test/actions.md @@ -150,6 +150,7 @@ The following test actions return a variable: * [grabTextFrom](#grabtextfrom) * [grabValueFrom](#grabvaluefrom) * [executeJS](#executejs) +* [getOTP](#getotp) Learn more in [Using data returned by test actions](../data.md#use-data-returned-by-test-actions). @@ -1072,6 +1073,25 @@ The `ProductAttributeOptionGetter` entity must be defined in the corresponding [ This action can optionally contain one or more [requiredEntity](#requiredentity) child elements. +### getOTP + +Generate one-time password (OTP) based on a saved `secret` at path `magento/tfa/OTP_SHARED_SECRET` in MFTF credential storages. +The one-time password (OTP) is returned and accessible through the stepkey. + +MFTF use TOTP from [Spomky-Labs/otphp](https://github.com/Spomky-Labs/otphp). + +Attribute|Type|Use|Description +---|---|---|--- +`stepKey`|string|required| A unique identifier of the action. +`before`|string|optional| `stepKey` of action that must be executed next. +`after`|string|optional| `stepKey` of preceding action. + +#### Example + +```xml +<getOTP stepKey="getOtp"/> +``` + ### grabAttributeFrom See [grabAttributeFrom docs on codeception.com](http://codeception.com/docs/modules/WebDriver#grabAttributeFrom). From 557b15439b3760b953f07ef566701d301d07b8ed Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 12 May 2020 17:19:17 -0500 Subject: [PATCH 383/888] MQE-2122: MFTF 2FA documentation --- docs/test/actions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/test/actions.md b/docs/test/actions.md index 939f345df..14201b7bf 100644 --- a/docs/test/actions.md +++ b/docs/test/actions.md @@ -1078,7 +1078,7 @@ This action can optionally contain one or more [requiredEntity](#requiredentity) Generate one-time password (OTP) based on a saved `secret` at path `magento/tfa/OTP_SHARED_SECRET` in MFTF credential storages. The one-time password (OTP) is returned and accessible through the stepkey. -MFTF use TOTP from [Spomky-Labs/otphp](https://github.com/Spomky-Labs/otphp). +MFTF use TOTP from [Spomky-Labs/otphp](https://github.com/Spomky-Labs/otphp) if you want to know about this action. Attribute|Type|Use|Description ---|---|---|--- From 1ddc783f2e0d5ec756c56f81f980eb3f899b4acb Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Tue, 12 May 2020 18:37:59 -0500 Subject: [PATCH 384/888] Grammar and formatting --- docs/configure-2fa.md | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/docs/configure-2fa.md b/docs/configure-2fa.md index 16d63c4dd..ed3e3d27f 100644 --- a/docs/configure-2fa.md +++ b/docs/configure-2fa.md @@ -1,31 +1,34 @@ -# MFTF Configuration for Magento with Two-Factor Authentication (2FA) +# Configuring MFTF for Two-Factor Authentication (2FA) + +Using two-factor authentication (2FA) with MFTF is possible with some configurations settings in Magento. +In this document, we will use Google as the authentication provider. ## Configure Magento {#config-magento-2fa} -To prepare Magento for MFTF testing when 2FA is enabled, set the following configurations through Magento CLI +To prepare Magento for MFTF testing when 2FA is enabled, set the following configurations through the Magento CLI. -### Select `Google Authenticator` as Magento 2FA provider +First, select `Google Authenticator` as Magento's 2FA provider: ```bash bin/magento config:set twofactorauth/general/force_providers google ``` -### Set OTP window to `60` seconds +Now set the OTP window to `60` seconds: ```bash bin/magento config:set twofactorauth/google/otp_window 60 ``` -### Set a base32 encoded `secret` for `Google Authenticator` to generate OTP for the default admin user that you set for `MAGENTO_ADMIN_USERNAME` in .env. +Set a base32-encoded `secret` for `Google Authenticator` to generate a OTP for the default admin user that you set for `MAGENTO_ADMIN_USERNAME` in `.env`: ```bash bin/magento security:tfa:google:set-secret <MAGENTO_ADMIN_USERNAME> <OTP_SHARED_SECRET> ``` -## Configure MFTF {#config-mftf-2fa} +## Configure the MFTF {#config-mftf-2fa} -Save the same base32 encoded `secret` in MFTF Credential Storages, e.g. `.credentials` file, `HashiCorp Vault` or `AWS Secrets Manager`. -More details [here](../credentials.md). +Save the same base32-encoded `secret` in a MFTF credential storage, e.g. `.credentials` file, `HashiCorp Vault` or `AWS Secrets Manager`. +More details are [here](../credentials.md). The path of the `secret` should be: @@ -35,11 +38,11 @@ magento/tfa/OTP_SHARED_SECRET ## GetOTP {#getOTP} -One-time password (OTP) is required when an admin user logs in to Magento Admin page. -Use action `getOTP` [Reference](../test/actions.md#getotp) to generate the code and use it for the `Authenticator code` text field in 2FA - Google Auth page. +A one-time password (OTP) is required when an admin user logs into the Magento admin. +Use the action `getOTP` [Reference](../test/actions.md#getotp) to generate the code and use it for the `Authenticator code` text field in 2FA - Google Auth page. Note: -You will need to set the `secret` for any non default admin users first before using `getOTP`. For example +You will need to set the `secret` for any non-default admin users first, before using `getOTP`. For example: ```xml <magentoCLI command="security:tfa:google:set-secret admin2 {{_CREDS.magento/tfa/OTP_SHARED_SECRET}}" stepKey="setSecret"/> From dc71ad43ec51d931f219b3d31ec99eb291793aef Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Tue, 12 May 2020 18:39:59 -0500 Subject: [PATCH 385/888] Grammar and formatting --- docs/getting-started.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 36ef03836..99b8f197e 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -109,8 +109,9 @@ Clean the cache after changing the configuration values: bin/magento cache:clean config full_page ``` -### Testing with Magento Two-Factor Authentication (2FA) extension {#2fa} -If Magento under test has [Magento Two-Factor Authentication (2FA) extension][] installed and enabled, additional configures are needed to run MFTF tests. Learn more in [Configure MFTF for Magento with Two-Factor Authentication (2FA)](../configure-2fa.md). +### Testing with the Magento Two-Factor Authentication (2FA) extension {#2fa} + +If the Magento instance under test has the [Magento Two-Factor Authentication (2FA) extension][] installed and enabled, additional configurations is needed to run MFTF tests. Learn more in [Configure MFTF for Magento with Two-Factor Authentication (2FA)](./configure-2fa.md). ### Webserver configuration {#web-server-configuration} @@ -360,4 +361,4 @@ allure serve dev/tests/_output/allure-results/ [test suite]: suite.html [Find your MFTF version]: introduction.html#find-your-mftf-version [Installation Guide docroot]: https://devdocs.magento.com/guides/v2.3/install-gde/tutorials/change-docroot-to-pub.html -[Magento Two-Factor Authentication (2FA) extension]: https://devdocs.magento.com/guides/v2.3/security/two-factor-authentication.html \ No newline at end of file +[Magento Two-Factor Authentication (2FA) extension]: https://devdocs.magento.com/guides/v2.3/security/two-factor-authentication.html From 97e4d1fbf26727c14c44929cc80f450ca5a5238d Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Tue, 12 May 2020 18:41:38 -0500 Subject: [PATCH 386/888] Editorial pass --- docs/test/actions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/test/actions.md b/docs/test/actions.md index 14201b7bf..1d2f83802 100644 --- a/docs/test/actions.md +++ b/docs/test/actions.md @@ -1075,10 +1075,10 @@ This action can optionally contain one or more [requiredEntity](#requiredentity) ### getOTP -Generate one-time password (OTP) based on a saved `secret` at path `magento/tfa/OTP_SHARED_SECRET` in MFTF credential storages. +Generate a one-time password (OTP) based on a saved `secret` at path `magento/tfa/OTP_SHARED_SECRET` in a MFTF credential storage. The one-time password (OTP) is returned and accessible through the stepkey. -MFTF use TOTP from [Spomky-Labs/otphp](https://github.com/Spomky-Labs/otphp) if you want to know about this action. +MFTF use TOTP from [Spomky-Labs/otphp](https://github.com/Spomky-Labs/otphp), if you want to learn more about this action. Attribute|Type|Use|Description ---|---|---|--- From b73d01b8d441e247cdca61946de0f160bda51310 Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Tue, 12 May 2020 18:44:57 -0500 Subject: [PATCH 387/888] Fixed link paths --- docs/configure-2fa.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/configure-2fa.md b/docs/configure-2fa.md index ed3e3d27f..f50838f0c 100644 --- a/docs/configure-2fa.md +++ b/docs/configure-2fa.md @@ -28,7 +28,7 @@ bin/magento security:tfa:google:set-secret <MAGENTO_ADMIN_USERNAME> <OTP_SHARED_ ## Configure the MFTF {#config-mftf-2fa} Save the same base32-encoded `secret` in a MFTF credential storage, e.g. `.credentials` file, `HashiCorp Vault` or `AWS Secrets Manager`. -More details are [here](../credentials.md). +More details are [here](./credentials.md). The path of the `secret` should be: @@ -39,7 +39,7 @@ magento/tfa/OTP_SHARED_SECRET ## GetOTP {#getOTP} A one-time password (OTP) is required when an admin user logs into the Magento admin. -Use the action `getOTP` [Reference](../test/actions.md#getotp) to generate the code and use it for the `Authenticator code` text field in 2FA - Google Auth page. +Use the action `getOTP` [Reference](./test/actions.md#getotp) to generate the code and use it for the `Authenticator code` text field in 2FA - Google Auth page. Note: You will need to set the `secret` for any non-default admin users first, before using `getOTP`. For example: From f8ac3d20007c5c19c2f21ca493f3a917d13907fc Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Wed, 13 May 2020 11:20:47 -0500 Subject: [PATCH 388/888] MQE-2126: Can't modify DataEntity data --- .../DevDocs/Data/DeprecatedMessageData.xml | 3 +++ .../MFTF/DevDocs/Data/ExtendMessageData.xml | 16 +++++++++++ .../tests/MFTF/DevDocs/Data/MessageData.xml | 6 +++++ .../tests/MFTF/DevDocs/Test/DevDocsTest.xml | 1 + etc/di.xml | 1 + .../DataGenerator/etc/dataProfileSchema.xsd | 27 ++++++++++++++----- 6 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 dev/tests/functional/tests/MFTF/DevDocs/Data/ExtendMessageData.xml diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Data/DeprecatedMessageData.xml b/dev/tests/functional/tests/MFTF/DevDocs/Data/DeprecatedMessageData.xml index 1c2462c2f..ba1460a60 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Data/DeprecatedMessageData.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/Data/DeprecatedMessageData.xml @@ -11,4 +11,7 @@ <entity name="DeprecatedMessageData" deprecated="Entity is deprecated. Please use 'MessageData'."> <data key="message">Introduction to the Magento Functional Testing Framework</data> </entity> + <entity name="MessageData"> + <data key="justSomeField">Some data</data> + </entity> </entities> diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Data/ExtendMessageData.xml b/dev/tests/functional/tests/MFTF/DevDocs/Data/ExtendMessageData.xml new file mode 100644 index 000000000..040b80597 --- /dev/null +++ b/dev/tests/functional/tests/MFTF/DevDocs/Data/ExtendMessageData.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="MessageData"> + <array key="numbers"> + <item>Something New</item> + </array> + </entity> +</entities> diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Data/MessageData.xml b/dev/tests/functional/tests/MFTF/DevDocs/Data/MessageData.xml index 9c34b5672..2b9d3a520 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Data/MessageData.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/Data/MessageData.xml @@ -10,5 +10,11 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> <entity name="MessageData"> <data key="message">Introduction to the Magento Functional Testing Framework</data> + <array key="numbers"> + <item name="zero">0</item> + <item name="one">1</item> + <item name="two">2</item> + <item name="three">3</item> + </array> </entity> </entities> diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml b/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml index 3470a2440..3ac6c4c3a 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml @@ -46,5 +46,6 @@ <argument name="test" value="{{HelperData.entityField}}" /> <argument name="entityTest" value="HelperData" /> </actionGroup> + <comment userInput="{{MessageData.numbers}}" stepKey="outputMergedArray" /> </test> </tests> diff --git a/etc/di.xml b/etc/di.xml index f6a89fcb0..1d331e32b 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -157,6 +157,7 @@ <argument name="idAttributes" xsi:type="array"> <item name="/entities/entity" xsi:type="string">name</item> <item name="/entities/entity/(data|array)" xsi:type="string">key</item> + <item name="/entities/entity/array/item" xsi:type="string">name</item> <item name="/entities/entity/requiredEntity" xsi:type="string">type</item> </argument> <argument name="mergeablePaths" xsi:type="array"> diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd b/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd index 9d0d8bb35..923f7c48f 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd @@ -118,17 +118,32 @@ <xs:complexType name="arrayType"> <xs:sequence> - <xs:element name="item" type="xs:string" maxOccurs="unbounded" minOccurs="0"> - <xs:annotation> - <xs:documentation> - Individual piece of data to be passed in as part of the parrent array type. - </xs:documentation> - </xs:annotation> + <xs:element name="item" type="itemType" maxOccurs="unbounded" minOccurs="0"> + <xs:annotation> + <xs:documentation> + Individual piece of data to be passed in as part of the parrent array type. + </xs:documentation> + </xs:annotation> </xs:element> </xs:sequence> <xs:attribute type="xs:string" name="key" use="required"/> </xs:complexType> + + <xs:complexType name="itemType"> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute type="xs:string" name="name" use="optional"> + <xs:annotation> + <xs:documentation> + Key attribute of item pair. + </xs:documentation> + </xs:annotation> + </xs:attribute> + </xs:extension> + </xs:simpleContent> + </xs:complexType> + <xs:complexType name="requiredEntityType"> <xs:simpleContent> <xs:extension base="xs:string"> From 56d8288e72463df47f39578104e15be6c24da7c7 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Wed, 13 May 2020 13:16:53 -0500 Subject: [PATCH 389/888] MQE-2126: Can't modify DataEntity data --- .../DataGenerator/Config/Dom.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Config/Dom.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Config/Dom.php index d4b8f7c8f..ab55b0a63 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Config/Dom.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Config/Dom.php @@ -81,6 +81,13 @@ public function initDom($xml, $filename = null) } } + $itemNodes = $dom->getElementsByTagName('item'); + foreach ($itemNodes as $itemKey => $itemNode) { + if ($itemNode->hasAttribute("name") === false) { + $itemNode->setAttribute("name", (string)$itemKey); + } + } + return $dom; } } From cfbc5c0204972f944a754aaae54fe096d658ca8a Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Wed, 13 May 2020 14:22:50 -0500 Subject: [PATCH 390/888] MQE-2126: Can't modify DataEntity data --- src/Magento/FunctionalTestingFramework/Config/Dom.php | 4 ++-- .../FunctionalTestingFramework/DataGenerator/Config/Dom.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Config/Dom.php b/src/Magento/FunctionalTestingFramework/Config/Dom.php index 6d10811ca..881b677dc 100644 --- a/src/Magento/FunctionalTestingFramework/Config/Dom.php +++ b/src/Magento/FunctionalTestingFramework/Config/Dom.php @@ -246,8 +246,8 @@ protected function getNodePathByParent(\DOMElement $node, $parentPath) $idAttribute = $this->nodeMergingConfig->getIdAttribute($path); if ($idAttribute) { foreach (explode('|', $idAttribute) as $idAttributeValue) { - if ($value = $node->getAttribute($idAttributeValue)) { - $path .= "[@{$idAttributeValue}='{$value}']"; + if ($node->hasAttribute($idAttributeValue)) { + $path .= "[@{$idAttributeValue}='" . $node->getAttribute($idAttributeValue) . "']"; break; } } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Config/Dom.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Config/Dom.php index ab55b0a63..bc19c35aa 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Config/Dom.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Config/Dom.php @@ -82,12 +82,12 @@ public function initDom($xml, $filename = null) } $itemNodes = $dom->getElementsByTagName('item'); + /** @var \DOMElement $itemNode */ foreach ($itemNodes as $itemKey => $itemNode) { - if ($itemNode->hasAttribute("name") === false) { + if ($itemNode->hasAttribute("name") == false) { $itemNode->setAttribute("name", (string)$itemKey); } } - return $dom; } } From c1aa91822a7ad5c56cd5743170bbfd9ac8009d15 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Wed, 13 May 2020 14:29:59 -0500 Subject: [PATCH 391/888] MQE-2126: Can't modify DataEntity data - code review updates --- .../functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml | 6 +++++- docs/data.md | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml b/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml index 3ac6c4c3a..02d6481a8 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml @@ -46,6 +46,10 @@ <argument name="test" value="{{HelperData.entityField}}" /> <argument name="entityTest" value="HelperData" /> </actionGroup> - <comment userInput="{{MessageData.numbers}}" stepKey="outputMergedArray" /> + + <assertEqualsCanonicalizing stepKey="assertMergedArray"> + <actualResult type="array">{{MessageData.numbers}}</actualResult> + <expectedResult type="array">["Something New", "0", "1", "2", "3"]</expectedResult> + </assertEqualsCanonicalizing> </test> </tests> diff --git a/docs/data.md b/docs/data.md index fa4c90dcf..8b0a86e3d 100644 --- a/docs/data.md +++ b/docs/data.md @@ -276,6 +276,11 @@ Attributes|Type|Use|Description `<item>` is an individual piece of data to be passed in as part of the parent `<array>` type. +Attributes|Type|Use|Description +---|---|---|--- +`name`|string|optional|Key attribute of <item/> entity in which to assign a value. By default numeric key will be generated. + + <!-- Link Definitions --> [`<array>`]: #array-tag [`<data>`]: #data-tag From 8a6bbba89656afe374583309246946b8fffcb8ae Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Thu, 14 May 2020 11:56:34 -0500 Subject: [PATCH 392/888] MQE-2131: Chrome 75+ requires unhandledPromptBehavior driver capability --- etc/config/functional.suite.dist.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/etc/config/functional.suite.dist.yml b/etc/config/functional.suite.dist.yml index ffbb60990..78411f37f 100644 --- a/etc/config/functional.suite.dist.yml +++ b/etc/config/functional.suite.dist.yml @@ -34,5 +34,6 @@ modules: protocol: "%SELENIUM_PROTOCOL%" path: "%SELENIUM_PATH%" capabilities: + unhandledPromptBehavior: "ignore" chromeOptions: args: ["--window-size=1280,1024", "--disable-extensions", "--enable-automation", "--disable-gpu", "--enable-Passthrough"] From 9adfe92b9f09fc8d8ba5b6cc4651ad33aab877ce Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 14 May 2020 15:57:46 -0500 Subject: [PATCH 393/888] MQE-2129: Error creating data entity due to decryption error --- .../Handlers/PersistedObjectHandler.php | 38 +++++++++++++------ 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php index 927c0ab4e..8d0f9c92d 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php @@ -86,17 +86,6 @@ public function createEntity( foreach ($dependentObjectKeys as $objectKey) { $retrievedDependentObjects[] = $this->retrieveEntity($objectKey, $scope); } - - foreach ($overrideFields as $index => $field) { - try { - $decrptedField = CredentialStore::getInstance()->decryptAllSecretsInString($field); - if ($decrptedField !== false) { - $overrideFields[$index] = $decrptedField; - } - } catch (TestFrameworkException $e) { - //catch exception if Credentials are not defined - } - } $retrievedEntity = DataObjectHandler::getInstance()->getObject($entity); @@ -107,6 +96,8 @@ public function createEntity( ); } + $overrideFields = $this->resolveOverrideFields($overrideFields); + $persistedObject = new DataPersistenceHandler( $retrievedEntity, $retrievedDependentObjects, @@ -262,4 +253,29 @@ public function clearSuiteObjects() { $this->suiteObjects = []; } + + /** + * Resolve secret values in $overrideFields + * + * @param array $overrideFields + * @return array + */ + private function resolveOverrideFields($overrideFields) + { + foreach ($overrideFields as $index => $field) { + if (is_array($field)) { + $overrideFields[$index] = $this->resolveOverrideFields($field); + } else { + try { + $decrptedField = CredentialStore::getInstance()->decryptAllSecretsInString($field); + if ($decrptedField !== false) { + $overrideFields[$index] = $decrptedField; + } + } catch (TestFrameworkException $e) { + //catch exception if Credentials are not defined + } + } + } + return $overrideFields; + } } From 85580a81cfdd98da182a8fdb103edec1a5308c62 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 14 May 2020 18:00:42 -0500 Subject: [PATCH 394/888] MQE-2129: Error creating data entity due to decryption error --- .../DataGenerator/Handlers/PersistedObjectHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php index 8d0f9c92d..49da76697 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php @@ -265,7 +265,7 @@ private function resolveOverrideFields($overrideFields) foreach ($overrideFields as $index => $field) { if (is_array($field)) { $overrideFields[$index] = $this->resolveOverrideFields($field); - } else { + } elseif (is_string($field)) { try { $decrptedField = CredentialStore::getInstance()->decryptAllSecretsInString($field); if ($decrptedField !== false) { From 369cb63cb50901507e34af0697ded7f74aa47424 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Thu, 14 May 2020 17:18:40 -0500 Subject: [PATCH 395/888] MQE-2130: All PayPal SmartButton tests fail with error even though they are skipped --- .../Helper/HelperContainer.php | 25 +++++++++++++------ .../Helper/views/TestInjectMethod.mustache | 16 +++++------- .../ObjectManager/ObjectHandlerInterface.php | 2 +- .../Suite/Generators/GroupClassGenerator.php | 6 ++++- .../Suite/views/SuiteClass.mustache | 13 ++++++++++ 5 files changed, 43 insertions(+), 19 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Helper/HelperContainer.php b/src/Magento/FunctionalTestingFramework/Helper/HelperContainer.php index 83a71fbc0..f3b5852b8 100644 --- a/src/Magento/FunctionalTestingFramework/Helper/HelperContainer.php +++ b/src/Magento/FunctionalTestingFramework/Helper/HelperContainer.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types = 1); namespace Magento\FunctionalTestingFramework\Helper; @@ -11,7 +12,7 @@ /** * Class HelperContainer */ -class HelperContainer +class HelperContainer extends \Codeception\Module { /** * @var Helper[] @@ -19,12 +20,22 @@ class HelperContainer private $helpers = []; /** - * HelperContainer constructor. - * @param array $helpers + * Create custom helper class. + * + * @param string $helperClass + * @return Helper + * @throws \Exception */ - public function __construct(array $helpers = []) + public function create(string $helperClass): Helper { - $this->helpers = $helpers; + if (get_parent_class($helperClass) !== Helper::class) { + throw new \Exception("Helper class must extend " . Helper::class); + } + if (!isset($this->helpers[$helperClass])) { + $this->helpers[$helperClass] = $this->moduleContainer->create($helperClass); + } + + return $this->helpers[$helperClass]; } /** @@ -34,7 +45,7 @@ public function __construct(array $helpers = []) * @return Helper * @throws TestFrameworkException */ - public function get(string $className) + public function get(string $className): Helper { if ($this->has($className)) { return $this->helpers[$className]; @@ -48,7 +59,7 @@ public function get(string $className) * @param string $className * @return boolean */ - public function has(string $className) + public function has(string $className): bool { return array_key_exists($className, $this->helpers); } diff --git a/src/Magento/FunctionalTestingFramework/Helper/views/TestInjectMethod.mustache b/src/Magento/FunctionalTestingFramework/Helper/views/TestInjectMethod.mustache index d921120cf..36f2f8bf6 100644 --- a/src/Magento/FunctionalTestingFramework/Helper/views/TestInjectMethod.mustache +++ b/src/Magento/FunctionalTestingFramework/Helper/views/TestInjectMethod.mustache @@ -6,14 +6,10 @@ /** * Special method which automatically creates the respective objects. */ - public function _inject( - {{argumentsWithTypes}} - ) { - $this->helperContainer = new \Magento\FunctionalTestingFramework\Helper\HelperContainer( - [ - {{#arguments}} - '{{type}}' => {{var}}, - {{/arguments}} - ] - ); + public function _inject(\Magento\FunctionalTestingFramework\Helper\HelperContainer $helperContainer) + { + $this->helperContainer = $helperContainer; + {{#arguments}} + $this->helperContainer->create("{{type}}"); + {{/arguments}} } diff --git a/src/Magento/FunctionalTestingFramework/ObjectManager/ObjectHandlerInterface.php b/src/Magento/FunctionalTestingFramework/ObjectManager/ObjectHandlerInterface.php index 94147dc08..8bde3b96d 100644 --- a/src/Magento/FunctionalTestingFramework/ObjectManager/ObjectHandlerInterface.php +++ b/src/Magento/FunctionalTestingFramework/ObjectManager/ObjectHandlerInterface.php @@ -24,7 +24,7 @@ public static function getInstance(); * Function to return a single object by name * * @param string $objectName - * @return object + * @return mixed */ public function getObject($objectName); diff --git a/src/Magento/FunctionalTestingFramework/Suite/Generators/GroupClassGenerator.php b/src/Magento/FunctionalTestingFramework/Suite/Generators/GroupClassGenerator.php index 415d884b6..67930f09a 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Generators/GroupClassGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Generators/GroupClassGenerator.php @@ -131,14 +131,18 @@ private function buildHookMustacheArray($hookObj) { $actions = []; $mustacheHookArray['actions'][] = ['webDriverInit' => true]; + $mustacheHookArray['helpers'] = []; foreach ($hookObj->getActions() as $action) { /** @var ActionObject $action */ $index = count($actions); + if ($action->getType() === ActionObject::ACTION_TYPE_HELPER) { + $mustacheHookArray['helpers'][] = $action->getCustomActionAttributes()['class']; + } //deleteData contains either url or createDataKey, if it contains the former it needs special formatting if ($action->getType() !== "createData" && !array_key_exists(TestGenerator::REQUIRED_ENTITY_REFERENCE, $action->getCustomActionAttributes())) { - $actions = $this->buildWebDriverActionsMustacheArray($action, $actions, $index); + $actions = $this->buildWebDriverActionsMustacheArray($action, $actions); continue; } diff --git a/src/Magento/FunctionalTestingFramework/Suite/views/SuiteClass.mustache b/src/Magento/FunctionalTestingFramework/Suite/views/SuiteClass.mustache index b98405c03..0e60437ee 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/views/SuiteClass.mustache +++ b/src/Magento/FunctionalTestingFramework/Suite/views/SuiteClass.mustache @@ -20,12 +20,25 @@ class {{suiteName}} extends \Codeception\GroupObject private $testCount = {{testCount}}; private $preconditionFailure = null; private $currentTestRun = 0; + {{#helpers}} + /** + * @var \Magento\FunctionalTestingFramework\Helper\HelperContainer $helperContainer + */ + private $helperContainer; + {{/helpers}} private static $HOOK_EXECUTION_INIT = "\n/******** Beginning execution of {{suiteName}} suite %s block ********/\n"; private static $HOOK_EXECUTION_END = "\n/******** Execution of {{suiteName}} suite %s block complete ********/\n"; {{#before}} public function _before(\Codeception\Event\TestEvent $e) { + {{#helpers}} + /** @var \Magento\FunctionalTestingFramework\Helper\HelperContainer $helperContainer */ + $this->helperContainer = $this->getModule('\Magento\FunctionalTestingFramework\Helper\HelperContainer'); + {{/helpers}} + {{#helpers}} + $this->helperContainer->create("{{ . }}"); + {{/helpers}} // increment test count per execution $this->currentTestRun++; $this->executePreConditions(); From 657aabbc7bcfc8f0e8707db14dbd8e784fe092db Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Tue, 19 May 2020 11:35:59 -0500 Subject: [PATCH 396/888] Grammar and formatting --- docs/data.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data.md b/docs/data.md index 31aa1ac97..834a0402a 100644 --- a/docs/data.md +++ b/docs/data.md @@ -7,7 +7,7 @@ The following diagram shows the XML structure of an MFTF data object: <!-- {% raw %} --> -The MFTF `<data>` entities are stored in the following directory <module_dir>/Test/Mftf/Data/ +The MFTF `<data>` entities are stored in `<module_dir>/Test/Mftf/Data/`. ## Supply data to test by reference to a data entity From df5a57e4cb58e42c390b44d144935245e15eee48 Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Tue, 19 May 2020 11:59:38 -0500 Subject: [PATCH 397/888] MQE-2117: CHANGELOG.MD and Composer version bump (#709) * MQE-2117: CHANGELOG.MD and Composer version bump updated changelog * MQE-2117: CHANGELOG.MD and Composer version bump fixed formatting * MQE-2117: CHANGELOG.MD and Composer version bump fixed formatting --- CHANGELOG.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8b6a20e1..0ed2920f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ Magento Functional Testing Framework Changelog ================================================ +3.0.0 RC3 +--------- + +### Enhancements + +* Maintainability + * Added support for Two-Factor Authentication (2FA). [See configure-2fa page for details](./docs/configure-2fa.md) + * Added new static check `annotationsCheck` that checks and reports missing annotations in tests. + * Updated `mftf static-checks` command to allow executing static-checks defined in `staticRuleSet.json` by default. [See command page for details](./docs/commands/mftf.md#static-checks) + * Added new upgrade script to remove unused arguments from action groups. + * Added unhandledPromptBehavior driver capability for Chrome 75+ support. + * Removed redundant and unused classes. + +### Fixes + +* Fixed issue with custom helper usage in suites. +* Fixed issue with decryption of secrets during data entity creation. +* Fixed issue with merging of `array` items in data entity. + 3.0.0 RC2 --------- From 916661452ece8e2381e18eee5297a3b84d8e8e62 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Tue, 19 May 2020 12:33:15 -0500 Subject: [PATCH 398/888] MQE-2130: All PayPal SmartButton tests fail with error even though they are skipped --- etc/config/functional.suite.dist.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/etc/config/functional.suite.dist.yml b/etc/config/functional.suite.dist.yml index 78411f37f..0ffc7af58 100644 --- a/etc/config/functional.suite.dist.yml +++ b/etc/config/functional.suite.dist.yml @@ -16,6 +16,7 @@ modules: - \Magento\FunctionalTestingFramework\Module\MagentoAssert - \Magento\FunctionalTestingFramework\Module\MagentoActionProxies - Asserts + - \Magento\FunctionalTestingFramework\Helper\HelperContainer config: \Magento\FunctionalTestingFramework\Module\MagentoWebDriver: url: "%MAGENTO_BASE_URL%" @@ -34,6 +35,6 @@ modules: protocol: "%SELENIUM_PROTOCOL%" path: "%SELENIUM_PATH%" capabilities: - unhandledPromptBehavior: "ignore" - chromeOptions: - args: ["--window-size=1280,1024", "--disable-extensions", "--enable-automation", "--disable-gpu", "--enable-Passthrough"] + unhandledPromptBehavior: "ignore" + chromeOptions: + args: ["--window-size=1280,1024", "--disable-extensions", "--enable-automation", "--disable-gpu", "--enable-Passthrough"] From 9505f04a011c1d68b905d8472fcf8c21aabb8c74 Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Fri, 22 May 2020 12:57:20 -0500 Subject: [PATCH 399/888] =?UTF-8?q?MQE-2138:=20Annotation=20static=20check?= =?UTF-8?q?=20incorrectly=20flags=20some=20extends=20test=E2=80=A6=20(#713?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * MQE-2138: Annotation static check incorrectly flags some extends tests for missing issueIds * MQE-2138: annotation static check incorrectly flags some extends tests for missing issueIds Co-authored-by: Ji Lu <jilu1@adobe.com> --- .../StaticCheck/AnnotationsCheck.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php index 86cbec2db..6d415b52d 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php @@ -70,8 +70,11 @@ public function execute(InputInterface $input) $allTests = TestObjectHandler::getInstance(false)->getAllObjects(); foreach ($allTests as $test) { + if ($this->validateSkipIssueId($test)) { + //if test is skipped ignore other checks + continue; + } $this->validateRequiredAnnotations($test); - $this->validateSkipIssueId($test); $this->aggregateStoriesTitlePairs($test); $this->aggregateTestCaseIdTitlePairs($test); } @@ -150,19 +153,22 @@ private function validateRequiredAnnotations($test) * Validates that if the test is skipped, that it has an issueId value. * * @param TestObject $test - * @return void + * @return boolean */ private function validateSkipIssueId($test) { + $validateSkipped = false; $annotations = $test->getAnnotations(); $skip = $annotations['skip'] ?? null; if ($skip !== null) { - $issueId = $skip[0] ?? null; - if ($issueId === null || strlen($issueId) == 0) { + $validateSkipped = true; + if ((!isset($skip[0]) || strlen($skip[0]) == 0) + && (!isset($skip['issueId']) || strlen($skip['issueId']) == 0)) { $this->errors[][] = "Test {$test->getName()} is skipped but the issueId is empty."; } } + return $validateSkipped; } /** From cbf369428c329929def23f490d9fce2c72057eb1 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Fri, 22 May 2020 14:08:47 -0500 Subject: [PATCH 400/888] Update functional.suite.dist.yml --- etc/config/functional.suite.dist.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/config/functional.suite.dist.yml b/etc/config/functional.suite.dist.yml index 0ffc7af58..726c9674a 100644 --- a/etc/config/functional.suite.dist.yml +++ b/etc/config/functional.suite.dist.yml @@ -37,4 +37,4 @@ modules: capabilities: unhandledPromptBehavior: "ignore" chromeOptions: - args: ["--window-size=1280,1024", "--disable-extensions", "--enable-automation", "--disable-gpu", "--enable-Passthrough"] + args: ["--window-size=1280,1024", "--disable-extensions", "--enable-automation", "--disable-gpu", "--enable-Passthrough", "--disable-dev-shm-usage"] From f11b3f5c4d58b99cdc90c75763b9e94613d853cb Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Tue, 26 May 2020 17:08:15 -0500 Subject: [PATCH 401/888] MQE-2141: MFTF BIC Documentation --- docs/backward-incompatible-changes.md | 151 ++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 docs/backward-incompatible-changes.md diff --git a/docs/backward-incompatible-changes.md b/docs/backward-incompatible-changes.md new file mode 100644 index 000000000..500f4883a --- /dev/null +++ b/docs/backward-incompatible-changes.md @@ -0,0 +1,151 @@ +# MFTF 3.0.0 backward incompatible changes + +This page highlights backward incompatible changes between releases that have a major impact and require detailed explanation and special instructions to ensure third-party tests continue working with Magento core tests. + +## Version requirement changes + +We changed the minimum PHP version requirement from 7.0 to 7.3. Because of the PHP version requirement change, this MFTF version supports only Magento 2.4 or later. + +## Folder structure changes + +We removed support to read test modules from deprecated path `dev/tests/acceptance/tests/functional/Magento/FunctionalTest`. If there are test modules in this path, they would need to be moved to `dev/tests/acceptance/tests/functional/Magento`. + +## XSD schema changes + +- Files under test modules `ActionGroup`, `Page`, `Section`, `Test` and `Suite` support only a single entity per file. + +- `file` attribute from `<module>` has been removed from suite schema. `<module file=""/>` is no longer supported in suites. + +- Metadata filename format changed to ***`*Meta.xml`***. + +- Only nested assertion syntax will be supported. [See assertions page for details](./docs/test/assertions.md). Here is an example of a nested assertion syntax. +```xml +<assertEquals stepKey="assertAddressOrderPage"> + <actualResult type="const">$billingAddressOrderPage</actualResult> + <expectedResult type="const">$shippingAddressOrderPage</expectedResult> +</assertEquals> +``` +### Upgrading tests to new schema + +The following table lists the upgrade scripts that are available to upgrade tests to the new schema. + +| Script name | Description | +|-----------------------|-----------------------------------------------------------------------------------------------------------| +|`splitMultipleEntitiesFiles`| Splits files that have multiple entities into multiple files with one entity per file. | +|`upgradeAssertionSchema`| Updates assert actions that use old assertion syntax to new nested syntax.| +|`renameMetadataFiles`| Renames Metadata filenames to `*Meta.xml`.| +|`removeModuleFileInSuiteFiles`| Removes occurrences of `<module file=""/>` from all `<suite>`s.| +|`removeUnusedArguments`| Removes unused arguments from action groups.| +|`upgradeTestSchema`| Replaces relative schema paths to URN in test files.| + +Here's how you can upgrade tests: + +- Run `bin/mftf reset --hard` to remove old generated configurations. +- Run `bin/mftf build:project` to generate new configurations. +- Run `bin/mftf upgrade:tests`. [See command page for details](./docs/commands/mftf.md#upgradetests). +- Lastly, try to generate all tests. Tests should all be generated as a result of the upgrades. If not, the most likely issue will be a changed XML schema. Check error messaging and search your codebase for the attributes listed. + +## MFTF commands + +`--debug` option `NONE` removed for strict schema validation. Ensure there are no schema validation errors in test modules before running MFTF commands. + +## MFTF actions + +###`executeInSelenium` and `performOn` removed + +**Action**: Deprecated actions `executeInSelenium` and `performOn` are removed in favor of new action `helper`. + +**Reason**: `executeInSelenium` and `performOn` allowed custom PHP code to be written inline inside of XML files which was difficult to maintain, troubleshoot, and modify. + +**Details**: `helper` will allow test writers to solve advanced requirements beyond what MFTF offers out of the box.[See custom-helpers](./docs/custom-helpers.md) for more information on the usage. + +Here's an example of using `helper` instead of `executeSelenium` to achieve same workflow. + +Old usage: +```xml +<executeInSelenium function="function ($webdriver) use ($I) { + $heading = $webdriver->findElement(\Facebook\WebDriver\WebDriverBy::xpath('//div[contains(@class, \'inline-wysiwyg\')]//h2')); + $actions = new \Facebook\WebDriver\Interactions\WebDriverActions($webdriver); + $actions->moveToElement($heading, {{TinyMCEPartialHeadingSelection.startX}}, {{TinyMCEPartialHeadingSelection.startY}}) + ->clickAndHold() + ->moveToElement($heading, {{TinyMCEPartialHeadingSelection.endX}}, {{TinyMCEPartialHeadingSelection.endY}}) + ->release() + ->perform(); + }" stepKey="selectHeadingTextInTinyMCE"/> +``` + +New usage: +```xml +<helper class="\Magento\PageBuilder\Test\Mftf\Helper\SelectText" method="selectText" stepKey="selectHeadingTextInTinyMCE"> + <argument name="context">//div[contains(@class, 'inline-wysiwyg')]//h2</argument> + <argument name="startX">{{TinyMCEPartialHeadingSelection.startX}}</argument> + <argument name="startY">{{TinyMCEPartialHeadingSelection.startY}}</argument> + <argument name="endX">{{TinyMCEPartialHeadingSelection.endX}}</argument> + <argument name="endY">{{TinyMCEPartialHeadingSelection.endY}}</argument> +</helper> +``` +### `pauseExecution` removed + +**Action**: `pauseExecution` is removed in favor of `pause`. + +**Reason**: `[WebDriver]pauseExecution` is removed in Codeception 3 in favor of `I->pause()`. + +**Description**: [See actions page for details](./docs/test/actions.md#pause). Here's a usage example. +```xml +<pause stepKey="pauseExecutionKey"/> +``` + +### Removed assert actions + +**Action**: Assert actions `assertInternalType`, `assertNotInternalType` and `assertArraySubset` are removed. + +**Reason**: PHPUnit 9 has dropped support for these assertions. + +### Updated assert actions + +**Action**: `delta` attribute has been removed from `assertEquals` and `assertNotEquals`. Instead, below assert actions have been introduced: + - `assertEqualsWithDelta` + - `assertNotEqualsWithDelta` + - `assertEqualsCanonicalizing` + - `assertNotEqualsCanonicalizing` + - `assertEqualsIgnoringCase` + - `assertNotEqualsIgnoringCase` + +**Reason**: PHPUnit 9 has dropped support for optional parameters for `assertEquals` and `assertNotEquals` and has introduced these new assertions. + +**Description**: Usages of `assertEquals` or `assertNotEquals` with `delta` specified, should be replaced with appropriate assertion from above list. + +### `assertContains` supports only iterable haystacks + +**Action**: `assertContains` and `assertNotContains` now support only iterable haystacks. Below assert actions have been added to work with string haystacks: +- `assertStringContainsString` +- `assertStringNotContainsString` +- `assertStringContainsStringIgnoringCase` +- `assertStringNotContainsStringIgnoringCase` + +**Reason**: With PHPUnit 9, `assertContains` and `assertNotContains` only allows iterable haystacks. New assertions have been introduced to support string haystacks. + +**Description**: Usages of `assertContains` and `assertNotContains` with string haystacks should be replaced with appropriate assertion from above list. + +Usage example for string haystacks: +```xml +<assertStringContainsString stepKey="assertDiscountOnPrice2"> +<actualResult type="const">$grabSimpleProdPrice2</actualResult> +<expectedResult type="string">$110.70</expectedResult> +</assertStringContainsString> +``` + +### `formatMoney` removed + +**Action**: `formatMoney` has been removed in favor of `formatCurrency`. + +**Reason**: PHP 7.4 has deprecated use of `formatMoney`. + +**Description**: Format input to specified currency according to the locale specified. + +Usage example: +```xml +<formatCurrency userInput="1234.56789000" locale="de_DE" currency="USD" stepKey="usdInDE"/> +``` + + From a411c0cbb881f979b7b4c0ac9f7810e976deae5e Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Tue, 26 May 2020 17:18:14 -0500 Subject: [PATCH 402/888] MQE-2141: MFTF BIC Documentation --- docs/backward-incompatible-changes.md | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/docs/backward-incompatible-changes.md b/docs/backward-incompatible-changes.md index 500f4883a..fe529619a 100644 --- a/docs/backward-incompatible-changes.md +++ b/docs/backward-incompatible-changes.md @@ -57,9 +57,11 @@ Here's how you can upgrade tests: **Reason**: `executeInSelenium` and `performOn` allowed custom PHP code to be written inline inside of XML files which was difficult to maintain, troubleshoot, and modify. -**Details**: `helper` will allow test writers to solve advanced requirements beyond what MFTF offers out of the box.[See custom-helpers](./docs/custom-helpers.md) for more information on the usage. +**Details**: -Here's an example of using `helper` instead of `executeSelenium` to achieve same workflow. +`helper` will allow test writers to solve advanced requirements beyond what MFTF offers out of the box.[See custom-helpers](./docs/custom-helpers.md) for more information on the usage. + +Here's an example of using `helper` in place of `executeSelenium` to achieve same workflow. Old usage: ```xml @@ -84,13 +86,16 @@ New usage: <argument name="endY">{{TinyMCEPartialHeadingSelection.endY}}</argument> </helper> ``` + ### `pauseExecution` removed **Action**: `pauseExecution` is removed in favor of `pause`. **Reason**: `[WebDriver]pauseExecution` is removed in Codeception 3 in favor of `I->pause()`. -**Description**: [See actions page for details](./docs/test/actions.md#pause). Here's a usage example. +**Details**: + +[See actions page for details](./docs/test/actions.md#pause). Here's a usage example. ```xml <pause stepKey="pauseExecutionKey"/> ``` @@ -113,7 +118,9 @@ New usage: **Reason**: PHPUnit 9 has dropped support for optional parameters for `assertEquals` and `assertNotEquals` and has introduced these new assertions. -**Description**: Usages of `assertEquals` or `assertNotEquals` with `delta` specified, should be replaced with appropriate assertion from above list. +**Details**: + +Usages of `assertEquals` or `assertNotEquals` with `delta` specified, should be replaced with appropriate assertion from above list. ### `assertContains` supports only iterable haystacks @@ -125,7 +132,9 @@ New usage: **Reason**: With PHPUnit 9, `assertContains` and `assertNotContains` only allows iterable haystacks. New assertions have been introduced to support string haystacks. -**Description**: Usages of `assertContains` and `assertNotContains` with string haystacks should be replaced with appropriate assertion from above list. +**Details**: + +Usages of `assertContains` and `assertNotContains` with string haystacks should be replaced with appropriate assertion from above list. Usage example for string haystacks: ```xml @@ -141,11 +150,9 @@ Usage example for string haystacks: **Reason**: PHP 7.4 has deprecated use of `formatMoney`. -**Description**: Format input to specified currency according to the locale specified. +**Details**: Format input to specified currency according to the locale specified. Usage example: ```xml <formatCurrency userInput="1234.56789000" locale="de_DE" currency="USD" stepKey="usdInDE"/> ``` - - From aea82ab1b307b0ad25c49467c713800927acf58f Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Wed, 27 May 2020 10:04:47 -0500 Subject: [PATCH 403/888] Grammar and formatting --- docs/backward-incompatible-changes.md | 87 ++++++++++++++------------- 1 file changed, 46 insertions(+), 41 deletions(-) diff --git a/docs/backward-incompatible-changes.md b/docs/backward-incompatible-changes.md index fe529619a..c50f490ca 100644 --- a/docs/backward-incompatible-changes.md +++ b/docs/backward-incompatible-changes.md @@ -4,46 +4,44 @@ This page highlights backward incompatible changes between releases that have a ## Version requirement changes -We changed the minimum PHP version requirement from 7.0 to 7.3. Because of the PHP version requirement change, this MFTF version supports only Magento 2.4 or later. +We changed the minimum PHP version requirement from 7.0 to 7.3. Because of the PHP version requirement change, this MFTF version only supports Magento 2.4 or later. ## Folder structure changes -We removed support to read test modules from deprecated path `dev/tests/acceptance/tests/functional/Magento/FunctionalTest`. If there are test modules in this path, they would need to be moved to `dev/tests/acceptance/tests/functional/Magento`. +We removed support to read test modules from the deprecated path `dev/tests/acceptance/tests/functional/Magento/FunctionalTest`. If there are test modules in this path, they should be moved to `dev/tests/acceptance/tests/functional/Magento`. ## XSD schema changes -- Files under test modules `ActionGroup`, `Page`, `Section`, `Test` and `Suite` support only a single entity per file. +- Files under test modules `ActionGroup`, `Page`, `Section`, `Test` and `Suite` only support a single entity per file. +- The `file` attribute from `<module>` has been removed from the suite schema. `<module file=""/>` is no longer supported in suites. +- Metadata filename format changed to ***`*Meta.xml`***. +- Only nested assertion syntax will be supported. See the [assertions page](./docs/test/assertions.md) for details. Here is an example of the nested assertion syntax: + ```xml + <assertEquals stepKey="assertAddressOrderPage"> + <actualResult type="const">$billingAddressOrderPage</actualResult> + <expectedResult type="const">$shippingAddressOrderPage</expectedResult> + </assertEquals> + ``` -- `file` attribute from `<module>` has been removed from suite schema. `<module file=""/>` is no longer supported in suites. - -- Metadata filename format changed to ***`*Meta.xml`***. - -- Only nested assertion syntax will be supported. [See assertions page for details](./docs/test/assertions.md). Here is an example of a nested assertion syntax. -```xml -<assertEquals stepKey="assertAddressOrderPage"> - <actualResult type="const">$billingAddressOrderPage</actualResult> - <expectedResult type="const">$shippingAddressOrderPage</expectedResult> -</assertEquals> -``` -### Upgrading tests to new schema +### Upgrading tests to the new schema The following table lists the upgrade scripts that are available to upgrade tests to the new schema. | Script name | Description | |-----------------------|-----------------------------------------------------------------------------------------------------------| |`splitMultipleEntitiesFiles`| Splits files that have multiple entities into multiple files with one entity per file. | -|`upgradeAssertionSchema`| Updates assert actions that use old assertion syntax to new nested syntax.| +|`upgradeAssertionSchema`| Updates assert actions that uses the old assertion syntax into the new nested syntax.| |`renameMetadataFiles`| Renames Metadata filenames to `*Meta.xml`.| |`removeModuleFileInSuiteFiles`| Removes occurrences of `<module file=""/>` from all `<suite>`s.| |`removeUnusedArguments`| Removes unused arguments from action groups.| |`upgradeTestSchema`| Replaces relative schema paths to URN in test files.| -Here's how you can upgrade tests: +To run the upgrade tests: -- Run `bin/mftf reset --hard` to remove old generated configurations. -- Run `bin/mftf build:project` to generate new configurations. -- Run `bin/mftf upgrade:tests`. [See command page for details](./docs/commands/mftf.md#upgradetests). -- Lastly, try to generate all tests. Tests should all be generated as a result of the upgrades. If not, the most likely issue will be a changed XML schema. Check error messaging and search your codebase for the attributes listed. +1. Run `bin/mftf reset --hard` to remove old generated configurations. +1. Run `bin/mftf build:project` to generate new configurations. +1. Run `bin/mftf upgrade:tests`. [See command page for details](./docs/commands/mftf.md#upgradetests). +1. Lastly, try to generate all tests. Tests should all be generated as a result of the upgrades. If not, the most likely issue will be a changed XML schema. Check error messaging and search your codebase for the attributes listed. ## MFTF commands @@ -51,7 +49,7 @@ Here's how you can upgrade tests: ## MFTF actions -###`executeInSelenium` and `performOn` removed +### `executeInSelenium` and `performOn` removed **Action**: Deprecated actions `executeInSelenium` and `performOn` are removed in favor of new action `helper`. @@ -59,11 +57,12 @@ Here's how you can upgrade tests: **Details**: -`helper` will allow test writers to solve advanced requirements beyond what MFTF offers out of the box.[See custom-helpers](./docs/custom-helpers.md) for more information on the usage. +The `helper` allows test writers to solve advanced requirements beyond what MFTF offers out of the box. See [custom-helpers](./docs/custom-helpers.md) for more information on usage. -Here's an example of using `helper` in place of `executeSelenium` to achieve same workflow. +Here is an example of using `helper` in place of `executeSelenium` to achieve same workflow. Old usage: + ```xml <executeInSelenium function="function ($webdriver) use ($I) { $heading = $webdriver->findElement(\Facebook\WebDriver\WebDriverBy::xpath('//div[contains(@class, \'inline-wysiwyg\')]//h2')); @@ -77,6 +76,7 @@ Old usage: ``` New usage: + ```xml <helper class="\Magento\PageBuilder\Test\Mftf\Helper\SelectText" method="selectText" stepKey="selectHeadingTextInTinyMCE"> <argument name="context">//div[contains(@class, 'inline-wysiwyg')]//h2</argument> @@ -95,7 +95,8 @@ New usage: **Details**: -[See actions page for details](./docs/test/actions.md#pause). Here's a usage example. +See the [actions page for details](./docs/test/actions.md#pause). Here is a usage example: + ```xml <pause stepKey="pauseExecutionKey"/> ``` @@ -108,39 +109,42 @@ New usage: ### Updated assert actions -**Action**: `delta` attribute has been removed from `assertEquals` and `assertNotEquals`. Instead, below assert actions have been introduced: - - `assertEqualsWithDelta` - - `assertNotEqualsWithDelta` - - `assertEqualsCanonicalizing` - - `assertNotEqualsCanonicalizing` - - `assertEqualsIgnoringCase` - - `assertNotEqualsIgnoringCase` +**Action**: The `delta` attribute has been removed from `assertEquals` and `assertNotEquals`. Instead, new assert actions have been introduced: + + - `assertEqualsWithDelta` + - `assertNotEqualsWithDelta` + - `assertEqualsCanonicalizing` + - `assertNotEqualsCanonicalizing` + - `assertEqualsIgnoringCase` + - `assertNotEqualsIgnoringCase` **Reason**: PHPUnit 9 has dropped support for optional parameters for `assertEquals` and `assertNotEquals` and has introduced these new assertions. **Details**: -Usages of `assertEquals` or `assertNotEquals` with `delta` specified, should be replaced with appropriate assertion from above list. +Usage of `assertEquals` or `assertNotEquals` with a specified `delta`, should be replaced with appropriate assertion from the above list. ### `assertContains` supports only iterable haystacks -**Action**: `assertContains` and `assertNotContains` now support only iterable haystacks. Below assert actions have been added to work with string haystacks: -- `assertStringContainsString` -- `assertStringNotContainsString` -- `assertStringContainsStringIgnoringCase` -- `assertStringNotContainsStringIgnoringCase` +**Action**: `assertContains` and `assertNotContains` now only supports iterable haystacks. These assert actions have been added to work with string haystacks: + +- `assertStringContainsString` +- `assertStringNotContainsString` +- `assertStringContainsStringIgnoringCase` +- `assertStringNotContainsStringIgnoringCase` **Reason**: With PHPUnit 9, `assertContains` and `assertNotContains` only allows iterable haystacks. New assertions have been introduced to support string haystacks. **Details**: -Usages of `assertContains` and `assertNotContains` with string haystacks should be replaced with appropriate assertion from above list. +Usages of `assertContains` and `assertNotContains` with string haystacks should be replaced with appropriate assertion from the above list. Usage example for string haystacks: + ```xml <assertStringContainsString stepKey="assertDiscountOnPrice2"> -<actualResult type="const">$grabSimpleProdPrice2</actualResult> -<expectedResult type="string">$110.70</expectedResult> + <actualResult type="const">$grabSimpleProdPrice2</actualResult> + <expectedResult type="string">$110.70</expectedResult> </assertStringContainsString> ``` @@ -153,6 +157,7 @@ Usage example for string haystacks: **Details**: Format input to specified currency according to the locale specified. Usage example: + ```xml <formatCurrency userInput="1234.56789000" locale="de_DE" currency="USD" stepKey="usdInDE"/> ``` From f57b87c1041398794f19b96d72f68d2782710460 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Wed, 27 May 2020 14:39:04 -0500 Subject: [PATCH 404/888] MQE-2143: Cleanup mftf.log Changed deprecation and notices to log only during test generation --- .../Util/Logger/MftfLogger.php | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php b/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php index 0e8c1e17f..c7f6b44e7 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php +++ b/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php @@ -13,7 +13,7 @@ class MftfLogger extends Logger { /** - * Prints a deprecation warning, as well as adds a log at the WARNING level. + * Prints a deprecation warning, as well as adds a log at the WARNING level during test generation. * * @param string $message The log message. * @param array $context The log context. @@ -23,12 +23,14 @@ class MftfLogger extends Logger */ public function deprecation($message, array $context = [], $verbose = false) { - $message = "DEPRECATION: " . $message; // Suppress print during unit testing - if (MftfApplicationConfig::getConfig()->getPhase() !== MftfApplicationConfig::UNIT_TEST_PHASE && $verbose) { - print ($message . json_encode($context) . "\n"); + if (MftfApplicationConfig::getConfig()->getPhase() === MftfApplicationConfig::GENERATION_PHASE) { + $message = "DEPRECATION: " . $message; + if ($verbose) { + print ($message . json_encode($context) . "\n"); + } + parent::warning($message, $context); } - parent::warning($message, $context); } /** @@ -51,7 +53,7 @@ public function criticalFailure($message, array $context = [], $verbose = false) } /** - * Adds a log record at the NOTICE level. + * Adds a log record at the NOTICE level during test generation. * * @param string $message * @param array $context @@ -61,11 +63,13 @@ public function criticalFailure($message, array $context = [], $verbose = false) */ public function notification($message, array $context = [], $verbose = false) { - $message = "NOTICE: " . $message; - // Suppress print during unit testing - if (MftfApplicationConfig::getConfig()->getPhase() !== MftfApplicationConfig::UNIT_TEST_PHASE && $verbose) { - print ($message . implode("\n", $context) . "\n"); + // Print during generation phase + if (MftfApplicationConfig::getConfig()->getPhase() === MftfApplicationConfig::GENERATION_PHASE) { + $message = "NOTICE: " . $message; + if ($verbose) { + print ($message . implode("\n", $context) . "\n"); + } + parent::notice($message, $context); } - parent::notice($message, $context); } } From c2de761f7bd7bf0d7a1de52e58b7d9d1ac5030ac Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Thu, 28 May 2020 10:13:17 -0500 Subject: [PATCH 405/888] MQE-2143: Cleanup mftf.log --- .../Util/Logger/MftfLogger.php | 61 +++++++++++++------ 1 file changed, 42 insertions(+), 19 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php b/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php index c7f6b44e7..0c374800a 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php +++ b/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php @@ -7,28 +7,51 @@ namespace Magento\FunctionalTestingFramework\Util\Logger; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; -use Monolog\Handler\StreamHandler; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Monolog\Handler\HandlerInterface; use Monolog\Logger; class MftfLogger extends Logger { /** - * Prints a deprecation warning, as well as adds a log at the WARNING level during test generation. + * MFTF execution phase + * + * @var string + */ + private $phase; + + /** + * MftfLogger constructor. + * + * @param string $name The logging channel + * @param HandlerInterface[] $handlers Optional stack of handlers, the first one in the array is called first, etc. + * @param callable[] $processors Optional array of processors + * @throws TestFrameworkException + */ + public function __construct($name, array $handlers = array(), array $processors = array()) + { + parent::__construct($name, $handlers, $processors); + $this->phase = MftfApplicationConfig::getConfig()->getPhase(); + } + + /** + * Prints a deprecation warning, as well as adds a log at the WARNING level. + * Suppresses logging during execution phase. * * @param string $message The log message. * @param array $context The log context. * @param boolean $verbose * @return void - * @throws \Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException */ public function deprecation($message, array $context = [], $verbose = false) { - // Suppress print during unit testing - if (MftfApplicationConfig::getConfig()->getPhase() === MftfApplicationConfig::GENERATION_PHASE) { - $message = "DEPRECATION: " . $message; - if ($verbose) { - print ($message . json_encode($context) . "\n"); - } + $message = "DEPRECATION: " . $message; + // print during test generation + if ($this->phase === MftfApplicationConfig::GENERATION_PHASE && $verbose) { + print ($message . json_encode($context) . "\n"); + } + // suppress logging during test execution + if ($this->phase !== MftfApplicationConfig::EXECUTION_PHASE) { parent::warning($message, $context); } } @@ -40,35 +63,35 @@ public function deprecation($message, array $context = [], $verbose = false) * @param array $context The log context. * @param boolean $verbose * @return void - * @throws \Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException */ public function criticalFailure($message, array $context = [], $verbose = false) { $message = "FAILURE: " . $message; // Suppress print during unit testing - if (MftfApplicationConfig::getConfig()->getPhase() !== MftfApplicationConfig::UNIT_TEST_PHASE && $verbose) { + if ($this->phase !== MftfApplicationConfig::UNIT_TEST_PHASE && $verbose) { print ($message . implode("\n", $context) . "\n"); } parent::critical($message, $context); } /** - * Adds a log record at the NOTICE level during test generation. + * Adds a log record at the NOTICE level. + * Suppresses logging during execution phase. * * @param string $message * @param array $context * @param boolean $verbose * @return void - * @throws \Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException */ public function notification($message, array $context = [], $verbose = false) { - // Print during generation phase - if (MftfApplicationConfig::getConfig()->getPhase() === MftfApplicationConfig::GENERATION_PHASE) { - $message = "NOTICE: " . $message; - if ($verbose) { - print ($message . implode("\n", $context) . "\n"); - } + $message = "NOTICE: " . $message; + // print during test generation + if ($this->phase === MftfApplicationConfig::GENERATION_PHASE && $verbose) { + print ($message . json_encode($context) . "\n"); + } + // suppress logging during test execution + if ($this->phase !== MftfApplicationConfig::EXECUTION_PHASE) { parent::notice($message, $context); } } From 6f2affb6ddb167de610c218e99a775a4354f2910 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 28 May 2020 10:17:43 -0500 Subject: [PATCH 406/888] MQE-2135: MFTF static check output directory should not depend on current working directory --- .../StaticCheck/ActionGroupArgumentsCheck.php | 2 +- .../StaticCheck/AnnotationsCheck.php | 2 +- .../DeprecatedEntityUsageCheck.php | 2 +- .../StaticCheck/StaticChecksList.php | 25 +++++++++++++++++++ .../StaticCheck/TestDependencyCheck.php | 2 +- .../Util/Script/ScriptUtil.php | 14 +++++++---- 6 files changed, 38 insertions(+), 9 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php index e6afded68..8b95fb9d5 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/ActionGroupArgumentsCheck.php @@ -65,7 +65,7 @@ public function execute(InputInterface $input) $this->output = $this->scriptUtil->printErrorsToFile( $this->errors, - self::ERROR_LOG_FILENAME, + StaticChecksList::getErrorFilesPath() . DIRECTORY_SEPARATOR . self::ERROR_LOG_FILENAME . '.txt', self::ERROR_LOG_MESSAGE ); } diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php index 86cbec2db..10aa853ec 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php @@ -82,7 +82,7 @@ public function execute(InputInterface $input) $scriptUtil = new ScriptUtil(); $this->output = $scriptUtil->printErrorsToFile( $this->errors, - self::ERROR_LOG_FILENAME, + StaticChecksList::getErrorFilesPath() . DIRECTORY_SEPARATOR . self::ERROR_LOG_FILENAME . '.txt', self::ERROR_LOG_MESSAGE ); } diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/DeprecatedEntityUsageCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/DeprecatedEntityUsageCheck.php index af5a1835e..5da16ec6a 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/DeprecatedEntityUsageCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/DeprecatedEntityUsageCheck.php @@ -128,7 +128,7 @@ public function execute(InputInterface $input) // Hold on to the output and print any errors to a file $this->output = $this->scriptUtil->printErrorsToFile( $this->errors, - self::ERROR_LOG_FILENAME, + StaticChecksList::getErrorFilesPath() . DIRECTORY_SEPARATOR . self::ERROR_LOG_FILENAME . '.txt', self::ERROR_LOG_MESSAGE ); } diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php b/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php index 4b4b9b4c0..7cd894e00 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php @@ -7,6 +7,9 @@ namespace Magento\FunctionalTestingFramework\StaticCheck; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; + /** * Class StaticChecksList has a list of static checks to run on test xml * @codingStandardsIgnoreFile @@ -14,6 +17,7 @@ class StaticChecksList implements StaticCheckListInterface { const DEPRECATED_ENTITY_USAGE_CHECK_NAME = 'deprecatedEntityUsage'; + const STATIC_RESULTS = 'tests' . DIRECTORY_SEPARATOR .'_output' . DIRECTORY_SEPARATOR . 'static-results'; /** * Property contains all static check scripts. @@ -22,10 +26,18 @@ class StaticChecksList implements StaticCheckListInterface */ private $checks; + /** + * Directory path for static checks error files + * + * @var string + */ + private static $errorFilesPath = null; + /** * Constructor * * @param array $checks + * @throws TestFrameworkException */ public function __construct(array $checks = []) { @@ -35,6 +47,11 @@ public function __construct(array $checks = []) self::DEPRECATED_ENTITY_USAGE_CHECK_NAME => new DeprecatedEntityUsageCheck(), 'annotations' => new AnnotationsCheck() ] + $checks; + + // Static checks error files directory + if (null === self::$errorFilesPath) { + self::$errorFilesPath = FilePathFormatter::format(TESTS_BP) . self::STATIC_RESULTS; + } } /** @@ -44,4 +61,12 @@ public function getStaticChecks() { return $this->checks; } + + /** + * Return the directory path for the static check error files + */ + public static function getErrorFilesPath() + { + return self::$errorFilesPath; + } } diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php index 9f20f2e08..6bfe17219 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php @@ -121,7 +121,7 @@ public function execute(InputInterface $input) // hold on to the output and print any errors to a file $this->output = $this->scriptUtil->printErrorsToFile( $this->errors, - self::ERROR_LOG_FILENAME, + StaticChecksList::getErrorFilesPath() . DIRECTORY_SEPARATOR . self::ERROR_LOG_FILENAME . '.txt', self::ERROR_LOG_MESSAGE ); } diff --git a/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php b/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php index 84016721b..14f9c27e0 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php @@ -56,18 +56,22 @@ public function getAllModulePaths() /** * Prints out given errors to file, and returns summary result string * @param array $errors - * @param string $filename + * @param string $filePath * @param string $message * @return string */ - public function printErrorsToFile($errors, $filename, $message) + public function printErrorsToFile($errors, $filePath, $message) { if (empty($errors)) { return $message . ": No errors found."; } - $outputPath = getcwd() . DIRECTORY_SEPARATOR . $filename . ".txt"; - $fileResource = fopen($outputPath, 'w'); + $dirname = dirname($filePath); + if (!file_exists($dirname)) { + mkdir($dirname, 0777, true); + } + + $fileResource = fopen($filePath, 'w'); foreach ($errors as $test => $error) { fwrite($fileResource, $error[0] . PHP_EOL); @@ -75,7 +79,7 @@ public function printErrorsToFile($errors, $filename, $message) fclose($fileResource); $errorCount = count($errors); - $output = $message . ": Errors found across {$errorCount} file(s). Error details output to {$outputPath}"; + $output = $message . ": Errors found across {$errorCount} file(s). Error details output to {$filePath}"; return $output; } From b29afaff40880076cbc954f96760bba4253594f6 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Thu, 28 May 2020 11:56:23 -0500 Subject: [PATCH 407/888] MQE-2143: Cleanup mftf.log fixed static-checks --- .../FunctionalTestingFramework/Util/Logger/MftfLogger.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php b/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php index 0c374800a..5955235ce 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php +++ b/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php @@ -23,12 +23,12 @@ class MftfLogger extends Logger /** * MftfLogger constructor. * - * @param string $name The logging channel - * @param HandlerInterface[] $handlers Optional stack of handlers, the first one in the array is called first, etc. - * @param callable[] $processors Optional array of processors + * @param string $name + * @param HandlerInterface[] $handlers + * @param callable[] $processors * @throws TestFrameworkException */ - public function __construct($name, array $handlers = array(), array $processors = array()) + public function __construct($name, array $handlers = [], array $processors = []) { parent::__construct($name, $handlers, $processors); $this->phase = MftfApplicationConfig::getConfig()->getPhase(); From 46068452f3b5d4dc41884ee462d8b41f3fa7356c Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 28 May 2020 16:58:16 -0500 Subject: [PATCH 408/888] MQE-2135: MFTF static check output directory should not depend on current working directory --- docs/commands/mftf.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index b71e45148..f1ef3955d 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -430,13 +430,15 @@ The example parameters are taken from the `etc/config/.env.example` file. ### `static-checks` -Runs all or specific MFTF static-checks on the test codebase that MFTF is currently attached to. +Runs all or specific MFTF static-checks on the test codebase that MFTF is currently attached to. Behavior for determining what tests to run is as follows: * If test names are specified, only those tests are run. * If no test names are specified, tests are run according to `staticRuleset.json`. * If no `staticRuleset.json` is found, all tests are run. +Static checks errors are written to *.txt files under TEST_BP/tests/_output/static-results/ + #### Usage ```bash From 3c04057471a3ef20fdd47c5f95566f79b4ea607f Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Fri, 29 May 2020 16:32:19 -0500 Subject: [PATCH 409/888] MQE-2135: MFTF static check output directory should not depend on current working directory --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 1ad606e97..fad995502 100755 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,4 @@ dev/tests/mftf.log dev/tests/docs/* dev/tests/_output dev/tests/functional.suite.yml -mftf-annotations-static-check.txt + From 482d2b0886c619ffd480cbe48c2e9aa527518fd2 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Mon, 1 Jun 2020 10:05:58 -0500 Subject: [PATCH 410/888] MQE-2141: MFTF BIC Documentation addressed review comments --- docs/backward-incompatible-changes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backward-incompatible-changes.md b/docs/backward-incompatible-changes.md index c50f490ca..746e4546b 100644 --- a/docs/backward-incompatible-changes.md +++ b/docs/backward-incompatible-changes.md @@ -2,7 +2,7 @@ This page highlights backward incompatible changes between releases that have a major impact and require detailed explanation and special instructions to ensure third-party tests continue working with Magento core tests. -## Version requirement changes +## Minimum supported PHP version changes We changed the minimum PHP version requirement from 7.0 to 7.3. Because of the PHP version requirement change, this MFTF version only supports Magento 2.4 or later. From 05d6e0797ca08c0909b2c5bcdb9b5dd1e947ef91 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 1 Jun 2020 16:20:12 -0500 Subject: [PATCH 411/888] Create MFTF Release Candidate 3 --- composer.json | 2 +- composer.lock | 281 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 280 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 541b75966..7bbc69268 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "3.0.0", + "version": "3.0.0-RC3", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index 39dc222bd..2d45550ef 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "bebbc11e36de2f68821cbeebeafe04ad", + "content-hash": "34e8bc951072914b0c115d2d4893b9b0", "packages": [ { "name": "allure-framework/allure-codeception", @@ -896,6 +896,16 @@ "dependency", "package" ], + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], "time": "2020-04-10T09:44:22+00:00" }, { @@ -1984,6 +1994,12 @@ "sftp", "storage" ], + "funding": [ + { + "url": "https://offset.earth/frankdejonge", + "type": "other" + } + ], "time": "2020-04-16T13:21:26+00:00" }, { @@ -3203,6 +3219,16 @@ "testing", "xunit" ], + "funding": [ + { + "url": "https://phpunit.de/donate.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-04-23T04:42:05+00:00" }, { @@ -3616,6 +3642,12 @@ ], "description": "Collection of value objects that represent the PHP code units", "homepage": "https://github.com/sebastianbergmann/code-unit", + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-03-30T11:59:20+00:00" }, { @@ -4474,6 +4506,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-03-30T11:41:10+00:00" }, { @@ -4527,6 +4573,20 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-03-27T16:56:45+00:00" }, { @@ -4597,6 +4657,20 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-03-27T16:54:36+00:00" }, { @@ -4705,6 +4779,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-03-27T16:56:45+00:00" }, { @@ -4754,6 +4842,20 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-03-27T16:56:45+00:00" }, { @@ -4809,6 +4911,20 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-03-30T14:14:32+00:00" }, { @@ -4871,6 +4987,20 @@ "mime", "mime-type" ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-03-27T16:56:45+00:00" }, { @@ -4929,6 +5059,20 @@ "polyfill", "portable" ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-02-27T09:26:54+00:00" }, { @@ -4991,6 +5135,20 @@ "portable", "shim" ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-03-09T19:04:49+00:00" }, { @@ -5050,6 +5208,20 @@ "portable", "shim" ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-03-09T19:04:49+00:00" }, { @@ -5105,6 +5277,20 @@ "portable", "shim" ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-02-27T09:26:54+00:00" }, { @@ -5163,6 +5349,20 @@ "portable", "shim" ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-02-27T09:26:54+00:00" }, { @@ -5212,6 +5412,20 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-03-27T16:54:36+00:00" }, { @@ -5329,6 +5543,20 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-03-30T11:41:10+00:00" }, { @@ -5558,6 +5786,12 @@ "env", "environment" ], + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } + ], "time": "2020-04-12T15:11:38+00:00" }, { @@ -6620,6 +6854,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-03-27T16:54:36+00:00" }, { @@ -6693,6 +6941,20 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-03-30T10:09:30+00:00" }, { @@ -6742,6 +7004,20 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-03-15T09:38:08+00:00" }, { @@ -6798,5 +7074,6 @@ "ext-json": "*", "ext-openssl": "*" }, - "platform-dev": [] + "platform-dev": [], + "plugin-api-version": "1.1.0" } From 908240344ad6b91b15c38e6ba2d6503f2fc03d35 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 1 Jun 2020 17:12:28 -0500 Subject: [PATCH 412/888] Create MFTF Release Candidate 3 --- bin/mftf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/mftf b/bin/mftf index 7a9ca1cf2..ddb237fb6 100755 --- a/bin/mftf +++ b/bin/mftf @@ -31,7 +31,7 @@ try { $version = $version['version']; $application = new Symfony\Component\Console\Application(); $application->setName('Magento Functional Testing Framework CLI'); - $application->setVersion($version); + $application->setVersion('3.0.0'); /** @var \Magento\FunctionalTestingFramework\Console\CommandListInterface $commandList */ $commandList = new \Magento\FunctionalTestingFramework\Console\CommandList; foreach ($commandList->getCommands() as $command) { From ca634817f7b926d6c728300912a5c55000f6d33c Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 2 Jun 2020 17:38:09 -0500 Subject: [PATCH 413/888] MQE-2150: group value "skip" no longer causes test to be skipped --- ...Issues.txt => GroupSkipGenerationTest.txt} | 11 +++++----- ...Issues.xml => GroupSkipGenerationTest.xml} | 8 +++---- .../Tests/GroupSkipGenerationTest.php | 22 +++++++++++++++++++ .../Tests/SkippedGenerationTest.php | 11 ---------- docs/merging.md | 2 +- docs/suite.md | 2 +- docs/test/annotations.md | 2 +- .../Test/Objects/TestObject.php | 3 --- .../Test/Util/AnnotationExtractor.php | 7 ------ 9 files changed, 34 insertions(+), 34 deletions(-) rename dev/tests/verification/Resources/{SkippedTestNoIssues.txt => GroupSkipGenerationTest.txt} (65%) rename dev/tests/verification/TestModule/Test/{SkippedTest/SkippedTestNoIssues.xml => GroupSkipGenerationTest.xml} (64%) create mode 100644 dev/tests/verification/Tests/GroupSkipGenerationTest.php diff --git a/dev/tests/verification/Resources/SkippedTestNoIssues.txt b/dev/tests/verification/Resources/GroupSkipGenerationTest.txt similarity index 65% rename from dev/tests/verification/Resources/SkippedTestNoIssues.txt rename to dev/tests/verification/Resources/GroupSkipGenerationTest.txt index 387ada571..89884df82 100644 --- a/dev/tests/verification/Resources/SkippedTestNoIssues.txt +++ b/dev/tests/verification/Resources/GroupSkipGenerationTest.txt @@ -13,14 +13,14 @@ use Yandex\Allure\Adapter\Model\SeverityLevel; use Yandex\Allure\Adapter\Annotation\TestCaseId; /** - * @Title("[NO TESTCASEID]: skippedNoIssuesTest") - * @Description("<h3>Test files</h3>verification/TestModule/Test/SkippedTest/SkippedTestNoIssues.xml<br>") + * @Title("[NO TESTCASEID]: GroupSkipGenerationTestTitle") + * @Description("GroupSkipGenerationTestDescription<h3>Test files</h3>verification/TestModule/Test/GroupSkipGenerationTest.xml<br>") * @group skip */ -class SkippedTestNoIssuesCest +class GroupSkipGenerationTestCest { /** - * @Stories({"skippedNo"}) + * @Stories({"GroupSkipGenerationTestStory"}) * @Severity(level = SeverityLevel::MINOR) * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -28,8 +28,7 @@ class SkippedTestNoIssuesCest * @return void * @throws \Exception */ - public function SkippedTestNoIssues(AcceptanceTester $I, \Codeception\Scenario $scenario) + public function GroupSkipGenerationTest(AcceptanceTester $I) { - $scenario->skip("This test is skipped due to the following issues:\nNo issues have been specified."); } } diff --git a/dev/tests/verification/TestModule/Test/SkippedTest/SkippedTestNoIssues.xml b/dev/tests/verification/TestModule/Test/GroupSkipGenerationTest.xml similarity index 64% rename from dev/tests/verification/TestModule/Test/SkippedTest/SkippedTestNoIssues.xml rename to dev/tests/verification/TestModule/Test/GroupSkipGenerationTest.xml index 02f800536..35cf74d33 100644 --- a/dev/tests/verification/TestModule/Test/SkippedTest/SkippedTestNoIssues.xml +++ b/dev/tests/verification/TestModule/Test/GroupSkipGenerationTest.xml @@ -7,11 +7,11 @@ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> - <test name="SkippedTestNoIssues"> + <test name="GroupSkipGenerationTest"> <annotations> - <stories value="skippedNo"/> - <title value="skippedNoIssuesTest"/> - <description value=""/> + <stories value="GroupSkipGenerationTestStory"/> + <title value="GroupSkipGenerationTestTitle"/> + <description value="GroupSkipGenerationTestDescription"/> <severity value="AVERAGE"/> <group value="skip"/> </annotations> diff --git a/dev/tests/verification/Tests/GroupSkipGenerationTest.php b/dev/tests/verification/Tests/GroupSkipGenerationTest.php new file mode 100644 index 000000000..ad0ba6ec0 --- /dev/null +++ b/dev/tests/verification/Tests/GroupSkipGenerationTest.php @@ -0,0 +1,22 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace tests\verification\Tests; + +use tests\util\MftfTestCase; + +class GroupSkipGenerationTest extends MftfTestCase +{ + /** + * Tests group skip test generation + * + * @throws \Exception + * @throws \Magento\FunctionalTestingFramework\Exceptions\TestReferenceException + */ + public function testGroupSkipGenerationTest() + { + $this->generateAndCompareTest('GroupSkipGenerationTest'); + } +} diff --git a/dev/tests/verification/Tests/SkippedGenerationTest.php b/dev/tests/verification/Tests/SkippedGenerationTest.php index 2d259e02c..2bc73986a 100644 --- a/dev/tests/verification/Tests/SkippedGenerationTest.php +++ b/dev/tests/verification/Tests/SkippedGenerationTest.php @@ -41,15 +41,4 @@ public function testMultipleSkippedIssuesGeneration() { $this->generateAndCompareTest('SkippedTestTwoIssues'); } - - /** - * Tests skipped test generation with no specified issues. Will be deprecated after MFTF 3.0.0 - * - * @throws \Exception - * @throws \Magento\FunctionalTestingFramework\Exceptions\TestReferenceException - */ - public function testSkippedNoIssueGeneration() - { - $this->generateAndCompareTest('SkippedTestNoIssues'); - } } diff --git a/docs/merging.md b/docs/merging.md index e4b91fb5f..ad3198623 100644 --- a/docs/merging.md +++ b/docs/merging.md @@ -35,7 +35,7 @@ To add a `<test>`, create a new `*Test.xml` file or add a `<test>` node to an ex ## Remove a test Tests cannot be removed while merging. -If a [`<test>`][tests] must be skipped due to a module completely invalidating a function, you can add the test to the `skip` group. +If a [`<test>`][tests] must be skipped due to a module completely invalidating a function, you can use `skip` annotation to skip the test. Learn more about running tests with different options using [`mftf`] or [`codecept`] commands. diff --git a/docs/suite.md b/docs/suite.md index 65bcedce0..7917cd347 100644 --- a/docs/suite.md +++ b/docs/suite.md @@ -46,7 +46,7 @@ The format of a suite: - must not match any existing group value. For example, the suite `<suite name="ExampleTest">` will fail during test run if any test contains in annotations `<group value="ExampleTest">`. - must not be `default` or `skip`. Tests that are not in any suite are generated under the `default` suite. - The suite name `skip` is synonymous to including a test in the `<group value="skip"/>`, which will be deprecated in MFTF 3.0.0. + The suite name `skip` is synonymous to including a test in the `<group value="skip"/>`. - can contain letters, numbers, and underscores. - should be upper camel case. diff --git a/docs/test/annotations.md b/docs/test/annotations.md index f30b8104e..4e9194bb0 100644 --- a/docs/test/annotations.md +++ b/docs/test/annotations.md @@ -87,7 +87,7 @@ Add `<skip>` to the test to skip it during test run. Attribute|Type|Use|Definition ---|---|---|--- -`value`|string|required|A value that is used to group tests. It should be lower case. `skip` is reserved to ignore content of the test and generate an empty test. +`value`|string|required|A value that is used to group tests. It should be lower case. #### Example diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php index 01319bc67..82bb04906 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php @@ -161,11 +161,8 @@ public function getDeprecated() */ public function isSkipped() { - // TODO deprecation|deprecate MFTF 3.0.0 remove elseif when group skip is no longer allowed if (array_key_exists('skip', $this->annotations)) { return true; - } elseif (array_key_exists('group', $this->annotations) && (in_array("skip", $this->annotations['group']))) { - return true; } return false; } diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php index 031215abb..46adb7ce2 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php @@ -92,13 +92,6 @@ public function extractAnnotations($testAnnotations, $filename, $validateAnnotat foreach ($annotationData as $annotationValue) { $annotationValues[] = $annotationValue[self::ANNOTATION_VALUE]; } - // TODO deprecation|deprecate MFTF 3.0.0 - if ($annotationKey == "group" && in_array("skip", $annotationValues)) { - LoggingUtil::getInstance()->getLogger(AnnotationExtractor::class)->warning( - "Use of group skip will be deprecated in MFTF 3.0.0. Please update tests to use skip tags.", - ["test" => $filename] - ); - } $annotationObjects[$annotationKey] = $annotationValues; } From 64944fe7d8f8394ba05cb66174e1927e5414f530 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Wed, 3 Jun 2020 09:43:02 -0500 Subject: [PATCH 414/888] MQE-2160: Extended data entity won't merge array items --- .../functional/tests/MFTF/DevDocs/Data/MessageData.xml | 6 ++++++ .../functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml | 4 ++-- .../verification/Resources/ExtendedParameterArrayTest.txt | 4 ++-- .../DataGenerator/Util/DataExtensionUtil.php | 2 +- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Data/MessageData.xml b/dev/tests/functional/tests/MFTF/DevDocs/Data/MessageData.xml index 2b9d3a520..f35812e54 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Data/MessageData.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/Data/MessageData.xml @@ -17,4 +17,10 @@ <item name="three">3</item> </array> </entity> + + <entity name="ExtendedMessageData" extends="MessageData"> + <array key="numbers"> + <item name="TESTING CASE">TESTING CASE</item> + </array> + </entity> </entities> diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml b/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml index 02d6481a8..bda1cfb57 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml @@ -48,8 +48,8 @@ </actionGroup> <assertEqualsCanonicalizing stepKey="assertMergedArray"> - <actualResult type="array">{{MessageData.numbers}}</actualResult> - <expectedResult type="array">["Something New", "0", "1", "2", "3"]</expectedResult> + <actualResult type="array">{{ExtendedMessageData.numbers}}</actualResult> + <expectedResult type="array">["Something New", "0", "1", "2", "3", "TESTING CASE"]</expectedResult> </assertEqualsCanonicalizing> </test> </tests> diff --git a/dev/tests/verification/Resources/ExtendedParameterArrayTest.txt b/dev/tests/verification/Resources/ExtendedParameterArrayTest.txt index d09e9a0b6..2d3004717 100644 --- a/dev/tests/verification/Resources/ExtendedParameterArrayTest.txt +++ b/dev/tests/verification/Resources/ExtendedParameterArrayTest.txt @@ -26,9 +26,9 @@ class ExtendParentDataTestCest public function ExtendParentDataTest(AcceptanceTester $I) { $I->createEntity("simpleDataKey", "test", "extendParentData", [], []); // stepKey: simpleDataKey - $I->searchAndMultiSelectOption("#selector", ["otherName"]); + $I->searchAndMultiSelectOption("#selector", ["name", "otherName"]); $I->searchAndMultiSelectOption("#selector", ["extendName"]); - $I->searchAndMultiSelectOption("#selector", ["item"]); + $I->searchAndMultiSelectOption("#selector", ["postname", "item"]); $I->searchAndMultiSelectOption("#selector", [msq("extendParentData") . "prename"]); $I->searchAndMultiSelectOption("#selector", ["postnameExtend" . msq("extendParentData")]); } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Util/DataExtensionUtil.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Util/DataExtensionUtil.php index 3a12bdce1..2ed331c6b 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Util/DataExtensionUtil.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Util/DataExtensionUtil.php @@ -62,7 +62,7 @@ public function extendEntity($entityObject) // Get all data for both parent and child and merge $referencedData = $parentEntity->getAllData(); - $newData = array_merge($referencedData, $entityObject->getAllData()); + $newData = array_merge_recursive($referencedData, $entityObject->getAllData()); // Get all linked references for both parent and child and merge $referencedLinks = $parentEntity->getLinkedEntities(); From 9236244ef6e6c1581b8f9fe526b8d6eba115f8bd Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Wed, 3 Jun 2020 11:18:44 -0500 Subject: [PATCH 415/888] MQE-2160: Extended data entity won't merge array items --- dev/tests/verification/Resources/ExtendParentDataTest.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/tests/verification/Resources/ExtendParentDataTest.txt b/dev/tests/verification/Resources/ExtendParentDataTest.txt index 70cb6b70b..f2ddc4ffd 100644 --- a/dev/tests/verification/Resources/ExtendParentDataTest.txt +++ b/dev/tests/verification/Resources/ExtendParentDataTest.txt @@ -27,9 +27,9 @@ class ExtendParentDataTestCest public function ExtendParentDataTest(AcceptanceTester $I) { $I->createEntity("simpleDataKey", "test", "extendParentData", [], []); // stepKey: simpleDataKey - $I->searchAndMultiSelectOption("#selector", ["otherName"]); // stepKey: getName + $I->searchAndMultiSelectOption("#selector", ["name", "otherName"]); // stepKey: getName $I->searchAndMultiSelectOption("#selector", ["extendName"]); // stepKey: getNameExtend - $I->searchAndMultiSelectOption("#selector", ["item"]); // stepKey: emptyPost + $I->searchAndMultiSelectOption("#selector", ["postname", "item"]); // stepKey: emptyPost $I->searchAndMultiSelectOption("#selector", [msq("extendParentData") . "prename"]); // stepKey: originalPre $I->searchAndMultiSelectOption("#selector", ["postnameExtend" . msq("extendParentData")]); // stepKey: secondUniquePre } From 5b461c5accc2b4e9330a7fa3292e8701a9018536 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 3 Jun 2020 14:47:16 -0500 Subject: [PATCH 416/888] MQE-2158: move proxies function from MagentoWebDriver back into MagentoActionProxies --- .../Module/MagentoActionProxies.php | 110 ++++++++++++++++- .../Module/MagentoWebDriver.php | 115 ------------------ 2 files changed, 109 insertions(+), 116 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoActionProxies.php b/src/Magento/FunctionalTestingFramework/Module/MagentoActionProxies.php index 5a3b2360b..9bf5ebd38 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoActionProxies.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoActionProxies.php @@ -10,6 +10,7 @@ use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; /** * Class MagentoActionProxies @@ -20,5 +21,112 @@ */ class MagentoActionProxies extends CodeceptionModule { - // TODO: placeholder for proxy functions currently in MagentoWebDriver (MQE-1904) + /** + * Create an entity + * + * @param string $key StepKey of the createData action. + * @param string $scope + * @param string $entity Name of xml entity to create. + * @param array $dependentObjectKeys StepKeys of other createData actions that are required. + * @param array $overrideFields Array of FieldName => Value of override fields. + * @param string $storeCode + * @return void + * @throws TestReferenceException + */ + public function createEntity( + $key, + $scope, + $entity, + $dependentObjectKeys = [], + $overrideFields = [], + $storeCode = '' + ) { + PersistedObjectHandler::getInstance()->createEntity( + $key, + $scope, + $entity, + $dependentObjectKeys, + $overrideFields, + $storeCode + ); + } + + /** + * Retrieves and updates a previously created entity + * + * @param string $key StepKey of the createData action. + * @param string $scope + * @param string $updateEntity Name of the static XML data to update the entity with. + * @param array $dependentObjectKeys StepKeys of other createData actions that are required. + * @return void + */ + public function updateEntity($key, $scope, $updateEntity, $dependentObjectKeys = []) + { + PersistedObjectHandler::getInstance()->updateEntity( + $key, + $scope, + $updateEntity, + $dependentObjectKeys + ); + } + + /** + * Performs GET on given entity and stores entity for use + * + * @param string $key StepKey of getData action. + * @param string $scope + * @param string $entity Name of XML static data to use. + * @param array $dependentObjectKeys StepKeys of other createData actions that are required. + * @param string $storeCode + * @param integer $index + * @return void + */ + public function getEntity($key, $scope, $entity, $dependentObjectKeys = [], $storeCode = '', $index = null) + { + PersistedObjectHandler::getInstance()->getEntity( + $key, + $scope, + $entity, + $dependentObjectKeys, + $storeCode, + $index + ); + } + + /** + * Retrieves and deletes a previously created entity + * + * @param string $key StepKey of the createData action. + * @param string $scope + * @return void + */ + public function deleteEntity($key, $scope) + { + PersistedObjectHandler::getInstance()->deleteEntity($key, $scope); + } + + /** + * Retrieves a field from an entity, according to key and scope given + * + * @param string $stepKey + * @param string $field + * @param string $scope + * @return string + */ + public function retrieveEntityField($stepKey, $field, $scope) + { + return PersistedObjectHandler::getInstance()->retrieveEntityField($stepKey, $field, $scope); + } + + /** + * Get encrypted value by key + * + * @param string $key + * @return string|null + * @throws TestFrameworkException + */ + public function getSecret($key) + { + return CredentialStore::getInstance()->getSecret($key); + } } diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 5ee26cf92..473e750b6 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -26,7 +26,6 @@ use Magento\FunctionalTestingFramework\DataTransport\Protocol\CurlTransport; use Yandex\Allure\Adapter\Support\AttachmentSupport; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; /** * MagentoWebDriver module provides common Magento web actions through Selenium WebDriver. @@ -953,120 +952,6 @@ public function getOTP() return OTP::getOTP(); } - /** - * Create an entity - * TODO: move this function to MagentoActionProxies after MQE-1904 - * - * @param string $key StepKey of the createData action. - * @param string $scope - * @param string $entity Name of xml entity to create. - * @param array $dependentObjectKeys StepKeys of other createData actions that are required. - * @param array $overrideFields Array of FieldName => Value of override fields. - * @param string $storeCode - * @return void - */ - public function createEntity( - $key, - $scope, - $entity, - $dependentObjectKeys = [], - $overrideFields = [], - $storeCode = '' - ) { - PersistedObjectHandler::getInstance()->createEntity( - $key, - $scope, - $entity, - $dependentObjectKeys, - $overrideFields, - $storeCode - ); - } - - /** - * Retrieves and updates a previously created entity - * TODO: move this function to MagentoActionProxies after MQE-1904 - * - * @param string $key StepKey of the createData action. - * @param string $scope - * @param string $updateEntity Name of the static XML data to update the entity with. - * @param array $dependentObjectKeys StepKeys of other createData actions that are required. - * @return void - */ - public function updateEntity($key, $scope, $updateEntity, $dependentObjectKeys = []) - { - PersistedObjectHandler::getInstance()->updateEntity( - $key, - $scope, - $updateEntity, - $dependentObjectKeys - ); - } - - /** - * Performs GET on given entity and stores entity for use - * TODO: move this function to MagentoActionProxies after MQE-1904 - * - * @param string $key StepKey of getData action. - * @param string $scope - * @param string $entity Name of XML static data to use. - * @param array $dependentObjectKeys StepKeys of other createData actions that are required. - * @param string $storeCode - * @param integer $index - * @return void - */ - public function getEntity($key, $scope, $entity, $dependentObjectKeys = [], $storeCode = '', $index = null) - { - PersistedObjectHandler::getInstance()->getEntity( - $key, - $scope, - $entity, - $dependentObjectKeys, - $storeCode, - $index - ); - } - - /** - * Retrieves and deletes a previously created entity - * TODO: move this function to MagentoActionProxies after MQE-1904 - * - * @param string $key StepKey of the createData action. - * @param string $scope - * @return void - */ - public function deleteEntity($key, $scope) - { - PersistedObjectHandler::getInstance()->deleteEntity($key, $scope); - } - - /** - * Retrieves a field from an entity, according to key and scope given - * TODO: move this function to MagentoActionProxies after MQE-1904 - * - * @param string $stepKey - * @param string $field - * @param string $scope - * @return string - */ - public function retrieveEntityField($stepKey, $field, $scope) - { - return PersistedObjectHandler::getInstance()->retrieveEntityField($stepKey, $field, $scope); - } - - /** - * Get encrypted value by key - * TODO: move this function to MagentoActionProxies after MQE-1904 - * - * @param string $key - * @return string|null - * @throws TestFrameworkException - */ - public function getSecret($key) - { - return CredentialStore::getInstance()->getSecret($key); - } - /** * Waits proper amount of time to perform Cron execution * From a0e287e06484dd2706b1a6e27fae32d2eddab02e Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Wed, 3 Jun 2020 17:31:51 -0500 Subject: [PATCH 417/888] MQE-2160: Extended data entity won't merge array items --- composer.json | 3 ++- composer.lock | 2 +- dev/tests/verification/Resources/ExtendParentDataTest.txt | 4 ++-- .../verification/Resources/ExtendedParameterArrayTest.txt | 4 ++-- .../DataGenerator/Handlers/DataObjectHandler.php | 4 ++-- .../DataGenerator/Util/DataExtensionUtil.php | 2 +- 6 files changed, 10 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index 7bbc69268..ebc7065bb 100755 --- a/composer.json +++ b/composer.json @@ -32,7 +32,8 @@ "symfony/finder": "^5.0", "symfony/mime": "^5.0", "symfony/process": "^4.4", - "vlucas/phpdotenv": "^2.4" + "vlucas/phpdotenv": "^2.4", + "weew/helpers-array": "^1.3" }, "require-dev": { "brainmaestro/composer-git-hooks": "^2.3.1", diff --git a/composer.lock b/composer.lock index 2d45550ef..1006d1973 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "34e8bc951072914b0c115d2d4893b9b0", + "content-hash": "67a2c5f33cfd03674f7db80019817fb5", "packages": [ { "name": "allure-framework/allure-codeception", diff --git a/dev/tests/verification/Resources/ExtendParentDataTest.txt b/dev/tests/verification/Resources/ExtendParentDataTest.txt index f2ddc4ffd..70cb6b70b 100644 --- a/dev/tests/verification/Resources/ExtendParentDataTest.txt +++ b/dev/tests/verification/Resources/ExtendParentDataTest.txt @@ -27,9 +27,9 @@ class ExtendParentDataTestCest public function ExtendParentDataTest(AcceptanceTester $I) { $I->createEntity("simpleDataKey", "test", "extendParentData", [], []); // stepKey: simpleDataKey - $I->searchAndMultiSelectOption("#selector", ["name", "otherName"]); // stepKey: getName + $I->searchAndMultiSelectOption("#selector", ["otherName"]); // stepKey: getName $I->searchAndMultiSelectOption("#selector", ["extendName"]); // stepKey: getNameExtend - $I->searchAndMultiSelectOption("#selector", ["postname", "item"]); // stepKey: emptyPost + $I->searchAndMultiSelectOption("#selector", ["item"]); // stepKey: emptyPost $I->searchAndMultiSelectOption("#selector", [msq("extendParentData") . "prename"]); // stepKey: originalPre $I->searchAndMultiSelectOption("#selector", ["postnameExtend" . msq("extendParentData")]); // stepKey: secondUniquePre } diff --git a/dev/tests/verification/Resources/ExtendedParameterArrayTest.txt b/dev/tests/verification/Resources/ExtendedParameterArrayTest.txt index 2d3004717..d09e9a0b6 100644 --- a/dev/tests/verification/Resources/ExtendedParameterArrayTest.txt +++ b/dev/tests/verification/Resources/ExtendedParameterArrayTest.txt @@ -26,9 +26,9 @@ class ExtendParentDataTestCest public function ExtendParentDataTest(AcceptanceTester $I) { $I->createEntity("simpleDataKey", "test", "extendParentData", [], []); // stepKey: simpleDataKey - $I->searchAndMultiSelectOption("#selector", ["name", "otherName"]); + $I->searchAndMultiSelectOption("#selector", ["otherName"]); $I->searchAndMultiSelectOption("#selector", ["extendName"]); - $I->searchAndMultiSelectOption("#selector", ["postname", "item"]); + $I->searchAndMultiSelectOption("#selector", ["item"]); $I->searchAndMultiSelectOption("#selector", [msq("extendParentData") . "prename"]); $I->searchAndMultiSelectOption("#selector", ["postnameExtend" . msq("extendParentData")]); } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php index 26b603915..5a4b42dc4 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php @@ -226,8 +226,8 @@ private function processParserOutput($parserOutput) private function processArray($arrayItems, $data, $key) { $items = []; - foreach ($arrayItems as $item) { - $items[] = $item[self::_VALUE]; + foreach ($arrayItems as $key => $item) { + $items[$key] = $item[self::_VALUE]; } return array_merge($items, $data[$key] ?? []); diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Util/DataExtensionUtil.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Util/DataExtensionUtil.php index 2ed331c6b..53fe71fc0 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Util/DataExtensionUtil.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Util/DataExtensionUtil.php @@ -62,7 +62,7 @@ public function extendEntity($entityObject) // Get all data for both parent and child and merge $referencedData = $parentEntity->getAllData(); - $newData = array_merge_recursive($referencedData, $entityObject->getAllData()); + $newData = array_extend($referencedData, $entityObject->getAllData()); // Get all linked references for both parent and child and merge $referencedLinks = $parentEntity->getLinkedEntities(); From 15903fc4fead847d1536a40f78d4b39f3cd463ec Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Thu, 4 Jun 2020 09:55:25 -0500 Subject: [PATCH 418/888] MQE-2161: Chrome 81 requires --ignore-certificate-errors flag --- etc/config/functional.suite.dist.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/config/functional.suite.dist.yml b/etc/config/functional.suite.dist.yml index 726c9674a..3254b728d 100644 --- a/etc/config/functional.suite.dist.yml +++ b/etc/config/functional.suite.dist.yml @@ -37,4 +37,4 @@ modules: capabilities: unhandledPromptBehavior: "ignore" chromeOptions: - args: ["--window-size=1280,1024", "--disable-extensions", "--enable-automation", "--disable-gpu", "--enable-Passthrough", "--disable-dev-shm-usage"] + args: ["--window-size=1280,1024", "--disable-extensions", "--enable-automation", "--disable-gpu", "--enable-Passthrough", "--disable-dev-shm-usage", "--ignore-certificate-errors"] From 2353f1cbc5a7fc48e81f9e93c35481b5789b113b Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Fri, 5 Jun 2020 12:25:05 -0500 Subject: [PATCH 419/888] MQE-2153: CHANGELOG.md updated for 3.0.0-RC4 --- CHANGELOG.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ed2920f3..3793c8f63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ Magento Functional Testing Framework Changelog ================================================ +3.0.0 RC4 +--------- + +### Enhancements + +* Customizability + * Changed `<group value="skip"/>` to no longer skip a test, instead test is added to `skip` group. +* Maintainability + * Trimmed `mftf.log` to not include notices and warnings at test execution time. + * Added chrome option `--ignore-certificate-errors` in `functional.suite.dist.yml`. +* Traceability + * Changed `bin/mftf static-checks` error file directory from current working directory to `TESTS_BP/tests/_output/static-results/`. +* Readability + * Documented [3.0.0 Backward Incompatible Changes.](./docs/backward-incompatible-changes.md) + +### Fixes + +* Fixed issue with Extended data entity won't merge array items. + 3.0.0 RC3 --------- @@ -8,7 +27,7 @@ Magento Functional Testing Framework Changelog * Maintainability * Added support for Two-Factor Authentication (2FA). [See configure-2fa page for details](./docs/configure-2fa.md) * Added new static check `annotationsCheck` that checks and reports missing annotations in tests. - * Updated `mftf static-checks` command to allow executing static-checks defined in `staticRuleSet.json` by default. [See command page for details](./docs/commands/mftf.md#static-checks) + * Updated `bin/mftf static-checks` command to allow executing static-checks defined in `staticRuleSet.json` by default. [See command page for details](./docs/commands/mftf.md#static-checks) * Added new upgrade script to remove unused arguments from action groups. * Added unhandledPromptBehavior driver capability for Chrome 75+ support. * Removed redundant and unused classes. From b532751476477e1302e4e9c6f4cf160be4de86ec Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Fri, 5 Jun 2020 12:57:21 -0500 Subject: [PATCH 420/888] MQE-2153: CHANGELOG.md updated for 3.0.0-RC4 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3793c8f63..dce9f3641 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ Magento Functional Testing Framework Changelog ### Fixes -* Fixed issue with Extended data entity won't merge array items. +* Fixed issue with extended data entity won't merge array items. 3.0.0 RC3 --------- From 2c1b8ab2882948ab1fe943521f7500e42e2685bd Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Fri, 5 Jun 2020 13:02:27 -0500 Subject: [PATCH 421/888] Editorial pass --- CHANGELOG.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dce9f3641..1ad1ea299 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,18 +6,18 @@ Magento Functional Testing Framework Changelog ### Enhancements * Customizability - * Changed `<group value="skip"/>` to no longer skip a test, instead test is added to `skip` group. + * `<group value="skip"/>` no longer skips a test. Instead, the test is added to the `skip` group. * Maintainability - * Trimmed `mftf.log` to not include notices and warnings at test execution time. - * Added chrome option `--ignore-certificate-errors` in `functional.suite.dist.yml`. + * `mftf.log` no longer includes notices and warnings at test execution time. + * Added the Chrome option `--ignore-certificate-errors` to `functional.suite.dist.yml`. * Traceability - * Changed `bin/mftf static-checks` error file directory from current working directory to `TESTS_BP/tests/_output/static-results/`. + * Changed the `bin/mftf static-checks` error file directory from the current working directory to `TESTS_BP/tests/_output/static-results/`. * Readability * Documented [3.0.0 Backward Incompatible Changes.](./docs/backward-incompatible-changes.md) ### Fixes -* Fixed issue with extended data entity won't merge array items. +* Fixed issue where an extended data entity would not merge array items. Array items should merge properly now. 3.0.0 RC3 --------- From b4e676bd2c9448fb1d1af1d78f87b8995aac257b Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Fri, 5 Jun 2020 17:17:36 -0500 Subject: [PATCH 422/888] Revert "MQE-2158: move proxies function from MagentoWebDriver back into MagentoActionProxies" This reverts commit 5b461c5a --- .../Module/MagentoActionProxies.php | 110 +---------------- .../Module/MagentoWebDriver.php | 115 ++++++++++++++++++ 2 files changed, 116 insertions(+), 109 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoActionProxies.php b/src/Magento/FunctionalTestingFramework/Module/MagentoActionProxies.php index 9bf5ebd38..5a3b2360b 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoActionProxies.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoActionProxies.php @@ -10,7 +10,6 @@ use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; -use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; /** * Class MagentoActionProxies @@ -21,112 +20,5 @@ */ class MagentoActionProxies extends CodeceptionModule { - /** - * Create an entity - * - * @param string $key StepKey of the createData action. - * @param string $scope - * @param string $entity Name of xml entity to create. - * @param array $dependentObjectKeys StepKeys of other createData actions that are required. - * @param array $overrideFields Array of FieldName => Value of override fields. - * @param string $storeCode - * @return void - * @throws TestReferenceException - */ - public function createEntity( - $key, - $scope, - $entity, - $dependentObjectKeys = [], - $overrideFields = [], - $storeCode = '' - ) { - PersistedObjectHandler::getInstance()->createEntity( - $key, - $scope, - $entity, - $dependentObjectKeys, - $overrideFields, - $storeCode - ); - } - - /** - * Retrieves and updates a previously created entity - * - * @param string $key StepKey of the createData action. - * @param string $scope - * @param string $updateEntity Name of the static XML data to update the entity with. - * @param array $dependentObjectKeys StepKeys of other createData actions that are required. - * @return void - */ - public function updateEntity($key, $scope, $updateEntity, $dependentObjectKeys = []) - { - PersistedObjectHandler::getInstance()->updateEntity( - $key, - $scope, - $updateEntity, - $dependentObjectKeys - ); - } - - /** - * Performs GET on given entity and stores entity for use - * - * @param string $key StepKey of getData action. - * @param string $scope - * @param string $entity Name of XML static data to use. - * @param array $dependentObjectKeys StepKeys of other createData actions that are required. - * @param string $storeCode - * @param integer $index - * @return void - */ - public function getEntity($key, $scope, $entity, $dependentObjectKeys = [], $storeCode = '', $index = null) - { - PersistedObjectHandler::getInstance()->getEntity( - $key, - $scope, - $entity, - $dependentObjectKeys, - $storeCode, - $index - ); - } - - /** - * Retrieves and deletes a previously created entity - * - * @param string $key StepKey of the createData action. - * @param string $scope - * @return void - */ - public function deleteEntity($key, $scope) - { - PersistedObjectHandler::getInstance()->deleteEntity($key, $scope); - } - - /** - * Retrieves a field from an entity, according to key and scope given - * - * @param string $stepKey - * @param string $field - * @param string $scope - * @return string - */ - public function retrieveEntityField($stepKey, $field, $scope) - { - return PersistedObjectHandler::getInstance()->retrieveEntityField($stepKey, $field, $scope); - } - - /** - * Get encrypted value by key - * - * @param string $key - * @return string|null - * @throws TestFrameworkException - */ - public function getSecret($key) - { - return CredentialStore::getInstance()->getSecret($key); - } + // TODO: placeholder for proxy functions currently in MagentoWebDriver (MQE-1904) } diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 473e750b6..5ee26cf92 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -26,6 +26,7 @@ use Magento\FunctionalTestingFramework\DataTransport\Protocol\CurlTransport; use Yandex\Allure\Adapter\Support\AttachmentSupport; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; /** * MagentoWebDriver module provides common Magento web actions through Selenium WebDriver. @@ -952,6 +953,120 @@ public function getOTP() return OTP::getOTP(); } + /** + * Create an entity + * TODO: move this function to MagentoActionProxies after MQE-1904 + * + * @param string $key StepKey of the createData action. + * @param string $scope + * @param string $entity Name of xml entity to create. + * @param array $dependentObjectKeys StepKeys of other createData actions that are required. + * @param array $overrideFields Array of FieldName => Value of override fields. + * @param string $storeCode + * @return void + */ + public function createEntity( + $key, + $scope, + $entity, + $dependentObjectKeys = [], + $overrideFields = [], + $storeCode = '' + ) { + PersistedObjectHandler::getInstance()->createEntity( + $key, + $scope, + $entity, + $dependentObjectKeys, + $overrideFields, + $storeCode + ); + } + + /** + * Retrieves and updates a previously created entity + * TODO: move this function to MagentoActionProxies after MQE-1904 + * + * @param string $key StepKey of the createData action. + * @param string $scope + * @param string $updateEntity Name of the static XML data to update the entity with. + * @param array $dependentObjectKeys StepKeys of other createData actions that are required. + * @return void + */ + public function updateEntity($key, $scope, $updateEntity, $dependentObjectKeys = []) + { + PersistedObjectHandler::getInstance()->updateEntity( + $key, + $scope, + $updateEntity, + $dependentObjectKeys + ); + } + + /** + * Performs GET on given entity and stores entity for use + * TODO: move this function to MagentoActionProxies after MQE-1904 + * + * @param string $key StepKey of getData action. + * @param string $scope + * @param string $entity Name of XML static data to use. + * @param array $dependentObjectKeys StepKeys of other createData actions that are required. + * @param string $storeCode + * @param integer $index + * @return void + */ + public function getEntity($key, $scope, $entity, $dependentObjectKeys = [], $storeCode = '', $index = null) + { + PersistedObjectHandler::getInstance()->getEntity( + $key, + $scope, + $entity, + $dependentObjectKeys, + $storeCode, + $index + ); + } + + /** + * Retrieves and deletes a previously created entity + * TODO: move this function to MagentoActionProxies after MQE-1904 + * + * @param string $key StepKey of the createData action. + * @param string $scope + * @return void + */ + public function deleteEntity($key, $scope) + { + PersistedObjectHandler::getInstance()->deleteEntity($key, $scope); + } + + /** + * Retrieves a field from an entity, according to key and scope given + * TODO: move this function to MagentoActionProxies after MQE-1904 + * + * @param string $stepKey + * @param string $field + * @param string $scope + * @return string + */ + public function retrieveEntityField($stepKey, $field, $scope) + { + return PersistedObjectHandler::getInstance()->retrieveEntityField($stepKey, $field, $scope); + } + + /** + * Get encrypted value by key + * TODO: move this function to MagentoActionProxies after MQE-1904 + * + * @param string $key + * @return string|null + * @throws TestFrameworkException + */ + public function getSecret($key) + { + return CredentialStore::getInstance()->getSecret($key); + } + /** * Waits proper amount of time to perform Cron execution * From 1e37e95dbf742b1848f5152f319fa7404358f101 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Sat, 6 Jun 2020 14:57:21 -0500 Subject: [PATCH 423/888] MQE-2162: Chrome remains running after MFTF suite finishes --- etc/config/.env.example | 1 + etc/config/functional.suite.dist.yml | 1 + .../Suite/views/SuiteClass.mustache | 49 ++++++++++++++++--- .../Suite/views/partials/testActions.mustache | 11 ++--- 4 files changed, 48 insertions(+), 14 deletions(-) diff --git a/etc/config/.env.example b/etc/config/.env.example index 86df31b3d..5597e08b5 100644 --- a/etc/config/.env.example +++ b/etc/config/.env.example @@ -21,6 +21,7 @@ MAGENTO_ADMIN_PASSWORD=123123q #SELENIUM_PORT=4444 #SELENIUM_PROTOCOL=http #SELENIUM_PATH=/wd/hub +SELENIUM_CLOSE_ALL_SESSIONS=true #*** Browser for running tests, default chrome. Uncomment and change if you want to run tests on another browser (ex. firefox). BROWSER=chrome diff --git a/etc/config/functional.suite.dist.yml b/etc/config/functional.suite.dist.yml index 3254b728d..fefcec410 100644 --- a/etc/config/functional.suite.dist.yml +++ b/etc/config/functional.suite.dist.yml @@ -34,6 +34,7 @@ modules: port: "%SELENIUM_PORT%" protocol: "%SELENIUM_PROTOCOL%" path: "%SELENIUM_PATH%" + close_all_sessions: "%SELENIUM_CLOSE_ALL_SESSIONS%" capabilities: unhandledPromptBehavior: "ignore" chromeOptions: diff --git a/src/Magento/FunctionalTestingFramework/Suite/views/SuiteClass.mustache b/src/Magento/FunctionalTestingFramework/Suite/views/SuiteClass.mustache index 0e60437ee..a9fdcd6df 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/views/SuiteClass.mustache +++ b/src/Magento/FunctionalTestingFramework/Suite/views/SuiteClass.mustache @@ -2,8 +2,10 @@ namespace Group; +use Facebook\WebDriver\Remote\RemoteWebDriver; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; +use Magento\FunctionalTestingFramework\Module\MagentoWebDriver; /** * Group class is Codeception Extension which is allowed to handle to all internal events. @@ -55,18 +57,20 @@ class {{suiteName}} extends \Codeception\GroupObject if ($this->currentTestRun == 1) { print sprintf(self::$HOOK_EXECUTION_INIT, "before"); + /** @var MagentoWebDriver $webDriver */ + $webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); + try { {{> testActions}} - - // reset configuration and close session - $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver')->_resetConfig(); - $webDriver->webDriver->close(); - $webDriver->webDriver = null; - } catch (\Exception $exception) { $this->preconditionFailure = $exception->getMessage(); } + // reset configuration and close session + $webDriver->_resetConfig(); + $webDriver->webDriver->close(); + $webDriver->webDriver = null; + print sprintf(self::$HOOK_EXECUTION_END, "before"); } } @@ -84,6 +88,9 @@ class {{suiteName}} extends \Codeception\GroupObject if ($this->currentTestRun == $this->testCount) { print sprintf(self::$HOOK_EXECUTION_INIT, "after"); + /** @var MagentoWebDriver $webDriver */ + $webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); + try { // Find out if Test in Suite failed, will cause potential failures in suite after $cest = $e->getTest(); @@ -112,8 +119,38 @@ class {{suiteName}} extends \Codeception\GroupObject } PersistedObjectHandler::getInstance()->clearSuiteObjects(); + + $this->closeSession($webDriver); + print sprintf(self::$HOOK_EXECUTION_END, "after"); } } {{/after}} + + /** + * Close session method closes current session. + * If config 'close_all_sessions' is set to 'true' all sessions will be closed. + * + * @param MagentoWebDriver $webDriver + * return void + */ + private function closeSession(MagentoWebDriver $webDriver): void + { + $webDriverConfig = $webDriver->_getConfig(); + $webDriver->_closeSession(); + if (isset($webDriverConfig['close_all_sessions']) && $webDriverConfig['close_all_sessions'] === "true") { + $wdHost = sprintf( + '%s://%s:%s%s', + $webDriverConfig['protocol'], + $webDriverConfig['host'], + $webDriverConfig['port'], + $webDriverConfig['path'] + ); + $availableSessions = RemoteWebDriver::getAllSessions($wdHost); + foreach ($availableSessions as $session) { + $remoteWebDriver = RemoteWebDriver::createBySessionID($session['id'], $wdHost); + $remoteWebDriver->quit(); + } + } + } } diff --git a/src/Magento/FunctionalTestingFramework/Suite/views/partials/testActions.mustache b/src/Magento/FunctionalTestingFramework/Suite/views/partials/testActions.mustache index 2ed5e8d5e..73079f169 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/views/partials/testActions.mustache +++ b/src/Magento/FunctionalTestingFramework/Suite/views/partials/testActions.mustache @@ -1,15 +1,10 @@ {{#actions}} {{#webDriverInit}} -$webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); - -// close any open sessions if ($webDriver->webDriver != null) { - $webDriver->webDriver->close(); - $webDriver->webDriver = null; + $webDriver->_restart(); +} else { + $webDriver->_initializeSession(); } - -// initialize the webdriver session -$webDriver->_initializeSession(); {{/webDriverInit}} {{#action}} {{{action}}} From 5079cca1f0342e7c5b198a8afc66c65ba904c17e Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Sat, 6 Jun 2020 15:11:56 -0500 Subject: [PATCH 424/888] MQE-2162: Chrome remains running after MFTF suite finishes - verification test fix --- .../Resources/functionalSuiteHooks.txt | 71 +++++++++++++------ .../Resources/functionalSuiteWithComments.txt | 71 +++++++++++++------ 2 files changed, 98 insertions(+), 44 deletions(-) diff --git a/dev/tests/verification/Resources/functionalSuiteHooks.txt b/dev/tests/verification/Resources/functionalSuiteHooks.txt index 908cff8aa..3b5f6bae0 100644 --- a/dev/tests/verification/Resources/functionalSuiteHooks.txt +++ b/dev/tests/verification/Resources/functionalSuiteHooks.txt @@ -2,8 +2,10 @@ namespace Group; +use Facebook\WebDriver\Remote\RemoteWebDriver; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; +use Magento\FunctionalTestingFramework\Module\MagentoWebDriver; /** * Group class is Codeception Extension which is allowed to handle to all internal events. @@ -41,17 +43,15 @@ class functionalSuiteHooks extends \Codeception\GroupObject if ($this->currentTestRun == 1) { print sprintf(self::$HOOK_EXECUTION_INIT, "before"); + /** @var MagentoWebDriver $webDriver */ + $webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); + try { - $webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); - - // close any open sessions if ($webDriver->webDriver != null) { - $webDriver->webDriver->close(); - $webDriver->webDriver = null; + $webDriver->_restart(); + } else { + $webDriver->_initializeSession(); } - - // initialize the webdriver session - $webDriver->_initializeSession(); $webDriver->amOnPage("some.url"); // stepKey: before $createFields['someKey'] = "dataHere"; PersistedObjectHandler::getInstance()->createEntity( @@ -64,16 +64,15 @@ class functionalSuiteHooks extends \Codeception\GroupObject print("Entering Action Group [AC] actionGroupWithTwoArguments"); $webDriver->see("John", msq("uniqueData") . "John"); // stepKey: seeFirstNameAC print("Exiting Action Group [AC] actionGroupWithTwoArguments"); - - // reset configuration and close session - $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver')->_resetConfig(); - $webDriver->webDriver->close(); - $webDriver->webDriver = null; - } catch (\Exception $exception) { $this->preconditionFailure = $exception->getMessage(); } + // reset configuration and close session + $webDriver->_resetConfig(); + $webDriver->webDriver->close(); + $webDriver->webDriver = null; + print sprintf(self::$HOOK_EXECUTION_END, "before"); } } @@ -89,6 +88,9 @@ class functionalSuiteHooks extends \Codeception\GroupObject if ($this->currentTestRun == $this->testCount) { print sprintf(self::$HOOK_EXECUTION_INIT, "after"); + /** @var MagentoWebDriver $webDriver */ + $webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); + try { // Find out if Test in Suite failed, will cause potential failures in suite after $cest = $e->getTest(); @@ -111,16 +113,11 @@ class functionalSuiteHooks extends \Codeception\GroupObject } } } - $webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); - - // close any open sessions if ($webDriver->webDriver != null) { - $webDriver->webDriver->close(); - $webDriver->webDriver = null; + $webDriver->_restart(); + } else { + $webDriver->_initializeSession(); } - - // initialize the webdriver session - $webDriver->_initializeSession(); $webDriver->amOnPage("some.url"); // stepKey: after $webDriver->deleteEntityByUrl("deleteThis"); // stepKey: delete print("Entering Action Group [AC] actionGroupWithTwoArguments"); @@ -131,7 +128,37 @@ class functionalSuiteHooks extends \Codeception\GroupObject } PersistedObjectHandler::getInstance()->clearSuiteObjects(); + + $this->closeSession($webDriver); + print sprintf(self::$HOOK_EXECUTION_END, "after"); } } + + /** + * Close session method closes current session. + * If config 'close_all_sessions' is set to 'true' all sessions will be closed. + * + * @param MagentoWebDriver $webDriver + * return void + */ + private function closeSession(MagentoWebDriver $webDriver): void + { + $webDriverConfig = $webDriver->_getConfig(); + $webDriver->_closeSession(); + if (isset($webDriverConfig['close_all_sessions']) && $webDriverConfig['close_all_sessions'] === "true") { + $wdHost = sprintf( + '%s://%s:%s%s', + $webDriverConfig['protocol'], + $webDriverConfig['host'], + $webDriverConfig['port'], + $webDriverConfig['path'] + ); + $availableSessions = RemoteWebDriver::getAllSessions($wdHost); + foreach ($availableSessions as $session) { + $remoteWebDriver = RemoteWebDriver::createBySessionID($session['id'], $wdHost); + $remoteWebDriver->quit(); + } + } + } } diff --git a/dev/tests/verification/Resources/functionalSuiteWithComments.txt b/dev/tests/verification/Resources/functionalSuiteWithComments.txt index 0e15b7909..c8523d0c1 100644 --- a/dev/tests/verification/Resources/functionalSuiteWithComments.txt +++ b/dev/tests/verification/Resources/functionalSuiteWithComments.txt @@ -2,8 +2,10 @@ namespace Group; +use Facebook\WebDriver\Remote\RemoteWebDriver; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; +use Magento\FunctionalTestingFramework\Module\MagentoWebDriver; /** * Group class is Codeception Extension which is allowed to handle to all internal events. @@ -41,17 +43,15 @@ class functionalSuiteWithComments extends \Codeception\GroupObject if ($this->currentTestRun == 1) { print sprintf(self::$HOOK_EXECUTION_INIT, "before"); + /** @var MagentoWebDriver $webDriver */ + $webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); + try { - $webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); - - // close any open sessions if ($webDriver->webDriver != null) { - $webDriver->webDriver->close(); - $webDriver->webDriver = null; + $webDriver->_restart(); + } else { + $webDriver->_initializeSession(); } - - // initialize the webdriver session - $webDriver->_initializeSession(); print("Comment in Before"); $webDriver->amOnPage("some.url"); // stepKey: before $createFields['someKey'] = "dataHere"; @@ -66,16 +66,15 @@ class functionalSuiteWithComments extends \Codeception\GroupObject print("Entering Action Group [AC] actionGroupWithTwoArguments"); $webDriver->see("John", msq("uniqueData") . "John"); // stepKey: seeFirstNameAC print("Exiting Action Group [AC] actionGroupWithTwoArguments"); - - // reset configuration and close session - $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver')->_resetConfig(); - $webDriver->webDriver->close(); - $webDriver->webDriver = null; - } catch (\Exception $exception) { $this->preconditionFailure = $exception->getMessage(); } + // reset configuration and close session + $webDriver->_resetConfig(); + $webDriver->webDriver->close(); + $webDriver->webDriver = null; + print sprintf(self::$HOOK_EXECUTION_END, "before"); } } @@ -91,6 +90,9 @@ class functionalSuiteWithComments extends \Codeception\GroupObject if ($this->currentTestRun == $this->testCount) { print sprintf(self::$HOOK_EXECUTION_INIT, "after"); + /** @var MagentoWebDriver $webDriver */ + $webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); + try { // Find out if Test in Suite failed, will cause potential failures in suite after $cest = $e->getTest(); @@ -113,23 +115,48 @@ class functionalSuiteWithComments extends \Codeception\GroupObject } } } - $webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); - - // close any open sessions if ($webDriver->webDriver != null) { - $webDriver->webDriver->close(); - $webDriver->webDriver = null; + $webDriver->_restart(); + } else { + $webDriver->_initializeSession(); } - - // initialize the webdriver session - $webDriver->_initializeSession(); print("afterBlock"); } catch (\Exception $exception) { print $exception->getMessage(); } PersistedObjectHandler::getInstance()->clearSuiteObjects(); + + $this->closeSession($webDriver); + print sprintf(self::$HOOK_EXECUTION_END, "after"); } } + + /** + * Close session method closes current session. + * If config 'close_all_sessions' is set to 'true' all sessions will be closed. + * + * @param MagentoWebDriver $webDriver + * return void + */ + private function closeSession(MagentoWebDriver $webDriver): void + { + $webDriverConfig = $webDriver->_getConfig(); + $webDriver->_closeSession(); + if (isset($webDriverConfig['close_all_sessions']) && $webDriverConfig['close_all_sessions'] === "true") { + $wdHost = sprintf( + '%s://%s:%s%s', + $webDriverConfig['protocol'], + $webDriverConfig['host'], + $webDriverConfig['port'], + $webDriverConfig['path'] + ); + $availableSessions = RemoteWebDriver::getAllSessions($wdHost); + foreach ($availableSessions as $session) { + $remoteWebDriver = RemoteWebDriver::createBySessionID($session['id'], $wdHost); + $remoteWebDriver->quit(); + } + } + } } From 23d869306793701b3eb50b51c44cd7f8fc536601 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Mon, 8 Jun 2020 10:40:28 -0500 Subject: [PATCH 425/888] MQE-2162: Chrome remains running after MFTF suite finishes - Docs added --- docs/configuration.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/configuration.md b/docs/configuration.md index d2ce5e1a5..5a912b66c 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -321,6 +321,16 @@ Enables addition of browser logs to Allure steps ENABLE_BROWSER_LOG=true ``` +### SELENIUM_CLOSE_ALL_SESSIONS + +Forces MFTF to close all Selenium sessions after running a suite. + +Use this if you're having issues with sessions hanging in an MFTF suite. + +```conf +SELENIUM_CLOSE_ALL_SESSIONS=true +``` + ### BROWSER_LOG_BLACKLIST Blacklists types of browser log entries from appearing in Allure steps. From cebd92f8ac9478ae941232361101bd0f205bde4e Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 8 Jun 2020 12:56:52 -0500 Subject: [PATCH 426/888] MQE-2153: CHANGELOG.md updated and composer version bumped to 3.0.0-RC4 --- CHANGELOG.md | 1 + composer.json | 2 +- composer.lock | 281 +------------------------------------------------- 3 files changed, 4 insertions(+), 280 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ad1ea299..c285d511b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ Magento Functional Testing Framework Changelog ### Fixes * Fixed issue where an extended data entity would not merge array items. Array items should merge properly now. +* Fixed issue where Chrome remains running after MFTF suite finishes. 3.0.0 RC3 --------- diff --git a/composer.json b/composer.json index ebc7065bb..c94ca7e0a 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "3.0.0-RC3", + "version": "3.0.0-RC4", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index 1006d1973..f98e1db13 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "67a2c5f33cfd03674f7db80019817fb5", + "content-hash": "98d36dbb7c244643cd4f2bd83fa391d6", "packages": [ { "name": "allure-framework/allure-codeception", @@ -896,16 +896,6 @@ "dependency", "package" ], - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], "time": "2020-04-10T09:44:22+00:00" }, { @@ -1994,12 +1984,6 @@ "sftp", "storage" ], - "funding": [ - { - "url": "https://offset.earth/frankdejonge", - "type": "other" - } - ], "time": "2020-04-16T13:21:26+00:00" }, { @@ -3219,16 +3203,6 @@ "testing", "xunit" ], - "funding": [ - { - "url": "https://phpunit.de/donate.html", - "type": "custom" - }, - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], "time": "2020-04-23T04:42:05+00:00" }, { @@ -3642,12 +3616,6 @@ ], "description": "Collection of value objects that represent the PHP code units", "homepage": "https://github.com/sebastianbergmann/code-unit", - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], "time": "2020-03-30T11:59:20+00:00" }, { @@ -4506,20 +4474,6 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-03-30T11:41:10+00:00" }, { @@ -4573,20 +4527,6 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-03-27T16:56:45+00:00" }, { @@ -4657,20 +4597,6 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-03-27T16:54:36+00:00" }, { @@ -4779,20 +4705,6 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-03-27T16:56:45+00:00" }, { @@ -4842,20 +4754,6 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-03-27T16:56:45+00:00" }, { @@ -4911,20 +4809,6 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-03-30T14:14:32+00:00" }, { @@ -4987,20 +4871,6 @@ "mime", "mime-type" ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-03-27T16:56:45+00:00" }, { @@ -5059,20 +4929,6 @@ "polyfill", "portable" ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-02-27T09:26:54+00:00" }, { @@ -5135,20 +4991,6 @@ "portable", "shim" ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-03-09T19:04:49+00:00" }, { @@ -5208,20 +5050,6 @@ "portable", "shim" ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-03-09T19:04:49+00:00" }, { @@ -5277,20 +5105,6 @@ "portable", "shim" ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-02-27T09:26:54+00:00" }, { @@ -5349,20 +5163,6 @@ "portable", "shim" ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-02-27T09:26:54+00:00" }, { @@ -5412,20 +5212,6 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-03-27T16:54:36+00:00" }, { @@ -5543,20 +5329,6 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-03-30T11:41:10+00:00" }, { @@ -5786,12 +5558,6 @@ "env", "environment" ], - "funding": [ - { - "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", - "type": "tidelift" - } - ], "time": "2020-04-12T15:11:38+00:00" }, { @@ -6854,20 +6620,6 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-03-27T16:54:36+00:00" }, { @@ -6941,20 +6693,6 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-03-30T10:09:30+00:00" }, { @@ -7004,20 +6742,6 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-03-15T09:38:08+00:00" }, { @@ -7074,6 +6798,5 @@ "ext-json": "*", "ext-openssl": "*" }, - "platform-dev": [], - "plugin-api-version": "1.1.0" + "platform-dev": [] } From 7a7e4033cab73d19d1b5ec05a93cd9541bc4f6e8 Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Fri, 12 Jun 2020 14:19:58 -0500 Subject: [PATCH 427/888] MQE-2140: [chrome81] dragAndDrop with x and y offsets no longer works (#725) * MQE-2143: [chrome81] dragAndDrop with x and y offsets no longer works * MQE-2140: [chrome81] dragAndDrop with x and y offsets no longer works * MQE-2140: [chrome81] dragAndDrop with x and y offsets no longer works * MQE-2140: [chrome81] dragAndDrop with x and y offsets no longer works --- .../Module/MagentoWebDriver.php | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 5ee26cf92..984881e4e 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -745,23 +745,24 @@ public function _before(TestInterface $test) */ public function dragAndDrop($source, $target, $xOffset = null, $yOffset = null) { - if ($xOffset !== null || $yOffset !== null) { - $snodes = $this->matchFirstOrFail($this->baseElement, $source); - $tnodes = $this->matchFirstOrFail($this->baseElement, $target); + $snodes = $this->matchFirstOrFail($this->baseElement, $source); + $tnodes = $this->matchFirstOrFail($this->baseElement, $target); + $action = new WebDriverActions($this->webDriver); + if ($xOffset !== null || $yOffset !== null) { $targetX = intval($tnodes->getLocation()->getX() + $xOffset); $targetY = intval($tnodes->getLocation()->getY() + $yOffset); $travelX = intval($targetX - $snodes->getLocation()->getX()); $travelY = intval($targetY - $snodes->getLocation()->getY()); - - $action = new WebDriverActions($this->webDriver); - $action->moveToElement($snodes)->perform(); - $action->clickAndHold($snodes)->perform(); - $action->moveByOffset($travelX, $travelY)->perform(); + $action->moveToElement($snodes); + $action->clickAndHold($snodes); + $action->moveByOffset($travelX, $travelY); $action->release()->perform(); } else { - parent::dragAndDrop($source, $target); + $action->clickAndHold($snodes); + $action->moveToElement($tnodes); + $action->release($tnodes)->perform(); } } From bd2eee29eac0e438a2d09f63e6b5e3a8f852d933 Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Mon, 15 Jun 2020 11:31:51 -0500 Subject: [PATCH 428/888] MQE-2164: Remove terms from MFTF (#739) --- CHANGELOG.md | 4 +- bin/{blacklist.txt => blocklist.txt} | 2 +- bin/copyright-check | 4 +- bin/copyright-check.bat | 10 ++-- dev/tests/_bootstrap.php | 4 +- .../Sniffs/MicroOptimizations/IsNullSniff.php | 4 +- .../Util/ModuleResolverTest.php | 12 ++-- .../Validation/NameValidationUtilTest.php | 14 ++--- docs/configuration.md | 12 ++-- etc/codecoverage/index.php | 58 ------------------- etc/codecoverage/test.php | 10 ---- etc/config/.env.example | 6 +- .../Extension/TestContextExtension.php | 2 +- .../Page/Handlers/PageObjectHandler.php | 4 +- .../Test/Util/ActionObjectExtractor.php | 4 +- .../Test/Util/TestObjectExtractor.php | 2 +- .../Util/ModuleResolver.php | 34 +++++------ .../Util/Validation/NameValidationUtil.php | 2 +- 18 files changed, 60 insertions(+), 128 deletions(-) rename bin/{blacklist.txt => blocklist.txt} (96%) delete mode 100644 etc/codecoverage/index.php delete mode 100644 etc/codecoverage/test.php diff --git a/CHANGELOG.md b/CHANGELOG.md index c285d511b..4f6b83810 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -177,9 +177,9 @@ Magento Functional Testing Framework Changelog * Command verifies and troubleshoots some configuration steps required for running tests * Please see DevDocs for more details * `<*Data>` actions now contain `API Endpoint` and `Request Header` artifacts. - * Introduced new `.env` configurations `ENABLE_BROWSER_LOG` and `BROWSER_LOG_BLACKLIST` + * Introduced new `.env` configurations `ENABLE_BROWSER_LOG` and `BROWSER_LOG_BLOCKLIST` * Configuration enables allure artifacts for browser log entries if they are present after the step. - * Blacklist filters out logs from specific sources. + * Blocklist filters out logs from specific sources. * Customizability * Introduced `timeout=""` to `magentoCLI` actions. diff --git a/bin/blacklist.txt b/bin/blocklist.txt similarity index 96% rename from bin/blacklist.txt rename to bin/blocklist.txt index 39b3a6700..6d9f6f4e2 100644 --- a/bin/blacklist.txt +++ b/bin/blocklist.txt @@ -3,7 +3,7 @@ # # # THIS FILE CANNOT CONTAIN BLANK LINES # ################################################################### -bin/blacklist.txt +bin/blocklist.txt dev/tests/static/Magento/Sniffs/Commenting/FunctionCommentSniff.php dev/tests/static/Magento/Sniffs/Commenting/VariableCommentSniff.php dev/tests/verification/_generated diff --git a/bin/copyright-check b/bin/copyright-check index 79fe8df06..dc9976d77 100755 --- a/bin/copyright-check +++ b/bin/copyright-check @@ -5,13 +5,13 @@ FILE_EXTENSIONS='.php\|.xml\|.xsd' -BLACKLIST='bin/blacklist.txt' +BLOCKLIST='bin/blocklist.txt' RESULT='' # Iterate through the list of tracked files # that have the expected extensions # that are not ignored -for i in `git ls-tree --full-tree -r --name-only HEAD | grep $FILE_EXTENSIONS | grep -v -f $BLACKLIST` +for i in `git ls-tree --full-tree -r --name-only HEAD | grep $FILE_EXTENSIONS | grep -v -f $BLOCKLIST` do if echo `cat $i` | grep -q -v "Copyright © Magento, Inc. All rights reserved."; then # Copyright is missing diff --git a/bin/copyright-check.bat b/bin/copyright-check.bat index 9f2e23bfb..0a7612f77 100644 --- a/bin/copyright-check.bat +++ b/bin/copyright-check.bat @@ -3,7 +3,7 @@ @echo off SETLOCAL EnableDelayedExpansion -SET BLACKLIST_FILE=bin/blacklist.txt +SET BLOCKLIST_FILE=bin/blocklist.txt SET i=0 FOR /F %%x IN ('git ls-tree --full-tree -r --name-only HEAD') DO ( @@ -12,14 +12,14 @@ FOR /F %%x IN ('git ls-tree --full-tree -r --name-only HEAD') DO ( if "%%~xx"==".xml" set GOOD_EXT=1 if "%%~xx"==".xsd" set GOOD_EXT=1 IF DEFINED GOOD_EXT ( - SET BLACKLISTED= - FOR /F "tokens=* skip=5" %%f IN (%BLACKLIST_FILE%) DO ( + SET BLOCKLISTED= + FOR /F "tokens=* skip=5" %%f IN (%BLOCKLIST_FILE%) DO ( SET LINE=%%x IF NOT "!LINE!"=="!LINE:%%f=!" ( - SET BLACKLISTED=1 + SET BLOCKLISTED=1 ) ) - IF NOT DEFINED BLACKLISTED ( + IF NOT DEFINED BLOCKLISTED ( FIND "Copyright © Magento, Inc. All rights reserved." %%x >nul IF ERRORLEVEL 1 ( SET /A i+=1 diff --git a/dev/tests/_bootstrap.php b/dev/tests/_bootstrap.php index 66be4ee45..059441721 100644 --- a/dev/tests/_bootstrap.php +++ b/dev/tests/_bootstrap.php @@ -54,8 +54,8 @@ putenv("{$key}=${value}"); } -// Add our test module to the whitelist -putenv('MODULE_WHITELIST=Magento_TestModule'); +// Add our test module to the allowlist +putenv('MODULE_ALLOWLIST=Magento_TestModule'); // Define our own set of paths for the tests defined('FW_BP') || define('FW_BP', PROJECT_ROOT); diff --git a/dev/tests/static/Magento/Sniffs/MicroOptimizations/IsNullSniff.php b/dev/tests/static/Magento/Sniffs/MicroOptimizations/IsNullSniff.php index 928fc3a0d..9ec74cb4f 100644 --- a/dev/tests/static/Magento/Sniffs/MicroOptimizations/IsNullSniff.php +++ b/dev/tests/static/Magento/Sniffs/MicroOptimizations/IsNullSniff.php @@ -13,7 +13,7 @@ class IsNullSniff implements Sniff /** * @var string */ - protected $blacklist = 'is_null'; + protected $blocklist = 'is_null'; /** * @inheritdoc @@ -29,7 +29,7 @@ public function register() public function process(File $sourceFile, $stackPtr) { $tokens = $sourceFile->getTokens(); - if ($tokens[$stackPtr]['content'] === $this->blacklist) { + if ($tokens[$stackPtr]['content'] === $this->blocklist) { $sourceFile->addError( "is_null must be avoided. Use strict comparison instead.", $stackPtr, diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php index 81b162981..c554062fd 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php @@ -705,12 +705,12 @@ public function testApplyCustomModuleMethods() } /** - * Validate blacklisted modules are removed + * Validate blocklisted modules are removed * Module paths are sorted according to module name in alphabetically ascending order * * @throws \Exception */ - public function testGetModulePathsBlacklist() + public function testGetModulePathsBlocklist() { $this->setMockResolverClass( false, @@ -946,10 +946,10 @@ private function setMockResolverClass( * @param ModuleResolver $instance * @param array $mockPaths * @param array $mockModules - * @param array $mockBlacklist + * @param array $mockBlocklist * @throws \Exception */ - private function setMockResolverProperties($instance, $mockPaths = null, $mockModules = null, $mockBlacklist = []) + private function setMockResolverProperties($instance, $mockPaths = null, $mockModules = null, $mockBlocklist = []) { $property = new \ReflectionProperty(ModuleResolver::class, 'enabledModulePaths'); $property->setAccessible(true); @@ -959,9 +959,9 @@ private function setMockResolverProperties($instance, $mockPaths = null, $mockMo $property->setAccessible(true); $property->setValue($instance, $mockModules); - $property = new \ReflectionProperty(ModuleResolver::class, 'moduleBlacklist'); + $property = new \ReflectionProperty(ModuleResolver::class, 'moduleBlocklist'); $property->setAccessible(true); - $property->setValue($instance, $mockBlacklist); + $property->setValue($instance, $mockBlocklist); } /** diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Validation/NameValidationUtilTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Validation/NameValidationUtilTest.php index e9854be40..d43eb5282 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Validation/NameValidationUtilTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Validation/NameValidationUtilTest.php @@ -17,7 +17,7 @@ class NameValidationUtilTest extends MagentoTestCase */ public function testCurlyBracesInTestName() { - $this->validateBlacklistedTestName("{{curlyBraces}}"); + $this->validateBlocklistedTestName("{{curlyBraces}}"); } /** @@ -25,7 +25,7 @@ public function testCurlyBracesInTestName() */ public function testQuotesInTestName() { - $this->validateBlacklistedTestName("\"quotes\""); + $this->validateBlocklistedTestName("\"quotes\""); } /** @@ -33,7 +33,7 @@ public function testQuotesInTestName() */ public function testSingleQuotesInTestName() { - $this->validateBlacklistedTestName("'singleQuotes'"); + $this->validateBlocklistedTestName("'singleQuotes'"); } /** @@ -41,7 +41,7 @@ public function testSingleQuotesInTestName() */ public function testParenthesesInTestName() { - $this->validateBlacklistedTestName("(parenthesis)"); + $this->validateBlocklistedTestName("(parenthesis)"); } /** @@ -49,7 +49,7 @@ public function testParenthesesInTestName() */ public function testDollarSignInTestName() { - $this->validateBlacklistedTestName("\$dollarSign\$"); + $this->validateBlocklistedTestName("\$dollarSign\$"); } /** @@ -57,7 +57,7 @@ public function testDollarSignInTestName() */ public function testSpacesInTestName() { - $this->validateBlacklistedTestName("Test Name With Spaces"); + $this->validateBlocklistedTestName("Test Name With Spaces"); } /** @@ -66,7 +66,7 @@ public function testSpacesInTestName() * @param string $testName * @return void */ - private function validateBlacklistedTestName($testName) + private function validateBlocklistedTestName($testName) { $this->expectException(XmlException::class); NameValidationUtil::validateName($testName, "Test"); diff --git a/docs/configuration.md b/docs/configuration.md index 5a912b66c..b78b421b9 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -214,15 +214,15 @@ Example: TESTS_MODULE_PATH=~/magento2/dev/tests/acceptance/tests/functional/Magento/FunctionalTest ``` -### MODULE_WHITELIST +### MODULE_ALLOWLIST Use for a new module. -When adding a new directory at `Magento/FunctionalTest`, add the directory name to `MODULE_WHITELIST` to enable the MFTF to process it. +When adding a new directory at `Magento/FunctionalTest`, add the directory name to `MODULE_ALLOWLIST` to enable the MFTF to process it. Example: ```conf -MODULE_WHITELIST=Magento_Framework,Magento_ConfigurableProductWishlist,Magento_ConfigurableProductCatalogSearch +MODULE_ALLOWLIST=Magento_Framework,Magento_ConfigurableProductWishlist,Magento_ConfigurableProductCatalogSearch ``` ### MAGENTO_CLI_COMMAND_PATH @@ -331,14 +331,14 @@ Use this if you're having issues with sessions hanging in an MFTF suite. SELENIUM_CLOSE_ALL_SESSIONS=true ``` -### BROWSER_LOG_BLACKLIST +### BROWSER_LOG_BLOCKLIST -Blacklists types of browser log entries from appearing in Allure steps. +Blocklists types of browser log entries from appearing in Allure steps. Denoted in browser log entry as `"SOURCE": "type"`. ```conf -BROWSER_LOG_BLACKLIST=other,console-api +BROWSER_LOG_BLOCKLIST=other,console-api ``` ### WAIT_TIMEOUT diff --git a/etc/codecoverage/index.php b/etc/codecoverage/index.php deleted file mode 100644 index 5ae6c7e3f..000000000 --- a/etc/codecoverage/index.php +++ /dev/null @@ -1,58 +0,0 @@ -<?php -/** - * Application entry point - * - * Example - run a particular store or website: - * -------------------------------------------- - * require __DIR__ . '/app/bootstrap.php'; - * $params = $_SERVER; - * $params[\Magento\Store\Model\StoreManager::PARAM_RUN_CODE] = 'website2'; - * $params[\Magento\Store\Model\StoreManager::PARAM_RUN_TYPE] = 'website'; - * $bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $params); - * \/** @var \Magento\Framework\App\Http $app *\/ - * $app = $bootstrap->createApplication(\Magento\Framework\App\Http::class); - * $bootstrap->run($app); - * -------------------------------------------- - * - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -try { - require __DIR__ . '/app/bootstrap.php'; -} catch (\Exception $e) { - echo <<<HTML -<div style="font:12px/1.35em arial, helvetica, sans-serif;"> - <div style="margin:0 0 25px 0; border-bottom:1px solid #ccc;"> - <h3 style="margin:0;font-size:1.7em;font-weight:normal;text-transform:none;text-align:left;color:#2f2f2f;"> - Autoload error</h3> - </div> - <p>{$e->getMessage()}</p> -</div> -HTML; - exit(1); -} - -//Patch start -$driver = new pcov\Clobber\Driver\PHPUnit6(); -$coverage = new \SebastianBergmann\CodeCoverage\CodeCoverage($driver); -$coverage->filter()->addDirectoryToWhitelist("app/code/Magento/*"); -$coverage->filter()->removeDirectoryFromWhitelist("app/code/Magento/*/Test"); -$testName = "NO_TEST_NAME"; -if (file_exists(__DIR__ . '/CURRENT_TEST')) { - $testName = file_get_contents(__DIR__ . '/CURRENT_TEST'); -} -$id = !empty($testName) ? $testName : "NO_TEST_NAME"; -$coverage->start($id); -//Patch end - -$bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $_SERVER); -/** @var \Magento\Framework\App\Http $app */ -$app = $bootstrap->createApplication(\Magento\Framework\App\Http::class); -$bootstrap->run($app); - -// Patch start -$coverage->stop(); -$writer = new \SebastianBergmann\CodeCoverage\Report\PHP(); -$writer->process($coverage, '/var/www/html/coverage/reports/' . $id . "_" . md5(mt_rand()) . '.cov'); -// Patch end diff --git a/etc/codecoverage/test.php b/etc/codecoverage/test.php deleted file mode 100644 index a43388a2c..000000000 --- a/etc/codecoverage/test.php +++ /dev/null @@ -1,10 +0,0 @@ -<?php - -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -$test = $_GET['test'] ?? "NO_TEST_SPECIFIED"; -file_put_contents('CURRENT_TEST', $test); -echo 'SET CURRENT TEST TO ' . $test; \ No newline at end of file diff --git a/etc/config/.env.example b/etc/config/.env.example index 5597e08b5..53b12036f 100644 --- a/etc/config/.env.example +++ b/etc/config/.env.example @@ -48,7 +48,7 @@ BROWSER=chrome #DEFAULT_TIMEZONE=America/Los_Angeles #*** These properties impact the modules loaded into MFTF, you can point to your own full path, or a custom set of modules located with the core set -MODULE_WHITELIST=Magento_Framework,ConfigurableProductWishlist,ConfigurableProductCatalogSearch +MODULE_ALLOWLIST=Magento_Framework,ConfigurableProductWishlist,ConfigurableProductCatalogSearch #CUSTOM_MODULE_PATHS= #*** Bool property which allows the user to toggle debug output during test execution @@ -63,9 +63,9 @@ MODULE_WHITELIST=Magento_Framework,ConfigurableProductWishlist,ConfigurableProdu #*** Uncomment and set to enable all tests, regardless of passing status, to have all their Allure artifacts. #VERBOSE_ARTIFACTS=true -#*** Uncomment and set to enable browser log entries on actions in Allure. Blacklist is used to filter logs of a specific "source" +#*** Uncomment and set to enable browser log entries on actions in Allure. Blocklist is used to filter logs of a specific "source" #ENABLE_BROWSER_LOG=true -#BROWSER_LOG_BLACKLIST=other +BROWSER_LOG_BLOCKLIST=other #*** Elastic Search version used for test ***# ELASTICSEARCH_VERSION=7 diff --git a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php index 918bff47e..b28169d48 100644 --- a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php +++ b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php @@ -201,7 +201,7 @@ public function afterStep(\Codeception\Event\StepEvent $e) { $browserLog = $this->getDriver()->webDriver->manage()->getLog("browser"); if (getenv('ENABLE_BROWSER_LOG') === 'true') { - foreach (explode(',', getenv('BROWSER_LOG_BLACKLIST')) as $source) { + foreach (explode(',', getenv('BROWSER_LOG_BLOCKLIST')) as $source) { $browserLog = BrowserLogUtil::filterLogsOfType($browserLog, $source); } if (!empty($browserLog)) { diff --git a/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php b/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php index 8dcf090f0..73695c182 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php @@ -23,7 +23,7 @@ class PageObjectHandler implements ObjectHandlerInterface const PARAMETERIZED = 'parameterized'; const AREA = 'area'; const FILENAME = 'filename'; - const NAME_BLACKLIST_ERROR_MSG = "Page names cannot contain non alphanumeric characters.\tPage='%s'"; + const NAME_BLOCKLIST_ERROR_MSG = "Page names cannot contain non alphanumeric characters.\tPage='%s'"; /** * The singleton instance of this class @@ -58,7 +58,7 @@ private function __construct() $pageNameValidator = new NameValidationUtil(); foreach ($parserOutput as $pageName => $pageData) { if (preg_match('/[^a-zA-Z0-9_]/', $pageName)) { - throw new XmlException(sprintf(self::NAME_BLACKLIST_ERROR_MSG, $pageName)); + throw new XmlException(sprintf(self::NAME_BLOCKLIST_ERROR_MSG, $pageName)); } $filename = $pageData[self::FILENAME] ?? null; diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/ActionObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/ActionObjectExtractor.php index d9b8d32fb..03813315f 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/ActionObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/ActionObjectExtractor.php @@ -27,7 +27,7 @@ class ActionObjectExtractor extends BaseObjectExtractor const ACTION_GROUP_ARGUMENTS = 'arguments'; const ACTION_GROUP_ARG_VALUE = 'value'; const BEFORE_AFTER_ERROR_MSG = "Merge Error - Steps cannot have both before and after attributes.\tStepKey='%s'"; - const STEP_KEY_BLACKLIST_ERROR_MSG = "StepKeys cannot contain non alphanumeric characters.\tStepKey='%s'"; + const STEP_KEY_BLOCKLIST_ERROR_MSG = "StepKeys cannot contain non alphanumeric characters.\tStepKey='%s'"; const STEP_KEY_EMPTY_ERROR_MSG = "StepKeys cannot be empty.\tAction='%s'"; const DATA_PERSISTENCE_CUSTOM_FIELD = 'field'; const DATA_PERSISTENCE_CUSTOM_FIELD_KEY = 'key'; @@ -70,7 +70,7 @@ public function extractActions($testActions, $testName = null) } if (preg_match('/[^a-zA-Z0-9_]/', $stepKey)) { - throw new XmlException(sprintf(self::STEP_KEY_BLACKLIST_ERROR_MSG, $actionName)); + throw new XmlException(sprintf(self::STEP_KEY_BLOCKLIST_ERROR_MSG, $actionName)); } $actionAttributes = $this->stripDescriptorTags( diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php index cfe417dc9..ff3a1e5f8 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php @@ -90,7 +90,7 @@ public function getAnnotationExtractor() */ public function extractTestData($testData, $validateAnnotations = true) { - // validate the test name for blacklisted char (will cause allure report issues) MQE-483 + // validate the test name for blocklisted char (will cause allure report issues) MQE-483 NameValidationUtil::validateName($testData[self::NAME], "Test"); $testAnnotations = []; diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index c16b309ef..ecdf19613 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -25,9 +25,9 @@ class ModuleResolver { /** - * Environment field name for module whitelist. + * Environment field name for module allowlist. */ - const MODULE_WHITELIST = 'MODULE_WHITELIST'; + const MODULE_ALLOWLIST = 'MODULE_ALLOWLIST'; /** * Environment field name for custom module paths. @@ -132,7 +132,7 @@ class ModuleResolver * * @var array */ - protected $moduleBlacklist = [ + protected $moduleBlocklist = [ 'SampleTests', 'SampleTemplates' ]; @@ -270,7 +270,7 @@ public function getModulesPath($verbosePath = false) return $this->enabledModulePaths; } - $enabledModules = array_merge($this->getEnabledModules(), $this->getModuleWhitelist()); + $enabledModules = array_merge($this->getEnabledModules(), $this->getModuleAllowlist()); $enabledDirectoryPaths = $this->flipAndFilterModulePathsArray($allModulePaths, $enabledModules); $this->enabledModulePaths = $this->applyCustomModuleMethods($enabledDirectoryPaths); @@ -289,18 +289,18 @@ public function sortFilesByModuleSequence(array $files) } /** - * Return an array of module whitelist that not exist in target Magento instance. + * Return an array of module allowlist that not exist in target Magento instance. * * @return array */ - protected function getModuleWhitelist() + protected function getModuleAllowlist() { - $moduleWhitelist = getenv(self::MODULE_WHITELIST); + $moduleAllowlist = getenv(self::MODULE_ALLOWLIST); - if (empty($moduleWhitelist)) { + if (empty($moduleAllowlist)) { return []; } - return array_map('trim', explode(',', $moduleWhitelist)); + return array_map('trim', explode(',', $moduleAllowlist)); } /** @@ -693,7 +693,7 @@ private function printMagentoVersionInfo() */ protected function applyCustomModuleMethods($modulesPath) { - $modulePathsResult = $this->removeBlacklistModules($modulesPath); + $modulePathsResult = $this->removeBlocklistModules($modulesPath); $customModulePaths = $this->getCustomModulePaths(); array_map(function ($key, $value) { @@ -710,17 +710,17 @@ protected function applyCustomModuleMethods($modulesPath) } /** - * Remove blacklist modules from input module paths. + * Remove blocklist modules from input module paths. * * @param array $modulePaths * @return string[] */ - private function removeBlacklistModules($modulePaths) + private function removeBlocklistModules($modulePaths) { $modulePathsResult = $modulePaths; foreach ($modulePathsResult as $moduleName => $modulePath) { - // Remove module if it is in blacklist - if (in_array($moduleName, $this->getModuleBlacklist())) { + // Remove module if it is in blocklist + if (in_array($moduleName, $this->getModuleBlocklist())) { unset($modulePathsResult[$moduleName]); LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->info( "excluding module", @@ -754,13 +754,13 @@ private function getCustomModulePaths() } /** - * Getter for moduleBlacklist. + * Getter for moduleBlocklist. * * @return string[] */ - private function getModuleBlacklist() + private function getModuleBlocklist() { - return $this->moduleBlacklist; + return $this->moduleBlocklist; } /** diff --git a/src/Magento/FunctionalTestingFramework/Util/Validation/NameValidationUtil.php b/src/Magento/FunctionalTestingFramework/Util/Validation/NameValidationUtil.php index eb8d615a2..cf9f34164 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Validation/NameValidationUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/Validation/NameValidationUtil.php @@ -40,7 +40,7 @@ public function __construct() } /** - * Function which runs a validation against the blacklisted char defined in this class. Validation occurs to insure + * Function which runs a validation against the blocklisted char defined in this class. Validation occurs to insure * allure report does not error/future devOps builds do not error against illegal char. * * @param string $name From ec9c4d382f11d6ce49d15171a9e4b8b877f0d8d7 Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Mon, 15 Jun 2020 13:11:41 -0500 Subject: [PATCH 429/888] MQE-2144: Allure captures only <after> steps when test fails with WebDriverCurlException (#738) suppressed exception generate allure correctly --- .../Extension/TestContextExtension.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php index b28169d48..e4f433a2a 100644 --- a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php +++ b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php @@ -199,7 +199,11 @@ public function beforeStep(\Codeception\Event\StepEvent $e) */ public function afterStep(\Codeception\Event\StepEvent $e) { - $browserLog = $this->getDriver()->webDriver->manage()->getLog("browser"); + $browserLog = []; + try { + $browserLog = $this->getDriver()->webDriver->manage()->getLog("browser"); + } catch (\Exception $exception) { + } if (getenv('ENABLE_BROWSER_LOG') === 'true') { foreach (explode(',', getenv('BROWSER_LOG_BLOCKLIST')) as $source) { $browserLog = BrowserLogUtil::filterLogsOfType($browserLog, $source); From e5126f4eb476e227e3b668b622159c917f123175 Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Mon, 15 Jun 2020 14:51:46 -0500 Subject: [PATCH 430/888] MQE-2180: CHANGELOG.MD and Composer version bump (#740) * MQE-2180: CHANGELOG.MD and Composer version bump * MQE-2180: CHANGELOG.MD and Composer version bump --- CHANGELOG.md | 13 +++++++++++++ composer.json | 2 +- composer.lock | 5 +++-- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f6b83810..2401d413f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ Magento Functional Testing Framework Changelog ================================================ +3.0.0 RC5 +--------- + +### Enhancements + +* Readability + * Removed blacklist/whitelist terminology in MFTF. + +### Fixes + +* Fixed javascript error seen on chrome 81 for dragAndDrop action. +* Fixed allure issue when `WebDriverCurlException` is encountered in `afterStep`. + 3.0.0 RC4 --------- diff --git a/composer.json b/composer.json index c94ca7e0a..ea1d6b800 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "3.0.0-RC4", + "version": "3.0.0-RC5", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index f98e1db13..b9707723b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "98d36dbb7c244643cd4f2bd83fa391d6", + "content-hash": "79415f9a24ebaf47d34ea227fc07e142", "packages": [ { "name": "allure-framework/allure-codeception", @@ -6798,5 +6798,6 @@ "ext-json": "*", "ext-openssl": "*" }, - "platform-dev": [] + "platform-dev": [], + "plugin-api-version": "1.1.0" } From d3d5b2864bfed03e2b344a4a17690d2dade7a9d0 Mon Sep 17 00:00:00 2001 From: David Haecker <dhaecker@magento.com> Date: Tue, 16 Jun 2020 11:27:27 -0500 Subject: [PATCH 431/888] PWA-691: Fix Waits In PWA MFTF MagentoPwaWebDriver - Adding locators to wait for in PWA webdriver - Updating Magento webdriver to correctly use loading icon locators - Updating Magento webdriver to use pageload_timeout --- .../Module/MagentoPwaWebDriver.php | 24 ++++++++++++++++++- .../Module/MagentoWebDriver.php | 6 +++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoPwaWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoPwaWebDriver.php index 9b75cb10d..abfbaf751 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoPwaWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoPwaWebDriver.php @@ -17,6 +17,18 @@ */ class MagentoPwaWebDriver extends MagentoWebDriver { + /** + * List of known PWA loading masks by selector + * + * Overriding the MagentoWebDriver array to contain applicable PWA locators. + * + * @var array + */ + protected $loadingMasksLocators = [ + '//div[contains(@class, "indicator-global-3ae")]', + '//div[contains(@class, "indicator-message-2he")]' + ]; + /** * Go to the page. * @@ -24,12 +36,14 @@ class MagentoPwaWebDriver extends MagentoWebDriver * The AJAX check in 'waitForPageLoad' does NOT work with a PWA. * * @param string $page + * @param null $timeout * @throws \Exception * @return void */ - public function amOnPage($page) + public function amOnPage($page, $timeout = null) { WebDriver::amOnPage($page); + $this->waitForLoadingMaskToDisappear($timeout); } /** @@ -43,11 +57,15 @@ public function amOnPage($page) */ public function waitForPwaElementNotVisible($selector, $timeout = null) { + $timeout = $timeout ?? $this->_getConfig()['pageload_timeout']; + // Determine what type of Selector is used. // Then use the correct JavaScript to locate the Element. if (\Codeception\Util\Locator::isXPath($selector)) { + $this->waitForLoadingMaskToDisappear($timeout); $this->waitForJS("return !document.evaluate(`$selector`, document);", $timeout); } else { + $this->waitForLoadingMaskToDisappear($timeout); $this->waitForJS("return !document.querySelector(`$selector`);", $timeout); } } @@ -63,11 +81,15 @@ public function waitForPwaElementNotVisible($selector, $timeout = null) */ public function waitForPwaElementVisible($selector, $timeout = null) { + $timeout = $timeout ?? $this->_getConfig()['pageload_timeout']; + // Determine what type of Selector is used. // Then use the correct JavaScript to locate the Element. if (\Codeception\Util\Locator::isXPath($selector)) { + $this->waitForLoadingMaskToDisappear($timeout); $this->waitForJS("return !!document && !!document.evaluate(`$selector`, document);", $timeout); } else { + $this->waitForLoadingMaskToDisappear($timeout); $this->waitForJS("return !!document && !!document.querySelector(`$selector`);", $timeout); } } diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 984881e4e..2f4745df1 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -63,7 +63,7 @@ class MagentoWebDriver extends WebDriver * * @var array */ - public static $loadingMasksLocators = [ + protected $loadingMasksLocators = [ '//div[contains(@class, "loading-mask")]', '//div[contains(@class, "admin_data-grid-loading-mask")]', '//div[contains(@class, "admin__data-grid-loading-mask")]', @@ -439,7 +439,9 @@ public function waitForPageLoad($timeout = null) */ public function waitForLoadingMaskToDisappear($timeout = null) { - foreach (self::$loadingMasksLocators as $maskLocator) { + $timeout = $timeout ?? $this->_getConfig()['pageload_timeout']; + + foreach ($this->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); From 15b9b2955f046e5e7d5e4066523825fff66c2f77 Mon Sep 17 00:00:00 2001 From: David Haecker <dhaecker@magento.com> Date: Tue, 16 Jun 2020 12:32:16 -0500 Subject: [PATCH 432/888] PWA-691: Fix Waits In PWA MFTF MagentoPwaWebDriver - Adding locators to wait for in PWA webdriver --- .../FunctionalTestingFramework/Module/MagentoPwaWebDriver.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoPwaWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoPwaWebDriver.php index abfbaf751..9d6031e18 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoPwaWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoPwaWebDriver.php @@ -26,6 +26,8 @@ class MagentoPwaWebDriver extends MagentoWebDriver */ protected $loadingMasksLocators = [ '//div[contains(@class, "indicator-global-3ae")]', + '//div[contains(@class, "indicator-root-3J-")]', + '//div[contains(@class, "indicator-indicator-JHR")]', '//div[contains(@class, "indicator-message-2he")]' ]; From c502e467db838d4d13eadcda887ae8e63b672cc2 Mon Sep 17 00:00:00 2001 From: David Haecker <dhaecker@magento.com> Date: Tue, 16 Jun 2020 12:59:30 -0500 Subject: [PATCH 433/888] PWA-691: Fix Waits In PWA MFTF MagentoPwaWebDriver - Fixing locators to wait for in PWA webdriver --- .../Module/MagentoPwaWebDriver.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoPwaWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoPwaWebDriver.php index 9d6031e18..d16249d98 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoPwaWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoPwaWebDriver.php @@ -25,10 +25,10 @@ class MagentoPwaWebDriver extends MagentoWebDriver * @var array */ protected $loadingMasksLocators = [ - '//div[contains(@class, "indicator-global-3ae")]', - '//div[contains(@class, "indicator-root-3J-")]', - '//div[contains(@class, "indicator-indicator-JHR")]', - '//div[contains(@class, "indicator-message-2he")]' + '//div[contains(@class, "indicator-global-")]', + '//div[contains(@class, "indicator-root-")]', + '//img[contains(@class, "indicator-indicator-")]', + '//span[contains(@class, "indicator-message-")]' ]; /** From fb3da40f264318fd54ee9fb48153c8b46ae5814a Mon Sep 17 00:00:00 2001 From: David Haecker <dhaecker@magento.com> Date: Tue, 16 Jun 2020 15:35:57 -0500 Subject: [PATCH 434/888] PWA-691: Fix Waits In PWA MFTF MagentoPwaWebDriver - Fixing parameter types --- .../Module/MagentoPwaWebDriver.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoPwaWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoPwaWebDriver.php index d16249d98..46860b59d 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoPwaWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoPwaWebDriver.php @@ -38,7 +38,7 @@ class MagentoPwaWebDriver extends MagentoWebDriver * The AJAX check in 'waitForPageLoad' does NOT work with a PWA. * * @param string $page - * @param null $timeout + * @param integer $timeout * @throws \Exception * @return void */ @@ -52,8 +52,8 @@ public function amOnPage($page, $timeout = null) * Wait for a PWA Element to NOT be visible using JavaScript. * Add the WAIT_TIMEOUT variable to your .env file for this action. * - * @param null $selector - * @param null $timeout + * @param string $selector + * @param integer $timeout * @throws \Exception * @return void */ @@ -76,8 +76,8 @@ public function waitForPwaElementNotVisible($selector, $timeout = null) * Wait for a PWA Element to be visible using JavaScript. * Add the WAIT_TIMEOUT variable to your .env file for this action. * - * @param null $selector - * @param null $timeout + * @param string $selector + * @param integer $timeout * @throws \Exception * @return void */ From 72ffec286ad431c54601ff96cdd7d95e1484ff13 Mon Sep 17 00:00:00 2001 From: David Haecker <dhaecker@magento.com> Date: Tue, 16 Jun 2020 18:37:40 -0500 Subject: [PATCH 435/888] PWA-691: Fix Waits In PWA MFTF MagentoPwaWebDriver - Fixing static test failures --- .../Module/MagentoPwaWebDriver.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoPwaWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoPwaWebDriver.php index 46860b59d..272f4206d 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoPwaWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoPwaWebDriver.php @@ -37,7 +37,7 @@ class MagentoPwaWebDriver extends MagentoWebDriver * Overriding the MagentoWebDriver version because it contains 'waitForPageLoad'. * The AJAX check in 'waitForPageLoad' does NOT work with a PWA. * - * @param string $page + * @param string $page * @param integer $timeout * @throws \Exception * @return void @@ -52,7 +52,7 @@ public function amOnPage($page, $timeout = null) * Wait for a PWA Element to NOT be visible using JavaScript. * Add the WAIT_TIMEOUT variable to your .env file for this action. * - * @param string $selector + * @param string $selector * @param integer $timeout * @throws \Exception * @return void @@ -76,7 +76,7 @@ public function waitForPwaElementNotVisible($selector, $timeout = null) * Wait for a PWA Element to be visible using JavaScript. * Add the WAIT_TIMEOUT variable to your .env file for this action. * - * @param string $selector + * @param string $selector * @param integer $timeout * @throws \Exception * @return void From 3cc7ae5b749e0f620ea1db8ad471ba1896e11bdc Mon Sep 17 00:00:00 2001 From: Mohamed Azarudeen <mohamed.azarudeen@ziffity.com> Date: Wed, 24 Jun 2020 20:13:08 +0530 Subject: [PATCH 436/888] Removed invalid sample test name --- docs/commands/mftf.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index f1ef3955d..427cdbbf7 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -39,13 +39,13 @@ vendor/bin/mftf generate:tests ### Generate tests by test name ```bash -vendor/bin/mftf generate:tests AdminLoginTest StorefrontPersistedCustomerLoginTest +vendor/bin/mftf generate:tests AdminLoginSuccessfulTest StorefrontPersistedCustomerLoginTest ``` ### Generate test by test and suite name ```bash -vendor/bin/mftf generate:tests LoginSuite:AdminLoginTest +vendor/bin/mftf generate:tests LoginSuite:AdminLoginSuccessfulTest ``` ### Generate and run the tests for a specified group @@ -59,7 +59,7 @@ This command cleans up the previously generated tests; generates and runs tests ### Generate and run particular tests ```bash -vendor/bin/mftf run:test AdminLoginTest StorefrontPersistedCustomerLoginTest -r +vendor/bin/mftf run:test AdminLoginSuccessfulTest StorefrontPersistedCustomerLoginTest -r ``` This command cleans up the previously generated tests; generates and runs the `LoginAsAdminTest` and `LoginAsCustomerTest` tests. @@ -67,10 +67,10 @@ This command cleans up the previously generated tests; generates and runs the `L ### Generate and run particular test in a specific suite's context ```bash -vendor/bin/mftf run:test LoginSuite:AdminLoginTest -r +vendor/bin/mftf run:test LoginSuite:AdminLoginSuccessfulTest -r ``` -This command cleans up previously generated tests; generates and run `AdminLoginTest` within the context of the `LoginSuite`. +This command cleans up previously generated tests; generates and run `AdminLoginSuccessfulTest` within the context of the `LoginSuite`. ### Generate and run a testManifest.txt file @@ -362,7 +362,7 @@ vendor/bin/mftf run:manifest path/to/your/testManifest.txt Each line should contain either: one test path or one group (-g) reference. ``` -tests/functional/tests/MFTF/_generated/default/AdminLoginTestCest.php +tests/functional/tests/MFTF/_generated/default/AdminLoginSuccessfulTestCest.php -g PaypalTestSuite tests/functional/tests/MFTF/_generated/default/SomeOtherTestCest.php tests/functional/tests/MFTF/_generated/default/ThirdTestCest.php From c0255eece466c1871e679b5f9077927508c4b9f8 Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Wed, 24 Jun 2020 18:25:15 -0500 Subject: [PATCH 437/888] =?UTF-8?q?MQE-1861:=20Suite=20precondition=20fail?= =?UTF-8?q?ure=20when=20using=20<createData>=20with=20<re=E2=80=A6=20(#744?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * MQE-1861: Suite precondition failure when using <createData> with <requiredEntity> * MQE-1861: Suite precondition failure when using <createData> with <requiredEntity> Added verification test --- .../Resources/functionalSuiteHooks.txt | 29 +++++++++++++++---- .../Resources/functionalSuiteWithComments.txt | 3 +- .../TestModule/Suite/functionalSuiteHooks.xml | 12 ++++++-- .../Suite/Generators/GroupClassGenerator.php | 8 ++--- .../Suite/views/partials/testActions.mustache | 6 ++-- 5 files changed, 43 insertions(+), 15 deletions(-) diff --git a/dev/tests/verification/Resources/functionalSuiteHooks.txt b/dev/tests/verification/Resources/functionalSuiteHooks.txt index 3b5f6bae0..041b088b1 100644 --- a/dev/tests/verification/Resources/functionalSuiteHooks.txt +++ b/dev/tests/verification/Resources/functionalSuiteHooks.txt @@ -53,14 +53,33 @@ class functionalSuiteHooks extends \Codeception\GroupObject $webDriver->_initializeSession(); } $webDriver->amOnPage("some.url"); // stepKey: before - $createFields['someKey'] = "dataHere"; + $createOneFields['someKey'] = "dataHere"; PersistedObjectHandler::getInstance()->createEntity( - "create", + "createOne", "suite", - "createThis", - $createFields + "createEntityOne", + [], + $createOneFields ); - $webDriver->click(PersistedObjectHandler::getInstance()->retrieveEntityField('create', 'data', 'suite')); // stepKey: clickWithData + PersistedObjectHandler::getInstance()->createEntity( + "createTwo", + "suite", + "createEntityTwo", + ["createEntityOne"] + ); + PersistedObjectHandler::getInstance()->createEntity( + "createThree", + "suite", + "createEntityThree", + [] + ); + PersistedObjectHandler::getInstance()->createEntity( + "createFour", + "suite", + "createEntityFour", + ["createEntityTwo", "createEntityThree"] + ); + $webDriver->click(PersistedObjectHandler::getInstance()->retrieveEntityField('createTwo', 'data', 'suite')); // stepKey: clickWithData print("Entering Action Group [AC] actionGroupWithTwoArguments"); $webDriver->see("John", msq("uniqueData") . "John"); // stepKey: seeFirstNameAC print("Exiting Action Group [AC] actionGroupWithTwoArguments"); diff --git a/dev/tests/verification/Resources/functionalSuiteWithComments.txt b/dev/tests/verification/Resources/functionalSuiteWithComments.txt index c8523d0c1..6c646dd18 100644 --- a/dev/tests/verification/Resources/functionalSuiteWithComments.txt +++ b/dev/tests/verification/Resources/functionalSuiteWithComments.txt @@ -59,7 +59,8 @@ class functionalSuiteWithComments extends \Codeception\GroupObject "create", "suite", "createThis", - $createFields + [], + $createFields ); print("<click stepKey=\"comment with element\" userInput=\"helloworld\"/>"); $webDriver->click(PersistedObjectHandler::getInstance()->retrieveEntityField('create', 'data', 'suite')); // stepKey: clickWithData diff --git a/dev/tests/verification/TestModule/Suite/functionalSuiteHooks.xml b/dev/tests/verification/TestModule/Suite/functionalSuiteHooks.xml index 4fc459e7d..b4dca7f8d 100644 --- a/dev/tests/verification/TestModule/Suite/functionalSuiteHooks.xml +++ b/dev/tests/verification/TestModule/Suite/functionalSuiteHooks.xml @@ -13,10 +13,18 @@ </include> <before> <amOnPage url="some.url" stepKey="before"/> - <createData entity="createThis" stepKey="create"> + <createData entity="createEntityOne" stepKey="createOne"> <field key="someKey">dataHere</field> </createData> - <click stepKey="clickWithData" userInput="$create.data$"/> + <createData entity="createEntityTwo" stepKey="createTwo"> + <requiredEntity createDataKey="createEntityOne"/> + </createData> + <createData entity="createEntityThree" stepKey="createThree"/> + <createData entity="createEntityFour" stepKey="createFour"> + <requiredEntity createDataKey="createEntityTwo"/> + <requiredEntity createDataKey="createEntityThree"/> + </createData> + <click stepKey="clickWithData" userInput="$createTwo.data$"/> <actionGroup ref="actionGroupWithTwoArguments" stepKey="AC"> <argument name="somePerson" value="simpleData"/> <argument name="anotherPerson" value="uniqueData"/> diff --git a/src/Magento/FunctionalTestingFramework/Suite/Generators/GroupClassGenerator.php b/src/Magento/FunctionalTestingFramework/Suite/Generators/GroupClassGenerator.php index 67930f09a..bb0157152 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Generators/GroupClassGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Generators/GroupClassGenerator.php @@ -225,16 +225,16 @@ private function buildPersistenceMustacheArray($action, $entityArray) $action->getCustomActionAttributes()[TestGenerator::REQUIRED_ENTITY_REFERENCE]; // append entries for any required entities to this entry - if (array_key_exists('requiredEntities', $action->getCustomActionAttributes())) { - $entityArray[self::REQUIRED_ENTITY_KEY] = - $this->buildReqEntitiesMustacheArray($action->getCustomActionAttributes()); + $requiredEntities = $this->buildReqEntitiesMustacheArray($action->getCustomActionAttributes()); + if (!array_key_exists(-1, $requiredEntities)) { + $entityArray[self::REQUIRED_ENTITY_KEY] = $requiredEntities; } // append entries for customFields if specified by the user. if (array_key_exists('customFields', $action->getCustomActionAttributes())) { $entityArray['customFields'] = $action->getStepKey() . 'Fields'; } - + return $entityArray; } diff --git a/src/Magento/FunctionalTestingFramework/Suite/views/partials/testActions.mustache b/src/Magento/FunctionalTestingFramework/Suite/views/partials/testActions.mustache index 73079f169..eaa0959cb 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/views/partials/testActions.mustache +++ b/src/Magento/FunctionalTestingFramework/Suite/views/partials/testActions.mustache @@ -13,9 +13,9 @@ if ($webDriver->webDriver != null) { PersistedObjectHandler::getInstance()->createEntity( "{{stepKey}}", "suite", - "{{entityName}}"{{#requiredEntities}}, - [$this->{{entityName}}{{^last}}, {{/last}}]{{/requiredEntities}}{{#customFields}}, - ${{customFields}}{{/customFields}} + "{{entityName}}", + [{{#requiredEntities}}"{{entityName}}"{{^last}}, {{/last}}{{/requiredEntities}}]{{#customFields}}, + ${{customFields}}{{/customFields}} ); {{/createData}} {{#deleteData}} From f630b5dc5f0be24f7fc5b5c87179b403535eb7f0 Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Fri, 26 Jun 2020 15:04:58 -0500 Subject: [PATCH 438/888] MQE-2203: Create CHANGELOG.MD entry for 3.0.0 (#748) consolidated change log for 3.0.0 --- CHANGELOG.md | 158 +++++++++++++++++++-------------------------------- 1 file changed, 60 insertions(+), 98 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2401d413f..f1c5fad6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,118 +1,53 @@ Magento Functional Testing Framework Changelog ================================================ -3.0.0 RC5 ---------- - -### Enhancements - -* Readability - * Removed blacklist/whitelist terminology in MFTF. - -### Fixes - -* Fixed javascript error seen on chrome 81 for dragAndDrop action. -* Fixed allure issue when `WebDriverCurlException` is encountered in `afterStep`. - -3.0.0 RC4 +3.0.0 --------- ### Enhancements * Customizability + * Introduced MFTF helpers `<helper>` to create custom actions outside of MFTF.[See custom-helpers page for details](./docs/custom-helpers.md) + * Removed deprecated actions `<executeSelenium>` and `<performOn>`. * `<group value="skip"/>` no longer skips a test. Instead, the test is added to the `skip` group. -* Maintainability - * `mftf.log` no longer includes notices and warnings at test execution time. - * Added the Chrome option `--ignore-certificate-errors` to `functional.suite.dist.yml`. -* Traceability - * Changed the `bin/mftf static-checks` error file directory from the current working directory to `TESTS_BP/tests/_output/static-results/`. -* Readability - * Documented [3.0.0 Backward Incompatible Changes.](./docs/backward-incompatible-changes.md) - -### Fixes - -* Fixed issue where an extended data entity would not merge array items. Array items should merge properly now. -* Fixed issue where Chrome remains running after MFTF suite finishes. - -3.0.0 RC3 ---------- - -### Enhancements - -* Maintainability - * Added support for Two-Factor Authentication (2FA). [See configure-2fa page for details](./docs/configure-2fa.md) - * Added new static check `annotationsCheck` that checks and reports missing annotations in tests. - * Updated `bin/mftf static-checks` command to allow executing static-checks defined in `staticRuleSet.json` by default. [See command page for details](./docs/commands/mftf.md#static-checks) - * Added new upgrade script to remove unused arguments from action groups. - * Added unhandledPromptBehavior driver capability for Chrome 75+ support. - * Removed redundant and unused classes. - -### Fixes - -* Fixed issue with custom helper usage in suites. -* Fixed issue with decryption of secrets during data entity creation. -* Fixed issue with merging of `array` items in data entity. - -3.0.0 RC2 ---------- - -### Enhancements - -* Maintainability - * Added support for PHP 7.4. - * Removed support for PHP 7.2. - * Added support for PHPUnit 9. - * Improved assertion actions to support PHPUnit 9 changes. [See assertions page for details](./docs/test/assertions.md) - * Added new actions: `assertEqualsWithDelta`, `assertNotEqualsWithDelta`, `assertEqualsCanonicalizing`, `assertNotEqualsCanonicalizing`, `assertEqualsIgnoringCase`, `assertNotEqualsIgnoringCase`. - * Added new actions: `assertStringContainsString`, `assertStringNotContainsString`, `assertStringContainsStringIgnoringCase`, `assertStringNotContainsStringIgnoringCase` for string haystacks. - * Removed actions: `assertInternalType`, `assertNotInternalType`, `assertArraySubset`. - * Removed delta option from `assertEquals` and `assertNotEquals`. - * Removed action `pauseExecution` and added `pause`. [See actions page for details](./docs/test/actions.md#pause) - * Removed action `formatMoney` and added `formatCurrency`. [See actions page for details](./docs/test/actions.md#formatcurrency) - * Added new static check that checks and reports references to deprecated test entities. -* Bumped dependencies to support PHP/PHPUnit upgrade. - -* Traceability - * Introduced new `.env` configuration `VERBOSE_ARTIFACTS` to toggle saving attachments in Allure. [See configuration page for details](./docs/configuration.md) -### Fixes - -* Fixed issue of resolving arguments of type `entity` in action groups within a custom helper. -* Fixed reporting issue in output file for `testDependencies` static check. -* Fixed a bug in `actionGroupArguments` static check when action group filename is missing `ActionGroup`. -* Fixed issue of running suites under root `_suite` directory in Standalone MFTF. - -### GitHub Issues/Pull Requests - -* [#567](https://github.com/magento/magento2-functional-testing-framework/pull/567) -- log attachments for failed requests. - -3.0.0 RC1 ---------- - -### Enhancements - -* Customizability - * Introduced MFTF helpers `<helper>` to create custom actions outside of MFTF. - * Removed deprecated actions `<executeSelenium>` and `<performOn>`. * Maintainability + * Added support for PHP 7.4. + * Added support for PHPUnit 9. + * Dropped support for PHP 7.0, 7.1, 7.2. * Schema updates for test entities to only allow single entity per file except Data and Metadata. * Support for sub-folders in test modules. * Removed support to read test entities from `<magento>dev/tests/acceptance/tests/functional/Magento/FunctionalTest`. - * Removed support for PHP 7.0 and 7.1. * Removed file attribute for `<module>` in suiteSchema. + * Removed action `pauseExecution` and added `pause`. [See actions page for details](./docs/test/actions.md#pause) + * Removed action `formatMoney` and added `formatCurrency`. [See actions page for details](./docs/test/actions.md#formatcurrency) + * Improved assertion actions to support PHPUnit 9 changes. [See assertions page for details](./docs/test/assertions.md) + * Added new actions: `assertEqualsWithDelta`, `assertNotEqualsWithDelta`, `assertEqualsCanonicalizing`, `assertNotEqualsCanonicalizing`, `assertEqualsIgnoringCase`, `assertNotEqualsIgnoringCase`. + * Added new actions: `assertStringContainsString`, `assertStringNotContainsString`, `assertStringContainsStringIgnoringCase`, `assertStringNotContainsStringIgnoringCase` for string haystacks. + * Removed actions: `assertInternalType`, `assertNotInternalType`, `assertArraySubset`. + * Removed delta option from `assertEquals` and `assertNotEquals`. + * Added static check `deprecatedEntityUsage` that checks and reports references to deprecated test entities. + * Added static check `annotations` that checks and reports missing annotations in tests. + * Updated `bin/mftf static-checks` command to allow executing static-checks defined in `staticRuleSet.json` by default. [See command page for details](./docs/commands/mftf.md#static-checks) + * Added support for Two-Factor Authentication (2FA). [See configure-2fa page for details](./docs/configure-2fa.md) + * Added new upgrade script to remove unused arguments from action groups. + * `mftf.log` no longer includes notices and warnings at test execution time. + * Added unhandledPromptBehavior driver capability for Chrome 75+ support. + * Added the Chrome option `--ignore-certificate-errors` to `functional.suite.dist.yml`. + * Traceability - * Removed `--debug` option NONE to disallow ability to turn off schema validation. + * Removed `--debug` option `NONE` to disallow ability to turn off schema validation. * Notices added for test entity naming convention violations. * Metadata file names changed to `*Meta.xml`. + * Introduced new `.env` configuration `VERBOSE_ARTIFACTS` to toggle saving attachments in Allure. [See configuration page for details](./docs/configuration.md) + * Changed the `bin/mftf static-checks` error file directory from the current working directory to `TESTS_BP/tests/_output/static-results/`. + * Readability - * Support only nested assertion syntax [See assertions page for details](./docs/test/assertions.md) + * Support only nested assertion syntax [See assertions page for details](./docs/test/assertions.md). + * Documented [3.0.0 Backward Incompatible Changes](./docs/backward-incompatible-changes.md). + * Removed blacklist/whitelist terminology in MFTF. + * Upgrade scripts added to upgrade tests to MFTF major version requirements. See upgrade instructions below. -* Bumped dependencies to latest possible versions. - -### Fixes - -* Throw exception during generation when leaving out .url for `amOnPage`. -* `request_timeout` and `connection_timeout` added to functional.suite.yml.dist. -* Fixed `ModuleResolver` to resolve test modules moved out of deprecated path. +* Bumped dependencies to support PHP/PHPUnit upgrade. ### Upgrade Instructions @@ -120,12 +55,39 @@ Magento Functional Testing Framework Changelog * Run `bin/mftf build:project` to generate new configurations. * Run `bin/mftf upgrade:tests`. [See command page for details](./docs/commands/mftf.md#upgradetests). * After running the above command, some tests may need manually updates: - * Remove all occurrences of `<executeInSelenium>` and `<performOn>` - * Remove all occurrences of `<module file=""/>` from any `<suite>`s + * Remove all occurrences of `<executeInSelenium>` and `<performOn>`. + * Remove all occurrences of `<module file=""/>` from any `<suite>`s. * Ensure all `<assert*>` actions in your tests have a valid schema. * Lastly, try to generate all tests. Tests should all be generated as a result of the upgrades. * If not, the most likely issue will be a changed XML schema. Check error messaging and search your codebase for the attributes listed. +### Fixes + +* Throw exception during generation when leaving out .url for `amOnPage`. +* `request_timeout` and `connection_timeout` added to functional.suite.yml.dist. +* Fixed `ModuleResolver` to resolve test modules moved out of deprecated path. +* Fixed issue of resolving arguments of type `entity` in action groups within a custom helper. +* Fixed reporting issue in output file for `testDependencies` static check. +* Fixed a bug in `actionGroupArguments` static check when action group filename is missing `ActionGroup`. +* Fixed issue of running suites under root `_suite` directory in Standalone MFTF. +* Fixed issue with custom helper usage in suites. +* Fixed issue with decryption of secrets during data entity creation. +* Fixed issue with merging of `array` items in data entity. +* Fixed issue where an extended data entity would not merge array items. Array items should merge properly now. +* Fixed issue where Chrome remains running after MFTF suite finishes. +* Fixed javascript error seen on Chrome 83 for dragAndDrop action. +* Fixed allure issue when `WebDriverCurlException` is encountered in `afterStep`. + +### GitHub Issues/Pull Requests + +* [#567](https://github.com/magento/magento2-functional-testing-framework/pull/567) -- log attachments for failed requests. + +### Demo Video links + +* [MFTF 3.0.0 RC1](https://www.youtube.com/watch?v=z0ZaZCmnw-A&t=2s) +* [MFTF 3.0.0 RC2](https://www.youtube.com/watch?v=BJOQAw6dX5o) +* [MFTF 3.0.0 RC3](https://www.youtube.com/watch?v=scLb7pi8pR0) + 2.6.3 ----- From 185852385432c7260087e717fc9093fb2aad09d8 Mon Sep 17 00:00:00 2001 From: Alastair Mucklow <amucklow@strangerpixel.com> Date: Wed, 8 Jul 2020 11:19:44 +0100 Subject: [PATCH 439/888] Amend element name --- docs/test/annotations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/test/annotations.md b/docs/test/annotations.md index 4e9194bb0..8fdcd2240 100644 --- a/docs/test/annotations.md +++ b/docs/test/annotations.md @@ -112,7 +112,7 @@ Attribute|Type|Use ### severity -The `<return>` element is an implementation of a [`@Severity`] Allure tag; Metadata for report. +The `<severity>` element is an implementation of a [`@Severity`] Allure tag; Metadata for report. Attribute|Type|Use|Acceptable values ---|---|---|--- From 1941831d7d9e44b91843b5260ad8f1d434e910de Mon Sep 17 00:00:00 2001 From: Alastair Mucklow <amucklow@strangerpixel.com> Date: Wed, 8 Jul 2020 11:45:40 +0100 Subject: [PATCH 440/888] Replace broken devhub.io/zh paths with github.com paths --- docs/test/annotations.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/test/annotations.md b/docs/test/annotations.md index 8fdcd2240..055ca9450 100644 --- a/docs/test/annotations.md +++ b/docs/test/annotations.md @@ -213,14 +213,14 @@ Attribute|Type|Use <!-- Link definitions --> -[`@Description`]: https://devhub.io/zh/repos/allure-framework-allure-phpunit#extended-test-class-or-test-method-description -[`@Features`]: https://devhub.io/zh/repos/allure-framework-allure-phpunit#map-test-classes-and-test-methods-to-features-and-stories +[`@Description`]: https://github.com/allure-framework/allure-phpunit#extended-test-class-or-test-method-description +[`@Features`]: https://github.com/allure-framework/allure-phpunit#map-test-classes-and-test-methods-to-features-and-stories [`@group`]: http://codeception.com/docs/07-AdvancedUsage#Groups [`@return`]: http://codeception.com/docs/07-AdvancedUsage#Examples -[`@Severity`]: https://devhub.io/zh/repos/allure-framework-allure-phpunit#set-test-severity -[`@Stories`]: https://devhub.io/zh/repos/allure-framework-allure-phpunit#map-test-classes-and-test-methods-to-features-and-stories +[`@Severity`]: https://github.com/allure-framework/allure-phpunit#set-test-severity +[`@Stories`]: https://github.com/allure-framework/allure-phpunit#map-test-classes-and-test-methods-to-features-and-stories [`@TestCaseId`]: https://github.com/allure-framework/allure1/wiki/Test-Case-ID -[`@Title`]: https://devhub.io/zh/repos/allure-framework-allure-phpunit#human-readable-test-class-or-test-method-title +[`@Title`]: https://github.com/allure-framework/allure-phpunit#human-readable-test-class-or-test-method-title [description]: #description [features]: #features [group]: #group From 30f2c653c669c98e116e6bde77b7692d5a97b4e0 Mon Sep 17 00:00:00 2001 From: Alastair Mucklow <amucklow@strangerpixel.com> Date: Wed, 8 Jul 2020 12:22:27 +0100 Subject: [PATCH 441/888] Make intro text clearer and more accurate --- docs/test/annotations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/test/annotations.md b/docs/test/annotations.md index 055ca9450..d61565aec 100644 --- a/docs/test/annotations.md +++ b/docs/test/annotations.md @@ -112,7 +112,7 @@ Attribute|Type|Use ### severity -The `<severity>` element is an implementation of a [`@Severity`] Allure tag; Metadata for report. +The `<severity>` element is an implementation of the [`@Severity`] Allure annotation, which is used to prioritise test methods by severity. Attribute|Type|Use|Acceptable values ---|---|---|--- From ffbcac774edec1d9f718ef4c0de8b80d861fbb3a Mon Sep 17 00:00:00 2001 From: Alastair Mucklow <amucklow@strangerpixel.com> Date: Wed, 8 Jul 2020 12:22:42 +0100 Subject: [PATCH 442/888] Fix order (Blocker is the most severe) --- docs/test/annotations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/test/annotations.md b/docs/test/annotations.md index d61565aec..69c75a2d0 100644 --- a/docs/test/annotations.md +++ b/docs/test/annotations.md @@ -116,7 +116,7 @@ The `<severity>` element is an implementation of the [`@Severity`] Allure annota Attribute|Type|Use|Acceptable values ---|---|---|--- -`value`|string|required|`MINOR`, `AVERAGE`, `MAJOR`, `BLOCKER`, `CRITICAL` +`value`|string|required|`MINOR`, `AVERAGE`, `MAJOR`, `CRITICAL`, `BLOCKER` #### Example From a0a966fdcc4b17b8245a4c0e119c67cfa2d40409 Mon Sep 17 00:00:00 2001 From: Alastair Mucklow <amucklow@strangerpixel.com> Date: Wed, 8 Jul 2020 12:23:14 +0100 Subject: [PATCH 443/888] Add usage guidelines table outlining the difference between levels --- docs/test/annotations.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/test/annotations.md b/docs/test/annotations.md index 69c75a2d0..1e2e50f58 100644 --- a/docs/test/annotations.md +++ b/docs/test/annotations.md @@ -124,6 +124,16 @@ Attribute|Type|Use|Acceptable values <severity value="CRITICAL"/> ``` +#### Usage guidelines + +Severity Level|Usage +---|--- +`BLOCKER`|If this test fails, the customer is completely blocked from purchasing a product. +`CRITICAL`|This is a serious problem impacting conversion, or affecting the operation of the store. +`MAJOR`|Store conversion rate is reduced owing to this issue. For example, something is broken or missing that impacts checkout frequency or cart volume. +`AVERAGE`|A fault on the storefront that can negatively impact conversion rate (like UI errors or omissions), or problems with Magento admin functionality. +`MINOR`|An application or configuration fault that has no impact on conversion rate. + ### skip Use the `<skip>` element to skip a test. From f958045af0dcef47ca75fdf2adc81bf4bb418829 Mon Sep 17 00:00:00 2001 From: Alastair Mucklow <amucklow@strangerpixel.com> Date: Wed, 8 Jul 2020 12:34:24 +0100 Subject: [PATCH 444/888] Trim text --- docs/test/annotations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/test/annotations.md b/docs/test/annotations.md index 1e2e50f58..79cc00e80 100644 --- a/docs/test/annotations.md +++ b/docs/test/annotations.md @@ -112,7 +112,7 @@ Attribute|Type|Use ### severity -The `<severity>` element is an implementation of the [`@Severity`] Allure annotation, which is used to prioritise test methods by severity. +The `<severity>` element is an implementation of the [`@Severity`] Allure annotation, which is used to prioritise tests by severity. Attribute|Type|Use|Acceptable values ---|---|---|--- From 6bf46e5b762d61018338b336372281a076539d8f Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@Donalds-MacBook-Pro.local> Date: Wed, 8 Jul 2020 13:25:15 -0500 Subject: [PATCH 445/888] Remove refs to Test Migration repo --- docs/best-practices.md | 3 --- docs/introduction.md | 7 ------- v2 | 1 + 3 files changed, 1 insertion(+), 10 deletions(-) create mode 160000 v2 diff --git a/docs/best-practices.md b/docs/best-practices.md index 613f398ca..b80542d9f 100644 --- a/docs/best-practices.md +++ b/docs/best-practices.md @@ -40,8 +40,6 @@ We recommend to keep Action Groups having single responsibility, for example `Ad Althought the Magento Core team and Contributors join forces to cover most of the features with tests, it is impossible to have this done quickly. If you've covered Magento Core feature with Functional Tests - you are more than welcome to contribute. -You can also help with MFTF Test Migration to get the experience and valuable feedback from other community members and maintainers. - ## Action group 1. [Action group] names should be sufficiently descriptive to inform a test writer of what the action group does and when it should be used. Add additional explanation in annotations if needed. @@ -214,4 +212,3 @@ Since the configurable product module could be disabled, this approach is more r [merging]: merging.html [parameterized selectors]: section/parameterized-selectors.html [sections]: section.html -[MFTF Test Migration]: https://github.com/magento/magento-functional-tests-migration diff --git a/docs/introduction.md b/docs/introduction.md index 53b763d8c..2c4ded6ce 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -52,12 +52,6 @@ Test └── ... ``` -<div class="bs-callout bs-callout-info" markdown="1"> - -We are actively developing functional tests. Check out the [MFTF Test Migration][] repository. - -</div> - ## Use cases - Contributor: changes the core behaviour, fixing the annoing bug. @@ -122,4 +116,3 @@ Follow the [MFTF project] and [contribute on Github]. [Functional Testing Framework]: https://devdocs.magento.com/guides/v2.3/mtf/mtf_introduction.html [MFTF project]: https://github.com/magento/magento2-functional-testing-framework [Find your MFTF version]: #find-your-mftf-version -[MFTF Test Migration]: https://github.com/magento/magento-functional-tests-migration diff --git a/v2 b/v2 new file mode 160000 index 000000000..3343a82b8 --- /dev/null +++ b/v2 @@ -0,0 +1 @@ +Subproject commit 3343a82b84e5b25d30e6e39fb3d1aa0d8dc70634 From a37ebc4f20e85979379e6490f0a65b8d777740b4 Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@Donalds-MacBook-Pro.local> Date: Wed, 8 Jul 2020 13:46:05 -0500 Subject: [PATCH 446/888] Remove refs to Test Migration repo --- docs/best-practices.md | 3 --- docs/introduction.md | 7 ------- 2 files changed, 10 deletions(-) diff --git a/docs/best-practices.md b/docs/best-practices.md index 613f398ca..b80542d9f 100644 --- a/docs/best-practices.md +++ b/docs/best-practices.md @@ -40,8 +40,6 @@ We recommend to keep Action Groups having single responsibility, for example `Ad Althought the Magento Core team and Contributors join forces to cover most of the features with tests, it is impossible to have this done quickly. If you've covered Magento Core feature with Functional Tests - you are more than welcome to contribute. -You can also help with MFTF Test Migration to get the experience and valuable feedback from other community members and maintainers. - ## Action group 1. [Action group] names should be sufficiently descriptive to inform a test writer of what the action group does and when it should be used. Add additional explanation in annotations if needed. @@ -214,4 +212,3 @@ Since the configurable product module could be disabled, this approach is more r [merging]: merging.html [parameterized selectors]: section/parameterized-selectors.html [sections]: section.html -[MFTF Test Migration]: https://github.com/magento/magento-functional-tests-migration diff --git a/docs/introduction.md b/docs/introduction.md index 53b763d8c..2c4ded6ce 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -52,12 +52,6 @@ Test └── ... ``` -<div class="bs-callout bs-callout-info" markdown="1"> - -We are actively developing functional tests. Check out the [MFTF Test Migration][] repository. - -</div> - ## Use cases - Contributor: changes the core behaviour, fixing the annoing bug. @@ -122,4 +116,3 @@ Follow the [MFTF project] and [contribute on Github]. [Functional Testing Framework]: https://devdocs.magento.com/guides/v2.3/mtf/mtf_introduction.html [MFTF project]: https://github.com/magento/magento2-functional-testing-framework [Find your MFTF version]: #find-your-mftf-version -[MFTF Test Migration]: https://github.com/magento/magento-functional-tests-migration From d839076051da0a3fb4a04bad91dd9b778bb639ed Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Wed, 8 Jul 2020 15:01:52 -0500 Subject: [PATCH 447/888] MQE-2210: Merge DevDoc changes in master back into MFTF release branch (#749) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Small fix to the Mftf Getting Started doc The command from the 'Set up an embedded MFTF -> Step 3' has to be executed from project root. * Update filter documentation with special characters to be able to show correctly in devdocs * DevDocs: Test merging precedence * Adding the Selenium server download in the example * Getting started > Removing code snippet I removed an unnecessary code snippet which doesn't make sense where it's. * DevDocs: Update Best Practices * Add missing information about Backend Domain support. * DevDocs: Update documentation regarding Versioning * DevDocs: Update documentation regarding Update process * Update Introduction for MFTF * Editorial pass * Escaped Liquid tag syntax * Fix an issue with MimeType guesser and latest release of "symfony/http-foundation" * Fix an issue with MimeType guesser and latest release of "symfony/http-foundation" * MQE-2052: MFTF uses undeclared dependency * MQE-2210: Merge DevDoc changes in master back into MFTF release branch Co-authored-by: Karyna Tsymbal <k.tsymbal@atwix.com> Co-authored-by: Alex Kolesnyk <kolesnyk@adobe.com> Co-authored-by: Lukasz Bajsarowicz <lukasz.bajsarowicz@gmail.com> Co-authored-by: Rafael Corrêa Gomes <rafaelstz@users.noreply.github.com> Co-authored-by: Kevin Kozan <kkozan@adobe.com> Co-authored-by: Donald Booth <dobooth@adobe.com> Co-authored-by: Kevin Kozan <kkozan@magento.com> --- CHANGELOG.md | 3 + docs/best-practices.md | 66 +++++++++++++++---- docs/commands/mftf.md | 2 +- docs/configuration.md | 10 +++ docs/getting-started.md | 12 ++-- docs/img/mftf-extending-precedence.png | Bin 0 -> 127088 bytes docs/introduction.md | 86 ++++++++++++++++--------- docs/merging.md | 10 +++ docs/update.md | 43 +++++++++++++ docs/versioning.md | 7 +- 10 files changed, 184 insertions(+), 55 deletions(-) create mode 100644 docs/img/mftf-extending-precedence.png create mode 100644 docs/update.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 2401d413f..61c9f3ad7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -129,6 +129,9 @@ Magento Functional Testing Framework Changelog 2.6.3 ----- +### Fixes +* added dependency to packages MFTF used but never specified in composer.json + ### New Feature * `--filter` option was added to `bin/mftf generate:tests` command. For more details please go to https://devdocs.magento.com/mftf/docs/commands/mftf.html#generatetests diff --git a/docs/best-practices.md b/docs/best-practices.md index c0499fb12..0ce9448cb 100644 --- a/docs/best-practices.md +++ b/docs/best-practices.md @@ -2,10 +2,49 @@ Check out our best practices below to ensure you are getting the absolute most out of the Magento Functional Testing Framework. +## Focus on reusability + +### Use existing Tests and resources + +Magento offers more than **3000** acceptance tests, **2500** [Action group]s, **750** Page declarations with more than **1500** Section definitions. +It is very probable that behaviour you want to test already exists as a Test or Action Group. +Instead of writing everything by yourself - use `extends` attribute to refer to existing element and customize it. + +**Reusable Resources** + +{%raw%} + +* Tests (reusable with `<test extends="...">` argument) +* Action Group (reusable with including `<actionGroup ref="...">`, or extending `<actionGroup extends="...">`) +* Pages (reusable with reference `{{PageDefinition.url}}`) +* Sections (reusable with reference `{{SectionDefinition.elementDefinition}}`) +* Data Entities (reusable with reference `<createData entity="...">"` or extending `<entity extends="...">`) + +{%endraw%} + +<div class="bs-callout bs-callout-warning" markdown="1"> + +Avoid using resources that are marked as **Deprecated**. Usually there is a replacement provided for a deprecated resource. + +</div> + +### Extract repetitive Actions + +Instead of writing a few of Tests that perform mostly the same actions, you should thing about [Action group] that is a container for repetitive Actions. +If each run needs different data, use `<arguments>` to inject necessary information. + +We recommend to keep Action Groups having single responsibility, for example `AdminLoginActionGroup`, which expected outcome is being logged in as Administrator when [Action group] is executed. + +## Contribute + +Althought the Magento Core team and Contributors join forces to cover most of the features with tests, it is impossible to have this done quickly. +If you've covered Magento Core feature with Functional Tests - you are more than welcome to contribute. + +You can also help with MFTF Test Migration to get the experience and valuable feedback from other community members and maintainers. + ## Action group -1. [Action group] names should be sufficiently descriptive to inform a test writer of what the action group does and when it should be used. - Add additional explanation in annotations if needed. +1. [Action group] names should be sufficiently descriptive to inform a test writer of what the action group does and when it should be used. Add additional explanation in annotations if needed. 2. Provide default values for the arguments that apply to your most common case scenarios. 3. One `<actionGroup>` tag is allowed per action group XML file. @@ -95,20 +134,20 @@ Use the _Foo.camelCase_ naming convention, which is similar to _Classes_ and _cl Use an upper case first letter for: -- File names. Example: _StorefrontCreateCustomerTest.xml_ -- Test name attributes. Example: `<test name="TestAllTheThingsTest">` -- Data entity names. Example: `<entity name="OutOfStockProduct">` -- Page name. Example: `<page name="AdminLoginPage">` -- Section name. Example: `<section name="AdminCategorySidebarActionSection">` -- Action group name. Example: `<actionGroup name="LoginToAdminActionGroup">` +* File names. Example: _StorefrontCreateCustomerTest.xml_ +* Test name attributes. Example: `<test name="TestAllTheThingsTest">` +* Data entity names. Example: `<entity name="OutOfStockProduct">` +* Page name. Example: `<page name="AdminLoginPage">` +* Section name. Example: `<section name="AdminCategorySidebarActionSection">` +* Action group name. Example: `<actionGroup name="LoginToAdminActionGroup">` #### Lower case Use a lower case first letter for: -- Data keys. Example: `<data key="firstName">` -- Element names. Examples: `<element name="confirmDeleteButton"/>` -- Step keys. For example: `<click selector="..." stepKey="clickLogin"/>` +* Data keys. Example: `<data key="firstName">` +* Element names. Examples: `<element name="confirmDeleteButton"/>` +* Step keys. For example: `<click selector="..." stepKey="clickLogin"/>` ## Page object @@ -147,9 +186,9 @@ Define these three elements and reference them by name in the tests. 1. Keep your tests short and granular for target testing, easier reviews, and easier merge conflict resolution. It also helps you to identify the cause of test failure. 1. Use comments to keep tests readable and maintainable: - - Keep the inline `<!-- XML comments -->` and [`<comment>`] tags up to date. + * Keep the inline `<!-- XML comments -->` and [`<comment>`] tags up to date. It helps to inform the reader of what you are testing and to yield a more descriptive Allure report. - - Explain in comments unclear or tricky test steps. + * Explain in comments unclear or tricky test steps. 1. Refer to [sections] instead of writing selectors. 1. One `<test>` tag is allowed per test XML file. @@ -178,3 +217,4 @@ Since the configurable product module could be disabled, this approach is more r [merging]: merging.html [parameterized selectors]: section/parameterized-selectors.html [sections]: section.html +[MFTF Test Migration]: https://github.com/magento/magento-functional-tests-migration diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index f1ef3955d..bc2e5c0ec 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -151,7 +151,7 @@ vendor/bin/mftf generate:tests [option] [<test name>] [<test name>] [--remove] | Option | Description| | ---| --- | | `--config=[<default> or <singleRun> or <parallel>]` | Creates a single manifest file with a list of all tests. The default location is `tests/functional/Magento/FunctionalTest/_generated/testManifest.txt`.<br/> You can split the list into multiple groups using `--config=parallel`; the groups will be generated in `_generated/groups/` like `_generated/groups/group1.txt, group2.txt, ...`.<br/> Available values: `default` (default), `singleRun`(same as `default`), and `parallel`.<br/> Example: `generate:tests --config=parallel`. | -| `--filter` | Option to filter tests to be generated.<br/>Template: '<filterName>:<filterValue>'.<br/>Existing filter types: severity.<br/>Existing severity values: BLOCKER, CRITICAL, MAJOR, AVERAGE, MINOR.<br/>Example: --filter=severity:CRITICAL| +| `--filter` | Option to filter tests to be generated.<br/>Template: '<filterName>:<filterValue>'.<br/>Existing filter types: severity.<br/>Existing severity values: BLOCKER, CRITICAL, MAJOR, AVERAGE, MINOR.<br/>Example: --filter=severity:CRITICAL| | `--force` | Forces test generation, regardless of the module merge order defined in the Magento instance. Example: `generate:tests --force`. | | `-i,--time` | Set time in minutes to determine the group size when `--config=parallel` is used. The __default value__ is `10`. Example: `generate:tests --config=parallel --time=15`| | `--tests` | Defines the test configuration as a JSON string.| diff --git a/docs/configuration.md b/docs/configuration.md index b78b421b9..b16f85d8f 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -32,6 +32,16 @@ Example: MAGENTO_BACKEND_NAME=admin_12346 ``` +### MAGENTO_BACKEND_BASE_URL + +(Optional) If you are running the Admin Panel on separate a domain, specify this value: + +Example: + +```conf +MAGENTO_BACKEND_BASE_URL=https://admin.magento2.test +``` + ### MAGENTO_ADMIN_USERNAME The username that tests can use to access the Magento Admin page diff --git a/docs/getting-started.md b/docs/getting-started.md index 99b8f197e..ec0afba0d 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -204,7 +204,7 @@ Learn more about environmental settings in [Configuration][]. ### Step 3. Enable the Magento CLI commands -In the `magento2/dev/tests/acceptance` directory, run the following command to enable the MFTF to send Magento CLI commands to your Magento instance. +In the Magento project root, run the following command to enable the MFTF to send Magento CLI commands to your Magento instance. ```bash cp dev/tests/acceptance/.htaccess.sample dev/tests/acceptance/.htaccess @@ -216,11 +216,11 @@ To run tests, you need a running Selenium server and [`mftf`][] commands. #### Run the Selenium server {#selenium-server} -Run the Selenium server in terminal. -For example, the following commands run the Selenium server for Google Chrome: +Run the Selenium server in the terminal. +For example, the following commands download and run the Selenium server for Google Chrome: ```bash -cd <path_to_directory_with_selenium_server_and_webdriver>/ +curl -O http://selenium-release.storage.googleapis.com/3.14/selenium-server-standalone-3.14.0.jar ``` ```bash @@ -233,10 +233,6 @@ java -Dwebdriver.chrome.driver=chromedriver -jar selenium-server-standalone-3.14 vendor/bin/mftf generate:tests ``` -```bash -cd dev/tests/acceptance -``` - ```bash vendor/bin/codecept run functional -c dev/tests/acceptance/codeception.yml ``` diff --git a/docs/img/mftf-extending-precedence.png b/docs/img/mftf-extending-precedence.png new file mode 100644 index 0000000000000000000000000000000000000000..deed5231f5592ca4a2f7dac8876361774f49b2c0 GIT binary patch literal 127088 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 literal 0 HcmV?d00001 diff --git a/docs/introduction.md b/docs/introduction.md index b68cca819..5a75777af 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -7,8 +7,15 @@ To find older documentation, please refer to the [docs folder] of your desired r [Find your MFTF version][] of the MFTF. -The Magento Functional Testing Framework (MFTF) aims to replace the [Functional Testing Framework] in future releases. -MFTF improves: +The Magento Functional Testing Framework (MFTF) is a framework used to perform automated end-to-end functional testing. + +## Goals + +- To facilitate functional testing and minimize the effort it takes to perform regression testing. +- Enable extension developers to provide the Functional Tests to offered extensions. +- Ensuring a common standard of quality between Magento, Extension Developers and System Intergrators. + +MFTF also focuses on - **Traceability** for clear logging and reporting capabilities. - **Modularity** to run tests based on installed modules and extensions. @@ -16,39 +23,64 @@ MFTF improves: - **Readability** using clear and declarative XML test steps. - **Maintainability** based on simple test creation and overall structure. -Because MFTF tests are written in XML, you no longer need to learn PHP to write tests. +## Audience -<div class="bs-callout bs-callout-info" markdown="1"> -We are actively developing functional tests. -Refer to `<magento_root>/app/code/<vendor_name>/<module_name>/Test/Mftf/` for examples. -Check out the [MFTF Test Migration][] repo. -</div> +- **Contributors**: Tests build confidence about the results of changes introduced to the platform. +- **Extension Developers**: Can adjust expected behaviour according to their customizations. +- **System Integrators**: MFTF coverage provided out-of-the-box with Magento is solid base for Acceptance / Regression Tests. -## Audience +## MFTF tests -This MFTF guide is intended for Magento developers and software engineers, such as QA specialists, PHP developers, and system integrators. +The MFTF supports two different locations for storing the tests and test artifacts: -## Goals +- `<magento_root>/app/code/<vendor_name>/<module_name>/Test/Mftf/` is the location of local, customized tests. +- `<magento_root>/vendor/<vendor_name>/<module_name>/Test/Mftf/` is location of tests provided by Magento and vendors. -The purpose of MFTF is to: +If you installed Magento with Composer, please refer to `vendor/magento/<module_dir>/Test/Mftf/` for examples. -- Facilitate functional testing and minimize the effort it takes to perform regression testing. -- Make it easier to support the extension and customization of tests via XML merging. +### Directory Structure -## Scope +The file structure under both of the both path cases is the same: + +```tree +Test +└── Mftf + ├── ActionGroup + │   └── ... + ├── Data + │   └── ... + ├── Metadata + │   └── ... + ├── Page + │   └── ... + ├── Section + │   └── ... + └── Test + └── ... +``` + +<div class="bs-callout bs-callout-info" markdown="1"> -MFTF will enable you to: +We are actively developing functional tests. Check out the [MFTF Test Migration][] repository. -- Test user interactions with web applications in testing. -- Write functional tests located in `<magento_root>/app/code/<vendor_name>/<module_name>/Test/Mftf/`. -- Cover basic functionality using out-of-the-box tests. You can test extended functionality using custom tests. -- Automate regression testing. +</div> ## Use cases -As a Magento developer, test changes, such as extended search functionality, a new form attribute, or new product tags. +- Contributor: changes the core behaviour, fixing the annoing bug. + He wants to have automated "supervisor" which is going to verify his work continuously across the stages of bug fixing. Finally, when fix is done - Functional Test is also proof of work done. +- Extension Developer: offers extension that changes core behaviour. + He can easily write new tests to make sure that after enabling the feature, Magento behaves properly. Everything with just extending existing tests. As a result he don't need to write coverage from scratch. +- Integration Agency: maintains Client's e-commerce. + They are able to customize tests delivered with Magento core to follow customizations implemented to Magento. After each upgrade they can just run the MFTF tests to know that no regression was introduced. + +## MFTF output -As a software engineer, perform regression testing before release to ensure that Magento works as expected with new functionality. +- Generated PHP Codeception tests +- Codeception results and console logs +- Screenshots and HTML failure report +- Allure formatted XML results +- Allure report dashboard of results ## Find your MFTF version @@ -57,11 +89,9 @@ There are two options to find out your MFTF version: - using the MFTF CLI - using the Composer CLI -### MFTF CLI +All the Command Line commands needs to be executed from `<magento_root>` -```bash -cd <magento_root>/ -``` +### MFTF CLI ```bash vendor/bin/mftf --version @@ -69,10 +99,6 @@ vendor/bin/mftf --version ### Composer CLI -```bash -cd <magento_root>/ -``` - ```bash composer show magento/magento2-functional-testing-framework ``` diff --git a/docs/merging.md b/docs/merging.md index ad3198623..fc187d576 100644 --- a/docs/merging.md +++ b/docs/merging.md @@ -27,6 +27,15 @@ For example: Although a file name does not influence merging, we recommend using the same file names in merging updates. This makes it easier to search later on. +## Merging precedence + +**Magento Functional Testing Framework** uses Module's `<sequence>` to merge all XML configurations into Codeception instructions. If there's no Sequence specified, MFTF would use: + +1. Vendor modules (Magento & Vendors) located in `vendor/` +1. Tests located in `app/code/*/*/Test/Mftf` + +![Usual precedence for merging MFTF Tests and resources][mftfExtendingPrecedence image] + ## Add a test You cannot add another [`<test>`][tests] using merging functionality. @@ -570,3 +579,4 @@ The `_defaultSample` results corresponds to: [`<sections>`]: ./section.md [`<tests>`]: ./test.md [`<action groups>`]: ./test/action-groups.md +[mftfExtendingPrecedence image]: img/mftf-extending-precedence.png diff --git a/docs/update.md b/docs/update.md new file mode 100644 index 000000000..ebd096158 --- /dev/null +++ b/docs/update.md @@ -0,0 +1,43 @@ +# Update the Magento Functional Testing Framework + +<div class="bs-callout bs-callout-info" markdown="1"> +Both Magento `2.2` and `2.3` supports MFTF `2.5.3` ([Find your version][] of the MFTF). +</div> + +Tests and the Framework itself are stored in different repositories. + +* Tests are stored in Module's directory. +* MFTF is installed separately (usually as a Composer dependency) + +To understand different types of update - please follow the [Versioning][] page. + +## Patch version update + +Takes place when **third** digit of version number changes. + +1. Make sure that [Security settings][] are set appropriately. +1. Get latest Framework version with `composer update magento/magento2-functional-testing-framework --with-dependencies` +1. Generate updated tests with `vendor/bin/mftf generate:tests` + +## Minor version update + +Takes place when **second** digit of version number changes. + +1. Check details about backward incompatible changes in the [Changelog][] and update your new or customized tests. +1. Perform all the actions provided for [Patch Version Update][] +1. When updating from versions below `2.5.0`, verify [WYSIWYG settings][] +1. You may need to run the `upgrade:tests` using `vendor/bin/mftf upgrade:tests app` + +## After updating + +1. It is a good idea to regenerate your IDE Schema Definition catalog with `vendor/bin/mftf generate:urn-catalog .idea/` +1. Update your tests, including data, metadata and other resoruces. Check if they contain tags that are unsupported in the newer version. +1. Remove the references to resources (ActionGroups, Sections, Tests) marked as deprecated. + +<!-- Link Definitions --> +[Changelog]: https://github.com/magento/magento2-functional-testing-framework/blob/master/CHANGELOG.md +[WYSIWYG settings]: getting-started.md#wysiwyg-settings +[Security settings]: getting-started.md#security-settings +[Find your version]: introduction.md#find-your-mftf-version +[Versioning]: versioning.md#versioning-policy +[Patch Version Update]: #patch-version-update diff --git a/docs/versioning.md b/docs/versioning.md index ecb8438c5..15b98f743 100644 --- a/docs/versioning.md +++ b/docs/versioning.md @@ -12,7 +12,6 @@ If a modification to MFTF forces tests to be changed, this is a backward incompa To find the version of MFTF that you are using, run the Magento CLI command: ```bash -cd <magento_root>/ vendor/bin/mftf --version ``` @@ -61,8 +60,10 @@ You must reset the patch and minor version to 0 when you change the major versio This table lists the version of the MFTF that was released with a particular version of Magento. |Magento version| MFTF version| -|---|---| +|--- |--- | +| 2.3.4 | 2.5.3 | +| 2.3.3 | 2.4.5 | | 2.3.2 | 2.3.14 | | 2.3.1 | 2.3.13 | -| 2.3.0 | 2.3.9 | +| 2.3.0 | 2.3.9 | | 2.2.8 | 2.3.13 | From c66387796f539c3c695148566b194b3719193aff Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Fri, 26 Jun 2020 15:04:58 -0500 Subject: [PATCH 448/888] MQE-2203: Create CHANGELOG.MD entry for 3.0.0 (#748) consolidated change log for 3.0.0 --- CHANGELOG.md | 158 +++++++++++++++++++-------------------------------- 1 file changed, 60 insertions(+), 98 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61c9f3ad7..d97bd7bfc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,118 +1,53 @@ Magento Functional Testing Framework Changelog ================================================ -3.0.0 RC5 ---------- - -### Enhancements - -* Readability - * Removed blacklist/whitelist terminology in MFTF. - -### Fixes - -* Fixed javascript error seen on chrome 81 for dragAndDrop action. -* Fixed allure issue when `WebDriverCurlException` is encountered in `afterStep`. - -3.0.0 RC4 +3.0.0 --------- ### Enhancements * Customizability + * Introduced MFTF helpers `<helper>` to create custom actions outside of MFTF.[See custom-helpers page for details](./docs/custom-helpers.md) + * Removed deprecated actions `<executeSelenium>` and `<performOn>`. * `<group value="skip"/>` no longer skips a test. Instead, the test is added to the `skip` group. -* Maintainability - * `mftf.log` no longer includes notices and warnings at test execution time. - * Added the Chrome option `--ignore-certificate-errors` to `functional.suite.dist.yml`. -* Traceability - * Changed the `bin/mftf static-checks` error file directory from the current working directory to `TESTS_BP/tests/_output/static-results/`. -* Readability - * Documented [3.0.0 Backward Incompatible Changes.](./docs/backward-incompatible-changes.md) - -### Fixes - -* Fixed issue where an extended data entity would not merge array items. Array items should merge properly now. -* Fixed issue where Chrome remains running after MFTF suite finishes. - -3.0.0 RC3 ---------- - -### Enhancements - -* Maintainability - * Added support for Two-Factor Authentication (2FA). [See configure-2fa page for details](./docs/configure-2fa.md) - * Added new static check `annotationsCheck` that checks and reports missing annotations in tests. - * Updated `bin/mftf static-checks` command to allow executing static-checks defined in `staticRuleSet.json` by default. [See command page for details](./docs/commands/mftf.md#static-checks) - * Added new upgrade script to remove unused arguments from action groups. - * Added unhandledPromptBehavior driver capability for Chrome 75+ support. - * Removed redundant and unused classes. - -### Fixes - -* Fixed issue with custom helper usage in suites. -* Fixed issue with decryption of secrets during data entity creation. -* Fixed issue with merging of `array` items in data entity. - -3.0.0 RC2 ---------- - -### Enhancements - -* Maintainability - * Added support for PHP 7.4. - * Removed support for PHP 7.2. - * Added support for PHPUnit 9. - * Improved assertion actions to support PHPUnit 9 changes. [See assertions page for details](./docs/test/assertions.md) - * Added new actions: `assertEqualsWithDelta`, `assertNotEqualsWithDelta`, `assertEqualsCanonicalizing`, `assertNotEqualsCanonicalizing`, `assertEqualsIgnoringCase`, `assertNotEqualsIgnoringCase`. - * Added new actions: `assertStringContainsString`, `assertStringNotContainsString`, `assertStringContainsStringIgnoringCase`, `assertStringNotContainsStringIgnoringCase` for string haystacks. - * Removed actions: `assertInternalType`, `assertNotInternalType`, `assertArraySubset`. - * Removed delta option from `assertEquals` and `assertNotEquals`. - * Removed action `pauseExecution` and added `pause`. [See actions page for details](./docs/test/actions.md#pause) - * Removed action `formatMoney` and added `formatCurrency`. [See actions page for details](./docs/test/actions.md#formatcurrency) - * Added new static check that checks and reports references to deprecated test entities. -* Bumped dependencies to support PHP/PHPUnit upgrade. - -* Traceability - * Introduced new `.env` configuration `VERBOSE_ARTIFACTS` to toggle saving attachments in Allure. [See configuration page for details](./docs/configuration.md) -### Fixes - -* Fixed issue of resolving arguments of type `entity` in action groups within a custom helper. -* Fixed reporting issue in output file for `testDependencies` static check. -* Fixed a bug in `actionGroupArguments` static check when action group filename is missing `ActionGroup`. -* Fixed issue of running suites under root `_suite` directory in Standalone MFTF. - -### GitHub Issues/Pull Requests - -* [#567](https://github.com/magento/magento2-functional-testing-framework/pull/567) -- log attachments for failed requests. - -3.0.0 RC1 ---------- - -### Enhancements - -* Customizability - * Introduced MFTF helpers `<helper>` to create custom actions outside of MFTF. - * Removed deprecated actions `<executeSelenium>` and `<performOn>`. * Maintainability + * Added support for PHP 7.4. + * Added support for PHPUnit 9. + * Dropped support for PHP 7.0, 7.1, 7.2. * Schema updates for test entities to only allow single entity per file except Data and Metadata. * Support for sub-folders in test modules. * Removed support to read test entities from `<magento>dev/tests/acceptance/tests/functional/Magento/FunctionalTest`. - * Removed support for PHP 7.0 and 7.1. * Removed file attribute for `<module>` in suiteSchema. + * Removed action `pauseExecution` and added `pause`. [See actions page for details](./docs/test/actions.md#pause) + * Removed action `formatMoney` and added `formatCurrency`. [See actions page for details](./docs/test/actions.md#formatcurrency) + * Improved assertion actions to support PHPUnit 9 changes. [See assertions page for details](./docs/test/assertions.md) + * Added new actions: `assertEqualsWithDelta`, `assertNotEqualsWithDelta`, `assertEqualsCanonicalizing`, `assertNotEqualsCanonicalizing`, `assertEqualsIgnoringCase`, `assertNotEqualsIgnoringCase`. + * Added new actions: `assertStringContainsString`, `assertStringNotContainsString`, `assertStringContainsStringIgnoringCase`, `assertStringNotContainsStringIgnoringCase` for string haystacks. + * Removed actions: `assertInternalType`, `assertNotInternalType`, `assertArraySubset`. + * Removed delta option from `assertEquals` and `assertNotEquals`. + * Added static check `deprecatedEntityUsage` that checks and reports references to deprecated test entities. + * Added static check `annotations` that checks and reports missing annotations in tests. + * Updated `bin/mftf static-checks` command to allow executing static-checks defined in `staticRuleSet.json` by default. [See command page for details](./docs/commands/mftf.md#static-checks) + * Added support for Two-Factor Authentication (2FA). [See configure-2fa page for details](./docs/configure-2fa.md) + * Added new upgrade script to remove unused arguments from action groups. + * `mftf.log` no longer includes notices and warnings at test execution time. + * Added unhandledPromptBehavior driver capability for Chrome 75+ support. + * Added the Chrome option `--ignore-certificate-errors` to `functional.suite.dist.yml`. + * Traceability - * Removed `--debug` option NONE to disallow ability to turn off schema validation. + * Removed `--debug` option `NONE` to disallow ability to turn off schema validation. * Notices added for test entity naming convention violations. * Metadata file names changed to `*Meta.xml`. + * Introduced new `.env` configuration `VERBOSE_ARTIFACTS` to toggle saving attachments in Allure. [See configuration page for details](./docs/configuration.md) + * Changed the `bin/mftf static-checks` error file directory from the current working directory to `TESTS_BP/tests/_output/static-results/`. + * Readability - * Support only nested assertion syntax [See assertions page for details](./docs/test/assertions.md) + * Support only nested assertion syntax [See assertions page for details](./docs/test/assertions.md). + * Documented [3.0.0 Backward Incompatible Changes](./docs/backward-incompatible-changes.md). + * Removed blacklist/whitelist terminology in MFTF. + * Upgrade scripts added to upgrade tests to MFTF major version requirements. See upgrade instructions below. -* Bumped dependencies to latest possible versions. - -### Fixes - -* Throw exception during generation when leaving out .url for `amOnPage`. -* `request_timeout` and `connection_timeout` added to functional.suite.yml.dist. -* Fixed `ModuleResolver` to resolve test modules moved out of deprecated path. +* Bumped dependencies to support PHP/PHPUnit upgrade. ### Upgrade Instructions @@ -120,12 +55,39 @@ Magento Functional Testing Framework Changelog * Run `bin/mftf build:project` to generate new configurations. * Run `bin/mftf upgrade:tests`. [See command page for details](./docs/commands/mftf.md#upgradetests). * After running the above command, some tests may need manually updates: - * Remove all occurrences of `<executeInSelenium>` and `<performOn>` - * Remove all occurrences of `<module file=""/>` from any `<suite>`s + * Remove all occurrences of `<executeInSelenium>` and `<performOn>`. + * Remove all occurrences of `<module file=""/>` from any `<suite>`s. * Ensure all `<assert*>` actions in your tests have a valid schema. * Lastly, try to generate all tests. Tests should all be generated as a result of the upgrades. * If not, the most likely issue will be a changed XML schema. Check error messaging and search your codebase for the attributes listed. +### Fixes + +* Throw exception during generation when leaving out .url for `amOnPage`. +* `request_timeout` and `connection_timeout` added to functional.suite.yml.dist. +* Fixed `ModuleResolver` to resolve test modules moved out of deprecated path. +* Fixed issue of resolving arguments of type `entity` in action groups within a custom helper. +* Fixed reporting issue in output file for `testDependencies` static check. +* Fixed a bug in `actionGroupArguments` static check when action group filename is missing `ActionGroup`. +* Fixed issue of running suites under root `_suite` directory in Standalone MFTF. +* Fixed issue with custom helper usage in suites. +* Fixed issue with decryption of secrets during data entity creation. +* Fixed issue with merging of `array` items in data entity. +* Fixed issue where an extended data entity would not merge array items. Array items should merge properly now. +* Fixed issue where Chrome remains running after MFTF suite finishes. +* Fixed javascript error seen on Chrome 83 for dragAndDrop action. +* Fixed allure issue when `WebDriverCurlException` is encountered in `afterStep`. + +### GitHub Issues/Pull Requests + +* [#567](https://github.com/magento/magento2-functional-testing-framework/pull/567) -- log attachments for failed requests. + +### Demo Video links + +* [MFTF 3.0.0 RC1](https://www.youtube.com/watch?v=z0ZaZCmnw-A&t=2s) +* [MFTF 3.0.0 RC2](https://www.youtube.com/watch?v=BJOQAw6dX5o) +* [MFTF 3.0.0 RC3](https://www.youtube.com/watch?v=scLb7pi8pR0) + 2.6.3 ----- From 2149401f4f6e8bdb4a92dcfa7045d825adb12a67 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 8 Jul 2020 15:17:03 -0500 Subject: [PATCH 449/888] MQE-2206: CHANGELOG.md and composer version bumped to 3.0.0 --- bin/mftf | 2 +- composer.json | 2 +- composer.lock | 5 ++--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/bin/mftf b/bin/mftf index ddb237fb6..7a9ca1cf2 100755 --- a/bin/mftf +++ b/bin/mftf @@ -31,7 +31,7 @@ try { $version = $version['version']; $application = new Symfony\Component\Console\Application(); $application->setName('Magento Functional Testing Framework CLI'); - $application->setVersion('3.0.0'); + $application->setVersion($version); /** @var \Magento\FunctionalTestingFramework\Console\CommandListInterface $commandList */ $commandList = new \Magento\FunctionalTestingFramework\Console\CommandList; foreach ($commandList->getCommands() as $command) { diff --git a/composer.json b/composer.json index ea1d6b800..f751129af 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "3.0.0-RC5", + "version": "3.0.0", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index b9707723b..d713e4f63 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "79415f9a24ebaf47d34ea227fc07e142", + "content-hash": "d3bdcdbe796e6703d82f051f888fb45b", "packages": [ { "name": "allure-framework/allure-codeception", @@ -6798,6 +6798,5 @@ "ext-json": "*", "ext-openssl": "*" }, - "platform-dev": [], - "plugin-api-version": "1.1.0" + "platform-dev": [] } From fd95a2ae14bc9a156634577bd1ce854118b2dd79 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Wed, 8 Jul 2020 15:31:02 -0500 Subject: [PATCH 450/888] MQE-2206: CHANGELOG.MD and Composer version bump fixed error in 2.6.3, 2.6.4 changelog --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d97bd7bfc..5a24b5f29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -88,12 +88,15 @@ Magento Functional Testing Framework Changelog * [MFTF 3.0.0 RC2](https://www.youtube.com/watch?v=BJOQAw6dX5o) * [MFTF 3.0.0 RC3](https://www.youtube.com/watch?v=scLb7pi8pR0) -2.6.3 +2.6.4 ----- ### Fixes * added dependency to packages MFTF used but never specified in composer.json +2.6.3 +----- + ### New Feature * `--filter` option was added to `bin/mftf generate:tests` command. For more details please go to https://devdocs.magento.com/mftf/docs/commands/mftf.html#generatetests From 26b0d6ecb310c72ddecbb0c21ae8837bf807da0d Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 8 Jul 2020 22:36:00 -0500 Subject: [PATCH 451/888] MQE-2207: merge 3.0.0-GA release branch to master --- CHANGELOG.md | 6 --- composer.json | 1 + composer.lock | 144 ++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 134 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7be443c5..5a24b5f29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -97,12 +97,6 @@ Magento Functional Testing Framework Changelog 2.6.3 ----- -### Fixes -* added dependency to packages MFTF used but never specified in composer.json - -2.6.3 ------ - ### New Feature * `--filter` option was added to `bin/mftf generate:tests` command. For more details please go to https://devdocs.magento.com/mftf/docs/commands/mftf.html#generatetests diff --git a/composer.json b/composer.json index f751129af..e1a04296f 100755 --- a/composer.json +++ b/composer.json @@ -30,6 +30,7 @@ "spomky-labs/otphp": "^10.0", "symfony/console": "^4.4", "symfony/finder": "^5.0", + "symfony/http-foundation": "^5.0", "symfony/mime": "^5.0", "symfony/process": "^4.4", "vlucas/phpdotenv": "^2.4", diff --git a/composer.lock b/composer.lock index d713e4f63..dff4f1006 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "d3bdcdbe796e6703d82f051f888fb45b", + "content-hash": "a0516f6072ced659bf4ed7a486756bb2", "packages": [ { "name": "allure-framework/allure-codeception", @@ -4529,6 +4529,56 @@ "homepage": "https://symfony.com", "time": "2020-03-27T16:56:45+00:00" }, + { + "name": "symfony/deprecation-contracts", + "version": "v2.1.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "5e20b83385a77593259c9f8beb2c43cd03b2ac14" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5e20b83385a77593259c9f8beb2c43cd03b2ac14", + "reference": "5e20b83385a77593259c9f8beb2c43cd03b2ac14", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "time": "2020-06-06T08:49:21+00:00" + }, { "name": "symfony/event-dispatcher", "version": "v4.4.7", @@ -4758,31 +4808,37 @@ }, { "name": "symfony/http-foundation", - "version": "v5.0.7", + "version": "v5.1.2", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "26fb006a2c7b6cdd23d52157b05f8414ffa417b6" + "reference": "f93055171b847915225bd5b0a5792888419d8d75" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/26fb006a2c7b6cdd23d52157b05f8414ffa417b6", - "reference": "26fb006a2c7b6cdd23d52157b05f8414ffa417b6", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/f93055171b847915225bd5b0a5792888419d8d75", + "reference": "f93055171b847915225bd5b0a5792888419d8d75", "shasum": "" }, "require": { - "php": "^7.2.5", - "symfony/mime": "^4.4|^5.0", - "symfony/polyfill-mbstring": "~1.1" + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/polyfill-mbstring": "~1.1", + "symfony/polyfill-php80": "^1.15" }, "require-dev": { "predis/predis": "~1.0", - "symfony/expression-language": "^4.4|^5.0" + "symfony/cache": "^4.4|^5.0", + "symfony/expression-language": "^4.4|^5.0", + "symfony/mime": "^4.4|^5.0" + }, + "suggest": { + "symfony/mime": "To use the file extension guesser" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "5.1-dev" } }, "autoload": { @@ -4809,7 +4865,7 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2020-03-30T14:14:32+00:00" + "time": "2020-06-15T06:52:54+00:00" }, { "name": "symfony/mime", @@ -5165,6 +5221,72 @@ ], "time": "2020-02-27T09:26:54+00:00" }, + { + "name": "symfony/polyfill-php80", + "version": "v1.17.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "4a5b6bba3259902e386eb80dd1956181ee90b5b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4a5b6bba3259902e386eb80dd1956181ee90b5b2", + "reference": "4a5b6bba3259902e386eb80dd1956181ee90b5b2", + "shasum": "" + }, + "require": { + "php": ">=7.0.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.17-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2020-06-06T08:46:27+00:00" + }, { "name": "symfony/process", "version": "v4.4.7", From 4cc0285dc8d92dc9b52ed5c30591ab305cd4436f Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Thu, 9 Jul 2020 16:06:45 -0500 Subject: [PATCH 452/888] Remove links temporarily --- docs/backward-incompatible-changes.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/backward-incompatible-changes.md b/docs/backward-incompatible-changes.md index 746e4546b..fbef67a4b 100644 --- a/docs/backward-incompatible-changes.md +++ b/docs/backward-incompatible-changes.md @@ -15,7 +15,7 @@ We removed support to read test modules from the deprecated path `dev/tests/acce - Files under test modules `ActionGroup`, `Page`, `Section`, `Test` and `Suite` only support a single entity per file. - The `file` attribute from `<module>` has been removed from the suite schema. `<module file=""/>` is no longer supported in suites. - Metadata filename format changed to ***`*Meta.xml`***. -- Only nested assertion syntax will be supported. See the [assertions page](./docs/test/assertions.md) for details. Here is an example of the nested assertion syntax: +- Only nested assertion syntax will be supported. Here is an example of the nested assertion syntax: ```xml <assertEquals stepKey="assertAddressOrderPage"> <actualResult type="const">$billingAddressOrderPage</actualResult> @@ -40,7 +40,7 @@ To run the upgrade tests: 1. Run `bin/mftf reset --hard` to remove old generated configurations. 1. Run `bin/mftf build:project` to generate new configurations. -1. Run `bin/mftf upgrade:tests`. [See command page for details](./docs/commands/mftf.md#upgradetests). +1. Run `bin/mftf upgrade:tests`. 1. Lastly, try to generate all tests. Tests should all be generated as a result of the upgrades. If not, the most likely issue will be a changed XML schema. Check error messaging and search your codebase for the attributes listed. ## MFTF commands @@ -57,7 +57,7 @@ To run the upgrade tests: **Details**: -The `helper` allows test writers to solve advanced requirements beyond what MFTF offers out of the box. See [custom-helpers](./docs/custom-helpers.md) for more information on usage. +The `helper` allows test writers to solve advanced requirements beyond what MFTF offers out of the box. Here is an example of using `helper` in place of `executeSelenium` to achieve same workflow. @@ -95,7 +95,7 @@ New usage: **Details**: -See the [actions page for details](./docs/test/actions.md#pause). Here is a usage example: +Here is a usage example: ```xml <pause stepKey="pauseExecutionKey"/> From 3211363edf29dc5be3256764d241ad115f642cd2 Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Thu, 9 Jul 2020 16:17:08 -0500 Subject: [PATCH 453/888] Add back links --- docs/backward-incompatible-changes.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/backward-incompatible-changes.md b/docs/backward-incompatible-changes.md index fbef67a4b..5ddf1c9cb 100644 --- a/docs/backward-incompatible-changes.md +++ b/docs/backward-incompatible-changes.md @@ -15,7 +15,7 @@ We removed support to read test modules from the deprecated path `dev/tests/acce - Files under test modules `ActionGroup`, `Page`, `Section`, `Test` and `Suite` only support a single entity per file. - The `file` attribute from `<module>` has been removed from the suite schema. `<module file=""/>` is no longer supported in suites. - Metadata filename format changed to ***`*Meta.xml`***. -- Only nested assertion syntax will be supported. Here is an example of the nested assertion syntax: +- Only nested assertion syntax will be supported. See the [assertions page](test/assertions.md) for details. Here is an example of the nested assertion syntax: ```xml <assertEquals stepKey="assertAddressOrderPage"> <actualResult type="const">$billingAddressOrderPage</actualResult> @@ -40,7 +40,7 @@ To run the upgrade tests: 1. Run `bin/mftf reset --hard` to remove old generated configurations. 1. Run `bin/mftf build:project` to generate new configurations. -1. Run `bin/mftf upgrade:tests`. +1. Run `bin/mftf upgrade:tests`. [See command page for details](commands/mftf.md#upgradetests). 1. Lastly, try to generate all tests. Tests should all be generated as a result of the upgrades. If not, the most likely issue will be a changed XML schema. Check error messaging and search your codebase for the attributes listed. ## MFTF commands @@ -57,7 +57,7 @@ To run the upgrade tests: **Details**: -The `helper` allows test writers to solve advanced requirements beyond what MFTF offers out of the box. +The `helper` allows test writers to solve advanced requirements beyond what MFTF offers out of the box. See [custom-helpers](custom-helpers.md) for more information on usage. Here is an example of using `helper` in place of `executeSelenium` to achieve same workflow. @@ -95,7 +95,7 @@ New usage: **Details**: -Here is a usage example: +See the [actions page for details](test/actions.md#pause). Here is a usage example: ```xml <pause stepKey="pauseExecutionKey"/> From 9c8ab083bcd1af42385be2eab827d04e9c7448c8 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 13 Jul 2020 09:44:33 -0500 Subject: [PATCH 454/888] Set theme jekyll-theme-hacker --- _config.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 _config.yml diff --git a/_config.yml b/_config.yml new file mode 100644 index 000000000..fc24e7a62 --- /dev/null +++ b/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-hacker \ No newline at end of file From b195677abe2e4a1cbe551c55a004be8455069697 Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Mon, 13 Jul 2020 13:43:35 -0500 Subject: [PATCH 455/888] MQE-2214: Part 1 Docs Annual Review --- docs/configuration.md | 16 ++++++++-------- docs/credentials.md | 18 +++++++++--------- docs/data.md | 4 ++-- docs/extending.md | 2 +- docs/getting-started.md | 36 ++++++++++++++++-------------------- docs/introduction.md | 22 +++++++--------------- 6 files changed, 43 insertions(+), 55 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index b16f85d8f..f6fffaf6e 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1,12 +1,12 @@ # Configuration The `*.env` file provides additional configuration for the Magento Functional Testing Framework (MFTF). -To run the MFTF on your Magento instance, specify the basic configuration values. +To run MFTF on your Magento instance, specify the basic configuration values. Advanced users can create custom configurations based on requirements and environment. ## Basic configuration -These basic configuration values are __required__ and must be set by the user before the MFTF can function correctly. +These basic configuration values are __required__ and must be set by the user before MFTF can function correctly. ### MAGENTO_BASE_URL @@ -34,7 +34,7 @@ MAGENTO_BACKEND_NAME=admin_12346 ### MAGENTO_BACKEND_BASE_URL -(Optional) If you are running the Admin Panel on separate a domain, specify this value: +(Optional) If you are running the Admin Panel on a separate domain, specify this value: Example: @@ -64,7 +64,7 @@ MAGENTO_ADMIN_PASSWORD=1234reTyt%$7 ## Advanced configuration -Depending on the environment you use, you may need to configure the MFTF more precisely by setting more configuration parameters then for basic configuration. +Depending on the environment you use, you may need to configure MFTF more precisely by setting additional configuration parameters. This section describes available configuration parameters and their default values (where applicable). ### DEFAULT_TIMEZONE @@ -173,8 +173,8 @@ MAGENTO_RESTAPI_SERVER_PORT=5000 ### \*_BP Settings to override base paths for the framework. -You can use it when the MFTF is applied as a separate tool. -For example, when you need to place the MFTF and the Magento codebase in separate projects. +You can use it when MFTF is applied as a separate tool. +For example, when you need to place MFTF and the Magento codebase in separate projects. ```conf MAGENTO_BP @@ -227,7 +227,7 @@ TESTS_MODULE_PATH=~/magento2/dev/tests/acceptance/tests/functional/Magento/Funct ### MODULE_ALLOWLIST Use for a new module. -When adding a new directory at `Magento/FunctionalTest`, add the directory name to `MODULE_ALLOWLIST` to enable the MFTF to process it. +When adding a new directory at `Magento/FunctionalTest`, add the directory name to `MODULE_ALLOWLIST` to enable MFTF to process it. Example: @@ -245,7 +245,7 @@ It points to `MAGENTO_BASE_URL` + `dev/tests/acceptance/utils/command.php` Modify the default value: - for non-default Magento installation -- when use a subdirectory in the `MAGENTO_BASE_URL` +- when using a subdirectory in the `MAGENTO_BASE_URL` Example: `dev/tests/acceptance/utils/command.php` diff --git a/docs/credentials.md b/docs/credentials.md index 402030985..0c6decb41 100644 --- a/docs/credentials.md +++ b/docs/credentials.md @@ -3,7 +3,7 @@ When you test functionality that involves external services such as UPS, FedEx, PayPal, or SignifyD, use the MFTF credentials feature to hide sensitive [data][] like integration tokens and API keys. -Currently the MFTF supports three types of credential storage: +Currently MFTF supports three types of credential storage: - **.credentials file** - **HashiCorp Vault** @@ -11,12 +11,12 @@ Currently the MFTF supports three types of credential storage: ## Configure File Storage -The MFTF creates a sample file for credentials during [initial setup][]: `magento2/dev/tests/acceptance/.credentials.example`. +MFTF creates a sample file for credentials during [initial setup][]: `magento2/dev/tests/acceptance/.credentials.example`. The file contains an example list of keys for fields that can require credentials. ### Create `.credentials` -To make the MFTF process the file with credentials, in the command line, navigate to `magento2/dev/tests/acceptance/` and rename `.credentials.example` to `.credentials`. +To make MFTF process the file with credentials, in the command line, navigate to `magento2/dev/tests/acceptance/` and rename `.credentials.example` to `.credentials`. ```bash cd dev/tests/acceptance/ @@ -78,7 +78,7 @@ vendor/my_awesome_service_token=rRVSVnh3cbDsVG39oTMz4A Hashicorp vault secures, stores, and tightly controls access to data in modern computing. It provides advanced data protection for your testing credentials. -The MFTF works with both `vault enterprise` and `vault open source` that use `KV Version 2` secret engine. +MFTF works with both `vault enterprise` and `vault open source` that use `KV Version 2` secret engine. ### Install vault CLI @@ -92,11 +92,11 @@ Authenticate to vault server via the vault CLI tool: [Login Vault][Login Vault]. vault login -method -path ``` -**Do not** use `-no-store` command option, as the MFTF will rely on the persisted token in the token helper (usually the local filesystem) for future API requests. +**Do not** use `-no-store` command option, as MFTF will rely on the persisted token in the token helper (usually the local filesystem) for future API requests. ### Store secrets in vault -The MFTF uses the `KV Version 2` secret engine for secret storage. +MFTF uses the `KV Version 2` secret engine for secret storage. More information for working with `KV Version 2` can be found in [Vault KV2][Vault KV2]. #### Secrets path and key convention @@ -225,7 +225,7 @@ export CREDENTIAL_AWS_ACCOUNT_ID=<Your_12_Digits_AWS_Account_ID> ## Configure multiple credential storage It is possible and sometimes useful to setup and use multiple credential storage at the same time. -In this case, the MFTF tests are able to read secret data at runtime from all storage options, in this case MFTF use the following precedence: +In this case, the MFTF tests are able to read secret data at runtime from all storage options. MFTF will use the following precedence: ``` .credentials File > HashiCorp Vault > AWS Secrets Manager @@ -253,7 +253,7 @@ For example, to reference secret data in the [`fillField`][] action, use the `us ## Implementation details The generated tests do not contain credentials values. -The MFTF dynamically retrieves, encrypts, and decrypts the sensitive data during test execution. +MFTF dynamically retrieves, encrypts, and decrypts the sensitive data during test execution. Decrypted credentials do not appear in the console, error logs, or [test reports][]. The decrypted values are only available in the `.credentials` file or within vault. @@ -277,4 +277,4 @@ The MFTF tests delivered with Magento application do not use credentials and do [`CREDENTIAL_AWS_SECRETS_MANAGER_PROFILE`]: configuration.md#credential_aws_secrets_manager_profile [`CREDENTIAL_AWS_SECRETS_MANAGER_REGION`]: configuration.md#credential_aws_secrets_manager_region [Key Management Service]: https://aws.amazon.com/kms/ -[Amazon Resource Name]: https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html \ No newline at end of file +[Amazon Resource Name]: https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html diff --git a/docs/data.md b/docs/data.md index 8b0a86e3d..33b833504 100644 --- a/docs/data.md +++ b/docs/data.md @@ -1,6 +1,6 @@ # Input testing data -The MFTF enables you to specify and use `<data>` entities defined in XML. Default `<data>` entities are provided for use and as templates for entity creation and manipulation. +MFTF enables you to specify and use `<data>` entities defined in XML. Default `<data>` entities are provided for use and as templates for entity creation and manipulation. The following diagram shows the XML structure of an MFTF data object: ![MFTF Data Object](img/data-dia.svg) @@ -67,7 +67,7 @@ In this example: As of MFTF 2.3.6, you no longer need to differentiate between scopes (a test, a hook, or a suite) for persisted data when referencing it in tests. </div> -The MFTF now stores the persisted data and attempts to retrieve it using the combination of `stepKey` and the scope of where it has been called. +MFTF now stores the persisted data and attempts to retrieve it using the combination of `stepKey` and the scope of where it has been called. The current scope is preferred, then widening to _test > hook > suite_ or _hook > test > suite_. This emphasizes the practice for the `stepKey` of `createData` to be descriptive and unique, as a duplicated `stepKey` in both a `<test>` and `<before>` prefers the `<test>` data. diff --git a/docs/extending.md b/docs/extending.md index 064ed3208..38f5c047d 100644 --- a/docs/extending.md +++ b/docs/extending.md @@ -115,7 +115,7 @@ __Use case__: Create two similar tests where the second test contains two additi </tests> ``` -### Update a test annotation +### Update a test before hook __Use case__: Create two similar tests where the second one contains two additional actions in the `before` hook: diff --git a/docs/getting-started.md b/docs/getting-started.md index ec0afba0d..7b982b379 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -1,9 +1,9 @@ # Getting started <div class="bs-callout bs-callout-info" markdown="1"> -[Find your MFTF version][] of the MFTF. -The latest Magento 2.3.x release supports MFTF 2.5.3. -The latest Magento 2.2.x release supports MFTF 2.4.5. +[Find your version] of MFTF. +The latest Magento 2.3.x release supports MFTF 2.6.4. +The latest Magento 2.2.x release supports MFTF 2.5.3. </div> ## Prepare environment {#prepare-environment} @@ -64,7 +64,7 @@ A Selenium web driver cannot enter data to fields with WYSIWYG. To disable the WYSIWYG and enable the web driver to process these fields as simple text areas: 1. Log in to the Magento Admin as an administrator. -2. Navigate to **Stores** > Settings > **Configuration** > **General** > **Content Management**. +2. Navigate to **Stores** > **Settings** > **Configuration** > **General** > **Content Management**. 3. In the WYSIWYG Options section set the **Enable WYSIWYG Editor** option to **Disabled Completely**. 4. Click **Save Config**. @@ -88,7 +88,7 @@ When you want to test the WYSIWYG functionality, re-enable WYSIWYG in your test To enable the **Admin Account Sharing** setting, to avoid unpredictable logout during a testing session, and disable the **Add Secret Key in URLs** setting, to open pages using direct URLs: -1. Navigate to **Stores** > Settings > **Configuration** > **Advanced** > **Admin** > **Security**. +1. Navigate to **Stores** > **Settings** > **Configuration** > **Advanced** > **Admin** > **Security**. 2. Set **Admin Account Sharing** to **Yes**. 3. Set **Add Secret Key to URLs** to **No**. 4. Click **Save Config**. @@ -115,7 +115,7 @@ If the Magento instance under test has the [Magento Two-Factor Authentication (2 ### Webserver configuration {#web-server-configuration} -The MFTF does not support executing CLI commands if your web server points to `<MAGE_ROOT_DIR>/pub` directory as recommended in the [Installation Guide][Installation Guide docroot]. For the MFTF to execute the CLI commands, the web server must point to the Magento root directory. +MFTF does not support executing CLI commands if your web server points to `<MAGE_ROOT_DIR>/pub` directory as recommended in the [Installation Guide][Installation Guide docroot]. For MFTF to execute the CLI commands, the web server must point to the Magento root directory. ### Nginx settings {#nginx-settings} @@ -137,11 +137,11 @@ location ~* ^/dev/tests/acceptance/utils($|/) { ## Set up an embedded MFTF {#setup-framework} -This is the default setup of the MFTF that you would need to cover your Magento project with functional tests. +This is the default setup of MFTF that you would need to cover your Magento project with functional tests. It installs the framework using an existing Composer dependency such as `magento/magento2-functional-testing-framework`. -If you want to set up the MFTF as a standalone tool, refer to [Set up a standalone MFTF][]. +If you want to set up MFTF as a standalone tool, refer to [Set up a standalone MFTF][]. -Install the MFTF. +Install MFTF. ```bash composer install @@ -204,7 +204,7 @@ Learn more about environmental settings in [Configuration][]. ### Step 3. Enable the Magento CLI commands -In the Magento project root, run the following command to enable the MFTF to send Magento CLI commands to your Magento instance. +In the Magento project root, run the following command to enable MFTF to send Magento CLI commands to your Magento instance. ```bash cp dev/tests/acceptance/.htaccess.sample dev/tests/acceptance/.htaccess @@ -251,9 +251,7 @@ See more commands in [`mftf`][]. ### Step 5. Generate reports {#reports} -During testing, the MFTF generates test reports in CLI. -You can generate visual representations of the report data using [Allure Framework][]. -To view the reports in GUI: +During testing, MFTF generates test reports in CLI. You can generate visual representations of the report data using the [Allure Framework][]. To view the reports in a GUI: - [Install Allure][] - Run the tool to serve the artifacts in `dev/tests/acceptance/tests/_output/allure-results/`: @@ -266,18 +264,16 @@ Learn more about Allure in the [official documentation][allure docs]. ## Set up a standalone MFTF -The MFTF is a root level Magento dependency, but it is also available for use as a standalone application. -You may want to use a standalone application when you develop for or contribute to MFTF, which facilitates debugging and tracking changes. -These guidelines demonstrate how to set up and run Magento acceptance functional tests using standalone MFTF. +MFTF is a root level Magento dependency, but it is also available for use as a standalone application. You may want to use a standalone application when you develop for or contribute to MFTF, which facilitates debugging and tracking changes. These guidelines demonstrate how to set up and run Magento acceptance functional tests using standalone MFTF. ### Prerequisites This installation requires a local instance of the Magento application. -The MFTF uses the [tests from Magento modules][mftf tests] as well as the `app/autoload.php` file. +MFTF uses the [tests from Magento modules][mftf tests] as well as the `app/autoload.php` file. ### Step 1. Clone the MFTF repository -If you develop or contribute to the MFTF, it makes sense to clone your fork of the MFTF repository. +If you develop or contribute to MFTF, it makes sense to clone your fork of the MFTF repository. For contribution guidelines, refer to the [Contribution Guidelines for the Magento Functional Testing Framework][contributing]. ### Step 2. Install the MFTF @@ -307,7 +303,7 @@ Create the `utils/` directory, if you didn't find it. ### Step 6. Remove the MFTF package dependency in Magento -The MFTF uses the Magento `app/autoload.php` file to read Magento modules. +MFTF uses the Magento `app/autoload.php` file to read Magento modules. The MFTF dependency in Magento supersedes the standalone registered namespaces unless it is removed at a Composer level. ```bash @@ -355,6 +351,6 @@ allure serve dev/tests/_output/allure-results/ [selenium server]: https://www.seleniumhq.org/download/ [Set up a standalone MFTF]: #set-up-a-standalone-mftf [test suite]: suite.html -[Find your MFTF version]: introduction.html#find-your-mftf-version +[Find your version]: introduction.html#find-your-mftf-version [Installation Guide docroot]: https://devdocs.magento.com/guides/v2.3/install-gde/tutorials/change-docroot-to-pub.html [Magento Two-Factor Authentication (2FA) extension]: https://devdocs.magento.com/guides/v2.3/security/two-factor-authentication.html diff --git a/docs/introduction.md b/docs/introduction.md index 5a75777af..5a7869381 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -5,15 +5,15 @@ These are the docs for the latest MFTF release. To find older documentation, please refer to the [docs folder] of your desired release in Github. </div> -[Find your MFTF version][] of the MFTF. +[Find your version] of MFTF. The Magento Functional Testing Framework (MFTF) is a framework used to perform automated end-to-end functional testing. ## Goals - To facilitate functional testing and minimize the effort it takes to perform regression testing. -- Enable extension developers to provide the Functional Tests to offered extensions. -- Ensuring a common standard of quality between Magento, Extension Developers and System Intergrators. +- Enable extension developers to provide functional tests for their extensions. +- Ensure a common standard of quality between Magento, extension developers and system integrators. MFTF also focuses on @@ -31,7 +31,7 @@ MFTF also focuses on ## MFTF tests -The MFTF supports two different locations for storing the tests and test artifacts: +MFTF supports two different locations for storing the tests and test artifacts: - `<magento_root>/app/code/<vendor_name>/<module_name>/Test/Mftf/` is the location of local, customized tests. - `<magento_root>/vendor/<vendor_name>/<module_name>/Test/Mftf/` is location of tests provided by Magento and vendors. @@ -40,7 +40,7 @@ If you installed Magento with Composer, please refer to `vendor/magento/<module_ ### Directory Structure -The file structure under both of the both path cases is the same: +The file structure under both cases is the same: ```tree Test @@ -59,12 +59,6 @@ Test └── ... ``` -<div class="bs-callout bs-callout-info" markdown="1"> - -We are actively developing functional tests. Check out the [MFTF Test Migration][] repository. - -</div> - ## Use cases - Contributor: changes the core behaviour, fixing the annoing bug. @@ -130,7 +124,7 @@ codeception.dist.yml // Codeception configuration (generated while ru ## MFTF tests -The MFTF supports three different locations for storing the tests and test artifacts: +MFTF supports three different locations for storing the tests and test artifacts: - `<magento_root>/app/code/<vendor_name>/<module_name>/Test/Mftf/` is the directory to create new tests. - `<magento_root>/vendor/<vendor_name>/<module_name>/Test/Mftf/` is the directory with the out of the box tests (fetched by the Composer). - `<magento_root>/dev/tests/acceptance/tests/functional/<vendor_name>/<module_name>/` is used to store tests that depend on multiple modules. @@ -163,8 +157,6 @@ Follow the [MFTF project] and [contribute on Github]. <!-- Link definitions --> [contribute on Github]: https://github.com/magento/magento2-functional-testing-framework/blob/master/.github/CONTRIBUTING.md -[Functional Testing Framework]: https://devdocs.magento.com/guides/v2.3/mtf/mtf_introduction.html [MFTF project]: https://github.com/magento/magento2-functional-testing-framework -[Find your MFTF version]: #find-your-mftf-version -[MFTF Test Migration]: https://github.com/magento/magento-functional-tests-migration +[Find your version]: #find-your-mftf-version [docs folder]: https://github.com/magento/magento2-functional-testing-framework/tree/master/docs From 20498b78f406ecd06ab18f9293f945008080064d Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Thu, 16 Jul 2020 11:22:17 -0500 Subject: [PATCH 456/888] MQE-2214: Part 1 Docs Annual Review --- docs/configuration.md | 4 ++-- docs/extending.md | 22 +++++++++++----------- docs/getting-started.md | 8 ++++---- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index f6fffaf6e..ce3adadd7 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -221,13 +221,13 @@ The path to where the MFTF modules mirror Magento modules. Example: ```conf -TESTS_MODULE_PATH=~/magento2/dev/tests/acceptance/tests/functional/Magento/FunctionalTest +TESTS_MODULE_PATH=~/magento2/dev/tests/acceptance/tests/functional/Magento ``` ### MODULE_ALLOWLIST Use for a new module. -When adding a new directory at `Magento/FunctionalTest`, add the directory name to `MODULE_ALLOWLIST` to enable MFTF to process it. +When adding a new directory at `tests/functional/Magento`, add the directory name to `MODULE_ALLOWLIST` to enable MFTF to process it. Example: diff --git a/docs/extending.md b/docs/extending.md index 38f5c047d..ecfc2018a 100644 --- a/docs/extending.md +++ b/docs/extending.md @@ -177,14 +177,14 @@ Extend an [action group] to add or update [actions] in your module. ### Update an action -__Use case__: The `CountProductA` test counts the particular product. +__Use case__: The `AssertAdminCountProductActionGroup` action group counts the particular product. Modify the action group to use another product. > Action groups with "extends": ```xml <actionGroups> - <actionGroup name="CountProductA"> + <actionGroup name="AssertAdminCountProductActionGroup"> <arguments> <argument name="count" type="string"/> </arguments> @@ -195,7 +195,7 @@ Modify the action group to use another product. </assertCount> </actionGroup> - <actionGroup name="CountProductB" extends="CountProductA"> + <actionGroup name="AssertAdminOtherCountProductActionGroup" extends="AssertAdminCountProductActionGroup"> <grabMultiple selector="selectorForProductB" stepKey="grabProducts"/> </actionGroup> </actionGroups> @@ -205,7 +205,7 @@ Modify the action group to use another product. ```xml <actionGroups> - <actionGroup name="CountProductA"> + <actionGroup name="AssertAdminCountProductActionGroup"> <arguments> <argument name="count" type="string"/> </arguments> @@ -216,7 +216,7 @@ Modify the action group to use another product. </assertCount> </actionGroup> - <actionGroup name="CountProductB"> + <actionGroup name="AssertAdminOtherCountProductActionGroup"> <arguments> <argument name="count" type="string"/> </arguments> @@ -231,21 +231,21 @@ Modify the action group to use another product. ### Add an action -__Use case__: The `GetProductCount` action group returns the count of products. -Add a new test `VerifyProductCount` that asserts the count of products: +__Use case__: The `AdminGetProductCountActionGroup` action group returns the count of products. +Add a new test `AssertAdminVerifyProductCountActionGroup` that asserts the count of products: > Action groups with "extends": ```xml <actionGroups> - <actionGroup name="GetProductCount"> + <actionGroup name="AdminGetProductCountActionGroup"> <arguments> <argument name="productSelector" type="string"/> </arguments> <grabMultiple selector="{{productSelector}}" stepKey="grabProducts"/> </actionGroup> - <actionGroup name="VerifyProductCount" extends="GetProductCount"> + <actionGroup name="AssertAdminVerifyProductCountActionGroup" extends="AdminGetProductCountActionGroup"> <arguments> <argument name="count" type="string"/> </arguments> @@ -261,14 +261,14 @@ Add a new test `VerifyProductCount` that asserts the count of products: ```xml <actionGroups> - <actionGroup name="GetProductCount"> + <actionGroup name="AdminGetProductCountActionGroup"> <arguments> <argument name="productSelector" type="string"/> </arguments> <grabMultiple selector="{{productSelector}}" stepKey="grabProducts"/> </actionGroup> - <actionGroup name="VerifyProductCount"> + <actionGroup name="AssertAdminVerifyProductCountActionGroup"> <arguments> <argument name="count" type="string"/> <argument name="productSelector" type="string"/> diff --git a/docs/getting-started.md b/docs/getting-started.md index 7b982b379..af4f8d62e 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -44,7 +44,7 @@ cd magento2/ ``` ```bash -git checkout 2.3-develop +git checkout 2.4-develop ``` Install the Magento application. @@ -241,10 +241,10 @@ See more commands in [`codecept`][]. #### Run a simple test {#run-test} -To clean up the previously generated tests, and then generate and run a single test `AdminLoginTest`, run: +To clean up the previously generated tests, and then generate and run a single test `AdminLoginSuccessfulTest`, run: ```bash -vendor/bin/mftf run:test AdminLoginTest --remove +vendor/bin/mftf run:test AdminLoginSuccessfulTest --remove ``` See more commands in [`mftf`][]. @@ -315,7 +315,7 @@ composer remove magento/magento2-functional-testing-framework --dev -d <path to Generate and run a single test that will check your logging to the Magento Admin functionality: ```bash -bin/mftf run:test AdminLoginTest +bin/mftf run:test AdminLoginSuccessfulTest ``` You can find the generated test at `dev/tests/functional/tests/MFTF/_generated/default/`. From 6917199706308eaafd285c721a8405d577650c2b Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Thu, 16 Jul 2020 14:17:06 -0500 Subject: [PATCH 457/888] MQE-2214: Part 1 Docs Annual Review --- docs/extending.md | 130 +++++++++++++++++----------------------------- 1 file changed, 49 insertions(+), 81 deletions(-) diff --git a/docs/extending.md b/docs/extending.md index ecfc2018a..fe06d9637 100644 --- a/docs/extending.md +++ b/docs/extending.md @@ -21,25 +21,19 @@ Unlike merging, the parent test (or action group) will still exist after the tes <!-- {% raw %} --> -__Use case__: Create two similar tests with different `url` (`"{{AdminCategoryPage.url}}"` and `"{{OtherCategoryPage.url}}"`) in a test step. +__Use case__: Create two similar tests with a different action group reference by overwriting a `stepKey`. > Test with "extends": ```xml <tests> - <test name="AdminCategoryTest"> - <annotations> - ... - </annotations> - ...(several steps) - <amOnPage url="{{AdminCategoryPage.url}}" stepKey="navigateToAdminCategory"/> - ...(several steps) + <test name="AdminLoginSuccessfulTest"> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <actionGroup ref="AssertAdminSuccessLoginActionGroup" stepKey="assertLoggedIn"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> </test> - <test name="OtherCategoryTest" extends="AdminCategoryTest"> - <annotations> - ... - </annotations> - <amOnPage url="{{OtherCategoryPage.url}}" stepKey="navigateToAdminCategory"/> + <test name="AdminLoginAsOtherUserSuccessfulTest" extends="AdminLoginSuccessfulTest"> + <actionGroup ref="AdminLoginAsOtherUserActionGroup" stepKey="loginAsAdmin"/> </test> </tests> ``` @@ -48,46 +42,35 @@ __Use case__: Create two similar tests with different `url` (`"{{AdminCategoryPa ```xml <tests> - <test name="AdminCategoryTest"> - <annotations> - ... - </annotations> - ...(several steps) - <amOnPage url="{{AdminCategoryPage.url}}" stepKey="navigateToAdminCategory"/> - ...(several steps) + <test name="AdminLoginSuccessfulTest"> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <actionGroup ref="AssertAdminSuccessLoginActionGroup" stepKey="assertLoggedIn"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> </test> - <test name="OtherCategoryTest"> - <annotations> - ... - </annotations> - ...(several steps) - <amOnPage url="{{OtherCategoryPage.url}}" stepKey="navigateToAdminCategory"/> - ...(several steps) + <test name="AdminLoginAsOtherUserSuccessfulTest"> + <actionGroup ref="AdminLoginAsOtherUserActionGroup" stepKey="loginAsAdmin"/> + <actionGroup ref="AssertAdminSuccessLoginActionGroup" stepKey="assertLoggedIn"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> </test> </tests> ``` ### Add a test step -__Use case__: Create two similar tests where the second test contains two additional steps: - -* `checkOption` before `click` (`stepKey="clickLogin"`) -* `seeInCurrentUrl` after `click` in the `LogInAsAdminTest` test (in the `.../Backend/Test/LogInAsAdminTest.xml` file) +__Use case__: Create two similar tests where the second test contains two additional steps specified to occur `before` or `after` other `stepKeys`. > Tests with "extends": ```xml <tests> - <test name="LogInAsAdminTest"> - <amOnPage url="{{AdminLoginPage}}" stepKey="navigateToAdmin"/> - <fillField selector="{{AdminLoginFormSection.username}}" userInput="admin" stepKey="fillUsername"/> - <fillField selector="{{AdminLoginFormSection.password}}" userInput="password" stepKey="fillPassword"/> - <click selector="{{AdminLoginFormSection.signIn}}" stepKey="clickLogin"/> - <see userInput="Lifetime Sales" stepKey="seeLifetimeSales"/> + <test name="AdminLoginSuccessfulTest"> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <actionGroup ref="AssertAdminSuccessLoginActionGroup" stepKey="assertLoggedIn"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> </test> - <test name="AlternativeLogInAsAdminTest" extends="LogInAsAdminTest"> - <checkOption selector="{{AdminLoginFormSection.rememberMe}}" stepKey="checkRememberMe" before="clickLogin"/> - <seeInCurrentUrl url="admin/admin/dashboard/" stepKey="seeAdminUrl" after="clickLogin"/> + <test name="AdminLoginCheckRememberMeSuccessfulTest" extends="AdminLoginSuccessfulTest"> + <actionGroup ref="AdminCheckRememberMeActionGroup" stepKey="checkRememberMe" after="loginAsAdmin"/> + <actionGroup ref="AssertAdminRememberMeActionGroup" stepKey="assertRememberMe" before="logoutFromAdmin"/> </test> </tests> ``` @@ -96,49 +79,39 @@ __Use case__: Create two similar tests where the second test contains two additi ```xml <tests> - <test name="LogInAsAdminTest"> - <amOnPage url="{{AdminLoginPage}}" stepKey="navigateToAdmin"/> - <fillField selector="{{AdminLoginFormSection.username}}" userInput="admin" stepKey="fillUsername"/> - <fillField selector="{{AdminLoginFormSection.password}}" userInput="password" stepKey="fillPassword"/> - <click selector="{{AdminLoginFormSection.signIn}}" stepKey="clickLogin"/> - <see userInput="Lifetime Sales" stepKey="seeLifetimeSales"/> + <test name="AdminLoginSuccessfulTest"> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <actionGroup ref="AssertAdminSuccessLoginActionGroup" stepKey="assertLoggedIn"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> </test> - <test name="AlternativeLogInAsAdminTest"> - <amOnPage url="{{AdminLoginPage}}" stepKey="navigateToAdmin"/> - <fillField selector="{{AdminLoginFormSection.username}}" userInput="admin" stepKey="fillUsername"/> - <fillField selector="{{AdminLoginFormSection.password}}" userInput="password" stepKey="fillPassword"/> - <checkOption selector="{{AdminLoginFormSection.rememberMe}}" stepKey="checkRememberMe"/> - <click selector="{{AdminLoginFormSection.signIn}}" stepKey="clickLogin"/> - <seeInCurrentUrl url="admin/admin/dashboard/" stepKey="seeAdminUrl"/> - <see userInput="Lifetime Sales" stepKey="seeLifetimeSales"/> + <test name="AdminLoginCheckRememberMeSuccessfulTest"> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <actionGroup ref="AdminCheckRememberMeActionGroup" stepKey="checkRememberMe"/> + <actionGroup ref="AssertAdminSuccessLoginActionGroup" stepKey="assertLoggedIn"/> + <actionGroup ref="AssertAdminRememberMeActionGroup" stepKey="assertRememberMe"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> </test> </tests> ``` ### Update a test before hook -__Use case__: Create two similar tests where the second one contains two additional actions in the `before` hook: - -* `checkOption` before `click` (`stepKey="clickLogin"`) -* `seeInCurrentUrl` after `click` in the `LogInAsAdminTest` test (in the `.../Backend/Test/LogInAsAdminTest.xml` file) +__Use case__: Create two similar tests where the second test contains an additional action in the `before` hook. > Tests with "extends": ```xml <tests> - <test name="LogInAsAdminTest"> + <test name="AdminLoginSuccessfulTest"> <before> - <amOnPage url="{{AdminLoginPage}}" stepKey="navigateToAdmin"/> - <fillField selector="{{AdminLoginFormSection.username}}" userInput="admin" stepKey="fillUsername"/> - <fillField selector="{{AdminLoginFormSection.password}}" userInput="password" stepKey="fillPassword"/> - <click selector="{{AdminLoginFormSection.signIn}}" stepKey="clickLogin"/> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> </before> - <see userInput="Lifetime Sales" stepKey="seeLifetimeSales"/> + <actionGroup ref="AssertAdminSuccessLoginActionGroup" stepKey="assertLoggedIn"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> </test> - <test name="AlternativeLogInAsAdminTest" extends="LogInAsAdminTest"> + <test name="AdminLoginCheckRememberMeSuccessfulTest" extends="AdminLoginSuccessfulTest"> <before> - <checkOption selector="{{AdminLoginFormSection.rememberMe}}" stepKey="checkRememberMe" before="clickLogin"/> - <seeInCurrentUrl url="admin/admin/dashboard/" stepKey="seeAdminUrl" after="clickLogin"/> + <actionGroup ref="AdminCheckRememberMeActionGroup" stepKey="checkRememberMe" after="loginAsAdmin"/> </before> </test> </tests> @@ -148,25 +121,20 @@ __Use case__: Create two similar tests where the second one contains two additio ```xml <tests> - <test name="LogInAsAdminTest"> + <test name="AdminLoginSuccessfulTest"> <before> - <amOnPage url="{{AdminLoginPage}}" stepKey="navigateToAdmin"/> - <fillField selector="{{AdminLoginFormSection.username}}" userInput="admin" stepKey="fillUsername"/> - <fillField selector="{{AdminLoginFormSection.password}}" userInput="password" stepKey="fillPassword"/> - <click selector="{{AdminLoginFormSection.signIn}}" stepKey="clickLogin"/> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> </before> - <see userInput="Lifetime Sales" stepKey="seeLifetimeSales"/> + <actionGroup ref="AssertAdminSuccessLoginActionGroup" stepKey="assertLoggedIn"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> </test> - <test name="AlternativeLogInAsAdminTest"> + <test name="AdminLoginCheckRememberMeSuccessfulTest"> <before> - <amOnPage url="{{AdminLoginPage}}" stepKey="navigateToAdmin"/> - <fillField selector="{{AdminLoginFormSection.username}}" userInput="admin" stepKey="fillUsername"/> - <fillField selector="{{AdminLoginFormSection.password}}" userInput="password" stepKey="fillPassword"/> - <checkOption selector="{{AdminLoginFormSection.rememberMe}}" stepKey="checkRememberMe"/> - <click selector="{{AdminLoginFormSection.signIn}}" stepKey="clickLogin"/> - <seeInCurrentUrl url="admin/admin/dashboard/" stepKey="seeAdminUrl"/> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <actionGroup ref="AdminCheckRememberMeActionGroup" stepKey="checkRememberMe"/> </before> - <see userInput="Lifetime Sales" stepKey="seeLifetimeSales"/> + <actionGroup ref="AssertAdminSuccessLoginActionGroup" stepKey="assertLoggedIn"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> </test> </tests> ``` From 8e42fda3a0c0974947f3034d6baf67d5a743cc40 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 20 Jul 2020 13:09:25 -0500 Subject: [PATCH 458/888] Mqe 2215: Docs Annual Review Part 2 (#760) * MQE-2215: Docs Annual Review * MQE-2215: Docs Annual Review --- docs/merge_points/extend-action-groups.md | 10 +++++----- docs/merge_points/extend-data.md | 2 +- docs/merge_points/extend-tests.md | 14 +++++++------- docs/merge_points/merge-action-groups.md | 8 ++++---- docs/merge_points/merge-sections.md | 7 +++---- docs/merge_points/merge-tests.md | 8 ++++---- 6 files changed, 24 insertions(+), 25 deletions(-) diff --git a/docs/merge_points/extend-action-groups.md b/docs/merge_points/extend-action-groups.md index 95d6cff90..6e7a54d70 100644 --- a/docs/merge_points/extend-action-groups.md +++ b/docs/merge_points/extend-action-groups.md @@ -9,7 +9,7 @@ In this example we add a `<click>` command to check the checkbox that our extens <!-- {% raw %} --> ```xml -<actionGroup name="FillAdminSimpleProductForm"> +<actionGroup name="AdminFillSimpleProductFormActionGroup"> <arguments> <argument name="category"/> <argument name="simpleProduct"/> @@ -34,10 +34,10 @@ In this example we add a `<click>` command to check the checkbox that our extens </actionGroup> ``` -## File to merge +## Extend file ```xml -<actionGroup name="FillAdminSimpleProductFormWithMyExtension" extends="FillAdminSimpleProductForm"> +<actionGroup name="AdminFillSimpleProductFormWithMyExtensionActionGroup" extends="AdminFillSimpleProductFormActionGroup"> <!-- This will be added after the step "fillQuantity" on line 12 in the above test. --> <click selector="{{MyExtensionSection.myCheckbox}}" stepKey="clickMyCheckbox" after="fillQuantity"/> </actionGroup> @@ -48,7 +48,7 @@ In this example we add a `<click>` command to check the checkbox that our extens Note that there are now two action groups below. ```xml -<actionGroup name="FillAdminSimpleProductForm"> +<actionGroup name="AdminFillSimpleProductFormActionGroup"> <arguments> <argument name="category"/> <argument name="simpleProduct"/> @@ -71,7 +71,7 @@ Note that there are now two action groups below. <click selector="{{AdminProductSEOSection.sectionHeader}}" stepKey="openSeoSectionAssert"/> <seeInField userInput="{{simpleProduct.urlKey}}" selector="{{AdminProductSEOSection.urlKeyInput}}" stepKey="assertFieldUrlKey"/> </actionGroup> -<actionGroup name="FillAdminSimpleProductFormWithMyExtension"> +<actionGroup name="AdminFillSimpleProductFormWithMyExtensionActionGroup"> <arguments> <argument name="category"/> <argument name="simpleProduct"/> diff --git a/docs/merge_points/extend-data.md b/docs/merge_points/extend-data.md index ebac16108..91d2a67bb 100644 --- a/docs/merge_points/extend-data.md +++ b/docs/merge_points/extend-data.md @@ -23,7 +23,7 @@ In this example we update the quantity to 1001 and add a new piece of data relev </entity> ``` -## File to merge +## Extend file ```xml <entity name="ExtensionProduct" type="product" extends="SimpleProduct"> diff --git a/docs/merge_points/extend-tests.md b/docs/merge_points/extend-tests.md index 6aab50764..763977049 100644 --- a/docs/merge_points/extend-tests.md +++ b/docs/merge_points/extend-tests.md @@ -25,8 +25,8 @@ In this example, we add an action group to a new copy of the original test for o <deleteData createDataKey="createPreReqCategory" stepKey="deletePreReqCategory"/> </after> - <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin1"/> - <actionGroup ref="FillAdminSimpleProductForm" stepKey="fillProductFieldsInAdmin"> + <actionGroup ref="AdminLoginActionGroup" stepKey="AdminLoginActionGroup1"/> + <actionGroup ref="AdminFillSimpleProductFormActionGroup" stepKey="fillProductFieldsInAdmin"> <argument name="category" value="$$createPreReqCategory$$"/> <argument name="simpleProduct" value="_defaultProduct"/> </actionGroup> @@ -40,7 +40,7 @@ In this example, we add an action group to a new copy of the original test for o </test> ``` -## File to merge +## Extend file ```xml <test name="AdminCreateSimpleProductExtensionTest" extends="AdminCreateSimpleProductTest"> @@ -89,8 +89,8 @@ Note that there are now two tests below. <deleteData createDataKey="createPreReqCategory" stepKey="deletePreReqCategory"/> </after> - <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin1"/> - <actionGroup ref="FillAdminSimpleProductForm" stepKey="fillProductFieldsInAdmin"> + <actionGroup ref="AdminLoginActionGroup" stepKey="AdminLoginActionGroup1"/> + <actionGroup ref="AdminFillSimpleProductFormActionGroup" stepKey="fillProductFieldsInAdmin"> <argument name="category" value="$$createPreReqCategory$$"/> <argument name="simpleProduct" value="_defaultProduct"/> </actionGroup> @@ -120,8 +120,8 @@ Note that there are now two tests below. <deleteData createDataKey="createPreReqCategory" stepKey="deletePreReqCategory"/> </after> - <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin1"/> - <actionGroup ref="FillAdminSimpleProductForm" stepKey="fillProductFieldsInAdmin"> + <actionGroup ref="AdminLoginActionGroup" stepKey="AdminLoginActionGroup1"/> + <actionGroup ref="AdminFillSimpleProductFormActionGroup" stepKey="fillProductFieldsInAdmin"> <argument name="category" value="$$createPreReqCategory$$"/> <argument name="simpleProduct" value="_defaultProduct"/> </actionGroup> diff --git a/docs/merge_points/merge-action-groups.md b/docs/merge_points/merge-action-groups.md index 3a4f70ab1..ca6d20e68 100644 --- a/docs/merge_points/merge-action-groups.md +++ b/docs/merge_points/merge-action-groups.md @@ -1,7 +1,7 @@ # Merge action groups An action group is a set of individual actions working together as a group. -These action groups can be shared between tests and they also be modified to your needs. +These action groups can be shared between tests and they also can be modified to your needs. In this example we add a `<click>` command to check the checkbox that our extension adds to the simple product creation form. @@ -10,7 +10,7 @@ In this example we add a `<click>` command to check the checkbox that our extens <!-- {% raw %} --> ```xml -<actionGroup name="FillAdminSimpleProductForm"> +<actionGroup name="AdminFillSimpleProductFormActionGroup"> <arguments> <argument name="category"/> <argument name="simpleProduct"/> @@ -38,7 +38,7 @@ In this example we add a `<click>` command to check the checkbox that our extens ## File to merge ```xml -<actionGroup name="FillAdminSimpleProductForm"> +<actionGroup name="AdminFillSimpleProductFormActionGroup"> <!-- This will be added after the step "fillQuantity" in the above test. --> <click selector="{{MyExtensionSection.myCheckbox}}" stepKey="clickMyCheckbox" after="fillQuantity"/> </actionGroup> @@ -47,7 +47,7 @@ In this example we add a `<click>` command to check the checkbox that our extens ## Resultant test ```xml -<actionGroup name="FillAdminSimpleProductForm"> +<actionGroup name="AdminFillSimpleProductFormActionGroup"> <arguments> <argument name="category"/> <argument name="simpleProduct"/> diff --git a/docs/merge_points/merge-sections.md b/docs/merge_points/merge-sections.md index dbd6e3828..135b3f7d8 100644 --- a/docs/merge_points/merge-sections.md +++ b/docs/merge_points/merge-sections.md @@ -9,7 +9,7 @@ In this example we add another selector to the section on the products page sect <!-- {% raw %} --> ```xml -<section name="ProductsPageSection"> +<section name="AdminProductsPageSection"> <element name="addProductButton" type="button" selector="//button[@id='add_new_product-button']"/> <element name="checkboxForProduct" type="button" selector="//*[contains(text(),'{{args}}')]/parent::td/preceding-sibling::td/label[@class='data-grid-checkbox-cell-inner']" parameterized="true"/> <element name="actions" type="button" selector="//div[@class='col-xs-2']/div[@class='action-select-wrap']/button[@class='action-select']"/> @@ -22,7 +22,7 @@ In this example we add another selector to the section on the products page sect ## File to merge ```xml -<section name="ProductsPageSection"> +<section name="AdminProductsPageSection"> <!-- myExtensionElement will simply be added to the page --> <element name="myExtensionElement" type="button" selector="input.myExtension"/> </section> @@ -31,7 +31,7 @@ In this example we add another selector to the section on the products page sect ## Resultant section ```xml -<section name="ProductsPageSection"> +<section name="AdminProductsPageSection"> <element name="addProductButton" type="button" selector="//button[@id='add_new_product-button']"/> <element name="checkboxForProduct" type="button" selector="//*[contains(text(),'{{args}}')]/parent::td/preceding-sibling::td/label[@class='data-grid-checkbox-cell-inner']" parameterized="true"/> <element name="actions" type="button" selector="//div[@class='col-xs-2']/div[@class='action-select-wrap']/button[@class='action-select']"/> @@ -41,7 +41,6 @@ In this example we add another selector to the section on the products page sect <!-- New element merged --> <element name="myExtensionElement" type="button" selector="input.myExtension"/> </section> -</page> ``` <!-- {% endraw %} --> \ No newline at end of file diff --git a/docs/merge_points/merge-tests.md b/docs/merge_points/merge-tests.md index 3958410e9..b9e50d296 100644 --- a/docs/merge_points/merge-tests.md +++ b/docs/merge_points/merge-tests.md @@ -25,8 +25,8 @@ In this example we add an action group that modifies the original test to intera <deleteData createDataKey="createPreReqCategory" stepKey="deletePreReqCategory"/> </after> - <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin1"/> - <actionGroup ref="FillAdminSimpleProductForm" stepKey="fillProductFieldsInAdmin"> + <actionGroup ref="AdminLoginActionGroup" stepKey="adminLoginActionGroup1"/> + <actionGroup ref="AdminFillSimpleProductFormActionGroup" stepKey="fillProductFieldsInAdmin"> <argument name="category" value="$$createPreReqCategory$$"/> <argument name="simpleProduct" value="_defaultProduct"/> </actionGroup> @@ -77,8 +77,8 @@ In this example we add an action group that modifies the original test to intera <deleteData createDataKey="createPreReqCategory" stepKey="deletePreReqCategory"/> </after> - <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin1"/> - <actionGroup ref="FillAdminSimpleProductForm" stepKey="fillProductFieldsInAdmin"> + <actionGroup ref="AdminLoginActionGroup" stepKey="AdminLoginActionGroup1"/> + <actionGroup ref="AdminFillSimpleProductFormActionGroup" stepKey="fillProductFieldsInAdmin"> <argument name="category" value="$$createPreReqCategory$$"/> <argument name="simpleProduct" value="_defaultProduct"/> </actionGroup> From ddf5564d190d6c83b2c0e36a9dd370d8a6c01a19 Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Tue, 21 Jul 2020 16:40:40 -0500 Subject: [PATCH 459/888] MQE-2216: Annual Docs Review Part 3 (#761) * MQE-2216: Part 3 Docs Annual Review Updated documentation based on 3.0.0 functionality. * MQE-2216: Part 3 Docs Annual Review * MQE-2216: Part 3 Docs Annual Review * MQE-2216: Annual Docs Review Part 3 --- docs/commands/codeception.md | 72 +++++----- docs/commands/mftf.md | 14 +- docs/merging.md | 257 +++++++++++++++++------------------ docs/metadata.md | 32 ++--- docs/page.md | 14 +- docs/reporting.md | 186 ++++++++++--------------- 6 files changed, 267 insertions(+), 308 deletions(-) diff --git a/docs/commands/codeception.md b/docs/commands/codeception.md index 6a96a89c7..8e6d76c11 100644 --- a/docs/commands/codeception.md +++ b/docs/commands/codeception.md @@ -1,7 +1,7 @@ # CLI commands: vendor/bin/codecept <div class="bs-callout bs-callout-warning" markdown="1"> -We do not recommend using Codeception commands directly as they can break the MFTF basic workflow. +We do not recommend using Codeception commands directly as they can break MFTF basic workflow. All the Codeception commands you need are wrapped using the [mftf tool][]. To run the Codeception testing framework commands directly, change your directory to the `<Magento root>`. @@ -36,7 +36,7 @@ vendor/bin/codecept run ``` <div class="bs-callout bs-callout-info"> -The following documentation corresponds to Codeception 2.3.8. +The following documentation corresponds to Codeception 4.1.4. </div> ```bash @@ -47,36 +47,44 @@ Arguments: test test to be run Options: - -o, --override=OVERRIDE Override config values (multiple values allowed) - --config (-c) Use custom path for config - --report Show output in compact style - --html Generate html with results (default: "report.html") - --xml Generate JUnit XML Log (default: "report.xml") - --tap Generate Tap Log (default: "report.tap.log") - --json Generate Json Log (default: "report.json") - --colors Use colors in output - --no-colors Force no colors in output (useful to override config file) - --silent Only outputs suite names and final results - --steps Show steps in output - --debug (-d) Show debug and scenario output - --coverage Run with code coverage (default: "coverage.serialized") - --coverage-html Generate CodeCoverage HTML report in path (default: "coverage") - --coverage-xml Generate CodeCoverage XML report in file (default: "coverage.xml") - --coverage-text Generate CodeCoverage text report in file (default: "coverage.txt") - --coverage-phpunit Generate CodeCoverage PHPUnit report in file (default: "coverage-phpunit") - --no-exit Do not finish with exit code - --group (-g) Groups of tests to be executed (multiple values allowed) - --skip (-s) Skip selected suites (multiple values allowed) - --skip-group (-x) Skip selected groups (multiple values allowed) - --env Run tests in selected environments. (multiple values allowed, environments can be merged with ',') - --fail-fast (-f) Stop after first failure - --help (-h) Display this help message. - --quiet (-q) Do not output any message. - --verbose (-v|vv|vvv) Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug - --version (-V) Display this application version. - --ansi Force ANSI output. - --no-ansi Disable ANSI output. - --no-interaction (-n) Do not ask any interactive question. + -o, --override=OVERRIDE Override config values (multiple values allowed) + -e, --ext=EXT Run with extension enabled (multiple values allowed) + --report Show output in compact style + --html[=HTML] Generate html with results [default: "report.html"] + --xml[=XML] Generate JUnit XML Log [default: "report.xml"] + --phpunit-xml[=PHPUNIT-XML] Generate PhpUnit XML Log [default: "phpunit-report.xml"] + --tap[=TAP] Generate Tap Log [default: "report.tap.log"] + --json[=JSON] Generate Json Log [default: "report.json"] + --colors Use colors in output + --no-colors Force no colors in output (useful to override config file) + --silent Only outputs suite names and final results + --steps Show steps in output + -d, --debug Show debug and scenario output + --bootstrap[=BOOTSTRAP] Execute custom PHP script before running tests. Path can be absolute or relative to current working directory [default: false] + --no-redirect Do not redirect to Composer-installed version in vendor/codeception + --coverage[=COVERAGE] Run with code coverage + --coverage-html[=COVERAGE-HTML] Generate CodeCoverage HTML report in path + --coverage-xml[=COVERAGE-XML] Generate CodeCoverage XML report in file + --coverage-text[=COVERAGE-TEXT] Generate CodeCoverage text report in file + --coverage-crap4j[=COVERAGE-CRAP4J] Generate CodeCoverage report in Crap4J XML format + --coverage-phpunit[=COVERAGE-PHPUNIT] Generate CodeCoverage PHPUnit report in path + --no-exit Don't finish with exit code + -g, --group=GROUP Groups of tests to be executed (multiple values allowed) + -s, --skip=SKIP Skip selected suites (multiple values allowed) + -x, --skip-group=SKIP-GROUP Skip selected groups (multiple values allowed) + --env=ENV Run tests in selected environments. (multiple values allowed) + -f, --fail-fast Stop after first failure + --no-rebuild Do not rebuild actor classes on start + --seed=SEED Define random seed for shuffle setting + --no-artifacts Don't report about artifacts + -h, --help Display this help message + -q, --quiet Do not output any message + -V, --version Display this application version + --ansi Force ANSI output + --no-ansi Disable ANSI output + -n, --no-interaction Do not ask any interactive question + -c, --config[=CONFIG] Use custom path for config + -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug ``` <!-- Link definitions --> diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index bc2e5c0ec..b7981808c 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -39,13 +39,13 @@ vendor/bin/mftf generate:tests ### Generate tests by test name ```bash -vendor/bin/mftf generate:tests AdminLoginTest StorefrontPersistedCustomerLoginTest +vendor/bin/mftf generate:tests AdminLoginSuccessfulTest StorefrontPersistedCustomerLoginTest ``` ### Generate test by test and suite name ```bash -vendor/bin/mftf generate:tests LoginSuite:AdminLoginTest +vendor/bin/mftf generate:tests WYSIWYGDisabledSuite:AdminCMSPageCreatePageTest ``` ### Generate and run the tests for a specified group @@ -59,18 +59,18 @@ This command cleans up the previously generated tests; generates and runs tests ### Generate and run particular tests ```bash -vendor/bin/mftf run:test AdminLoginTest StorefrontPersistedCustomerLoginTest -r +vendor/bin/mftf run:test AdminLoginSuccessfulTest StorefrontPersistedCustomerLoginTest -r ``` -This command cleans up the previously generated tests; generates and runs the `LoginAsAdminTest` and `LoginAsCustomerTest` tests. +This command cleans up the previously generated tests; generates and runs the `AdminLoginSuccessfulTest` and `StorefrontPersistedCustomerLoginTest` tests. ### Generate and run particular test in a specific suite's context ```bash -vendor/bin/mftf run:test LoginSuite:AdminLoginTest -r +vendor/bin/mftf run:test WYSIWYGDisabledSuite:AdminCMSPageCreatePageTest -r ``` -This command cleans up previously generated tests; generates and run `AdminLoginTest` within the context of the `LoginSuite`. +This command cleans up previously generated tests; generates and run `AdminCMSPageCreatePageTest` within the context of the `WYSIWYGDisabledSuite`. ### Generate and run a testManifest.txt file @@ -362,7 +362,7 @@ vendor/bin/mftf run:manifest path/to/your/testManifest.txt Each line should contain either: one test path or one group (-g) reference. ``` -tests/functional/tests/MFTF/_generated/default/AdminLoginTestCest.php +tests/functional/tests/MFTF/_generated/default/AdminLoginSuccessfulTestCest.php -g PaypalTestSuite tests/functional/tests/MFTF/_generated/default/SomeOtherTestCest.php tests/functional/tests/MFTF/_generated/default/ThirdTestCest.php diff --git a/docs/merging.md b/docs/merging.md index fc187d576..d8436492e 100644 --- a/docs/merging.md +++ b/docs/merging.md @@ -1,6 +1,6 @@ # Merging -The MFTF allows you to merge test components defined in XML files, such as: +MFTF allows you to merge test components defined in XML files, such as: - [`<tests>`][] - [`<pages>`][] @@ -20,9 +20,9 @@ For example: - All tests with `<test name="SampleTest>` will be merged into one. - All pages with `<page name="SamplePage>` will be merged into one. -- All sections with `<section name="SampleAction">` will be merged into one. +- All sections with `<section name="SampleSection">` will be merged into one. - All data entities with `<entity name="sampleData" type="sample">` will be merged into one. -- All action groups with `<actionGroup name="selectNotLoggedInCustomerGroup">` will be merged into one. +- All action groups with `<actionGroup name="SelectNotLoggedInCustomerGroupActionGroup">` will be merged into one. Although a file name does not influence merging, we recommend using the same file names in merging updates. This makes it easier to search later on. @@ -39,7 +39,7 @@ This makes it easier to search later on. ## Add a test You cannot add another [`<test>`][tests] using merging functionality. -To add a `<test>`, create a new `*Test.xml` file or add a `<test>` node to an existing `*Test.xml` file. +To add a `<test>`, create a new `*Test.xml` file. ## Remove a test @@ -50,38 +50,35 @@ Learn more about running tests with different options using [`mftf`] or [`codece ### Example -Skip the `AdminLoginTest` test in the `.../Backend/Test/AdminLoginTest.xml` file while merging with the `.../Foo/Test/AdminLoginTest.xml` file: +Skip the `AdminLoginSuccessfulTest` test in the `.../Backend/Test/AdminLoginSuccessfulTest.xml` file while merging with the `.../Foo/Test/AdminLoginSuccessfulTest.xml` file: <!-- {% raw %} --> ```xml <tests ...> - <test name="AdminLoginTest"> + <test name="AdminLoginSuccessfulTest"> <annotations> - <features value="Admin Login"/> + <features value="Backend"/> <stories value="Login on the Admin Login page"/> - <title value="You should be able to log into the Magento Admin backend."/> - <description value="You should be able to log into the Magento Admin backend."/> + <title value="Admin should be able to log into the Magento Admin backend successfully"/> + <description value="Admin should be able to log into the Magento Admin backend successfully"/> <severity value="CRITICAL"/> <testCaseId value="MAGETWO-71572"/> <group value="example"/> <group value="login"/> </annotations> - <amOnPage url="{{AdminLoginPage.url}}" stepKey="amOnAdminLoginPage"/> - <fillField selector="{{AdminLoginFormSection.username}}" userInput="{{_ENV.MAGENTO_ADMIN_USERNAME}}" stepKey="fillUsername"/> - <fillField selector="{{AdminLoginFormSection.password}}" userInput="{{_ENV.MAGENTO_ADMIN_PASSWORD}}" stepKey="fillPassword"/> - <click selector="{{AdminLoginFormSection.signIn}}" stepKey="clickOnSignIn"/> - <closeAdminNotification stepKey="closeAdminNotification"/> - <seeInCurrentUrl url="{{AdminLoginPage.url}}" stepKey="seeAdminLoginUrl"/> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <actionGroup ref="AssertAdminSuccessLoginActionGroup" stepKey="assertLoggedIn"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> </test> </tests> ``` -Create the `.../Foo/Test/AdminLoginTest.xml` file: +Create the `.../Foo/Test/AdminLoginSuccessfulTest.xml` file: ```xml <tests ...> - <test name="AdminLoginTest"> + <test name="AdminLoginSuccessfulTest"> <annotations> <skip> <issueId value="Issue#"/> @@ -91,29 +88,26 @@ Create the `.../Foo/Test/AdminLoginTest.xml` file: </tests> ``` -The `AdminLoginTest` result corresponds to: +The `AdminLoginSuccessfulTest` result corresponds to: ```xml -<test name="AdminLoginTest"> +<test name="AdminLoginSuccessfulTest"> <annotations> - <features value="Admin Login"/> + <features value="Backend"/> <stories value="Login on the Admin Login page"/> - <title value="You should be able to log into the Magento Admin backend."/> - <description value="You should be able to log into the Magento Admin backend."/> + <title value="Admin should be able to log into the Magento Admin backend successfully"/> + <description value="Admin should be able to log into the Magento Admin backend successfully"/> <severity value="CRITICAL"/> <testCaseId value="MAGETWO-71572"/> <group value="example"/> <group value="login"/> - <skip> - <issueId value="Issue#"/> - </skip> + <skip> + <issueId value="Issue#"/> + </skip> </annotations> - <amOnPage url="{{AdminLoginPage.url}}" stepKey="amOnAdminLoginPage"/> - <fillField selector="{{AdminLoginFormSection.username}}" userInput="{{_ENV.MAGENTO_ADMIN_USERNAME}}" stepKey="fillUsername"/> - <fillField selector="{{AdminLoginFormSection.password}}" userInput="{{_ENV.MAGENTO_ADMIN_PASSWORD}}" stepKey="fillPassword"/> - <click selector="{{AdminLoginFormSection.signIn}}" stepKey="clickOnSignIn"/> - <closeAdminNotification stepKey="closeAdminNotification"/> - <seeInCurrentUrl url="{{AdminLoginPage.url}}" stepKey="seeAdminLoginUrl"/> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <actionGroup ref="AssertAdminSuccessLoginActionGroup" stepKey="assertLoggedIn"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> </test> ``` @@ -126,159 +120,152 @@ See the previous examples. ### Add a test step -**Use case**: Add `checkOption` before `click` (`stepKey="clickLogin"`) and add `seeInCurrentUrl` after the `click` in the `LogInAsAdminTest` test (in the `.../Backend/Test/LogInAsAdminTest.xml` file) while merging with the `.../Foo/Test/LogInAsAdminTest.xml` file: +**Use case**: Add `AdminCheckOptionSalesActionGroup` before `AssertAdminSuccessLoginActionGroup` (`stepKey="assertLoggedIn"`) and add `AdminAssertSalesOnDashboardActionGroup` after the `AssertAdminSuccessLoginActionGroup` in the `AdminLoginSuccessfulTest` test (in the `.../Backend/Test/AdminLoginSuccessfulTest.xml` file) while merging with the `.../Foo/Test/AdminLoginSuccessfulTest.xml` file: ```xml <tests ...> - <test name="LogInAsAdminTest"> - <amOnPage url="{{AdminLoginPage}}" stepKey="navigateToAdmin"/> - <fillField selector="{{AdminLoginFormSection.username}}" userInput="admin" stepKey="fillUsername"/> - <fillField selector="{{AdminLoginFormSection.password}}" userInput="password" stepKey="fillPassword"/> - <click selector="{{AdminLoginFormSection.signIn}}" stepKey="clickLogin"/> - <see userInput="Lifetime Sales" stepKey="seeLifetimeSales"/> + <test name="AdminLoginSuccessfulTest"> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <actionGroup ref="AssertAdminSuccessLoginActionGroup" stepKey="assertLoggedIn"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> </test> </tests> ``` -Create the `.../Foo/Test/LogInAsAdminTest.xml` file: +Create the `.../Foo/Test/AdminLoginSuccessfulTest.xml` file: ```xml <tests ...> - <test name="LogInAsAdminTest"> - <checkOption selector="{{AdminLoginFormSection.rememberMe}}" stepKey="checkRememberMe" before="clickLogin"/> - <seeInCurrentUrl url="admin/admin/dashboard/" stepKey="seeAdminUrl" after="clickLogin"/> + <test name="AdminLoginSuccessfulTest"> + <actionGroup ref="AdminCheckOptionSalesActionGroup" stepKey="checkOptionSales" before="assertLoggedIn"/> + <actionGroup ref="AdminAssertSalesOnDashboardActionGroup" stepKey="assertSalesOnDashboard" after="assertLoggedIn"/> </test> </tests> ``` -The `LogInAsAdminTest` result corresponds to: +The `AdminLoginSuccessfulTest` result corresponds to: ```xml -<test name="LogInAsAdminTest"> - <amOnPage url="{{AdminLoginPage}}" stepKey="navigateToAdmin"/> - <fillField selector="{{AdminLoginFormSection.username}}" userInput="admin" stepKey="fillUsername"/> - <fillField selector="{{AdminLoginFormSection.password}}" userInput="password" stepKey="fillPassword"/> - <checkOption selector="{{AdminLoginFormSection.rememberMe}}" stepKey="checkRememberMe"/> - <click selector="{{AdminLoginFormSection.signIn}}" stepKey="clickLogin"/> - <seeInCurrentUrl url="admin/admin/dashboard/" stepKey="seeAdminUrl"/> - <see userInput="Lifetime Sales" stepKey="seeLifetimeSales"/> +<test name="AdminLoginSuccessfulTest"> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <actionGroup ref="AdminCheckOptionSalesActionGroup" stepKey="checkOptionSales" before="assertLoggedIn"/> + <actionGroup ref="AssertAdminSuccessLoginActionGroup" stepKey="assertLoggedIn"/> + <actionGroup ref="AdminAssertSalesOnDashboardActionGroup" stepKey="assertSalesOnDashboard" after="assertLoggedIn"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> </test> ``` ### Remove a test step -**Use case**: Remove `see` (`stepKey="seeLifetimeSales"`) from the `LogInAsAdminTest` test (in the `.../Backend/Test/LogInAsAdminTest.xml` file) while merging with the `.../Foo/Test/LogInAsAdminTest.xml` file: +**Use case**: Remove `AdminCheckOptionSalesActionGroup` (`stepKey="checkOptionSales"`) from the `LogInAsAdminTest` test (in the `.../Backend/Test/AdminLoginSuccessfulTest.xml` file) while merging with the `.../Foo/Test/AdminLoginSuccessfulTest.xml` file: ```xml <tests ...> - <test name="LogInAsAdminTest"> - <amOnPage url="{{AdminLoginPage}}" stepKey="navigateToAdmin"/> - <fillField selector="{{AdminLoginFormSection.username}}" userInput="admin" stepKey="fillUsername"/> - <fillField selector="{{AdminLoginFormSection.password}}" userInput="password" stepKey="fillPassword"/> - <click selector="{{AdminLoginFormSection.signIn}}" stepKey="clickLogin"/> - <see userInput="Lifetime Sales" stepKey="seeLifetimeSales"/> + <test name="AdminLoginSuccessfulTest"> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <actionGroup ref="AdminCheckOptionSalesActionGroup" stepKey="checkOptionSales"/> + <actionGroup ref="AssertAdminSuccessLoginActionGroup" stepKey="assertLoggedIn"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> </test> </tests> ``` -Create the `.../Foo/Test/LogInAsAdminTest.xml` file: +Create the `.../Foo/Test/AdminLoginSuccessfulTest.xml` file: ```xml <tests ...> - <test name="LogInAsAdminTest"> - <remove keyForRemoval="seeLifetimeSales"/> + <test name="AdminLoginSuccessfulTest"> + <remove keyForRemoval="checkOptionSales"/> </test> </tests> ``` -The `LogInAsAdminTest` result corresponds to: +The `AdminLoginSuccessfulTest` result corresponds to: ```xml -<test name="LogInAsAdminTest"> - <amOnPage url="{{AdminLoginPage}}" stepKey="navigateToAdmin"/> - <fillField selector="{{AdminLoginFormSection.username}}" userInput="admin" stepKey="fillUsername"/> - <fillField selector="{{AdminLoginFormSection.password}}" userInput="password" stepKey="fillPassword"/> - <click selector="{{AdminLoginFormSection.signIn}}" stepKey="clickLogin"/> +<test name="AdminLoginSuccessfulTest"> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <actionGroup ref="AssertAdminSuccessLoginActionGroup" stepKey="assertLoggedIn"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> </test> ``` ### Update a test step -**Use case**: Change selector in `fillField` (`stepKey="fillPassword"`) of the `LogInAsAdminTest` test (in the `.../Backend/Test/LogInAsAdminTest.xml` file) while merging with the `.../Foo/Test/LogInAsAdminTest.xml` file: +**Use case**: Change argument in `AdminCheckOptionSalesActionGroup` (`stepKey="checkOptionSales"`) of the `AdminLoginSuccessfulTest` test (in the `.../Backend/Test/AdminLoginSuccessfulTest.xml` file) while merging with the `.../Foo/Test/AdminLoginSuccessfulTest.xml` file: ```xml <tests ...> - <test name="LogInAsAdminTest"> - <amOnPage url="{{AdminLoginPage}}" stepKey="navigateToAdmin"/> - <fillField selector="{{AdminLoginFormSection.username}}" userInput="admin" stepKey="fillUsername"/> - <fillField selector="{{AdminLoginFormSection.password}}" userInput="password" stepKey="fillPassword"/> - <click selector="{{AdminLoginFormSection.signIn}}" stepKey="clickLogin"/> - <see userInput="Lifetime Sales" stepKey="seeLifetimeSales"/> + <test name="AdminLoginSuccessfulTest"> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <actionGroup ref="AdminCheckOptionSalesActionGroup" stepKey="checkOptionSales"> + <argument name="salesOption" value="{{AdminSalesData.lifeTimeSales}}"/> + </actionGroup> + <actionGroup ref="AssertAdminSuccessLoginActionGroup" stepKey="assertLoggedIn"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> </test> </tests> ``` -Create the `.../Foo/Test/LogInAsAdminTest.xml` file: +Create the `.../Foo/Test/AdminLoginSuccessfulTest.xml` file: ```xml -<tests ...> - <test name="LogInAsAdminTest"> - <fillField selector="{{AdminLoginFormSection.wrong-password}}" userInput="password" stepKey="fillPassword"/> - </test> -</tests> +<test name="AdminLoginSuccessfulTest"> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <actionGroup ref="AdminCheckOptionSalesActionGroup" stepKey="checkOptionSales"> + <argument name="salesOption" value="{{AdminSalesData.annualSales}}"/> + </actionGroup> + <actionGroup ref="AssertAdminSuccessLoginActionGroup" stepKey="assertLoggedIn"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> +</test> ``` -The `LogInAsAdminTest` result corresponds to: +The `AdminLoginSuccessfulTest` result corresponds to: ```xml -<test name="LogInAsAdminTest"> - <amOnPage url="{{AdminLoginPage}}" stepKey="navigateToAdmin"/> - <fillField selector="{{AdminLoginFormSection.username}}" userInput="admin" stepKey="fillUsername"/> - <fillField selector="{{AdminLoginFormSection.wrong-password}}" userInput="password" stepKey="fillPassword"/> - <click selector="{{AdminLoginFormSection.signIn}}" stepKey="clickLogin"/> - <see userInput="Lifetime Sales" stepKey="seeLifetimeSales"/> +<test name="AdminLoginSuccessfulTest"> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <actionGroup ref="AdminCheckOptionSalesActionGroup" stepKey="checkOptionSales"> + <argument name="salesOption" value="{{AdminSalesData.annualSales}}"/> + </actionGroup> + <actionGroup ref="AssertAdminSuccessLoginActionGroup" stepKey="assertLoggedIn"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> </test> ``` ### Add several test steps {#insert-after} -**Use case**: Add several actions after the `click` (`stepKey="clickLogin"`) in the `LogInAsAdminTest` test (in the `.../Backend/Test/LogInAsAdminTest.xml` file) while merging with the `.../Foo/Test/LogInAsAdminTest.xml` file: +**Use case**: Add several action groups after the `AdminLoginActionGroup` (`stepKey="loginAsAdmin"`) in the `AdminLoginSuccessfulTest` test (in the `.../Backend/Test/AdminLoginSuccessfulTest.xml` file) while merging with the `.../Foo/Test/LogInAsAdminTest.xml` file: ```xml -<tests ...> - <test name="LogInAsAdminTest"> - <amOnPage url="{{AdminLoginPage}}" stepKey="navigateToAdmin"/> - <fillField selector="{{AdminLoginFormSection.username}}" userInput="admin" stepKey="fillUsername"/> - <fillField selector="{{AdminLoginFormSection.password}}" userInput="password" stepKey="fillPassword"/> - <click selector="{{AdminLoginFormSection.signIn}}" stepKey="clickLogin"/> - <see userInput="Lifetime Sales" stepKey="seeLifetimeSales"/> - </test> -</tests> +<test name="AdminLoginSuccessfulTest"> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> +</test> ``` -Create the `.../Foo/Test/LogInAsAdminTest.xml` file: +Create the `.../Foo/Test/AdminLoginSuccessfulTest.xml` file: ```xml <tests ...> - <test name="LogInAsAdminTest" insertAfter="clickLogin"> - <checkOption selector="{{AdminLoginFormSection.rememberMe}}" stepKey="checkRememberMe"/> - <seeInCurrentUrl url="admin/admin/dashboard/" stepKey="seeAdminUrl"/> + <test name="AdminLoginSuccessfulTest" insertAfter="loginAsAdmin"> + <actionGroup ref="AdminCheckOptionSalesActionGroup" stepKey="checkOptionSales"/> + <actionGroup ref="AssertAdminSuccessLoginActionGroup" stepKey="assertLoggedIn"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> </test> </tests> ``` -The `LogInAsAdminTest` result corresponds to: +The `AdminLoginSuccessfulTest` result corresponds to: ```xml -<test name="LogInAsAdminTest"> - <amOnPage url="{{AdminLoginPage}}" stepKey="navigateToAdmin"/> - <fillField selector="{{AdminLoginFormSection.username}}" userInput="admin" stepKey="fillUsername"/> - <fillField selector="{{AdminLoginFormSection.password}}" userInput="password" stepKey="fillPassword"/> - <click selector="{{AdminLoginFormSection.signIn}}" stepKey="clickLogin"/> - <checkOption selector="{{AdminLoginFormSection.rememberMe}}" stepKey="checkRememberMe"/> - <seeInCurrentUrl url="admin/admin/dashboard/" stepKey="seeAdminUrl"/> - <see userInput="Lifetime Sales" stepKey="seeLifetimeSales"/> -</test> +<tests ...> + <test name="AdminLoginSuccessfulTest"> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <actionGroup ref="AdminCheckOptionSalesActionGroup" stepKey="checkOptionSales"/> + <actionGroup ref="AssertAdminSuccessLoginActionGroup" stepKey="assertLoggedIn"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> + </test> +</tests> ``` ## Merge action groups @@ -293,7 +280,7 @@ The controls change drastically in the B2B version, so it was abstracted to an a > Action group for selecting `customerGroup` in the `Cart Price Rules` section: ```xml -<actionGroup name="selectNotLoggedInCustomerGroup"> +<actionGroup name="SelectNotLoggedInCustomerGroupActionGroup"> <selectOption selector="{{AdminCartPriceRulesFormSection.customerGroups}}" userInput="NOT LOGGED IN" stepKey="selectCustomerGroup"/> </actionGroup> ``` @@ -302,7 +289,7 @@ The controls change drastically in the B2B version, so it was abstracted to an a ```xml <!-- name matches --> -<actionGroup name="selectNotLoggedInCustomerGroup"> +<actionGroup name="SelectNotLoggedInCustomerGroupActionGroup"> <!-- removes the original action --> <remove keyForRemoval="selectCustomerGroup"/> <!-- adds in sequence of actions to be performed instead--> @@ -323,62 +310,62 @@ To merge [pages][page], the `page name` must be the same as in the base module. ### Add a section **Use case**: The `FooBackend` module extends the `Backend` module and requires use of two new sections that must be covered with tests. -Add `BaseBackendSection` and `AnotherBackendSection` to the `BaseBackendPage` (`.../Backend/Page/BaseBackendPage.xml` file): +Add `AdminBaseBackendSection` and `AdminAnotherBackendSection` to the `AdminBaseBackendPage` (`.../Backend/Page/AdminBaseBackendPage.xml` file): ```xml <pages ...> - <page name="BaseBackendPage" url="admin" area="admin" module="Magento_Backend"> - <section name="BaseBackendSection"/> - <section name="AnotherBackendSection"/> + <page name="AdminBaseBackendPage" url="admin" area="admin" module="Magento_Backend"> + <section name="AdminBaseBackendSection"/> + <section name="AdminAnotherBackendSection"/> </page> </pages> ``` -Create the `.../FooBackend/Page/BaseBackendPage.xml` file: +Create the `.../FooBackend/Page/AdminBaseBackendPage.xml` file: ```xml <pages ...> - <page name="BaseBackendPage" url="admin" area="admin" module="Magento_Backend"> - <section name="NewExtensionSection"/> + <page name="AdminBaseBackendPage" url="admin" area="admin" module="Magento_Backend"> + <section name="AdminNewExtensionSection"/> </page> </pages> ``` -The `BaseBackendPage` result corresponds to: +The `AdminBaseBackendPage` result corresponds to: ```xml -<page name="BaseBackendPage" url="admin" area="admin" module="Magento_Backend"> +<page name="AdminBaseBackendPage" url="admin" area="admin" module="Magento_Backend"> - <section name="BaseBackendSection"/> - <section name="AnotherBackendSection"/> - <section name="NewExtensionSection"/> + <section name="AdminBaseBackendSection"/> + <section name="AdminAnotherBackendSection"/> + <section name="AdminNewExtensionSection"/> </page> ``` ### Remove a section -**Use case**: The `FooBackend` module extends the `Backend` module and requires deletion of the `AnotherBackendSection` section (the `.../Backend/Page/BaseBackendPage.xml` file): +**Use case**: The `FooBackend` module extends the `Backend` module and requires deletion of the `AdminAnotherBackendSection` section (the `.../Backend/Page/AdminBaseBackendPage.xml` file): ```xml -<page name="BaseBackendPage" url="admin" area="admin" module="Magento_Backend"> - <section name="BaseBackendSection"/> - <section name="AnotherBackendSection"/> +<page name="AdminBaseBackendPage" url="admin" area="admin" module="Magento_Backend"> + <section name="AdminBaseBackendSection"/> + <section name="AdminAnotherBackendSection"/> </page> ``` -Create the `.../FooBackend/Page/BaseBackendPage.xml` file: +Create the `.../FooBackend/Page/AdminBaseBackendPage.xml` file: ```xml -<page name="BaseBackendPage" url="admin" area="admin" module="Magento_Backend"> - <section name="AnotherBackendSection" remove="true"/> +<page name="AdminBaseBackendPage" url="admin" area="admin" module="Magento_Backend"> + <section name="AdminAnotherBackendSection" remove="true"/> </page> ``` -The `BaseBackendPage` result corresponds to: +The `AdminBaseBackendPage` result corresponds to: ```xml -<page name="BaseBackendPage" url="admin" area="admin" module="Magento_Backend"> - <section name="BaseBackendSection"/> +<page name="AdminBaseBackendPage" url="admin" area="admin" module="Magento_Backend"> + <section name="AdminBaseBackendSection"/> </page> ``` diff --git a/docs/metadata.md b/docs/metadata.md index 3f6032b57..414f4bc04 100644 --- a/docs/metadata.md +++ b/docs/metadata.md @@ -1,6 +1,6 @@ # Metadata -In this topic we talk about handling entities that you need in your tests (such as categories, products, wish lists, and similar) using the MFTF. +In this topic we talk about handling entities that you need in your tests (such as categories, products, wish lists, and similar) using MFTF. Using data handling actions like [`createData`], [`deleteData`], [`updateData`], and [`getData`], you are able to create, delete, update, and read entities for your tests. The framework enables you to send HTTP requests with these statically defined data entities: @@ -29,7 +29,7 @@ Each [operation] includes: - The type of body content encoding in [contentType]. - The body of the request represented as a tree of objects, arrays, and fields. -When a test step requires handling the specified data entity, the MFTF performs the following steps: +When a test step requires handling the specified data entity, MFTF performs the following steps: - Reads input data (`<data/>`) and the type (the `type` attribute) of the specified [entity]. - Searches the metadata operation for the `dataType` that matches the entity's `type`. For example, `<entity type="product">` matches `<operation dataType="product"`. @@ -94,8 +94,8 @@ Example: ### Sending a REST API request -The MFTF allows you to handle basic CRUD operations with an object using [Magento REST API][api reference] requests. -To convert a request to the MFTF format, wrap the corresponding REST API request into XML tags according to the [Reference documentation][reference]. +MFTF allows you to handle basic CRUD operations with an object using [Magento REST API][api reference] requests. +To convert a request to MFTF format, wrap the corresponding REST API request into XML tags according to the [Reference documentation][reference]. - GET is used for retrieving data from objects. - POST is used for creating new objects. @@ -123,7 +123,7 @@ Let's see what happens when you create a category: <createData entity="_defaultCategory" stepKey="createPreReqCategory"/> ``` -The MFTF searches in the _Data_ directory an entity with `<entity name="_defaultCategory">` and reads `type` of the entity. +MFTF searches in the _Data_ directory an entity with `<entity name="_defaultCategory">` and reads `type` of the entity. If there are more than one entity with the same name, all of the entities are merged. _Catalog/Data/CategoryData.xml_: @@ -136,8 +136,8 @@ _Catalog/Data/CategoryData.xml_: </entity> ``` -Here, `type` is equal to `"category"`, which instructs the MFTF to search an operation with `dataType="category"`. -Since the action is __to create__ a category, the MFTF will also search for operation with `type="create"` in _Metadata_ for `dataType="category"`. +Here, `type` is equal to `"category"`, which instructs MFTF to search an operation with `dataType="category"`. +Since the action is __to create__ a category, MFTF will also search for operation with `type="create"` in _Metadata_ for `dataType="category"`. _Catalog/Metadata/CategoryMeta.xml_: @@ -236,26 +236,26 @@ The corresponding test step is: <createData entity="guestCart" stepKey="createGuestCart"/> ``` -The MFTF searches in the _Data_ directory an entity with `<entity name="guestCart">` and reads `type`. +MFTF searches in the _Data_ directory an entity with `<entity name="GuestCart">` and reads `type`. _Quote/Data/GuestCartData.xml_: ```xml -<entity name="guestCart" type="guestCart"> +<entity name="GuestCart" type="GuestCart"> </entity> ``` -`type="guestCart"` points to the operation with `dataType=guestCart"` and `type="create"` in the _Metadata_ directory. +`type="guestCart"` points to the operation with `dataType=GuestCart"` and `type="create"` in the _Metadata_ directory. _Catalog/Data/CategoryData.xml_: ```xml -<operation name="CreateGuestCart" dataType="guestCart" type="create" auth="anonymous" url="/V1/guest-carts" method="POST"> +<operation name="CreateGuestCart" dataType="GuestCart" type="create" auth="anonymous" url="/V1/guest-carts" method="POST"> <contentType>application/json</contentType> </operation> ``` -As a result, the MFTF sends an unauthorized POST request with an empty body to the `https://example.com/rest/V1/guest-carts` and stores the single string response that the endpoint returns. +As a result, MFTF sends an unauthorized POST request with an empty body to the `https://example.com/rest/V1/guest-carts` and stores the single string response that the endpoint returns. ### Handling a REST API response {#rest-response} @@ -267,7 +267,7 @@ Let's see how to handle data after you created a category with custom attributes <createData entity="customizedCategory" stepKey="createPreReqCategory"/> ``` -The MFTF receives the corresponding JSON response and enables you to reference its data using a variable of format: +MFTF receives the corresponding JSON response and enables you to reference its data using a variable of format: **$** _stepKey_ **.** _JsonKey_ **$** @@ -377,7 +377,7 @@ The operation enables you to assign the following form fields: ### Create an object in storefront {#create-object-as-customerFormKey} -The MFTF uses the `CreateWishlist` operation to create a wish list on storefront: +MFTF uses the `CreateWishlist` operation to create a wish list on storefront: Source file is _Wishlist/Metadata/WishlistMeta.xml_ @@ -558,7 +558,7 @@ Example: <!-- LINK DEFINITIONS --> [actions]: test/actions.md -[api reference]: https://devdocs.magento.com/guides/v2.3/get-started/bk-get-started-api.html +[api reference]: https://devdocs.magento.com/guides/v2.4/get-started/bk-get-started-api.html [application/x-www-form-urlencoded]: https://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1 {:target="_blank"} [catalogCategoryRepositoryV1 image]: img/catalogCategoryRepository-operations.png @@ -573,7 +573,7 @@ Example: [getData]: test/actions.md#getdata [HTML forms]: https://www.w3.org/TR/html401/interact/forms.html {:target="\_blank"} -[oauth]: https://devdocs.magento.com/guides/v2.3/get-started/authentication/gs-authentication-oauth.html +[oauth]: https://devdocs.magento.com/guides/v2.4/get-started/authentication/gs-authentication-oauth.html {:target="\_blank"} [operation]: #operation-tag [reference]: #reference diff --git a/docs/page.md b/docs/page.md index 41afd274f..fd03cfd58 100644 --- a/docs/page.md +++ b/docs/page.md @@ -1,6 +1,6 @@ # Page structure -The MFTF uses a modified concept of [PageObjects], which models the testing areas of your page as objects within the code. +MFTF uses a modified concept of [PageObjects], which models the testing areas of your page as objects within the code. This reduces occurrences of duplicated code and enables you to fix things quickly, in one place, when things change. You define the contents of a page, for reference in a [`<test>`], at both the [`<page>`] and [`<section>`] level. @@ -61,7 +61,7 @@ Example (_Catalog/Page/AdminCategoryPage.xml_ file): <?xml version="1.0" encoding="UTF-8"?> <pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../..dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> <page name="AdminCategoryPage" url="catalog/category/" module="Magento_Catalog" area="admin"> <section name="AdminCategorySidebarActionSection"/> <section name="AdminCategorySidebarTreeSection"/> @@ -97,7 +97,7 @@ Example (_Catalog/Page/StorefrontCategoryPage.xml_ file): <?xml version="1.0" encoding="UTF-8"?> <pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../..dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> <page name="StorefrontCategoryPage" url="/{{var1}}.html" module="Magento_Catalog" parameterized="true" area="storefront"> <section name="StorefrontCategoryMainSection"/> </page> @@ -107,15 +107,15 @@ Example (_Catalog/Page/StorefrontCategoryPage.xml_ file): This example shows the page with the name `StorefrontCategoryPage`. It will be merged with the other `StorefrontCategoryPage` pages from other modules. -The following is an example of a call in test: +The following is an example of a call in a test: ```xml -<amOnPage url="{{StorefrontCategoryPage.url($$createPreReqCategory.name$$)}}" stepKey="navigateToCategoryPage"/> +<amOnPage url="{{StorefrontCategoryPage.url($createPreReqCategory.name$)}}" stepKey="navigateToCategoryPage"/> ``` The `StorefrontCategoryPage` page is declared as parameterized, where the `url` contains a `{{var1}}` parameter. -The corresponding web page is generated by the Magento Catalog module and is called by the `baseUrl`+`/$$createPreReqCategory.name$$.html` URl. +The corresponding web page is generated by the Magento Catalog module and is called by the `baseUrl`+`/$createPreReqCategory.name$.html` URl. `{{var1}}` is substituted with the `name` of the previously created category in the `createPreReqCategory` action. @@ -132,7 +132,7 @@ There are several XML elements that are used in `<page>` in the MFTF. ### pages {#pages-tag} `<pages>` are elements that point to the corresponding XML Schema location. -It contains one or more `<page>` elements. +It contains only one `<page>` element. ### page {#page-tag} diff --git a/docs/reporting.md b/docs/reporting.md index 59a8617ba..629c3cfd8 100644 --- a/docs/reporting.md +++ b/docs/reporting.md @@ -57,42 +57,49 @@ The general information can be useful for MFTF contributors, but can be ignored Let's consider the general part of the following test execution report: ```terminal -==== Redirecting to Composer-installed version in vendor/codeception ==== -Codeception PHP Testing Framework v2.3.9 -Powered by PHPUnit 6.5.13 by Sebastian Bergmann and contributors. +Generate Tests Command Run +Codeception PHP Testing Framework v4.1.4 +Powered by PHPUnit 9.1.3 by Sebastian Bergmann and contributors. +Running with seed: Magento\FunctionalTestingFramework.functional Tests (2) ------------------------ -Modules: \Magento\FunctionalTestingFramework\Module\MagentoWebDriver, \Magento\FunctionalTestingFramework\Helper\Acceptance, \Magento\FunctionalTestingFramework\Helper\MagentoFakerData, \Magento\FunctionalTestingFramework\Module\MagentoRestDriver, PhpBrowser, \Magento\FunctionalTestingFramework\Module\MagentoSequence, \Magento\FunctionalTes +Modules: \Magento\FunctionalTestingFramework\Module\MagentoWebDriver, \Magento\FunctionalTestingFramework\Module\MagentoSequence, \Magento\FunctionalTestingFramework\Module\MagentoAssert, \Magento\FunctionalTestingFramework\Module\MagentoActionProxies, Asserts, \Magento\FunctionalTestingFramework\Helper\HelperContainer ``` -After the test generation command (mentioned in the previous section), MFTF delegates control to the `vendor/codeception` tool, which is the `Codeception PHP Testing Framework` of version `2.3.9` that uses `PHPUnit` of version `6.5.13`. +After the test generation command (mentioned in the previous section), MFTF delegates control to the `vendor/codeception` tool, which is the `Codeception PHP Testing Framework` of version `4.1.4` that uses `PHPUnit` of version `9.1.3`. The tool runs `2 Tests` using the configuration defined in the `functional` suite under the `Magento\FunctionalTestingFramework` namespace. The corresponding configuration file is `acceptance/tests/functional.suite.yml`. -It enables `Modules: \Magento\FunctionalTestingFramework\Module\MagentoWebDriver, \Magento\FunctionalTestingFramework\Helper\Acceptance, \Magento\FunctionalTestingFramework\Helper\MagentoFakerData, \Magento\FunctionalTestingFramework\Module\MagentoRestDriver, PhpBrowser, \Magento\FunctionalTestingFramework\Module\MagentoSequence, ...` +It enables `Modules: \Magento\FunctionalTestingFramework\Module\MagentoWebDriver, \Magento\FunctionalTestingFramework\Module\MagentoSequence, \Magento\FunctionalTestingFramework\Module\MagentoAssert, \Magento\FunctionalTestingFramework\Module\MagentoActionProxies, Asserts, \Magento\FunctionalTestingFramework\Helper\HelperContainer,..` #### Passed tests The next chunk of the log reports about test execution of the first test: ```terminal -AdminLoginTestCest: Admin login test -Signature: Magento\AcceptanceTest\_default\Backend\AdminLoginTestCest:AdminLoginTest -Test: tests/functional/Magento/FunctionalTest/_generated/default/AdminLoginTestCest.php:AdminLoginTest +AdminLoginSuccessfulTestCest: Admin login successful test +Signature: Magento\AcceptanceTest\_default\Backend\AdminLoginSuccessfulTestCest:AdminLoginSuccessfulTest +Test: tests/functional/Magento/_generated/default/AdminLoginSuccessfulTestCest.php:AdminLoginSuccessfulTest Scenario -- -I am on page "/admin/admin" -I fill field "#username","admin" -I fill field "#login","123123q" -I click ".actions .action-primary" -I wait for page load 30 -I close admin notification -I see in current url "/admin/admin" -PASSED +[loginAsAdmin] AdminLoginActionGroup + [navigateToAdmin] am on page "/admin/admin" + [fillUsername] fill field "#username","admin" + [fillPassword] fill field "#login","123123q" + [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",60 + [assertAdminAccountTextElement] see element ".page-header .admin-user-account-text" +[logoutFromAdmin] AdminLogoutActionGroup + [amOnLogoutPage] am on page "/admin/admin/auth/logout/" + PASSED ``` -The running test is `AdminLoginTestCest`, which is `Admin login test` (this text is generated from the test name but with the `Cest` part excluded). -Its test signature is `Magento\AcceptanceTest\_default\Backend\AdminLoginTestCest:AdminLoginTest` that matches a `className:methodName` format using namespaces. -A path to the corresponding `Test` is `tests/functional/Magento/FunctionalTest/_generated/default/AdminLoginTestCest.php:AdminLoginTest` (relative to the `acceptance/` directory). +The running test is `AdminLoginSuccessfulTestCest`, which is `Admin login successful test` (this text is generated from the test name but with the `Cest` part excluded). +Its test signature is `Magento\AcceptanceTest\_default\Backend\AdminLoginSuccessfulTestCest:AdminLoginSuccessfulTest` that matches a `className:methodName` format using namespaces. +A path to the corresponding `Test` is `tests/functional/Magento/_generated/default/AdminLoginSuccessfulTestCest.php:AdminLoginSuccessfulTest` (relative to the `acceptance/` directory). `Scenario` lists the tests steps as they run during test execution, ending with the successful test verdict `PASSED`. It means that all test steps were processed as expected. @@ -104,51 +111,54 @@ The second test fails with the following report: ```terminal AdminMenuNavigationWithSecretKeysTestCest: Admin menu navigation with secret keys test Signature: Magento\AcceptanceTest\_default\Backend\AdminMenuNavigationWithSecretKeysTestCest:AdminMenuNavigationWithSecretKeysTest -Test: tests/functional/Magento/FunctionalTest/_generated/default/AdminMenuNavigationWithSecretKeysTestCest.php:AdminMenuNavigationWithSecretKeysTest +Test: tests/functional/Magento/_generated/default/AdminMenuNavigationWithSecretKeysTestCest.php:AdminMenuNavigationWithSecretKeysTest Scenario -- -I magento cli "config:set admin/security/use_form_key 1" +[enableUrlSecretKeys] magento cli "config:set admin/security/use_form_key 1",60 Value was saved. -I magento cli "cache:clean config full_page" + +[cleanInvalidatedCaches1] magento cli "cache:clean config full_page",60 Cleaned cache types: config full_page -I am on page "/admin/admin" -I wait for page load -I fill field "#username","admin" -I fill field "#login","123123q" -I click ".actions .action-primary" -I wait for page load 30 -I close admin notification -I click "//li[@id='menu-magento-backend-stores']" -I wait for loading mask to disappear -I click "#nav li[data-ui-id='menu-magento-config-system-config']" -I wait for page load -I see current url matches "~\/admin\/system_config\/~" -I see "#something" -I save screenshot -FAIL - -I magento cli "config:set admin/security/use_form_key 0" + +[loginAsAdmin] AdminLoginActionGroup + [navigateToAdmin] am on page "/admin/admin" + [fillUsername] fill field "#username","admin" + [fillPassword] fill field "#login","123123q" + [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 +[clickStoresMenuOption1] click "#menu-magento-backend-stores" +[waitForStoresMenu1] wait for loading mask to disappear +[clickStoresConfigurationMenuOption1] click "#nav li[data-ui-id='menu-magento-config-system-config']" +[waitForConfigurationPageLoad1] wait for page load 60 +[seeCurrentUrlMatchesConfigPath1] see current url matches "~\/admin\/system_config\/~" +[clickCatalogMenuOption] click "#something" +[saveScreenshot] save screenshot +[disableUrlSecretKeys] magento cli "config:set admin/security/use_form_key 0",60 Value was saved. -I magento cli "cache:clean config full_page" + +[cleanInvalidatedCaches2] magento cli "cache:clean config full_page",60 Cleaned cache types: config full_page -I am on page "/admin/admin/auth/logout/" + +[logout] AdminLogoutActionGroup + [amOnPage] am on page "/admin/admin/auth/logout/" + FAIL -------------------------------------------------------------------------------- ``` The general test details and scenario has the same format as in the Passed test. -The interesting part starts near the `FAIL` line. ```terminal -I see "#something" -I save screenshot -FAIL +[clickCatalogMenuOption] click "#something" +[saveScreenshot] save screenshot ``` When a test step fails, MFTF always saves a screenshot of the web page with the failing state immediately after the failure occurs. -`I save screenshot` follows the failing test step `I see "#something"` in our case. +`[saveScreenshot] save screenshot` follows the failing test step `[clickCatalogMenuOption] click "#something"` in our case. A screenshot of the fail goes at the `acceptance/tests/_output` directory in both PNG and HTML formats: @@ -165,27 +175,19 @@ The file name encodes: - with the `AdminMenuNavigationWithSecretKeysTest` test name - and execution status `fail` -Actions after `FAIL` are run as a part of the [`after`][] hook of the test. +Actions after `saveScreenshot` are run as a part of the [`after`][] hook of the test. ### Test result report After MFTF completed test execution, it generates a general report about test results along with detailed information about each fail. ```terminal --------------------------------------------------------------------------------- -DEPRECATION: Calling the "Symfony\Component\BrowserKit\Client::getInternalResponse()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0. /Users/.../magento2ce/vendor/symfony/browser-kit/Client.php:208 - -Time: 52.43 seconds, Memory: 16.00MB +Time: 02:07.534, Memory: 150.50 MB There was 1 failure: --------- ``` - -First you see warnings and deprecations. -The `DEPRECATION` here is thrown by an MFTF dependency (Symfony) that is out of the scope for test writers and should be considered by MFTF contributors. -If you encounter this type of reporting, [report an issue][]. - -Then, MFTF reports that the test run took 52.43 seconds using 16 MB of system RAM. +MFTF reports that the test run took 02:07.534 using 150.50 MB of system RAM. And, finally, that there was `1 failure`. Next, the report provides details about the test failure. @@ -193,75 +195,38 @@ Next, the report provides details about the test failure. ```terminal --------- 1) AdminMenuNavigationWithSecretKeysTestCest: Admin menu navigation with secret keys test -Test tests/functional/Magento/FunctionalTest/_generated/default/AdminMenuNavigationWithSecretKeysTestCest.php:AdminMenuNavigationWithSecretKeysTest -Step See "#something" -Fail Failed asserting that on page /admin/admin/system_config/index/key/678b7ba922c.../ ---> DASHBOARD -SALES -CATALOG -CUSTOMERS -MARKETING -CONTENT -REPORTS -STORES -SYSTEM -FIND PARTNERS & EXTENSIONS -Configuration -admin -1 -Store View: Default Config -What is this? -Save Config -Country Options -State Options -Locale Options -Store Information -Store Name -Store Phone Number -Store Hours of Operation -Countr -[Content too long to display. See complete response in '/Users/dmytroshevtsov/Projects/vagrant/vagrant-magento/magento2ce/dev/tests/acceptance/tests/_output/' directory] ---> contains "#something". + Test tests/functional/Magento/_generated/default/AdminMenuNavigationWithSecretKeysTestCest.php:AdminMenuNavigationWithSecretKeysTest + Step Click "#something" + Fail CSS or XPath element with '#something' was not found. Scenario Steps: -23. $I->amOnPage("/admin/admin/auth/logout/") at tests/functional/Magento/FunctionalTest/_generated/default/AdminMenuNavigationWithSecretKeysTestCest.php:54 -22. // Cleaned cache types: + 27. // Exiting Action Group [logout] AdminLogoutActionGroup + 26. $I->amOnPage("/admin/admin/auth/logout/") at tests/functional/Magento/_generated/default/AdminMenuNavigationWithSecretKeysTestCest.php:55 + 25. // Entering Action Group [logout] AdminLogoutActionGroup + 24. // Cleaned cache types: config full_page -21. $I->magentoCLI("cache:clean config full_page") at tests/functional/Magento/FunctionalTest/_generated/default/AdminMenuNavigationWithSecretKeysTestCest.php:52 -20. // Value was saved. -19. $I->magentoCLI("config:set admin/security/use_form_key 0") at tests/functional/Magento/FunctionalTest/_generated/default/AdminMenuNavigationWithSecretKeysTestCest.php:50 -18. $I->saveScreenshot() at tests/functional/Magento/FunctionalTest/_generated/default/AdminMenuNavigationWithSecretKeysTestCest.php:63 + + 23. $I->magentoCLI("cache:clean config full_page",60) at tests/functional/Magento/_generated/default/AdminMenuNavigationWithSecretKeysTestCest.php:52 + 22. // Value was saved. ``` - `1) AdminMenuNavigationWithSecretKeysTestCest: Admin menu navigation with secret keys test` - the failed Codeception test is *AdminMenuNavigationWithSecretKeysTestCest*. It references to the PHP class that implemented the failed test. -- `Test tests/functional/Magento/FunctionalTest/_generated/default/AdminMenuNavigationWithSecretKeysTestCest.php:AdminMenuNavigationWithSecretKeysTest` - the test is implemented in the *AdminMenuNavigationWithSecretKeysTest* test method of the *tests/functional/Magento/FunctionalTest/_generated/default/AdminMenuNavigationWithSecretKeysTestCest.php* file under `<magento root>/dev/tests/acceptance/`. +- `Test tests/functional/Magento/_generated/default/AdminMenuNavigationWithSecretKeysTestCest.php:AdminMenuNavigationWithSecretKeysTest` - the test is implemented in the *AdminMenuNavigationWithSecretKeysTest* test method of the *tests/functional/Magento/FunctionalTest/_generated/default/AdminMenuNavigationWithSecretKeysTestCest.php* file under `<magento root>/dev/tests/acceptance/`. It matches the corresponding test defined in XML that is *AdminMenuNavigationWithSecretKeysTest* defined in `<test name="AdminMenuNavigationWithSecretKeysTest">...</test>` -- `Step See "#something"` - the failing test step is the *see* action with the *#something* selector. It would correspond the `<see selector="#something" ... />` test step in the XML defined tests. - -- `Fail Failed asserting that on page /admin/admin/system_config/index/key/678b7ba922c.../` - the fail occurred on the web page `<MAGENTO_BASE_URL>/admin/admin/system_config/index/key/678b7ba922c.../`. - -```terminal ---> ... -[Content too long to display. See complete response in '/../../magento2/dev/tests/acceptance/tests/_output/' directory] ---> contains "#something". -``` - -The web page is too long to be reported in the CLI, and it is stored at *'/../../magento2/dev/tests/acceptance/tests/_output/'*. -Search the web page by test name *AdminMenuNavigationWithSecretKeysTest*. -The failing test assertion is that the web page contains *contains* a CSS locator *#something*. +- `Step Click "#something"` - the failing test step is the *click* action with the *#something* selector. It would correspond the `<click selector="#something" ... />` test step in the XML defined tests. Finally, the report finishes with fairly self-descriptive lines. ```terminal FAILURES! -Tests: 2, Assertions: 3, Failures: 1. +Tests: 2, Assertions: 2, Failures: 1. ``` -MFTF encountered failures due to the last test run, that included *2* tests with *3* assertions. +MFTF encountered failures due to the last test run, that included *2* tests with *2* assertions. *1* assertion fails. ## Allure @@ -324,8 +289,7 @@ And if you run the `open` command with no arguments while you are in the same di allure open ``` -Allure would attempt to open a generated report at the `magento2/allure-report/` directory.' -%} +Allure would attempt to open a generated report at the `magento2/allure-report/` directory. To clean up existing reports before generation (for example after getting new results), use the `--clean` flag: From ef5be1dcece0cc9b451a255d076e1e64c29444c1 Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Wed, 22 Jul 2020 11:03:45 -0500 Subject: [PATCH 460/888] MQE-1886: Ability to use grab data between ActionGroups (#755) * MQE-1886: Ability to use grab data between ActionGroups * MQE-1886: Ability to use grab data between ActionGroups verification tests + other fixes * MQE-1886: Ability to use grab data between ActionGroups added functional test. * MQE-1886: Ability to use grab data between ActionGroups added functional test. Removed functional test for return. --- .../ActionGroupReturningValueTest.txt | 75 ++++++++++++++++++ .../ExtendedActionGroupReturningValueTest.txt | 40 ++++++++++ ...ndedChildActionGroupReturningValueTest.txt | 43 +++++++++++ .../MergedActionGroupReturningValueTest.txt | 77 +++++++++++++++++++ .../ActionGroupReturningValueActionGroup.xml | 21 +++++ ...edActionGroupReturningValueActionGroup.xml | 21 +++++ ...lActionGroupWithReturnValueActionGroup.xml | 14 ++++ ...geActionGroupReturningValueActionGroup.xml | 19 +++++ ...geActionGroupReturningValueActionGroup.xml | 14 ++++ .../ActionGroupReturningValueTest.xml | 30 ++++++++ .../ExtendedActionGroupReturningValueTest.xml | 22 ++++++ ...ndedChildActionGroupReturningValueTest.xml | 23 ++++++ .../MergedActionGroupReturningValueTest.xml | 32 ++++++++ .../ActionGroupWithReturnGenerationTest.php | 52 +++++++++++++ docs/data.md | 2 + docs/test/action-groups.md | 28 +++++++ docs/test/actions.md | 16 ++++ etc/di.xml | 2 +- .../Module/MagentoWebDriver.php | 12 +++ .../Test/etc/Actions/customActions.xsd | 26 +++++++ .../Test/etc/actionTypeTags.xsd | 6 ++ .../Test/etc/mergedActionGroupSchema.xsd | 62 +++++++++------ .../Util/TestGenerator.php | 10 +++ 23 files changed, 623 insertions(+), 24 deletions(-) create mode 100644 dev/tests/verification/Resources/ActionGroupReturningValueTest.txt create mode 100644 dev/tests/verification/Resources/ExtendedActionGroupReturningValueTest.txt create mode 100644 dev/tests/verification/Resources/ExtendedChildActionGroupReturningValueTest.txt create mode 100644 dev/tests/verification/Resources/MergedActionGroupReturningValueTest.txt create mode 100644 dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupReturningValueActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ExtendedActionGroupReturningValueActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupWithReturnValueActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/MergeActionGroupReturningValueActionGroup.xml create mode 100644 dev/tests/verification/TestModule/ActionGroup/MergeFunctionalActionGroup/MergeActionGroupReturningValueActionGroup.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupReturningValueTest.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupTest/ExtendedActionGroupReturningValueTest.xml create mode 100644 dev/tests/verification/TestModule/Test/ActionGroupTest/ExtendedChildActionGroupReturningValueTest.xml create mode 100644 dev/tests/verification/TestModule/Test/MergeFunctionalTest/MergedActionGroupReturningValueTest.xml create mode 100644 dev/tests/verification/Tests/ActionGroupWithReturnGenerationTest.php diff --git a/dev/tests/verification/Resources/ActionGroupReturningValueTest.txt b/dev/tests/verification/Resources/ActionGroupReturningValueTest.txt new file mode 100644 index 000000000..08e0b44f8 --- /dev/null +++ b/dev/tests/verification/Resources/ActionGroupReturningValueTest.txt @@ -0,0 +1,75 @@ +<?php +namespace Magento\AcceptanceTest\_default\Backend; + +use Magento\FunctionalTestingFramework\AcceptanceTester; +use \Codeception\Util\Locator; +use Yandex\Allure\Adapter\Annotation\Features; +use Yandex\Allure\Adapter\Annotation\Stories; +use Yandex\Allure\Adapter\Annotation\Title; +use Yandex\Allure\Adapter\Annotation\Description; +use Yandex\Allure\Adapter\Annotation\Parameter; +use Yandex\Allure\Adapter\Annotation\Severity; +use Yandex\Allure\Adapter\Model\SeverityLevel; +use Yandex\Allure\Adapter\Annotation\TestCaseId; + +/** + * @group functional + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupReturningValueTest.xml<br>") + */ +class ActionGroupReturningValueTestCest +{ + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _before(AcceptanceTester $I) + { + $I->createEntity("createPersonParam", "hook", "ReplacementPerson", [], []); // stepKey: createPersonParam + $I->comment("Entering Action Group [beforeGroup] FunctionalActionGroup"); + $I->fillField("#foo", "myData1"); // stepKey: fillField1BeforeGroup + $I->fillField("#bar", "myData2"); // stepKey: fillField2BeforeGroup + $I->comment("Exiting Action Group [beforeGroup] FunctionalActionGroup"); + } + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + $I->comment("Entering Action Group [afterGroup] FunctionalActionGroup"); + $I->fillField("#foo", "myData1"); // stepKey: fillField1AfterGroup + $I->fillField("#bar", "myData2"); // stepKey: fillField2AfterGroup + $I->comment("Exiting Action Group [afterGroup] FunctionalActionGroup"); + } + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _failed(AcceptanceTester $I) + { + $I->saveScreenshot(); // stepKey: saveScreenshot + } + + /** + * @Severity(level = SeverityLevel::CRITICAL) + * @Features({"TestModule"}) + * @Stories({"MQE-433"}) + * @Parameter(name = "AcceptanceTester", value="$I") + * @param AcceptanceTester $I + * @return void + * @throws \Exception + */ + public function ActionGroupReturningValueTest(AcceptanceTester $I) + { + $I->amOnPage("/someUrl"); // stepKey: step1 + $I->comment("Entering Action Group [actionGroupWithReturnValue1] FunctionalActionGroupWithReturnValueActionGroup"); + $grabTextFrom1ActionGroupWithReturnValue1 = $I->grabTextFrom("#foo"); // stepKey: grabTextFrom1ActionGroupWithReturnValue1 + $actionGroupWithReturnValue1 = $I->return($grabTextFrom1ActionGroupWithReturnValue1); // stepKey: returnActionGroupWithReturnValue1 + $I->comment("Exiting Action Group [actionGroupWithReturnValue1] FunctionalActionGroupWithReturnValueActionGroup"); + $I->comment("Entering Action Group [actionGroupWithStringUsage1] actionGroupWithStringUsage"); + $I->see($actionGroupWithReturnValue1, "#element .{$actionGroupWithReturnValue1}"); // stepKey: see1ActionGroupWithStringUsage1 + $I->comment("Exiting Action Group [actionGroupWithStringUsage1] actionGroupWithStringUsage"); + } +} diff --git a/dev/tests/verification/Resources/ExtendedActionGroupReturningValueTest.txt b/dev/tests/verification/Resources/ExtendedActionGroupReturningValueTest.txt new file mode 100644 index 000000000..2f26a6463 --- /dev/null +++ b/dev/tests/verification/Resources/ExtendedActionGroupReturningValueTest.txt @@ -0,0 +1,40 @@ +<?php +namespace Magento\AcceptanceTest\_default\Backend; + +use Magento\FunctionalTestingFramework\AcceptanceTester; +use \Codeception\Util\Locator; +use Yandex\Allure\Adapter\Annotation\Features; +use Yandex\Allure\Adapter\Annotation\Stories; +use Yandex\Allure\Adapter\Annotation\Title; +use Yandex\Allure\Adapter\Annotation\Description; +use Yandex\Allure\Adapter\Annotation\Parameter; +use Yandex\Allure\Adapter\Annotation\Severity; +use Yandex\Allure\Adapter\Model\SeverityLevel; +use Yandex\Allure\Adapter\Annotation\TestCaseId; + +/** + * @Title("[NO TESTCASEID]: Extended ActionGroup Returning Value Test") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest/ExtendedActionGroupReturningValueTest.xml<br>") + */ +class ExtendedActionGroupReturningValueTestCest +{ + /** + * @Severity(level = SeverityLevel::CRITICAL) + * @Features({"TestModule"}) + * @Parameter(name = "AcceptanceTester", value="$I") + * @param AcceptanceTester $I + * @return void + * @throws \Exception + */ + public function ExtendedActionGroupReturningValueTest(AcceptanceTester $I) + { + $I->comment("Entering Action Group [actionGroupReturningValue] ActionGroupReturningValueActionGroup"); + $grabProducts1ActionGroupReturningValue = $I->grabMultiple("selector"); // stepKey: grabProducts1ActionGroupReturningValue + $I->assertCount(99, $grabProducts1ActionGroupReturningValue); // stepKey: assertCountActionGroupReturningValue + $actionGroupReturningValue = $I->return($grabProducts1ActionGroupReturningValue); // stepKey: returnProducts1ActionGroupReturningValue + $I->comment("Exiting Action Group [actionGroupReturningValue] ActionGroupReturningValueActionGroup"); + $I->comment("Entering Action Group [actionGroupWithStringUsage1] actionGroupWithStringUsage"); + $I->see($actionGroupReturningValue, "#element .{$actionGroupReturningValue}"); // stepKey: see1ActionGroupWithStringUsage1 + $I->comment("Exiting Action Group [actionGroupWithStringUsage1] actionGroupWithStringUsage"); + } +} diff --git a/dev/tests/verification/Resources/ExtendedChildActionGroupReturningValueTest.txt b/dev/tests/verification/Resources/ExtendedChildActionGroupReturningValueTest.txt new file mode 100644 index 000000000..d043a5c04 --- /dev/null +++ b/dev/tests/verification/Resources/ExtendedChildActionGroupReturningValueTest.txt @@ -0,0 +1,43 @@ +<?php +namespace Magento\AcceptanceTest\_default\Backend; + +use Magento\FunctionalTestingFramework\AcceptanceTester; +use \Codeception\Util\Locator; +use Yandex\Allure\Adapter\Annotation\Features; +use Yandex\Allure\Adapter\Annotation\Stories; +use Yandex\Allure\Adapter\Annotation\Title; +use Yandex\Allure\Adapter\Annotation\Description; +use Yandex\Allure\Adapter\Annotation\Parameter; +use Yandex\Allure\Adapter\Annotation\Severity; +use Yandex\Allure\Adapter\Model\SeverityLevel; +use Yandex\Allure\Adapter\Annotation\TestCaseId; + +/** + * @Title("[NO TESTCASEID]: Extended Child ActionGroup Returning Value Test") + * @Description("<h3>Test files</h3>verification/TestModule/Test/ActionGroupTest/ExtendedChildActionGroupReturningValueTest.xml<br>") + */ +class ExtendedChildActionGroupReturningValueTestCest +{ + /** + * @Severity(level = SeverityLevel::CRITICAL) + * @Features({"TestModule"}) + * @Parameter(name = "AcceptanceTester", value="$I") + * @param AcceptanceTester $I + * @return void + * @throws \Exception + */ + public function ExtendedChildActionGroupReturningValueTest(AcceptanceTester $I) + { + $I->comment("Entering Action Group [extendedActionGroupReturningValue] ExtendedActionGroupReturningValueActionGroup"); + $grabProducts1ExtendedActionGroupReturningValue = $I->grabMultiple("selector"); // stepKey: grabProducts1ExtendedActionGroupReturningValue + $I->assertCount(99, $grabProducts1ExtendedActionGroupReturningValue); // stepKey: assertCountExtendedActionGroupReturningValue + $extendedActionGroupReturningValue = $I->return($grabProducts1ExtendedActionGroupReturningValue); // stepKey: returnProducts1ExtendedActionGroupReturningValue + $grabProducts2ExtendedActionGroupReturningValue = $I->grabMultiple("otherSelector"); // stepKey: grabProducts2ExtendedActionGroupReturningValue + $I->assertCount(8000, $grabProducts2ExtendedActionGroupReturningValue); // stepKey: assertSecondCountExtendedActionGroupReturningValue + $extendedActionGroupReturningValue = $I->return($grabProducts2ExtendedActionGroupReturningValue); // stepKey: returnProducts2ExtendedActionGroupReturningValue + $I->comment("Exiting Action Group [extendedActionGroupReturningValue] ExtendedActionGroupReturningValueActionGroup"); + $I->comment("Entering Action Group [actionGroupWithStringUsage1] actionGroupWithStringUsage"); + $I->see($extendedActionGroupReturningValue, "#element .{$extendedActionGroupReturningValue}"); // stepKey: see1ActionGroupWithStringUsage1 + $I->comment("Exiting Action Group [actionGroupWithStringUsage1] actionGroupWithStringUsage"); + } +} diff --git a/dev/tests/verification/Resources/MergedActionGroupReturningValueTest.txt b/dev/tests/verification/Resources/MergedActionGroupReturningValueTest.txt new file mode 100644 index 000000000..a4689779b --- /dev/null +++ b/dev/tests/verification/Resources/MergedActionGroupReturningValueTest.txt @@ -0,0 +1,77 @@ +<?php +namespace Magento\AcceptanceTest\_default\Backend; + +use Magento\FunctionalTestingFramework\AcceptanceTester; +use \Codeception\Util\Locator; +use Yandex\Allure\Adapter\Annotation\Features; +use Yandex\Allure\Adapter\Annotation\Stories; +use Yandex\Allure\Adapter\Annotation\Title; +use Yandex\Allure\Adapter\Annotation\Description; +use Yandex\Allure\Adapter\Annotation\Parameter; +use Yandex\Allure\Adapter\Annotation\Severity; +use Yandex\Allure\Adapter\Model\SeverityLevel; +use Yandex\Allure\Adapter\Annotation\TestCaseId; + +/** + * @group functional + * @Description("<h3>Test files</h3>verification/TestModule/Test/MergeFunctionalTest/MergedActionGroupReturningValueTest.xml<br>") + */ +class MergedActionGroupReturningValueTestCest +{ + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _before(AcceptanceTester $I) + { + $I->createEntity("createPersonParam", "hook", "ReplacementPerson", [], []); // stepKey: createPersonParam + $I->comment("Entering Action Group [beforeGroup] FunctionalActionGroup"); + $I->fillField("#foo", "myData1"); // stepKey: fillField1BeforeGroup + $I->fillField("#bar", "myData2"); // stepKey: fillField2BeforeGroup + $I->comment("Exiting Action Group [beforeGroup] FunctionalActionGroup"); + } + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + $I->comment("Entering Action Group [afterGroup] FunctionalActionGroup"); + $I->fillField("#foo", "myData1"); // stepKey: fillField1AfterGroup + $I->fillField("#bar", "myData2"); // stepKey: fillField2AfterGroup + $I->comment("Exiting Action Group [afterGroup] FunctionalActionGroup"); + } + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _failed(AcceptanceTester $I) + { + $I->saveScreenshot(); // stepKey: saveScreenshot + } + + /** + * @Severity(level = SeverityLevel::CRITICAL) + * @Features({"TestModule"}) + * @Stories({"MQE-433"}) + * @Parameter(name = "AcceptanceTester", value="$I") + * @param AcceptanceTester $I + * @return void + * @throws \Exception + */ + public function MergedActionGroupReturningValueTest(AcceptanceTester $I) + { + $I->amOnPage("/someUrl"); // stepKey: step1 + $I->comment("Entering Action Group [actionGroupWithReturnValue1] MergeActionGroupReturningValueActionGroup"); + $I->amOnPage("/Jane/Dane.html"); // stepKey: amOnPage1ActionGroupWithReturnValue1 + $I->click(".merge .Jane"); // stepKey: myMergedClickActionGroupWithReturnValue1 + $grabMultiple1ActionGroupWithReturnValue1 = $I->grabMultiple("#foo"); // stepKey: grabMultiple1ActionGroupWithReturnValue1 + $actionGroupWithReturnValue1 = $I->return($grabMultiple1ActionGroupWithReturnValue1); // stepKey: returnValueActionGroupWithReturnValue1 + $I->comment("Exiting Action Group [actionGroupWithReturnValue1] MergeActionGroupReturningValueActionGroup"); + $I->comment("Entering Action Group [actionGroupWithStringUsage1] actionGroupWithStringUsage"); + $I->see($actionGroupWithReturnValue1, "#element .{$actionGroupWithReturnValue1}"); // stepKey: see1ActionGroupWithStringUsage1 + $I->comment("Exiting Action Group [actionGroupWithStringUsage1] actionGroupWithStringUsage"); + } +} diff --git a/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupReturningValueActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupReturningValueActionGroup.xml new file mode 100644 index 000000000..ddb93c0c1 --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupReturningValueActionGroup.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="ActionGroupReturningValueActionGroup"> + <arguments> + <argument name="count" type="string"/> + </arguments> + <grabMultiple selector="selector" stepKey="grabProducts1"/> + <assertCount stepKey="assertCount"> + <expectedResult type="int">{{count}}</expectedResult> + <actualResult type="variable">grabProducts1</actualResult> + </assertCount> + <return value="{$grabProducts1}" stepKey="returnProducts1"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ExtendedActionGroupReturningValueActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ExtendedActionGroupReturningValueActionGroup.xml new file mode 100644 index 000000000..18933a2f2 --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ExtendedActionGroupReturningValueActionGroup.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="ExtendedActionGroupReturningValueActionGroup" extends="ActionGroupReturningValueActionGroup"> + <arguments> + <argument name="otherCount" type="string"/> + </arguments> + <grabMultiple selector="otherSelector" stepKey="grabProducts2"/> + <assertCount stepKey="assertSecondCount"> + <expectedResult type="int">{{otherCount}}</expectedResult> + <actualResult type="variable">grabProducts2</actualResult> + </assertCount> + <return value="{$grabProducts2}" stepKey="returnProducts2"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupWithReturnValueActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupWithReturnValueActionGroup.xml new file mode 100644 index 000000000..77900efd3 --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionalActionGroupWithReturnValueActionGroup.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="FunctionalActionGroupWithReturnValueActionGroup"> + <grabTextFrom selector="#foo" stepKey="grabTextFrom1"/> + <return value="{$grabTextFrom1}" stepKey="return"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/MergeActionGroupReturningValueActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/MergeActionGroupReturningValueActionGroup.xml new file mode 100644 index 000000000..83afbce0c --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/MergeActionGroupReturningValueActionGroup.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="MergeActionGroupReturningValueActionGroup"> + <arguments> + <argument name="myArg"/> + </arguments> + <fillField userInput="Please delete me" selector="#delete" stepKey="deleteMe"/> + <amOnPage url="{{SamplePage.url(myArg.firstname,myArg.lastname)}}" stepKey="amOnPage1"/> + <grabMultiple selector="#foo" stepKey="grabMultiple1"/> + <return value="{$grabMultiple1}" stepKey="returnValue"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/MergeFunctionalActionGroup/MergeActionGroupReturningValueActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/MergeFunctionalActionGroup/MergeActionGroupReturningValueActionGroup.xml new file mode 100644 index 000000000..d952fdddf --- /dev/null +++ b/dev/tests/verification/TestModule/ActionGroup/MergeFunctionalActionGroup/MergeActionGroupReturningValueActionGroup.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="MergeActionGroupReturningValueActionGroup"> + <click stepKey="myMergedClick" selector=".merge .{{myArg.firstname}}" after="amOnPage1"/> + <remove keyForRemoval="deleteMe"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupReturningValueTest.xml b/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupReturningValueTest.xml new file mode 100644 index 000000000..ade1f51db --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupFunctionalTest/ActionGroupReturningValueTest.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ActionGroupReturningValueTest"> + <annotations> + <severity value="CRITICAL"/> + <group value="functional"/> + <features value="Action Group Functional Cest"/> + <stories value="MQE-433"/> + </annotations> + <before> + <createData entity="ReplacementPerson" stepKey="createPersonParam"/> + <actionGroup ref="FunctionalActionGroup" stepKey="beforeGroup"/> + </before> + <amOnPage url="/someUrl" stepKey="step1"/> + <actionGroup ref="FunctionalActionGroupWithReturnValueActionGroup" stepKey="actionGroupWithReturnValue1"/> + <actionGroup ref="actionGroupWithStringUsage" stepKey="actionGroupWithStringUsage1"> + <argument name="someArgument" value="{$actionGroupWithReturnValue1}"/> + </actionGroup> + <after> + <actionGroup ref="FunctionalActionGroup" stepKey="afterGroup"/> + </after> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupTest/ExtendedActionGroupReturningValueTest.xml b/dev/tests/verification/TestModule/Test/ActionGroupTest/ExtendedActionGroupReturningValueTest.xml new file mode 100644 index 000000000..68042344c --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupTest/ExtendedActionGroupReturningValueTest.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ExtendedActionGroupReturningValueTest"> + <annotations> + <severity value="CRITICAL"/> + <title value="Extended ActionGroup Returning Value Test"/> + </annotations> + <actionGroup ref="ActionGroupReturningValueActionGroup" stepKey="actionGroupReturningValue"> + <argument name="count" value="99"/> + </actionGroup> + <actionGroup ref="actionGroupWithStringUsage" stepKey="actionGroupWithStringUsage1"> + <argument name="someArgument" value="{$actionGroupReturningValue}"/> + </actionGroup> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/ActionGroupTest/ExtendedChildActionGroupReturningValueTest.xml b/dev/tests/verification/TestModule/Test/ActionGroupTest/ExtendedChildActionGroupReturningValueTest.xml new file mode 100644 index 000000000..ecd46c3c4 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/ActionGroupTest/ExtendedChildActionGroupReturningValueTest.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="ExtendedChildActionGroupReturningValueTest"> + <annotations> + <severity value="CRITICAL"/> + <title value="Extended Child ActionGroup Returning Value Test"/> + </annotations> + <actionGroup ref="ExtendedActionGroupReturningValueActionGroup" stepKey="extendedActionGroupReturningValue"> + <argument name="count" value="99"/> + <argument name="otherCount" value="8000"/> + </actionGroup> + <actionGroup ref="actionGroupWithStringUsage" stepKey="actionGroupWithStringUsage1"> + <argument name="someArgument" value="{$extendedActionGroupReturningValue}"/> + </actionGroup> + </test> +</tests> diff --git a/dev/tests/verification/TestModule/Test/MergeFunctionalTest/MergedActionGroupReturningValueTest.xml b/dev/tests/verification/TestModule/Test/MergeFunctionalTest/MergedActionGroupReturningValueTest.xml new file mode 100644 index 000000000..baf7c0ded --- /dev/null +++ b/dev/tests/verification/TestModule/Test/MergeFunctionalTest/MergedActionGroupReturningValueTest.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="MergedActionGroupReturningValueTest"> + <annotations> + <severity value="CRITICAL"/> + <group value="functional"/> + <features value="Action Group Functional Cest"/> + <stories value="MQE-433"/> + </annotations> + <before> + <createData entity="ReplacementPerson" stepKey="createPersonParam"/> + <actionGroup ref="FunctionalActionGroup" stepKey="beforeGroup"/> + </before> + <amOnPage url="/someUrl" stepKey="step1"/> + <actionGroup ref="MergeActionGroupReturningValueActionGroup" stepKey="actionGroupWithReturnValue1"> + <argument name="myArg" value="DefaultPerson"/> + </actionGroup> + <actionGroup ref="actionGroupWithStringUsage" stepKey="actionGroupWithStringUsage1"> + <argument name="someArgument" value="{$actionGroupWithReturnValue1}"/> + </actionGroup> + <after> + <actionGroup ref="FunctionalActionGroup" stepKey="afterGroup"/> + </after> + </test> +</tests> diff --git a/dev/tests/verification/Tests/ActionGroupWithReturnGenerationTest.php b/dev/tests/verification/Tests/ActionGroupWithReturnGenerationTest.php new file mode 100644 index 000000000..e369a797d --- /dev/null +++ b/dev/tests/verification/Tests/ActionGroupWithReturnGenerationTest.php @@ -0,0 +1,52 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace tests\verification\Tests; + +use tests\util\MftfTestCase; + +class ActionGroupWithReturnGenerationTest extends MftfTestCase +{ + /** + * Test generation of a test referencing an action group that returns a value. + * + * @throws \Exception + * @throws \Magento\FunctionalTestingFramework\Exceptions\TestReferenceException + */ + public function testActionGroupReturningValue() + { + $this->generateAndCompareTest('ActionGroupReturningValueTest'); + } + /** + * Test generation of a test referencing a merged action group that returns a value. + * + * @throws \Exception + * @throws \Magento\FunctionalTestingFramework\Exceptions\TestReferenceException + */ + public function testMergedActionGroupReturningValue() + { + $this->generateAndCompareTest('MergedActionGroupReturningValueTest'); + } + /** + * Test generation of a test referencing an extended action group that returns a value. + * + * @throws \Exception + * @throws \Magento\FunctionalTestingFramework\Exceptions\TestReferenceException + */ + public function testExtendedActionGroupReturningValue() + { + $this->generateAndCompareTest('ExtendedActionGroupReturningValueTest'); + } + /** + * Test generation of a test referencing an extending child action group that returns a value. + * + * @throws \Exception + * @throws \Magento\FunctionalTestingFramework\Exceptions\TestReferenceException + */ + public function testExtendedChildActionGroupReturningValue() + { + $this->generateAndCompareTest('ExtendedChildActionGroupReturningValueTest'); + } +} diff --git a/docs/data.md b/docs/data.md index 8b0a86e3d..d642763d0 100644 --- a/docs/data.md +++ b/docs/data.md @@ -78,6 +78,8 @@ A test can also reference data that was returned as a result of [test actions][] Further in the test, the data grabbed by the `someSelector` selector can be referenced using the `stepKey` value. In this case, it is `grabStepKey`. +The `stepKey` value can only be referenced within the test scope that it is defined in (`test`, `before/after`). + The following example shows the usage of `grabValueFrom` in testing, where the returned value is used by action's `stepKey`: ```xml diff --git a/docs/test/action-groups.md b/docs/test/action-groups.md index 70af0621a..05adf795e 100644 --- a/docs/test/action-groups.md +++ b/docs/test/action-groups.md @@ -180,6 +180,34 @@ MFTF resolves `{{myCustomEntity.field1}}` the same as it would in a `selector` o </actionGroup> ``` +## Return a value + +Action groups can return a value using a `return` tag. + +```xml +<actionGroup name="GetOrderIdActionGroup"> + <seeElement selector="{{CheckoutSuccessMainSection.orderLink}}" stepKey="assertOrderLink"/> + <grabTextFrom selector="{{CheckoutSuccessMainSection.orderLink}}" stepKey="orderId"/> + <return value="{$orderId}" stepKey="returnOrderId"/> +</actionGroup> +``` + +The value returned can be accessed in later steps using action group step key `{$getOrderId}`. +```xml +<actionGroup ref="GetOrderIdActionGroup" stepKey="getOrderId"/> +<!--Filter the Order using Order ID --> +<actionGroup ref="FilterOrderGridByIdActionGroup" stepKey="filterOrderGridById"> + <argument name="orderId" value="{$getOrderId}"/> +</actionGroup> +``` +### Convention to return a value + +The following conventions apply to action groups returning a value: +- Only action groups can return value. Use of `return` tag is dis-allowed in tests and suites. +- An action group does not support multiple `return` tags. +- For [merging action groups](../merging.md#merge-action-groups), `return` is allowed only in one of the merging action groups. +- Value returned by an action group can only be referenced within the scope that the action group is defined in (`test`, `before/after`). + ## Optimizing action group structures Structuring properly an action group increases code reusability and readability. diff --git a/docs/test/actions.md b/docs/test/actions.md index 1d2f83802..562f6e8ff 100644 --- a/docs/test/actions.md +++ b/docs/test/actions.md @@ -151,6 +151,7 @@ The following test actions return a variable: * [grabValueFrom](#grabvaluefrom) * [executeJS](#executejs) * [getOTP](#getotp) +* [return](#return) Learn more in [Using data returned by test actions](../data.md#use-data-returned-by-test-actions). @@ -1240,6 +1241,21 @@ To access this value, use `{$grabInputName}` in later actions. --> <grabValueFrom selector="input#name" stepKey="grabInputName"/> ``` +### return + +Specifies what value is returned by an action group. The value can be then accessed in later steps using the action group stepKey. See [Action groups returning a value](./action-groups.md#return-a-value) for usage information. + +Attribute|Type|Use|Description +---|---|---|--- +`value`|string|required| value returned by action group. +`stepKey`|string|required| A unique identifier of the action. + +#### Example +```xml +<!-- Returns value of $grabInputName to the calling +<return value="{$grabInputName}" stepKey="returnInputName"/> +``` + ### loadSessionSnapshot See [loadSessionSnapshot docs on codeception.com](http://codeception.com/docs/modules/WebDriver#loadSessionSnapshot). diff --git a/etc/di.xml b/etc/di.xml index e561911da..f5184808c 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -8,7 +8,7 @@ <!-- Entity value gets replaced in Dom.php before reading $xml --> <!DOCTYPE config [ - <!ENTITY commonTestActions "acceptPopup|actionGroup|amOnPage|amOnUrl|amOnSubdomain|appendField|assertArrayIsSortasserted|assertElementContainsAttribute|attachFile|cancelPopup|checkOption|clearField|click|clickWithLeftButton|clickWithRightButton|closeAdminNotification|closeTab|comment|conditionalClick|createData|deleteData|updateData|getData|dontSee|dontSeeJsError|dontSeeCheckboxIsChecked|dontSeeCookie|dontSeeCurrentUrlEquals|dontSeeCurrentUrlMatches|dontSeeElement|dontSeeElementInDOM|dontSeeInCurrentUrl|dontSeeInField|dontSeeInFormFields|dontSeeInPageSource|dontSeeInSource|dontSeeInTitle|dontSeeLink|dontSeeOptionIsSelected|doubleClick|dragAndDrop|entity|executeJS|fillField|formatCurrency|generateDate|getOTP|grabAttributeFrom|grabCookie|grabFromCurrentUrl|grabMultiple|grabPageSource|grabTextFrom|grabValueFrom|loadSessionSnapshot|loginAsAdmin|magentoCLI|magentoCron|makeScreenshot|maximizeWindow|moveBack|moveForward|moveMouseOver|mSetLocale|mResetLocale|openNewTab|pause|parseFloat|pressKey|reloadPage|resetCookie|submitForm|resizeWindow|saveSessionSnapshot|scrollTo|scrollToTopOfPage|searchAndMultiSelectOption|see|seeCheckboxIsChecked|seeCookie|seeCurrentUrlEquals|seeCurrentUrlMatches|seeElement|seeElementInDOM|seeInCurrentUrl|seeInField|seeInFormFields|seeInPageSource|seeInPopup|seeInSource|seeInTitle|seeLink|seeNumberOfElements|seeOptionIsSelected|selectOption|setCookie|submitForm|switchToIFrame|switchToNextTab|switchToPreviousTab|switchToWindow|typeInPopup|uncheckOption|unselectOption|wait|waitForAjaxLoad|waitForElement|waitForElementChange|waitForElementNotVisible|waitForElementVisible|waitForPwaElementNotVisible|waitForPwaElementVisible|waitForJS|waitForLoadingMaskToDisappear|waitForPageLoad|waitForText|assertArrayHasKey|assertArrayNotHasKey|assertContains|assertStringContainsString|assertStringContainsStringIgnoringCase|assertCount|assertEmpty|assertEquals|assertFalse|assertFileExists|assertFileNotExists|assertGreaterOrEquals|assertGreaterThan|assertGreaterThanOrEqual|assertInstanceOf|assertIsEmpty|assertLessOrEquals|assertLessThan|assertLessThanOrEqual|assertNotContains|assertStringNotContainsString|assertStringNotContainsStringIgnoringCase|assertNotEmpty|assertNotEquals|assertNotInstanceOf|assertNotNull|assertNotRegExp|assertNotSame|assertNull|assertRegExp|assertSame|assertStringStartsNotWith|assertStringStartsWith|assertTrue|expectException|fail|dontSeeFullUrlEquals|dontSee|dontSeeFullUrlMatches|dontSeeInFullUrl|seeFullUrlEquals|seeFullUrlMatches|seeInFullUrl|grabFromFullUrl|helper|assertEqualsWithDelta|assertEqualsCanonicalizing|assertEqualsIgnoringCase|assertNotEqualsWithDelta|assertNotEqualsCanonicalizing|assertNotEqualsIgnoringCase"> + <!ENTITY commonTestActions "acceptPopup|actionGroup|amOnPage|amOnUrl|amOnSubdomain|appendField|assertArrayIsSortasserted|assertElementContainsAttribute|attachFile|cancelPopup|checkOption|clearField|click|clickWithLeftButton|clickWithRightButton|closeAdminNotification|closeTab|comment|conditionalClick|createData|deleteData|updateData|getData|dontSee|dontSeeJsError|dontSeeCheckboxIsChecked|dontSeeCookie|dontSeeCurrentUrlEquals|dontSeeCurrentUrlMatches|dontSeeElement|dontSeeElementInDOM|dontSeeInCurrentUrl|dontSeeInField|dontSeeInFormFields|dontSeeInPageSource|dontSeeInSource|dontSeeInTitle|dontSeeLink|dontSeeOptionIsSelected|doubleClick|dragAndDrop|entity|executeJS|fillField|formatCurrency|generateDate|getOTP|grabAttributeFrom|grabCookie|grabFromCurrentUrl|grabMultiple|grabPageSource|grabTextFrom|grabValueFrom|return|loadSessionSnapshot|loginAsAdmin|magentoCLI|magentoCron|makeScreenshot|maximizeWindow|moveBack|moveForward|moveMouseOver|mSetLocale|mResetLocale|openNewTab|pause|parseFloat|pressKey|reloadPage|resetCookie|submitForm|resizeWindow|saveSessionSnapshot|scrollTo|scrollToTopOfPage|searchAndMultiSelectOption|see|seeCheckboxIsChecked|seeCookie|seeCurrentUrlEquals|seeCurrentUrlMatches|seeElement|seeElementInDOM|seeInCurrentUrl|seeInField|seeInFormFields|seeInPageSource|seeInPopup|seeInSource|seeInTitle|seeLink|seeNumberOfElements|seeOptionIsSelected|selectOption|setCookie|submitForm|switchToIFrame|switchToNextTab|switchToPreviousTab|switchToWindow|typeInPopup|uncheckOption|unselectOption|wait|waitForAjaxLoad|waitForElement|waitForElementChange|waitForElementNotVisible|waitForElementVisible|waitForPwaElementNotVisible|waitForPwaElementVisible|waitForJS|waitForLoadingMaskToDisappear|waitForPageLoad|waitForText|assertArrayHasKey|assertArrayNotHasKey|assertContains|assertStringContainsString|assertStringContainsStringIgnoringCase|assertCount|assertEmpty|assertEquals|assertFalse|assertFileExists|assertFileNotExists|assertGreaterOrEquals|assertGreaterThan|assertGreaterThanOrEqual|assertInstanceOf|assertIsEmpty|assertLessOrEquals|assertLessThan|assertLessThanOrEqual|assertNotContains|assertStringNotContainsString|assertStringNotContainsStringIgnoringCase|assertNotEmpty|assertNotEquals|assertNotInstanceOf|assertNotNull|assertNotRegExp|assertNotSame|assertNull|assertRegExp|assertSame|assertStringStartsNotWith|assertStringStartsWith|assertTrue|expectException|fail|dontSeeFullUrlEquals|dontSee|dontSeeFullUrlMatches|dontSeeInFullUrl|seeFullUrlEquals|seeFullUrlMatches|seeInFullUrl|grabFromFullUrl|helper|assertEqualsWithDelta|assertEqualsCanonicalizing|assertEqualsIgnoringCase|assertNotEqualsWithDelta|assertNotEqualsCanonicalizing|assertNotEqualsIgnoringCase"> ]> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../src/Magento/FunctionalTestingFramework/ObjectManager/etc/config.xsd"> diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 2f4745df1..944735677 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -1122,4 +1122,16 @@ public function switchToIFrame($locator = null) $this->webDriver->switchTo()->frame($els[0]); } } + + /** + * Returns a value to origin of the action. + * TODO: move this function to MagentoActionProxies after MQE-1904 + * + * @param mixed $value + * @return mixed + */ + public function return($value) + { + return $value; + } } diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd index 2aad30c75..b1d6e1b02 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd @@ -29,6 +29,12 @@ </xs:choice> </xs:group> + <xs:group name="returnTags"> + <xs:choice> + <xs:element type="returnType" name="return" minOccurs="0" maxOccurs="1"/> + </xs:choice> + </xs:group> + <!-- Complex Types --> <xs:complexType name="helperType"> @@ -346,6 +352,26 @@ </xs:simpleContent> </xs:complexType> + <xs:complexType name="returnType"> + <xs:annotation> + <xs:documentation> + Used in an action group to return a value. Must be used only once in action group. Do not use in tests or suites. + </xs:documentation> + </xs:annotation> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute name="value" use="required" type="xs:string"> + <xs:annotation> + <xs:documentation> + Value or variable to be returned. + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attributeGroup ref="commonActionAttributes"/> + </xs:extension> + </xs:simpleContent> + </xs:complexType> + <xs:simpleType name="sortEnum" final="restriction"> <xs:annotation> <xs:documentation> diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/actionTypeTags.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/actionTypeTags.xsd index def2964af..d68cf43db 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/actionTypeTags.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/actionTypeTags.xsd @@ -68,6 +68,12 @@ </xs:choice> </xs:group> + <xs:group name="returnTypeTags"> + <xs:choice> + <xs:group ref="returnTags"/> + </xs:choice> + </xs:group> + <!-- Complex Types --> <xs:complexType name="failType"> diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/mergedActionGroupSchema.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/mergedActionGroupSchema.xsd index bd32ba879..f45c33acd 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/mergedActionGroupSchema.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/mergedActionGroupSchema.xsd @@ -15,29 +15,21 @@ </xs:choice> </xs:complexType> <xs:complexType name="actionsRefType"> - <xs:choice minOccurs="0" maxOccurs="unbounded"> - <xs:group ref="actionTypeTags"/> - <xs:element name="arguments"> - <xs:complexType> - <xs:sequence> - <xs:element name="argument" maxOccurs="unbounded" minOccurs="0"> - <xs:complexType> - <xs:attribute type="xs:string" name="name" use="required"/> - <xs:attribute type="xs:string" name="defaultValue"/> - <xs:attribute type="dataTypeEnum" name="type" default="entity"/> - </xs:complexType> - </xs:element> - </xs:sequence> - </xs:complexType> - </xs:element> - <xs:element name="annotations"> - <xs:complexType> - <xs:sequence> - <xs:element name="description"/> - </xs:sequence> - </xs:complexType> - </xs:element> - </xs:choice> + <xs:sequence> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:group ref="actionTypeTags"/> + <xs:element ref="arguments"/> + <xs:element ref="annotations"/> + </xs:choice> + <xs:sequence minOccurs="0"> + <xs:group ref="returnTags"/> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:group ref="actionTypeTags"/> + <xs:element ref="arguments"/> + <xs:element ref="annotations"/> + </xs:choice> + </xs:sequence> + </xs:sequence> <xs:attribute type="xs:string" name="name" use="required"/> <xs:attribute type="xs:string" name="filename"/> <xs:attribute type="xs:string" name="insertBefore"/> @@ -57,4 +49,28 @@ <xs:enumeration value="entity"/> </xs:restriction> </xs:simpleType> + + <!-- elements --> + + <xs:element name="arguments"> + <xs:complexType> + <xs:sequence> + <xs:element name="argument" maxOccurs="unbounded" minOccurs="0"> + <xs:complexType> + <xs:attribute type="xs:string" name="name" use="required"/> + <xs:attribute type="xs:string" name="defaultValue"/> + <xs:attribute type="dataTypeEnum" name="type" default="entity"/> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + </xs:element> + + <xs:element name="annotations"> + <xs:complexType> + <xs:sequence> + <xs:element name="description"/> + </xs:sequence> + </xs:complexType> + </xs:element> </xs:schema> diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 8253a75ba..80056b3b9 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1172,6 +1172,16 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $selector ); break; + case "return": + $actionOrigin = $actionObject->getActionOrigin(); + $actionOriginStepKey = $actionOrigin[ActionGroupObject::ACTION_GROUP_ORIGIN_TEST_REF]; + $testSteps .= $this->wrapFunctionCallWithReturnValue( + $actionOriginStepKey, + $actor, + $actionObject, + $value + ); + break; case "formatCurrency": $testSteps .= $this->wrapFunctionCallWithReturnValue( $stepKey, From ee10e683b4d0dfba64c8ad922906a71fc5034c77 Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Wed, 22 Jul 2020 12:33:02 -0500 Subject: [PATCH 461/888] Add raw tag to prevent build errors. --- docs/configure-2fa.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/configure-2fa.md b/docs/configure-2fa.md index f50838f0c..7b01913b9 100644 --- a/docs/configure-2fa.md +++ b/docs/configure-2fa.md @@ -44,6 +44,10 @@ Use the action `getOTP` [Reference](./test/actions.md#getotp) to generate the co Note: You will need to set the `secret` for any non-default admin users first, before using `getOTP`. For example: +{%raw%} + ```xml <magentoCLI command="security:tfa:google:set-secret admin2 {{_CREDS.magento/tfa/OTP_SHARED_SECRET}}" stepKey="setSecret"/> ``` + +{%endraw%} From 7b572667bff8c26c7dffd4a43cfb8a8dac8ba9cd Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Wed, 22 Jul 2020 14:28:01 -0500 Subject: [PATCH 462/888] MQE-2218: Part 5 Docs Annual Review (#764) * MQE-2218: Part 5 Docs Annual Review * Grammar tweak Co-authored-by: Donald Booth <dobooth@adobe.com> --- docs/best-practices.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/best-practices.md b/docs/best-practices.md index 0ce9448cb..a376768c2 100644 --- a/docs/best-practices.md +++ b/docs/best-practices.md @@ -37,11 +37,9 @@ We recommend to keep Action Groups having single responsibility, for example `Ad ## Contribute -Althought the Magento Core team and Contributors join forces to cover most of the features with tests, it is impossible to have this done quickly. +Although the Magento Core team and Contributors join forces to cover most of the features with tests, it is impossible to have this done quickly. If you've covered Magento Core feature with Functional Tests - you are more than welcome to contribute. -You can also help with MFTF Test Migration to get the experience and valuable feedback from other community members and maintainers. - ## Action group 1. [Action group] names should be sufficiently descriptive to inform a test writer of what the action group does and when it should be used. Add additional explanation in annotations if needed. @@ -108,7 +106,7 @@ Example: _StorefrontCreateCustomerTest.xml_. #### Action Group file name -Format: {_Admin_ or _Storefront_}{Action Group Summary}ActionGroup.xml`, where Action Group Summary describes with a few words what we can expect from it. +Format: {_Admin_ or _Storefront_}{Action Group Summary}ActionGroup.xml`, where Action Group Summary is a short description of what the action group does. Example: _AdminCreateStoreActionGroup.xml_ From a9b6bbe43ba983692b1b9ac79c58af3ddfc693c0 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Fri, 11 Oct 2019 11:52:11 -0500 Subject: [PATCH 463/888] MQE-1776: CICD System Documentation - Initial Draft --- docs/guides/cicd.md | 101 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 docs/guides/cicd.md diff --git a/docs/guides/cicd.md b/docs/guides/cicd.md new file mode 100644 index 000000000..a37392955 --- /dev/null +++ b/docs/guides/cicd.md @@ -0,0 +1,101 @@ +# How to use MFTF in CICD + +If you want to integrate MFTF tests into your CICD pipeline, then it's best to start with the conceptual flow of the pipeline code. + +## Concept + +The overall workflow that tests should follow is thus: + +* Obtain Magento instance + install pre-requisites +* Generate tests for running + * Options for single/parallel running +* Delegate and run tests + gather test run artifacts + * Re-run options +* Generate Allure report from aggregate + +### Obtain Magento instance + +To start, we need a Magento instance to operate against for generation and execution. + +``` +$ git clone https://github.com/magento/magento2 +or +$ composer create-project --repository=https://repo.magento.com/ magento/project-community-edition magento2ce +``` + +For more information on installing magento see [Install Magento using Composer]. + +After installing the Magento instance, you need to set a couple of configurations to the magento instance: + +``` +$ bin/magento config:set general/locale/timezone America/Los_Angeles +$ bin/magento config:set admin/security/admin_account_sharing 1 +$ bin/magento config:set admin/security/use_form_key 0 +$ bin/magento config:set cms/wysiwyg/enabled disabled +``` + +These help set the state for the `default` state of the Magento instance. If you are wanting to change the default state of the application (and have merged into the tests sufficiently to account for it), this is the step in which you would do it. + +#### Install allure + +This will be required to generate the report after your test runs. See [Allure] for details. + + +### Generate tests + +#### Single execution + +Simply generate tests based on what you want to run: + +``` +$ vendor/bin/mftf generate:tests +``` + +This will generate all tests, and a single manifest file under `dev/tests/acceptance/tests/functional/Magento/FunctionalTest/_generated/testManifest.txt` + +#### Parallel execution + +To generate all tests for use in parallel nodes: + +``` +$ vendor/bin/mftf generate:tests --config parallel +``` + +This will generate a folder under `dev/tests/acceptance/tests/functional/Magento/FunctionalTest/_generated/groups`. This folder contains several `group#.txt` files that can be used later with the `mftf run:manifest` command. + +### Delegate and run tests + +#### Single execution +If you are running on a single node, this step is simply to call: + +``` +$ vendor/bin/mftf run:manifest dev/tests/acceptance/tests/functional/Magento/FunctionalTest/_generated/testManifest.txt +``` + +#### Parallel execution +To run MFTF tests in parallel, you will need to clone the contents of the current node and duplicate them depending on how many nodes you have available for use. + +* Clone contents of current node as a baseline +* For each `groups/group#.txt` file: + * Set a node's contents to the baseline + * Run `vendor/bin/mftf run:manifest <current_group.txt>` + * Gather artifacts from `dev/tests/acceptance/tests/_output` from current node to master + +#### Rerun options +In either single or parallel execution, to re-run failed tests simply add a `run:failed` command after executing a manifest: + +``` +$ vendor/bin/mftf run:failed +``` + +### Generate Allure report + +In the master node, simply generate using your `<path_to_results>` into a desired output path + +``` +$ allure generate <path_to_results> -c -o <path_to_output> +``` + +<!-- Link definitions --> +[Install Magento using Composer]: https://devdocs.magento.com/guides/v2.3/install-gde/composer.html +[Allure]: https://docs.qameta.io/allure/ From 4e94af42edac1f22bb4ac96e91c3cd109151b393 Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Tue, 29 Oct 2019 11:09:02 -0500 Subject: [PATCH 464/888] Editorial pass --- docs/guides/cicd.md | 99 ++++++++++++++++++++++++--------------------- 1 file changed, 53 insertions(+), 46 deletions(-) diff --git a/docs/guides/cicd.md b/docs/guides/cicd.md index a37392955..425f743bf 100644 --- a/docs/guides/cicd.md +++ b/docs/guides/cicd.md @@ -1,99 +1,106 @@ # How to use MFTF in CICD -If you want to integrate MFTF tests into your CICD pipeline, then it's best to start with the conceptual flow of the pipeline code. +To integrate MFTF tests into your CICD pipeline, then it is best to start with the conceptual flow of the pipeline code. ## Concept -The overall workflow that tests should follow is thus: +The overall workflow that tests should follow is: -* Obtain Magento instance + install pre-requisites -* Generate tests for running - * Options for single/parallel running -* Delegate and run tests + gather test run artifacts - * Re-run options -* Generate Allure report from aggregate +- Obtain a Magento instance + install pre-requisites. +- Generate the tests. + - Set options for single or parallel running. +- Delegate and run tests and gather test-run artifacts. + - Re-run options. +- Generate the Allure reports from results. -### Obtain Magento instance +## Obtain a Magento instance -To start, we need a Magento instance to operate against for generation and execution. +To start, we need a Magento instance to operate against for test generation and execution. +```bash +git clone https://github.com/magento/magento2 ``` -$ git clone https://github.com/magento/magento2 + or -$ composer create-project --repository=https://repo.magento.com/ magento/project-community-edition magento2ce + +```bash +composer create-project --repository=https://repo.magento.com/ magento/project-community-edition magento2ce ``` For more information on installing magento see [Install Magento using Composer]. After installing the Magento instance, you need to set a couple of configurations to the magento instance: -``` -$ bin/magento config:set general/locale/timezone America/Los_Angeles -$ bin/magento config:set admin/security/admin_account_sharing 1 -$ bin/magento config:set admin/security/use_form_key 0 -$ bin/magento config:set cms/wysiwyg/enabled disabled +```bash +bin/magento config:set general/locale/timezone America/Los_Angeles +bin/magento config:set admin/security/admin_account_sharing 1 +bin/magento config:set admin/security/use_form_key 0 +bin/magento config:set cms/wysiwyg/enabled disabled ``` -These help set the state for the `default` state of the Magento instance. If you are wanting to change the default state of the application (and have merged into the tests sufficiently to account for it), this is the step in which you would do it. +These help set the `default` state of the Magento instance. If you wish to change the default state of the application (and have updated your tests sufficiently to account for it), this is the step in which you would do it. -#### Install allure +## Install allure This will be required to generate the report after your test runs. See [Allure] for details. +## Generate tests -### Generate tests - -#### Single execution +### Single execution -Simply generate tests based on what you want to run: +Generate tests based on what you want to run: -``` -$ vendor/bin/mftf generate:tests +```bash +vendor/bin/mftf generate:tests ``` -This will generate all tests, and a single manifest file under `dev/tests/acceptance/tests/functional/Magento/FunctionalTest/_generated/testManifest.txt` +This will generate all tests and a single manifest file under `dev/tests/acceptance/tests/functional/Magento/FunctionalTest/_generated/testManifest.txt` -#### Parallel execution +### Parallel execution To generate all tests for use in parallel nodes: -``` -$ vendor/bin/mftf generate:tests --config parallel +```bash +vendor/bin/mftf generate:tests --config parallel ``` This will generate a folder under `dev/tests/acceptance/tests/functional/Magento/FunctionalTest/_generated/groups`. This folder contains several `group#.txt` files that can be used later with the `mftf run:manifest` command. -### Delegate and run tests +## Delegate and run tests -#### Single execution -If you are running on a single node, this step is simply to call: +### Single execution +If you are running on a single node, call: + +```bash +vendor/bin/mftf run:manifest dev/tests/acceptance/tests/functional/Magento/FunctionalTest/_generated/testManifest.txt ``` -$ vendor/bin/mftf run:manifest dev/tests/acceptance/tests/functional/Magento/FunctionalTest/_generated/testManifest.txt -``` -#### Parallel execution -To run MFTF tests in parallel, you will need to clone the contents of the current node and duplicate them depending on how many nodes you have available for use. +### Parallel execution + +To run MFTF tests in parallel, clone the contents of the current node and duplicate them depending on how many nodes you have. + +- Clone contents of current node as a baseline. +- For each `groups/group#.txt` file: -* Clone contents of current node as a baseline -* For each `groups/group#.txt` file: - * Set a node's contents to the baseline - * Run `vendor/bin/mftf run:manifest <current_group.txt>` - * Gather artifacts from `dev/tests/acceptance/tests/_output` from current node to master + - Set a node's contents to the baseline. + - Run `vendor/bin/mftf run:manifest <current_group.txt>`. + - Gather artifacts from `dev/tests/acceptance/tests/_output` from current node to master. #### Rerun options -In either single or parallel execution, to re-run failed tests simply add a `run:failed` command after executing a manifest: -``` -$ vendor/bin/mftf run:failed +In either single or parallel execution, to re-run failed tests simply add the `run:failed` command after executing a manifest: + +```bash +vendor/bin/mftf run:failed ``` ### Generate Allure report In the master node, simply generate using your `<path_to_results>` into a desired output path -``` -$ allure generate <path_to_results> -c -o <path_to_output> +```bash +allure generate <path_to_results> -c -o <path_to_output> ``` <!-- Link definitions --> From 66ff24dc36e85b6164a2679ff77c1a005211ee50 Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Tue, 29 Oct 2019 11:10:29 -0500 Subject: [PATCH 465/888] Fixed links --- docs/guides/cicd.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guides/cicd.md b/docs/guides/cicd.md index 425f743bf..de54080ad 100644 --- a/docs/guides/cicd.md +++ b/docs/guides/cicd.md @@ -27,7 +27,7 @@ or composer create-project --repository=https://repo.magento.com/ magento/project-community-edition magento2ce ``` -For more information on installing magento see [Install Magento using Composer]. +For more information on installing magento see [Install Magento using Composer][]. After installing the Magento instance, you need to set a couple of configurations to the magento instance: @@ -42,7 +42,7 @@ These help set the `default` state of the Magento instance. If you wish to chang ## Install allure -This will be required to generate the report after your test runs. See [Allure] for details. +This will be required to generate the report after your test runs. See [Allure][] for details. ## Generate tests From 87f246a088aa7f1850c05a2b9cadd583b1457ec9 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Thu, 23 Jul 2020 16:41:05 -0500 Subject: [PATCH 466/888] MQE-2223: Part 7 Docs Review "MFTF Ease Of Use" PR #483 --- docs/guides/cicd.md | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/docs/guides/cicd.md b/docs/guides/cicd.md index de54080ad..689749319 100644 --- a/docs/guides/cicd.md +++ b/docs/guides/cicd.md @@ -1,6 +1,6 @@ # How to use MFTF in CICD -To integrate MFTF tests into your CICD pipeline, then it is best to start with the conceptual flow of the pipeline code. +To integrate MFTF tests into your CICD pipeline, it is best to start with the conceptual flow of the pipeline code. ## Concept @@ -40,6 +40,8 @@ bin/magento config:set cms/wysiwyg/enabled disabled These help set the `default` state of the Magento instance. If you wish to change the default state of the application (and have updated your tests sufficiently to account for it), this is the step in which you would do it. +If your magento instance has Two-Factor Authentication enabled, see [Configure 2FA][] to configure MFTF tests. + ## Install allure This will be required to generate the report after your test runs. See [Allure][] for details. @@ -54,7 +56,7 @@ Generate tests based on what you want to run: vendor/bin/mftf generate:tests ``` -This will generate all tests and a single manifest file under `dev/tests/acceptance/tests/functional/Magento/FunctionalTest/_generated/testManifest.txt` +This will generate all tests and a single manifest file under `dev/tests/acceptance/tests/functional/Magento/_generated/testManifest.txt` ### Parallel execution @@ -64,7 +66,7 @@ To generate all tests for use in parallel nodes: vendor/bin/mftf generate:tests --config parallel ``` -This will generate a folder under `dev/tests/acceptance/tests/functional/Magento/FunctionalTest/_generated/groups`. This folder contains several `group#.txt` files that can be used later with the `mftf run:manifest` command. +This will generate a folder under `dev/tests/acceptance/tests/functional/Magento/_generated/groups`. This folder contains several `group#.txt` files that can be used later with the `mftf run:manifest` command. ## Delegate and run tests @@ -73,21 +75,24 @@ This will generate a folder under `dev/tests/acceptance/tests/functional/Magento If you are running on a single node, call: ```bash -vendor/bin/mftf run:manifest dev/tests/acceptance/tests/functional/Magento/FunctionalTest/_generated/testManifest.txt +vendor/bin/mftf run:manifest dev/tests/acceptance/tests/functional/Magento/_generated/testManifest.txt ``` ### Parallel execution -To run MFTF tests in parallel, clone the contents of the current node and duplicate them depending on how many nodes you have. +You can optimize your pipeline by running tests in parallel across multiple nodes. + +Tests can be split up into roughly equal running groups using `--config parallel`. + +You don't want perform installation on each node again and build it. So, to save time, stash pre-made artifacts from earlier steps and un-stash on the nodes. -- Clone contents of current node as a baseline. -- For each `groups/group#.txt` file: +The groups can be then distributed on each of the nodes and run separately in an isolated environment. - - Set a node's contents to the baseline. - - Run `vendor/bin/mftf run:manifest <current_group.txt>`. - - Gather artifacts from `dev/tests/acceptance/tests/_output` from current node to master. + - Stash artifacts from main node and un-stash on current node. + - Run `vendor/bin/mftf run:manifest <current_group.txt>` on current node. + - Gather artifacts from `dev/tests/acceptance/tests/_output` from current node to main node. -#### Rerun options +### Rerun options In either single or parallel execution, to re-run failed tests simply add the `run:failed` command after executing a manifest: @@ -97,12 +102,13 @@ vendor/bin/mftf run:failed ### Generate Allure report -In the master node, simply generate using your `<path_to_results>` into a desired output path +In the main node, simply generate using your `<path_to_results>` into a desired output path ```bash allure generate <path_to_results> -c -o <path_to_output> ``` <!-- Link definitions --> -[Install Magento using Composer]: https://devdocs.magento.com/guides/v2.3/install-gde/composer.html +[Install Magento using Composer]: https://devdocs.magento.com/guides/v2.4/install-gde/composer.html +[Configure 2FA]: ../configure-2fa.md [Allure]: https://docs.qameta.io/allure/ From cf297c44529976818aa9dac9d46ac5b140159b28 Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Thu, 23 Jul 2020 17:10:55 -0500 Subject: [PATCH 467/888] Grammar and formatting --- docs/guides/cicd.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/guides/cicd.md b/docs/guides/cicd.md index 689749319..80cf134d8 100644 --- a/docs/guides/cicd.md +++ b/docs/guides/cicd.md @@ -11,7 +11,7 @@ The overall workflow that tests should follow is: - Set options for single or parallel running. - Delegate and run tests and gather test-run artifacts. - Re-run options. -- Generate the Allure reports from results. +- Generate the Allure reports from the results. ## Obtain a Magento instance @@ -29,7 +29,7 @@ composer create-project --repository=https://repo.magento.com/ magento/project-c For more information on installing magento see [Install Magento using Composer][]. -After installing the Magento instance, you need to set a couple of configurations to the magento instance: +After installing the Magento instance, set a couple of configurations to the Magento instance: ```bash bin/magento config:set general/locale/timezone America/Los_Angeles @@ -38,13 +38,13 @@ bin/magento config:set admin/security/use_form_key 0 bin/magento config:set cms/wysiwyg/enabled disabled ``` -These help set the `default` state of the Magento instance. If you wish to change the default state of the application (and have updated your tests sufficiently to account for it), this is the step in which you would do it. +These set the default state of the Magento instance. If you wish to change the default state of the application (and have updated your tests sufficiently to account for it), this is the step to do it. If your magento instance has Two-Factor Authentication enabled, see [Configure 2FA][] to configure MFTF tests. -## Install allure +## Install Allure -This will be required to generate the report after your test runs. See [Allure][] for details. +This is required for generating the report after your test runs. See [Allure][] for details. ## Generate tests @@ -56,7 +56,7 @@ Generate tests based on what you want to run: vendor/bin/mftf generate:tests ``` -This will generate all tests and a single manifest file under `dev/tests/acceptance/tests/functional/Magento/_generated/testManifest.txt` +This will generate all tests and a single manifest file under `dev/tests/acceptance/tests/functional/Magento/_generated/testManifest.txt`. ### Parallel execution @@ -66,7 +66,7 @@ To generate all tests for use in parallel nodes: vendor/bin/mftf generate:tests --config parallel ``` -This will generate a folder under `dev/tests/acceptance/tests/functional/Magento/_generated/groups`. This folder contains several `group#.txt` files that can be used later with the `mftf run:manifest` command. +This generates a folder under `dev/tests/acceptance/tests/functional/Magento/_generated/groups`. This folder contains several `group#.txt` files that can be used later with the `mftf run:manifest` command. ## Delegate and run tests @@ -84,17 +84,17 @@ You can optimize your pipeline by running tests in parallel across multiple node Tests can be split up into roughly equal running groups using `--config parallel`. -You don't want perform installation on each node again and build it. So, to save time, stash pre-made artifacts from earlier steps and un-stash on the nodes. +You do not want to perform installations on each node again and build it. So, to save time, stash pre-made artifacts from earlier steps and un-stash on the nodes. The groups can be then distributed on each of the nodes and run separately in an isolated environment. - - Stash artifacts from main node and un-stash on current node. - - Run `vendor/bin/mftf run:manifest <current_group.txt>` on current node. - - Gather artifacts from `dev/tests/acceptance/tests/_output` from current node to main node. +- Stash artifacts from main node and un-stash on current node. +- Run `vendor/bin/mftf run:manifest <current_group.txt>` on current node. +- Gather artifacts from `dev/tests/acceptance/tests/_output` from current node to main node. ### Rerun options -In either single or parallel execution, to re-run failed tests simply add the `run:failed` command after executing a manifest: +In either single or parallel execution, to re-run failed tests, simply add the `run:failed` command after executing a manifest: ```bash vendor/bin/mftf run:failed @@ -102,7 +102,7 @@ vendor/bin/mftf run:failed ### Generate Allure report -In the main node, simply generate using your `<path_to_results>` into a desired output path +In the main node, generate reports using your `<path_to_results>` into a desired output path: ```bash allure generate <path_to_results> -c -o <path_to_output> From eda8252c2a34907b3cfbd154247f749f1d24320f Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Fri, 24 Jul 2020 08:12:19 -0500 Subject: [PATCH 468/888] ME-2217: Part 4 Docs Annual Review (#763) --- docs/test/actions.md | 6 +++--- docs/test/annotations.md | 2 +- docs/versioning.md | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/test/actions.md b/docs/test/actions.md index 1d2f83802..9a51106de 100644 --- a/docs/test/actions.md +++ b/docs/test/actions.md @@ -95,7 +95,7 @@ Here, `url` contains a pointer to a `url` attribute of the `StorefrontCustomerSi ### 2. Enter a customer's email {#example-step2} ```xml -<fillField userInput="$$customer.email$$" selector="{{StorefrontCustomerSignInFormSection.emailField}}" stepKey="fillEmail"/> +<fillField userInput="$customer.email$" selector="{{StorefrontCustomerSignInFormSection.emailField}}" stepKey="fillEmail"/> ``` [`<fillField>`](#fillfield) fills a text field with the given string. @@ -122,7 +122,7 @@ This section is declared in `.../Customer/Section/StorefrontCustomerSignInFormSe ### 3. Enter a customer's password {#example-step3} ```xml -<fillField userInput="$$customer.password$$" selector="{{StorefrontCustomerSignInFormSection.passwordField}}" stepKey="fillPassword"/> +<fillField userInput="$customer.password$" selector="{{StorefrontCustomerSignInFormSection.passwordField}}" stepKey="fillPassword"/> ``` This `<action>` is very similar to the `<action>` in a previous step. @@ -218,7 +218,7 @@ Attribute|Type|Use|Description ```xml <!-- Open the `(baseURL)/admin` page. --> -<amOnPage url="/admin" stepKey="goToLogoutPage"/> +<amOnPage url="{{AdminLogoutPage.url}}" stepKey="goToLogoutPage"/> ``` ### amOnSubdomain diff --git a/docs/test/annotations.md b/docs/test/annotations.md index 4e9194bb0..8fdcd2240 100644 --- a/docs/test/annotations.md +++ b/docs/test/annotations.md @@ -112,7 +112,7 @@ Attribute|Type|Use ### severity -The `<return>` element is an implementation of a [`@Severity`] Allure tag; Metadata for report. +The `<severity>` element is an implementation of a [`@Severity`] Allure tag; Metadata for report. Attribute|Type|Use|Acceptable values ---|---|---|--- diff --git a/docs/versioning.md b/docs/versioning.md index 15b98f743..3cb51e405 100644 --- a/docs/versioning.md +++ b/docs/versioning.md @@ -61,6 +61,8 @@ This table lists the version of the MFTF that was released with a particular ver |Magento version| MFTF version| |--- |--- | +| 2.4.0 | 3.0.0 | +| 2.3.5 | 2.6.4 | | 2.3.4 | 2.5.3 | | 2.3.3 | 2.4.5 | | 2.3.2 | 2.3.14 | From 7a21f39bc8ece5842509dda3586d649aaf89d45e Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Fri, 24 Jul 2020 08:13:44 -0500 Subject: [PATCH 469/888] MQE-2219: Part 6 Docs Annual Review (#767) * MQE-2219: Part 6 Docs Annual Review * MQE-2219: Part 6 Docs Annual Review * MQE-2219: Part 6 Docs Annual Review --- docs/section.md | 24 ++++++++++++------------ docs/section/locator-functions.md | 2 +- docs/suite.md | 10 +++++----- docs/update.md | 16 +++++++++++++--- 4 files changed, 31 insertions(+), 21 deletions(-) diff --git a/docs/section.md b/docs/section.md index 421c98fdd..68a6507af 100644 --- a/docs/section.md +++ b/docs/section.md @@ -58,11 +58,11 @@ Example (`.../Catalog/Section/AdminCategorySidebarActionSection.xml` file): <?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="AdminCategorySidebarActionSection"> - <element name="addRootCategoryButton" type="button" selector="#add_root_category_button" timeout="30"/> - <element name="addSubcategoryButton" type="button" selector="#add_subcategory_button" timeout="30"/> - </section> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminCategorySidebarActionSection"> + <element name="AddRootCategoryButton" type="button" selector="#add_root_category_button" timeout="30"/> + <element name="AddSubcategoryButton" type="button" selector="#add_subcategory_button" timeout="30"/> + </section> </sections> ``` @@ -70,14 +70,14 @@ This example uses a `AdminCategorySidebarActionSection` section. All sections wi The `AdminCategorySidebarActionSection` section declares two buttons: -- `addRootCategoryButton` - button with a `#add_root_category_button` locator on the parent web page -- `addSubcategoryButton` - button with a `#add_subcategory_button` locator on the parent web page +- `AddRootCategoryButton` - button with a `#add_root_category_button` locator on the parent web page +- `AddSubcategoryButton` - button with a `#add_subcategory_button` locator on the parent web page The following is an example of a call in test: ```xml <!-- Click on the button with locator "#add_subcategory_button" on the web page--> -<click selector="{{AdminCategorySidebarActionSection.addSubcategoryButton}}" stepKey="clickOnAddSubCategory"/> +<click selector="{{AdminCategorySidebarActionSection.AddSubcategoryButton}}" stepKey="clickOnAddSubCategory"/> ``` ## Elements reference @@ -116,21 +116,21 @@ The most usual use case is a test step with a button click action. The section element code declaration containing the timeout attribute: -> StorefrontSigninSection.xml +> StorefrontCustomerSignInPopupFormSection.xml ```xml ... -<element name="signIn" type="button" selector="#signIn" timeout="30"/> +<element name="signIn" type="button" selector="#send2" timeout="30"/> ... ``` The test step that covers the use case: -> StorefrontSigninTest.xml +> CaptchaWithDisabledGuestCheckoutTest.xml ```xml ... -<click selector="{{StorefrontSigninSection.signIn}}" ../> +<click selector="{{StorefrontCustomerSignInPopupFormSection.signIn}}" stepKey="clickSignIn"/> ... ``` diff --git a/docs/section/locator-functions.md b/docs/section/locator-functions.md index 1e3dffd24..d2dc9924c 100644 --- a/docs/section/locator-functions.md +++ b/docs/section/locator-functions.md @@ -31,7 +31,7 @@ An element cannot, however, have both a `selector` and a `locatorFunction`. Given the above element definitions, you call the elements in a test just like any other element. No special reference is required, as you are still just referring to an `element` inside a `section`: ```xml -<test name="LocatorFuctionTest"> +<test name="LocatorFunctionTest"> <click selector="{{LocatorFunctionSection.simpleLocator}}" stepKey="SimpleLocator"/> <click selector="{{LocatorFunctionSection.simpleLocatorTwoParam('string1', 'string2')}}" stepKey="TwoParamLiteral"/> </test> diff --git a/docs/suite.md b/docs/suite.md index 7917cd347..9f623f276 100644 --- a/docs/suite.md +++ b/docs/suite.md @@ -6,8 +6,8 @@ You can form suites using separate tests, groups, and modules. Each suite must be defined in the `<VendorName>/<ModuleName>/Test/Mftf/Suite` directory. -The tests for each suite are generated in a separate directory under `<magento 2 root>/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/_generated/`. -All tests that are not within a suite are generated in the _default_ suite at `.../Magento/FunctionalTest/_generated/default/`. +The tests for each suite are generated in a separate directory under `<magento 2 root>/dev/tests/acceptance/tests/functional/Magento/_generated/`. +All tests that are not within a suite are generated in the _default_ suite at `<magento 2 root>/dev/tests/acceptance/tests/functional/Magento/_generated/default`. <div class="bs-callout bs-callout-info"> If a test is generated into at least one custom suite, it will not appear in the _default_ suite. @@ -61,7 +61,7 @@ The code lives in one place and executes once per suite. - Set up preconditions and postconditions using [actions] in [`<before>`] and [`<after>`] correspondingly, just similar to use in a [test]. - Clean up after suites just like after tests. - The MFTF enforces the presence of both `<before>` and `<after>` if either is present. +MFTF enforces the presence of both `<before>` and `<after>` if either is present. ## Test writing @@ -142,7 +142,7 @@ This suite includes all tests that contain the `<group value="WYSIWYG"/>` annota ### Execute Magento CLI commands in suite conditions ```xml -<suites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Suite/etc/suiteSchema.xsd"> +<suites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Suite/etc/suiteSchema.xsd"> <suite name="Cache"> <before> <magentoCLI stepKey="disableCache" command="cache:disable"/> @@ -170,7 +170,7 @@ The suite includes a specific test `SomeCacheRelatedTest` and every `<test>` tha ### Change Magento configurations in suite conditions ```xml -<suites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Suite/etc/suiteSchema.xsd"> +<suites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Suite/etc/suiteSchema.xsd"> <suite name="PaypalConfiguration"> <before> <createData entity="SamplePaypalConfig" stepKey="createSamplePaypalConfig"/> diff --git a/docs/update.md b/docs/update.md index ebd096158..dc5e7fbc8 100644 --- a/docs/update.md +++ b/docs/update.md @@ -1,7 +1,9 @@ # Update the Magento Functional Testing Framework <div class="bs-callout bs-callout-info" markdown="1"> -Both Magento `2.2` and `2.3` supports MFTF `2.5.3` ([Find your version][] of the MFTF). +[Find your version] of MFTF. +The latest Magento 2.4.x release supports MFTF 3.x. +The latest Magento 2.3.x release supports MFTF 2.6.x. </div> Tests and the Framework itself are stored in different repositories. @@ -26,16 +28,24 @@ Takes place when **second** digit of version number changes. 1. Check details about backward incompatible changes in the [Changelog][] and update your new or customized tests. 1. Perform all the actions provided for [Patch Version Update][] 1. When updating from versions below `2.5.0`, verify [WYSIWYG settings][] -1. You may need to run the `upgrade:tests` using `vendor/bin/mftf upgrade:tests app` +1. You may need to run the `upgrade:tests` using `vendor/bin/mftf upgrade:tests` + +## Major version update + +Takes place when **first** digit of version number changes. + +1. Check detailed explanation and instructions on major version upgrade in [Backward Incompatible Changes][] and upgrade your new or customized tests. +1. Perform all the actions provided for [Minor Version Update][] ## After updating 1. It is a good idea to regenerate your IDE Schema Definition catalog with `vendor/bin/mftf generate:urn-catalog .idea/` -1. Update your tests, including data, metadata and other resoruces. Check if they contain tags that are unsupported in the newer version. +1. Update your tests, including data, metadata and other resources. Check if they contain tags that are unsupported in the newer version. 1. Remove the references to resources (ActionGroups, Sections, Tests) marked as deprecated. <!-- Link Definitions --> [Changelog]: https://github.com/magento/magento2-functional-testing-framework/blob/master/CHANGELOG.md +[Backward Incompatible Changes]: backward-incompatible-changes.md [WYSIWYG settings]: getting-started.md#wysiwyg-settings [Security settings]: getting-started.md#security-settings [Find your version]: introduction.md#find-your-mftf-version From bd46a50414f98225c72f1c5436f227687cf3271c Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Fri, 24 Jul 2020 09:20:04 -0500 Subject: [PATCH 470/888] Remove accidental v2 directory --- v2 | 1 - 1 file changed, 1 deletion(-) delete mode 160000 v2 diff --git a/v2 b/v2 deleted file mode 160000 index 3343a82b8..000000000 --- a/v2 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3343a82b84e5b25d30e6e39fb3d1aa0d8dc70634 From 995a88c225a37df841d92ccd27474c72c088d746 Mon Sep 17 00:00:00 2001 From: Alastair Mucklow <amucklow@strangerpixel.com> Date: Wed, 8 Jul 2020 11:45:40 +0100 Subject: [PATCH 471/888] Replace broken devhub.io/zh paths with github.com paths --- docs/test/annotations.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/test/annotations.md b/docs/test/annotations.md index 8fdcd2240..055ca9450 100644 --- a/docs/test/annotations.md +++ b/docs/test/annotations.md @@ -213,14 +213,14 @@ Attribute|Type|Use <!-- Link definitions --> -[`@Description`]: https://devhub.io/zh/repos/allure-framework-allure-phpunit#extended-test-class-or-test-method-description -[`@Features`]: https://devhub.io/zh/repos/allure-framework-allure-phpunit#map-test-classes-and-test-methods-to-features-and-stories +[`@Description`]: https://github.com/allure-framework/allure-phpunit#extended-test-class-or-test-method-description +[`@Features`]: https://github.com/allure-framework/allure-phpunit#map-test-classes-and-test-methods-to-features-and-stories [`@group`]: http://codeception.com/docs/07-AdvancedUsage#Groups [`@return`]: http://codeception.com/docs/07-AdvancedUsage#Examples -[`@Severity`]: https://devhub.io/zh/repos/allure-framework-allure-phpunit#set-test-severity -[`@Stories`]: https://devhub.io/zh/repos/allure-framework-allure-phpunit#map-test-classes-and-test-methods-to-features-and-stories +[`@Severity`]: https://github.com/allure-framework/allure-phpunit#set-test-severity +[`@Stories`]: https://github.com/allure-framework/allure-phpunit#map-test-classes-and-test-methods-to-features-and-stories [`@TestCaseId`]: https://github.com/allure-framework/allure1/wiki/Test-Case-ID -[`@Title`]: https://devhub.io/zh/repos/allure-framework-allure-phpunit#human-readable-test-class-or-test-method-title +[`@Title`]: https://github.com/allure-framework/allure-phpunit#human-readable-test-class-or-test-method-title [description]: #description [features]: #features [group]: #group From 977b1ef43ed7be91fc29ca9ef89f11d756bcff28 Mon Sep 17 00:00:00 2001 From: Alastair Mucklow <amucklow@strangerpixel.com> Date: Wed, 8 Jul 2020 12:22:27 +0100 Subject: [PATCH 472/888] Make intro text clearer and more accurate --- docs/test/annotations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/test/annotations.md b/docs/test/annotations.md index 055ca9450..d61565aec 100644 --- a/docs/test/annotations.md +++ b/docs/test/annotations.md @@ -112,7 +112,7 @@ Attribute|Type|Use ### severity -The `<severity>` element is an implementation of a [`@Severity`] Allure tag; Metadata for report. +The `<severity>` element is an implementation of the [`@Severity`] Allure annotation, which is used to prioritise test methods by severity. Attribute|Type|Use|Acceptable values ---|---|---|--- From 8263ade22520d71eda59694ab11a04b604c9d755 Mon Sep 17 00:00:00 2001 From: Alastair Mucklow <amucklow@strangerpixel.com> Date: Wed, 8 Jul 2020 12:22:42 +0100 Subject: [PATCH 473/888] Fix order (Blocker is the most severe) --- docs/test/annotations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/test/annotations.md b/docs/test/annotations.md index d61565aec..69c75a2d0 100644 --- a/docs/test/annotations.md +++ b/docs/test/annotations.md @@ -116,7 +116,7 @@ The `<severity>` element is an implementation of the [`@Severity`] Allure annota Attribute|Type|Use|Acceptable values ---|---|---|--- -`value`|string|required|`MINOR`, `AVERAGE`, `MAJOR`, `BLOCKER`, `CRITICAL` +`value`|string|required|`MINOR`, `AVERAGE`, `MAJOR`, `CRITICAL`, `BLOCKER` #### Example From b871ae5bf1a7a94dd13132bdf675a38587ef08c2 Mon Sep 17 00:00:00 2001 From: Alastair Mucklow <amucklow@strangerpixel.com> Date: Wed, 8 Jul 2020 12:23:14 +0100 Subject: [PATCH 474/888] Add usage guidelines table outlining the difference between levels --- docs/test/annotations.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/test/annotations.md b/docs/test/annotations.md index 69c75a2d0..1e2e50f58 100644 --- a/docs/test/annotations.md +++ b/docs/test/annotations.md @@ -124,6 +124,16 @@ Attribute|Type|Use|Acceptable values <severity value="CRITICAL"/> ``` +#### Usage guidelines + +Severity Level|Usage +---|--- +`BLOCKER`|If this test fails, the customer is completely blocked from purchasing a product. +`CRITICAL`|This is a serious problem impacting conversion, or affecting the operation of the store. +`MAJOR`|Store conversion rate is reduced owing to this issue. For example, something is broken or missing that impacts checkout frequency or cart volume. +`AVERAGE`|A fault on the storefront that can negatively impact conversion rate (like UI errors or omissions), or problems with Magento admin functionality. +`MINOR`|An application or configuration fault that has no impact on conversion rate. + ### skip Use the `<skip>` element to skip a test. From 50249bc75cc6a72cef12997124c3420ab0033878 Mon Sep 17 00:00:00 2001 From: Alastair Mucklow <amucklow@strangerpixel.com> Date: Wed, 8 Jul 2020 12:34:24 +0100 Subject: [PATCH 475/888] Trim text --- docs/test/annotations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/test/annotations.md b/docs/test/annotations.md index 1e2e50f58..79cc00e80 100644 --- a/docs/test/annotations.md +++ b/docs/test/annotations.md @@ -112,7 +112,7 @@ Attribute|Type|Use ### severity -The `<severity>` element is an implementation of the [`@Severity`] Allure annotation, which is used to prioritise test methods by severity. +The `<severity>` element is an implementation of the [`@Severity`] Allure annotation, which is used to prioritise tests by severity. Attribute|Type|Use|Acceptable values ---|---|---|--- From 27dd329fddf69f0c2b061c33d6d6fa0f47efdd23 Mon Sep 17 00:00:00 2001 From: Ajith <ajithkumar.maragathavel@ziffity.com> Date: Sun, 19 Apr 2020 14:57:43 +0530 Subject: [PATCH 476/888] command added to modifiy the web server rewrites config --- docs/getting-started.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/getting-started.md b/docs/getting-started.md index af4f8d62e..c2d10c0cd 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -121,6 +121,18 @@ MFTF does not support executing CLI commands if your web server points to `<MAGE If the Nginx Web server is used on your development environment, then **Use Web Server Rewrites** setting in **Stores** > Settings > **Configuration** > **General** > **Web** > **Search Engine Optimization** must be set to **Yes**. +or via command line: + +```bash +bin/magento config:set web/seo/use_rewrites 1 +``` + +Clean the cache after changing the configuration values: + +```bash +bin/magento cache:clean config full_page +``` + To be able to run Magento command line commands in tests, add the following location block to the Nginx configuration file in the Magento root directory: ```conf From a1e81791f0e108e653d801e61c628b7200b298c1 Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Fri, 24 Apr 2020 09:30:48 -0500 Subject: [PATCH 477/888] Grammar --- docs/getting-started.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index c2d10c0cd..1c8200e3b 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -121,13 +121,13 @@ MFTF does not support executing CLI commands if your web server points to `<MAGE If the Nginx Web server is used on your development environment, then **Use Web Server Rewrites** setting in **Stores** > Settings > **Configuration** > **General** > **Web** > **Search Engine Optimization** must be set to **Yes**. -or via command line: +Or via command line: ```bash bin/magento config:set web/seo/use_rewrites 1 ``` -Clean the cache after changing the configuration values: +You must clean the cache after changing the configuration values: ```bash bin/magento cache:clean config full_page From ebd9a94d8469461d76c66032cfe2e3f10d46d15c Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@Donalds-MacBook-Pro.local> Date: Fri, 24 Jul 2020 14:46:36 -0500 Subject: [PATCH 478/888] Link fix --- docs/introduction.md | 7 ++++--- v2/docs/introduction.html | 0 2 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 v2/docs/introduction.html diff --git a/docs/introduction.md b/docs/introduction.md index 5a7869381..e5ce67d35 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -1,8 +1,9 @@ # Introduction to the Magento Functional Testing Framework <div class="bs-callout bs-callout-info" markdown="1"> -These are the docs for the latest MFTF release. -To find older documentation, please refer to the [docs folder] of your desired release in Github. +This documentation is for MFTF 3.0, which was release in conjunction with Magento 2.4. +MFTF 3.0 is a major update and introduces many new changes and fixes. +MFTF 2 docs can be found [here][]. </div> [Find your version] of MFTF. @@ -159,4 +160,4 @@ Follow the [MFTF project] and [contribute on Github]. [contribute on Github]: https://github.com/magento/magento2-functional-testing-framework/blob/master/.github/CONTRIBUTING.md [MFTF project]: https://github.com/magento/magento2-functional-testing-framework [Find your version]: #find-your-mftf-version -[docs folder]: https://github.com/magento/magento2-functional-testing-framework/tree/master/docs +[here]: ../v2/docs/introduction.html diff --git a/v2/docs/introduction.html b/v2/docs/introduction.html new file mode 100644 index 000000000..e69de29bb From f7e34266a1b7f242a64dea1b318bb3abcb0f6695 Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Fri, 24 Jul 2020 14:57:24 -0500 Subject: [PATCH 479/888] Remove accidental v2 folder --- v2/docs/introduction.html | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 v2/docs/introduction.html diff --git a/v2/docs/introduction.html b/v2/docs/introduction.html deleted file mode 100644 index e69de29bb..000000000 From 332da12b7f34a0ac7580c77807718abde5e3449c Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@Donalds-MacBook-Pro.local> Date: Fri, 24 Jul 2020 15:02:59 -0500 Subject: [PATCH 480/888] Remove stray file. --- v2/docs/introduction.html | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 v2/docs/introduction.html diff --git a/v2/docs/introduction.html b/v2/docs/introduction.html deleted file mode 100644 index e69de29bb..000000000 From 8c73f2cf767e2f1326d199927e5bd2afe4ff0de3 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 28 Jul 2020 13:24:57 -0500 Subject: [PATCH 481/888] MQE-2231: Adobe open source repository standards compliance --- .github/CONTRIBUTING.md | 13 ++++++-- CODE_OF_CONDUCT.md | 74 +++++++++++++++++++++++++++++++++++++++++ README.md | 10 +++--- 3 files changed, 90 insertions(+), 7 deletions(-) create mode 100644 CODE_OF_CONDUCT.md diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 271b66244..11334ae73 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -24,8 +24,16 @@ If there is no response from the contributor for two weeks, the issue is closed. Often when the MFTF team works on reviewing the suggested changes, we will add a label to the issue to indicate to our internal team certain information, like status or who is working the issue. If you’re ever curious what the different labels mean, see the [table][labels] below for an explanation of each one. -Refer to [Magento Contributor Agreement] for detailed information about the License Agreement. -All contributors are required to submit a click-through form to agree to the terms. +## Code Of Conduct + +This project adheres to the Adobe [Code Of Conduct](../CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. +Please report unacceptable behavior to [Grp-opensourceoffice@adobe.com](mailto:Grp-opensourceoffice@adobe.com). + +## Contributor License Agreement + +All third-party contributions to this project must be accompanied by a signed Contributor License Agreement (CLA). +This gives Adobe permission to redistribute your contributions as part of the project. +[Sign our CLA](https://opensource.adobe.com/cla.html). You only need to sign it once. ## Contribution requirements @@ -152,6 +160,7 @@ Label| Description **bugfix**| The issue or pull request is about fixing a bug. **enhancement**| The issue or pull request that makes the MFTF even more awesome (for example new features, optimization, refactoring, etc). + [fork]: #fork-a-repository [issue]: #report-an-issue [labels]: #read-labels diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..549b492a0 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Adobe Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language. +* Being respectful of differing viewpoints and experiences. +* Gracefully accepting constructive criticism. +* Focusing on what is best for the community. +* Showing empathy towards other community members. + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances. +* Trolling, insulting/derogatory comments, and personal or political attacks. +* Public or private harassment. +* Publishing others' private information, such as a physical or electronic + address, without explicit permission. +* Other conduct which could reasonably be considered inappropriate in a + professional setting. + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at Grp-opensourceoffice@adobe.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [https://contributor-covenant.org/version/1/4][version]. + +[homepage]: https://contributor-covenant.org +[version]: https://contributor-covenant.org/version/1/4/ \ No newline at end of file diff --git a/README.md b/README.md index fc42f0603..76bd66cc7 100755 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ These labels are applied by the MFTF development team to community contributed i To report security vulnerabilities and other security issues in the Magento software or web sites, send an email with the report at [security@magento.com][]. 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][]. +Learn more about reporting security issues [security][]. Stay up-to-date on the latest security news and patches for Magento by signing up for [Security Alert Notifications][]. @@ -66,15 +66,15 @@ Stay up-to-date on the latest security news and patches for Magento by signing u Each Magento source file included in this distribution is licensed under AGPL 3.0. -See the license [here][] or contact [license@magentocommerce.com][] for a copy. +See the license [license][] or contact [license@magentocommerce.com][] for a copy. <!-- Link Definitions --> [Getting Started]: docs/getting-started.md -[Contribution Guidelines]: https://github.com/magento/magento2-functional-testing-framework/blob/develop/.github/CONTRIBUTING.md +[Contribution Guidelines]: .github/CONTRIBUTING.md [DevDocs Contributing]: https://github.com/magento/devdocs/blob/master/.github/CONTRIBUTING.md [security@magento.com]: mailto:security@magento.com [encryption key]: https://info2.magento.com/rs/magentoenterprise/images/security_at_magento.asc -[here]: https://magento.com/security/reporting-magento-security-issue +[security]: https://magento.com/security/reporting-magento-security-issue [Security Alert Notifications]: https://magento.com/security/sign-up -[here]: LICENSE_AGPL3.txt +[license]: LICENSE_AGPL3.txt [license@magentocommerce.com]: mailto:license@magentocommerce.com From 48ebb3bd43bb905bbf685ddd303bc9ee58f69568 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 28 Jul 2020 13:24:57 -0500 Subject: [PATCH 482/888] MQE-2231: Adobe open source repository standards compliance --- .github/CONTRIBUTING.md | 13 ++++++-- CODE_OF_CONDUCT.md | 74 +++++++++++++++++++++++++++++++++++++++++ README.md | 10 +++--- 3 files changed, 90 insertions(+), 7 deletions(-) create mode 100644 CODE_OF_CONDUCT.md diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 271b66244..11334ae73 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -24,8 +24,16 @@ If there is no response from the contributor for two weeks, the issue is closed. Often when the MFTF team works on reviewing the suggested changes, we will add a label to the issue to indicate to our internal team certain information, like status or who is working the issue. If you’re ever curious what the different labels mean, see the [table][labels] below for an explanation of each one. -Refer to [Magento Contributor Agreement] for detailed information about the License Agreement. -All contributors are required to submit a click-through form to agree to the terms. +## Code Of Conduct + +This project adheres to the Adobe [Code Of Conduct](../CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. +Please report unacceptable behavior to [Grp-opensourceoffice@adobe.com](mailto:Grp-opensourceoffice@adobe.com). + +## Contributor License Agreement + +All third-party contributions to this project must be accompanied by a signed Contributor License Agreement (CLA). +This gives Adobe permission to redistribute your contributions as part of the project. +[Sign our CLA](https://opensource.adobe.com/cla.html). You only need to sign it once. ## Contribution requirements @@ -152,6 +160,7 @@ Label| Description **bugfix**| The issue or pull request is about fixing a bug. **enhancement**| The issue or pull request that makes the MFTF even more awesome (for example new features, optimization, refactoring, etc). + [fork]: #fork-a-repository [issue]: #report-an-issue [labels]: #read-labels diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..549b492a0 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Adobe Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language. +* Being respectful of differing viewpoints and experiences. +* Gracefully accepting constructive criticism. +* Focusing on what is best for the community. +* Showing empathy towards other community members. + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances. +* Trolling, insulting/derogatory comments, and personal or political attacks. +* Public or private harassment. +* Publishing others' private information, such as a physical or electronic + address, without explicit permission. +* Other conduct which could reasonably be considered inappropriate in a + professional setting. + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at Grp-opensourceoffice@adobe.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [https://contributor-covenant.org/version/1/4][version]. + +[homepage]: https://contributor-covenant.org +[version]: https://contributor-covenant.org/version/1/4/ \ No newline at end of file diff --git a/README.md b/README.md index fc42f0603..76bd66cc7 100755 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ These labels are applied by the MFTF development team to community contributed i To report security vulnerabilities and other security issues in the Magento software or web sites, send an email with the report at [security@magento.com][]. 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][]. +Learn more about reporting security issues [security][]. Stay up-to-date on the latest security news and patches for Magento by signing up for [Security Alert Notifications][]. @@ -66,15 +66,15 @@ Stay up-to-date on the latest security news and patches for Magento by signing u Each Magento source file included in this distribution is licensed under AGPL 3.0. -See the license [here][] or contact [license@magentocommerce.com][] for a copy. +See the license [license][] or contact [license@magentocommerce.com][] for a copy. <!-- Link Definitions --> [Getting Started]: docs/getting-started.md -[Contribution Guidelines]: https://github.com/magento/magento2-functional-testing-framework/blob/develop/.github/CONTRIBUTING.md +[Contribution Guidelines]: .github/CONTRIBUTING.md [DevDocs Contributing]: https://github.com/magento/devdocs/blob/master/.github/CONTRIBUTING.md [security@magento.com]: mailto:security@magento.com [encryption key]: https://info2.magento.com/rs/magentoenterprise/images/security_at_magento.asc -[here]: https://magento.com/security/reporting-magento-security-issue +[security]: https://magento.com/security/reporting-magento-security-issue [Security Alert Notifications]: https://magento.com/security/sign-up -[here]: LICENSE_AGPL3.txt +[license]: LICENSE_AGPL3.txt [license@magentocommerce.com]: mailto:license@magentocommerce.com From b8634984232a0920e0b87f5644c30463d16260fe Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 28 Jul 2020 14:00:30 -0500 Subject: [PATCH 483/888] MQE-2231: Adobe open source repository standards compliance --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 76bd66cc7..ddeacd6de 100755 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ These labels are applied by the MFTF development team to community contributed i To report security vulnerabilities and other security issues in the Magento software or web sites, send an email with the report at [security@magento.com][]. 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 [security][]. +Learn more about reporting [security issues][]. Stay up-to-date on the latest security news and patches for Magento by signing up for [Security Alert Notifications][]. @@ -66,7 +66,7 @@ Stay up-to-date on the latest security news and patches for Magento by signing u Each Magento source file included in this distribution is licensed under AGPL 3.0. -See the license [license][] or contact [license@magentocommerce.com][] for a copy. +See the [license][] or contact [license@magentocommerce.com][] for a copy. <!-- Link Definitions --> [Getting Started]: docs/getting-started.md @@ -74,7 +74,7 @@ See the license [license][] or contact [license@magentocommerce.com][] for a cop [DevDocs Contributing]: https://github.com/magento/devdocs/blob/master/.github/CONTRIBUTING.md [security@magento.com]: mailto:security@magento.com [encryption key]: https://info2.magento.com/rs/magentoenterprise/images/security_at_magento.asc -[security]: https://magento.com/security/reporting-magento-security-issue +[security issues]: https://magento.com/security/reporting-magento-security-issue [Security Alert Notifications]: https://magento.com/security/sign-up [license]: LICENSE_AGPL3.txt [license@magentocommerce.com]: mailto:license@magentocommerce.com From 13bc3175ca24ec285207ad71bf0b33c846f722a0 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 28 Jul 2020 14:02:03 -0500 Subject: [PATCH 484/888] MQE-2231: Adobe open source repository standards compliance --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ddeacd6de..07c43fff1 100755 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ These labels are applied by the MFTF development team to community contributed i To report security vulnerabilities and other security issues in the Magento software or web sites, send an email with the report at [security@magento.com][]. 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][]. +Learn more about reporting [security][] issues. Stay up-to-date on the latest security news and patches for Magento by signing up for [Security Alert Notifications][]. @@ -74,7 +74,7 @@ See the [license][] or contact [license@magentocommerce.com][] for a copy. [DevDocs Contributing]: https://github.com/magento/devdocs/blob/master/.github/CONTRIBUTING.md [security@magento.com]: mailto:security@magento.com [encryption key]: https://info2.magento.com/rs/magentoenterprise/images/security_at_magento.asc -[security issues]: https://magento.com/security/reporting-magento-security-issue +[security]: https://magento.com/security/reporting-magento-security-issue [Security Alert Notifications]: https://magento.com/security/sign-up [license]: LICENSE_AGPL3.txt [license@magentocommerce.com]: mailto:license@magentocommerce.com From 8218bc238e1f39bd70ae7f1efa89edd13026b272 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 28 Jul 2020 14:00:30 -0500 Subject: [PATCH 485/888] MQE-2231: Adobe open source repository standards compliance --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 76bd66cc7..ddeacd6de 100755 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ These labels are applied by the MFTF development team to community contributed i To report security vulnerabilities and other security issues in the Magento software or web sites, send an email with the report at [security@magento.com][]. 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 [security][]. +Learn more about reporting [security issues][]. Stay up-to-date on the latest security news and patches for Magento by signing up for [Security Alert Notifications][]. @@ -66,7 +66,7 @@ Stay up-to-date on the latest security news and patches for Magento by signing u Each Magento source file included in this distribution is licensed under AGPL 3.0. -See the license [license][] or contact [license@magentocommerce.com][] for a copy. +See the [license][] or contact [license@magentocommerce.com][] for a copy. <!-- Link Definitions --> [Getting Started]: docs/getting-started.md @@ -74,7 +74,7 @@ See the license [license][] or contact [license@magentocommerce.com][] for a cop [DevDocs Contributing]: https://github.com/magento/devdocs/blob/master/.github/CONTRIBUTING.md [security@magento.com]: mailto:security@magento.com [encryption key]: https://info2.magento.com/rs/magentoenterprise/images/security_at_magento.asc -[security]: https://magento.com/security/reporting-magento-security-issue +[security issues]: https://magento.com/security/reporting-magento-security-issue [Security Alert Notifications]: https://magento.com/security/sign-up [license]: LICENSE_AGPL3.txt [license@magentocommerce.com]: mailto:license@magentocommerce.com From b2bd6a873290ce80e96123b8531607e03b7c17ee Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 28 Jul 2020 14:02:03 -0500 Subject: [PATCH 486/888] MQE-2231: Adobe open source repository standards compliance --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ddeacd6de..07c43fff1 100755 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ These labels are applied by the MFTF development team to community contributed i To report security vulnerabilities and other security issues in the Magento software or web sites, send an email with the report at [security@magento.com][]. 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][]. +Learn more about reporting [security][] issues. Stay up-to-date on the latest security news and patches for Magento by signing up for [Security Alert Notifications][]. @@ -74,7 +74,7 @@ See the [license][] or contact [license@magentocommerce.com][] for a copy. [DevDocs Contributing]: https://github.com/magento/devdocs/blob/master/.github/CONTRIBUTING.md [security@magento.com]: mailto:security@magento.com [encryption key]: https://info2.magento.com/rs/magentoenterprise/images/security_at_magento.asc -[security issues]: https://magento.com/security/reporting-magento-security-issue +[security]: https://magento.com/security/reporting-magento-security-issue [Security Alert Notifications]: https://magento.com/security/sign-up [license]: LICENSE_AGPL3.txt [license@magentocommerce.com]: mailto:license@magentocommerce.com From 91b1d1ac210a0ac7737972838022b9bcabf18ce9 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 29 Jul 2020 10:17:13 -0500 Subject: [PATCH 487/888] MQE-2231: Adobe open source repository standards compliance --- .github/CONTRIBUTING.md | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 11334ae73..9a38dfc65 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -160,7 +160,6 @@ Label| Description **bugfix**| The issue or pull request is about fixing a bug. **enhancement**| The issue or pull request that makes the MFTF even more awesome (for example new features, optimization, refactoring, etc). - [fork]: #fork-a-repository [issue]: #report-an-issue [labels]: #read-labels From e3b5ca2db75eebb3eecf52d1ec4ac4cc4e05cec3 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 29 Jul 2020 10:18:27 -0500 Subject: [PATCH 488/888] MQE-2231: Adobe open source repository standards compliance --- .github/CONTRIBUTING.md | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 11334ae73..9a38dfc65 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -160,7 +160,6 @@ Label| Description **bugfix**| The issue or pull request is about fixing a bug. **enhancement**| The issue or pull request that makes the MFTF even more awesome (for example new features, optimization, refactoring, etc). - [fork]: #fork-a-repository [issue]: #report-an-issue [labels]: #read-labels From 492ca4b8bee7379e373e211928ba05c83206aaa5 Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Wed, 29 Jul 2020 10:38:07 -0500 Subject: [PATCH 489/888] Add v2 folder to gitignore for versioned docs. --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index fad995502..2eb2c1b34 100755 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,4 @@ dev/tests/mftf.log dev/tests/docs/* dev/tests/_output dev/tests/functional.suite.yml - +v2/* From 782886ad736f2389ff268d5fa701591f4d049889 Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Wed, 29 Jul 2020 10:54:34 -0500 Subject: [PATCH 490/888] Fixup --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2eb2c1b34..8fa26e2f9 100755 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,4 @@ dev/tests/mftf.log dev/tests/docs/* dev/tests/_output dev/tests/functional.suite.yml -v2/* +/v2/* From 0c1fc197b19d4a2a99b84c2a82648a714f5cf1fe Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Wed, 29 Jul 2020 10:56:05 -0500 Subject: [PATCH 491/888] No star --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8fa26e2f9..3166f9529 100755 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,4 @@ dev/tests/mftf.log dev/tests/docs/* dev/tests/_output dev/tests/functional.suite.yml -/v2/* +/v2/ From 21c625c776705a6fd4e627142b18913ce204fd04 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 29 Jul 2020 11:59:52 -0500 Subject: [PATCH 492/888] MQE-2231: Adobe open source repository standards compliance --- README.md | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 07c43fff1..5a4bbab11 100755 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Learn more about contributing in our [Contribution Guidelines][]. If you want to participate in the documentation work, see [DevDocs Contributing][]. -### Labels applied by the MFTF team +### 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. @@ -53,12 +53,10 @@ These labels are applied by the MFTF development team to community contributed i | **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 +## Reporting Security Issues -To report security vulnerabilities and other security issues in the Magento software or web sites, send an email with the report at [security@magento.com][]. -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. +To report security vulnerabilities or learn more about reporting security issues in Magento software or web sites visit the [Magento Bug Bounty Program](https://hackerone.com/magento) on hackerone. +Please create a hackerone account [there](https://hackerone.com/magento) to submit and follow-up on your issue. Stay up-to-date on the latest security news and patches for Magento by signing up for [Security Alert Notifications][]. @@ -72,9 +70,6 @@ See the [license][] or contact [license@magentocommerce.com][] for a copy. [Getting Started]: docs/getting-started.md [Contribution Guidelines]: .github/CONTRIBUTING.md [DevDocs Contributing]: https://github.com/magento/devdocs/blob/master/.github/CONTRIBUTING.md -[security@magento.com]: mailto:security@magento.com -[encryption key]: https://info2.magento.com/rs/magentoenterprise/images/security_at_magento.asc -[security]: https://magento.com/security/reporting-magento-security-issue [Security Alert Notifications]: https://magento.com/security/sign-up [license]: LICENSE_AGPL3.txt [license@magentocommerce.com]: mailto:license@magentocommerce.com From 6451fd377871faa0b4bdff48fb0a847ccebe97fb Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 29 Jul 2020 11:59:52 -0500 Subject: [PATCH 493/888] MQE-2231: Adobe open source repository standards compliance --- README.md | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 07c43fff1..5a4bbab11 100755 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Learn more about contributing in our [Contribution Guidelines][]. If you want to participate in the documentation work, see [DevDocs Contributing][]. -### Labels applied by the MFTF team +### 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. @@ -53,12 +53,10 @@ These labels are applied by the MFTF development team to community contributed i | **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 +## Reporting Security Issues -To report security vulnerabilities and other security issues in the Magento software or web sites, send an email with the report at [security@magento.com][]. -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. +To report security vulnerabilities or learn more about reporting security issues in Magento software or web sites visit the [Magento Bug Bounty Program](https://hackerone.com/magento) on hackerone. +Please create a hackerone account [there](https://hackerone.com/magento) to submit and follow-up on your issue. Stay up-to-date on the latest security news and patches for Magento by signing up for [Security Alert Notifications][]. @@ -72,9 +70,6 @@ See the [license][] or contact [license@magentocommerce.com][] for a copy. [Getting Started]: docs/getting-started.md [Contribution Guidelines]: .github/CONTRIBUTING.md [DevDocs Contributing]: https://github.com/magento/devdocs/blob/master/.github/CONTRIBUTING.md -[security@magento.com]: mailto:security@magento.com -[encryption key]: https://info2.magento.com/rs/magentoenterprise/images/security_at_magento.asc -[security]: https://magento.com/security/reporting-magento-security-issue [Security Alert Notifications]: https://magento.com/security/sign-up [license]: LICENSE_AGPL3.txt [license@magentocommerce.com]: mailto:license@magentocommerce.com From 967043ee5ede64793155df1ab1936b5df1ab4d6a Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 30 Jul 2020 17:15:47 -0500 Subject: [PATCH 494/888] MQE-2158: support using actions from multiple modules in Suites --- .../Module/MagentoActionProxies.php | 119 ++++++++++++++- .../Module/MagentoWebDriver.php | 137 ++---------------- .../Suite/Generators/GroupClassGenerator.php | 34 ++++- .../Suite/views/SuiteClass.mustache | 50 +++++-- .../Suite/views/partials/testActions.mustache | 6 +- 5 files changed, 194 insertions(+), 152 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoActionProxies.php b/src/Magento/FunctionalTestingFramework/Module/MagentoActionProxies.php index 5a3b2360b..55b19a7c1 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoActionProxies.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoActionProxies.php @@ -20,5 +20,122 @@ */ class MagentoActionProxies extends CodeceptionModule { - // TODO: placeholder for proxy functions currently in MagentoWebDriver (MQE-1904) + /** + * Create an entity + * + * @param string $key StepKey of the createData action. + * @param string $scope + * @param string $entity Name of xml entity to create. + * @param array $dependentObjectKeys StepKeys of other createData actions that are required. + * @param array $overrideFields Array of FieldName => Value of override fields. + * @param string $storeCode + * @return void + */ + public function createEntity( + $key, + $scope, + $entity, + $dependentObjectKeys = [], + $overrideFields = [], + $storeCode = '' + ) { + PersistedObjectHandler::getInstance()->createEntity( + $key, + $scope, + $entity, + $dependentObjectKeys, + $overrideFields, + $storeCode + ); + } + + /** + * Retrieves and updates a previously created entity + * + * @param string $key StepKey of the createData action. + * @param string $scope + * @param string $updateEntity Name of the static XML data to update the entity with. + * @param array $dependentObjectKeys StepKeys of other createData actions that are required. + * @return void + */ + public function updateEntity($key, $scope, $updateEntity, $dependentObjectKeys = []) + { + PersistedObjectHandler::getInstance()->updateEntity( + $key, + $scope, + $updateEntity, + $dependentObjectKeys + ); + } + + /** + * Performs GET on given entity and stores entity for use + * + * @param string $key StepKey of getData action. + * @param string $scope + * @param string $entity Name of XML static data to use. + * @param array $dependentObjectKeys StepKeys of other createData actions that are required. + * @param string $storeCode + * @param integer $index + * @return void + */ + public function getEntity($key, $scope, $entity, $dependentObjectKeys = [], $storeCode = '', $index = null) + { + PersistedObjectHandler::getInstance()->getEntity( + $key, + $scope, + $entity, + $dependentObjectKeys, + $storeCode, + $index + ); + } + + /** + * Retrieves and deletes a previously created entity + * + * @param string $key StepKey of the createData action. + * @param string $scope + * @return void + */ + public function deleteEntity($key, $scope) + { + PersistedObjectHandler::getInstance()->deleteEntity($key, $scope); + } + + /** + * Retrieves a field from an entity, according to key and scope given + * + * @param string $stepKey + * @param string $field + * @param string $scope + * @return string + */ + public function retrieveEntityField($stepKey, $field, $scope) + { + return PersistedObjectHandler::getInstance()->retrieveEntityField($stepKey, $field, $scope); + } + + /** + * Get encrypted value by key + * + * @param string $key + * @return string|null + * @throws TestFrameworkException + */ + public function getSecret($key) + { + return CredentialStore::getInstance()->getSecret($key); + } + + /** + * Returns a value to origin of the action + * + * @param mixed $value + * @return mixed + */ + public function return($value) + { + return $value; + } } diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 944735677..ef57aa3f1 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -15,6 +15,7 @@ use Codeception\Exception\ModuleConfigException; use Codeception\Exception\ModuleException; use Codeception\Util\Uri; +use Codeception\Lib\ModuleContainer; use Magento\FunctionalTestingFramework\DataTransport\WebApiExecutor; use Magento\FunctionalTestingFramework\DataTransport\Auth\WebApiAuth; use Magento\FunctionalTestingFramework\DataTransport\Auth\Tfa\OTP; @@ -180,6 +181,16 @@ public function _after(TestInterface $test) // DO NOT RESET SESSIONS } + /** + * Return ModuleContainer + * + * @return ModuleContainer + */ + public function getModuleContainer() + { + return $this->moduleContainer; + } + /** * Returns URL of a host. * @@ -956,120 +967,6 @@ public function getOTP() return OTP::getOTP(); } - /** - * Create an entity - * TODO: move this function to MagentoActionProxies after MQE-1904 - * - * @param string $key StepKey of the createData action. - * @param string $scope - * @param string $entity Name of xml entity to create. - * @param array $dependentObjectKeys StepKeys of other createData actions that are required. - * @param array $overrideFields Array of FieldName => Value of override fields. - * @param string $storeCode - * @return void - */ - public function createEntity( - $key, - $scope, - $entity, - $dependentObjectKeys = [], - $overrideFields = [], - $storeCode = '' - ) { - PersistedObjectHandler::getInstance()->createEntity( - $key, - $scope, - $entity, - $dependentObjectKeys, - $overrideFields, - $storeCode - ); - } - - /** - * Retrieves and updates a previously created entity - * TODO: move this function to MagentoActionProxies after MQE-1904 - * - * @param string $key StepKey of the createData action. - * @param string $scope - * @param string $updateEntity Name of the static XML data to update the entity with. - * @param array $dependentObjectKeys StepKeys of other createData actions that are required. - * @return void - */ - public function updateEntity($key, $scope, $updateEntity, $dependentObjectKeys = []) - { - PersistedObjectHandler::getInstance()->updateEntity( - $key, - $scope, - $updateEntity, - $dependentObjectKeys - ); - } - - /** - * Performs GET on given entity and stores entity for use - * TODO: move this function to MagentoActionProxies after MQE-1904 - * - * @param string $key StepKey of getData action. - * @param string $scope - * @param string $entity Name of XML static data to use. - * @param array $dependentObjectKeys StepKeys of other createData actions that are required. - * @param string $storeCode - * @param integer $index - * @return void - */ - public function getEntity($key, $scope, $entity, $dependentObjectKeys = [], $storeCode = '', $index = null) - { - PersistedObjectHandler::getInstance()->getEntity( - $key, - $scope, - $entity, - $dependentObjectKeys, - $storeCode, - $index - ); - } - - /** - * Retrieves and deletes a previously created entity - * TODO: move this function to MagentoActionProxies after MQE-1904 - * - * @param string $key StepKey of the createData action. - * @param string $scope - * @return void - */ - public function deleteEntity($key, $scope) - { - PersistedObjectHandler::getInstance()->deleteEntity($key, $scope); - } - - /** - * Retrieves a field from an entity, according to key and scope given - * TODO: move this function to MagentoActionProxies after MQE-1904 - * - * @param string $stepKey - * @param string $field - * @param string $scope - * @return string - */ - public function retrieveEntityField($stepKey, $field, $scope) - { - return PersistedObjectHandler::getInstance()->retrieveEntityField($stepKey, $field, $scope); - } - - /** - * Get encrypted value by key - * TODO: move this function to MagentoActionProxies after MQE-1904 - * - * @param string $key - * @return string|null - * @throws TestFrameworkException - */ - public function getSecret($key) - { - return CredentialStore::getInstance()->getSecret($key); - } - /** * Waits proper amount of time to perform Cron execution * @@ -1122,16 +1019,4 @@ public function switchToIFrame($locator = null) $this->webDriver->switchTo()->frame($els[0]); } } - - /** - * Returns a value to origin of the action. - * TODO: move this function to MagentoActionProxies after MQE-1904 - * - * @param mixed $value - * @return mixed - */ - public function return($value) - { - return $value; - } } diff --git a/src/Magento/FunctionalTestingFramework/Suite/Generators/GroupClassGenerator.php b/src/Magento/FunctionalTestingFramework/Suite/Generators/GroupClassGenerator.php index bb0157152..ccac30529 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Generators/GroupClassGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Generators/GroupClassGenerator.php @@ -6,6 +6,7 @@ namespace Magento\FunctionalTestingFramework\Suite\Generators; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Suite\Objects\SuiteObject; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; @@ -32,6 +33,10 @@ class GroupClassGenerator 'comment' => 'print' ]; const GROUP_DIR_NAME = 'Group'; + const FUNCTION_PLACEHOLDER = 'PLACEHOLDER'; + const FUNCTION_START = 'this->getModuleForAction("'; + const FUNCTION_END = '")'; + const FUNCTION_REPLACE_REGEX = '/(PLACEHOLDER->([^\(]+))\(/'; /** * Mustache_Engine instance for template loading @@ -142,7 +147,7 @@ private function buildHookMustacheArray($hookObj) //deleteData contains either url or createDataKey, if it contains the former it needs special formatting if ($action->getType() !== "createData" && !array_key_exists(TestGenerator::REQUIRED_ENTITY_REFERENCE, $action->getCustomActionAttributes())) { - $actions = $this->buildWebDriverActionsMustacheArray($action, $actions); + $actions = $this->buildModuleActionsMustacheArray($action, $actions); continue; } @@ -165,7 +170,7 @@ private function buildHookMustacheArray($hookObj) } /** - * Takes an action object and array of generated action steps. Converst the action object into generated php and + * Takes an action object and array of generated action steps. Convert the action object into generated php and * appends the entry to the given array. The result is returned by the function. * * @param ActionObject $action @@ -173,14 +178,21 @@ private function buildHookMustacheArray($hookObj) * @return array * @throws TestReferenceException */ - private function buildWebDriverActionsMustacheArray($action, $actionEntries) + private function buildModuleActionsMustacheArray($action, $actionEntries) { - $step = TestGenerator::getInstance()->generateStepsPhp([$action], TestGenerator::SUITE_SCOPE, 'webDriver'); + $step = TestGenerator::getInstance()->generateStepsPhp( + [$action], + TestGenerator::SUITE_SCOPE, + self::FUNCTION_PLACEHOLDER + ); $rawPhp = str_replace(["\t"], "", $step); $multipleCommands = explode(PHP_EOL, $rawPhp, -1); $multipleCommands = array_filter($multipleCommands); foreach ($multipleCommands as $command) { - $actionEntries = $this->replaceReservedTesterFunctions($command . PHP_EOL, $actionEntries, 'webDriver'); + $actionEntries = $this->replaceReservedTesterFunctions( + $command . PHP_EOL, $actionEntries, + self::FUNCTION_PLACEHOLDER + ); } return $actionEntries; @@ -204,7 +216,17 @@ private function replaceReservedTesterFunctions($formattedStep, $actionEntries, $resultingStep = str_replace($testActionCall, $replacement, $formattedStep); $actionEntries[] = ['action' => $resultingStep]; } else { - $actionEntries[] = ['action' => $formattedStep]; + $placeholder = self::FUNCTION_PLACEHOLDER; + $begin = self::FUNCTION_START; + $end = self::FUNCTION_END; + $resultingStep = preg_replace_callback( + self::FUNCTION_REPLACE_REGEX, + function($matches) use ($placeholder, $begin, $end) { + return str_replace($placeholder, $begin . $matches[2] . $end, $matches[1]) . '('; + }, + $formattedStep + ); + $actionEntries[] = ['action' => $resultingStep]; } } diff --git a/src/Magento/FunctionalTestingFramework/Suite/views/SuiteClass.mustache b/src/Magento/FunctionalTestingFramework/Suite/views/SuiteClass.mustache index a9fdcd6df..dc2fde915 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/views/SuiteClass.mustache +++ b/src/Magento/FunctionalTestingFramework/Suite/views/SuiteClass.mustache @@ -6,6 +6,11 @@ use Facebook\WebDriver\Remote\RemoteWebDriver; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; use Magento\FunctionalTestingFramework\Module\MagentoWebDriver; +use Magento\FunctionalTestingFramework\Module\MagentoAssert; +use Magento\FunctionalTestingFramework\Module\MagentoActionProxies; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Codeception\Lib\ModuleContainer; +use Codeception\Module; /** * Group class is Codeception Extension which is allowed to handle to all internal events. @@ -30,10 +35,16 @@ class {{suiteName}} extends \Codeception\GroupObject {{/helpers}} private static $HOOK_EXECUTION_INIT = "\n/******** Beginning execution of {{suiteName}} suite %s block ********/\n"; private static $HOOK_EXECUTION_END = "\n/******** Execution of {{suiteName}} suite %s block complete ********/\n"; + /** @var MagentoWebDriver */ + private $webDriver; + /** @var ModuleContainer */ + private $moduleContainer; {{#before}} public function _before(\Codeception\Event\TestEvent $e) { + $this->webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); + $this->moduleContainer = $this->webDriver->getModuleContainer(); {{#helpers}} /** @var \Magento\FunctionalTestingFramework\Helper\HelperContainer $helperContainer */ $this->helperContainer = $this->getModule('\Magento\FunctionalTestingFramework\Helper\HelperContainer'); @@ -51,15 +62,11 @@ class {{suiteName}} extends \Codeception\GroupObject } } - private function executePreConditions() { if ($this->currentTestRun == 1) { print sprintf(self::$HOOK_EXECUTION_INIT, "before"); - /** @var MagentoWebDriver $webDriver */ - $webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); - try { {{> testActions}} } catch (\Exception $exception) { @@ -67,9 +74,9 @@ class {{suiteName}} extends \Codeception\GroupObject } // reset configuration and close session - $webDriver->_resetConfig(); - $webDriver->webDriver->close(); - $webDriver->webDriver = null; + $this->webDriver->_resetConfig(); + $this->webDriver->webDriver->close(); + $this->webDriver->webDriver = null; print sprintf(self::$HOOK_EXECUTION_END, "before"); } @@ -82,15 +89,11 @@ class {{suiteName}} extends \Codeception\GroupObject $this->executePostConditions($e); } - private function executePostConditions(\Codeception\Event\TestEvent $e) { if ($this->currentTestRun == $this->testCount) { print sprintf(self::$HOOK_EXECUTION_INIT, "after"); - /** @var MagentoWebDriver $webDriver */ - $webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); - try { // Find out if Test in Suite failed, will cause potential failures in suite after $cest = $e->getTest(); @@ -120,7 +123,7 @@ class {{suiteName}} extends \Codeception\GroupObject PersistedObjectHandler::getInstance()->clearSuiteObjects(); - $this->closeSession($webDriver); + $this->closeSession($this->webDriver); print sprintf(self::$HOOK_EXECUTION_END, "after"); } @@ -131,13 +134,12 @@ class {{suiteName}} extends \Codeception\GroupObject * Close session method closes current session. * If config 'close_all_sessions' is set to 'true' all sessions will be closed. * - * @param MagentoWebDriver $webDriver * return void */ - private function closeSession(MagentoWebDriver $webDriver): void + private function closeSession(): void { - $webDriverConfig = $webDriver->_getConfig(); - $webDriver->_closeSession(); + $webDriverConfig = $this->webDriver->_getConfig(); + $this->webDriver->_closeSession(); if (isset($webDriverConfig['close_all_sessions']) && $webDriverConfig['close_all_sessions'] === "true") { $wdHost = sprintf( '%s://%s:%s%s', @@ -153,4 +155,20 @@ class {{suiteName}} extends \Codeception\GroupObject } } } + + /** + * Return the module for an action. + * + * @param string $action + * @return Module + * @throws \Exception + */ + private function getModuleForAction($action) + { + $module = $this->moduleContainer->moduleForAction($action); + if ($module === null) { + throw new TestFrameworkException('Invalid action "' . $action . '"' . PHP_EOL); + } + return $module; + } } diff --git a/src/Magento/FunctionalTestingFramework/Suite/views/partials/testActions.mustache b/src/Magento/FunctionalTestingFramework/Suite/views/partials/testActions.mustache index eaa0959cb..c07958778 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/views/partials/testActions.mustache +++ b/src/Magento/FunctionalTestingFramework/Suite/views/partials/testActions.mustache @@ -1,9 +1,9 @@ {{#actions}} {{#webDriverInit}} -if ($webDriver->webDriver != null) { - $webDriver->_restart(); +if ($this->webDriver->webDriver != null) { + $this->webDriver->_restart(); } else { - $webDriver->_initializeSession(); + $this->webDriver->_initializeSession(); } {{/webDriverInit}} {{#action}} From fc05c77aa68f72eae7bdc294933935c4148127f5 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 30 Jul 2020 17:33:17 -0500 Subject: [PATCH 495/888] MQE-2158: support using actions from multiple modules in Suites --- .../Suite/Generators/GroupClassGenerator.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Suite/Generators/GroupClassGenerator.php b/src/Magento/FunctionalTestingFramework/Suite/Generators/GroupClassGenerator.php index ccac30529..f90a25322 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Generators/GroupClassGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Generators/GroupClassGenerator.php @@ -190,7 +190,8 @@ private function buildModuleActionsMustacheArray($action, $actionEntries) $multipleCommands = array_filter($multipleCommands); foreach ($multipleCommands as $command) { $actionEntries = $this->replaceReservedTesterFunctions( - $command . PHP_EOL, $actionEntries, + $command . PHP_EOL, + $actionEntries, self::FUNCTION_PLACEHOLDER ); } @@ -221,7 +222,7 @@ private function replaceReservedTesterFunctions($formattedStep, $actionEntries, $end = self::FUNCTION_END; $resultingStep = preg_replace_callback( self::FUNCTION_REPLACE_REGEX, - function($matches) use ($placeholder, $begin, $end) { + function ($matches) use ($placeholder, $begin, $end) { return str_replace($placeholder, $begin . $matches[2] . $end, $matches[1]) . '('; }, $formattedStep From 7b53949b3b6bc9a0d0129e01f14155d436e1a215 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Fri, 31 Jul 2020 08:59:26 -0500 Subject: [PATCH 496/888] MQE-2158: support using actions from multiple modules in Suites --- .../Resources/functionalSuiteHooks.txt | 74 ++++--- .../functionalSuiteUsingSecretData.txt | 205 ++++++++++++++++++ .../Resources/functionalSuiteWithComments.txt | 68 +++--- .../Data/PersistedReplacementData.xml | 4 + .../Suite/functionalSuiteUsingSecretData.xml | 36 +++ .../IncludeUsingSecretDataTest.xml | 17 ++ .../Tests/SuiteGenerationTest.php | 59 +++++ 7 files changed, 410 insertions(+), 53 deletions(-) create mode 100644 dev/tests/verification/Resources/functionalSuiteUsingSecretData.txt create mode 100644 dev/tests/verification/TestModule/Suite/functionalSuiteUsingSecretData.xml create mode 100644 dev/tests/verification/TestModule/Test/SampleSuiteTest/IncludeUsingSecretDataTest.xml diff --git a/dev/tests/verification/Resources/functionalSuiteHooks.txt b/dev/tests/verification/Resources/functionalSuiteHooks.txt index 041b088b1..3156a59dd 100644 --- a/dev/tests/verification/Resources/functionalSuiteHooks.txt +++ b/dev/tests/verification/Resources/functionalSuiteHooks.txt @@ -6,6 +6,11 @@ use Facebook\WebDriver\Remote\RemoteWebDriver; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; use Magento\FunctionalTestingFramework\Module\MagentoWebDriver; +use Magento\FunctionalTestingFramework\Module\MagentoAssert; +use Magento\FunctionalTestingFramework\Module\MagentoActionProxies; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Codeception\Lib\ModuleContainer; +use Codeception\Module; /** * Group class is Codeception Extension which is allowed to handle to all internal events. @@ -24,9 +29,15 @@ class functionalSuiteHooks extends \Codeception\GroupObject private $currentTestRun = 0; private static $HOOK_EXECUTION_INIT = "\n/******** Beginning execution of functionalSuiteHooks suite %s block ********/\n"; private static $HOOK_EXECUTION_END = "\n/******** Execution of functionalSuiteHooks suite %s block complete ********/\n"; + /** @var MagentoWebDriver */ + private $webDriver; + /** @var ModuleContainer */ + private $moduleContainer; public function _before(\Codeception\Event\TestEvent $e) { + $this->webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); + $this->moduleContainer = $this->webDriver->getModuleContainer(); // increment test count per execution $this->currentTestRun++; $this->executePreConditions(); @@ -37,22 +48,18 @@ class functionalSuiteHooks extends \Codeception\GroupObject } } - private function executePreConditions() { if ($this->currentTestRun == 1) { print sprintf(self::$HOOK_EXECUTION_INIT, "before"); - /** @var MagentoWebDriver $webDriver */ - $webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); - try { - if ($webDriver->webDriver != null) { - $webDriver->_restart(); + if ($this->webDriver->webDriver != null) { + $this->webDriver->_restart(); } else { - $webDriver->_initializeSession(); + $this->webDriver->_initializeSession(); } - $webDriver->amOnPage("some.url"); // stepKey: before + $this->getModuleForAction("amOnPage")->amOnPage("some.url"); // stepKey: before $createOneFields['someKey'] = "dataHere"; PersistedObjectHandler::getInstance()->createEntity( "createOne", @@ -79,18 +86,18 @@ class functionalSuiteHooks extends \Codeception\GroupObject "createEntityFour", ["createEntityTwo", "createEntityThree"] ); - $webDriver->click(PersistedObjectHandler::getInstance()->retrieveEntityField('createTwo', 'data', 'suite')); // stepKey: clickWithData + $this->getModuleForAction("click")->click(PersistedObjectHandler::getInstance()->retrieveEntityField('createTwo', 'data', 'suite')); // stepKey: clickWithData print("Entering Action Group [AC] actionGroupWithTwoArguments"); - $webDriver->see("John", msq("uniqueData") . "John"); // stepKey: seeFirstNameAC + $this->getModuleForAction("see")->see("John", msq("uniqueData") . "John"); // stepKey: seeFirstNameAC print("Exiting Action Group [AC] actionGroupWithTwoArguments"); } catch (\Exception $exception) { $this->preconditionFailure = $exception->getMessage(); } // reset configuration and close session - $webDriver->_resetConfig(); - $webDriver->webDriver->close(); - $webDriver->webDriver = null; + $this->webDriver->_resetConfig(); + $this->webDriver->webDriver->close(); + $this->webDriver->webDriver = null; print sprintf(self::$HOOK_EXECUTION_END, "before"); } @@ -101,15 +108,11 @@ class functionalSuiteHooks extends \Codeception\GroupObject $this->executePostConditions($e); } - private function executePostConditions(\Codeception\Event\TestEvent $e) { if ($this->currentTestRun == $this->testCount) { print sprintf(self::$HOOK_EXECUTION_INIT, "after"); - /** @var MagentoWebDriver $webDriver */ - $webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); - try { // Find out if Test in Suite failed, will cause potential failures in suite after $cest = $e->getTest(); @@ -132,15 +135,15 @@ class functionalSuiteHooks extends \Codeception\GroupObject } } } - if ($webDriver->webDriver != null) { - $webDriver->_restart(); + if ($this->webDriver->webDriver != null) { + $this->webDriver->_restart(); } else { - $webDriver->_initializeSession(); + $this->webDriver->_initializeSession(); } - $webDriver->amOnPage("some.url"); // stepKey: after - $webDriver->deleteEntityByUrl("deleteThis"); // stepKey: delete + $this->getModuleForAction("amOnPage")->amOnPage("some.url"); // stepKey: after + $this->getModuleForAction("deleteEntityByUrl")->deleteEntityByUrl("deleteThis"); // stepKey: delete print("Entering Action Group [AC] actionGroupWithTwoArguments"); - $webDriver->see("John", msq("uniqueData") . "John"); // stepKey: seeFirstNameAC + $this->getModuleForAction("see")->see("John", msq("uniqueData") . "John"); // stepKey: seeFirstNameAC print("Exiting Action Group [AC] actionGroupWithTwoArguments"); } catch (\Exception $exception) { print $exception->getMessage(); @@ -148,7 +151,7 @@ class functionalSuiteHooks extends \Codeception\GroupObject PersistedObjectHandler::getInstance()->clearSuiteObjects(); - $this->closeSession($webDriver); + $this->closeSession($this->webDriver); print sprintf(self::$HOOK_EXECUTION_END, "after"); } @@ -158,13 +161,12 @@ class functionalSuiteHooks extends \Codeception\GroupObject * Close session method closes current session. * If config 'close_all_sessions' is set to 'true' all sessions will be closed. * - * @param MagentoWebDriver $webDriver * return void */ - private function closeSession(MagentoWebDriver $webDriver): void + private function closeSession(): void { - $webDriverConfig = $webDriver->_getConfig(); - $webDriver->_closeSession(); + $webDriverConfig = $this->webDriver->_getConfig(); + $this->webDriver->_closeSession(); if (isset($webDriverConfig['close_all_sessions']) && $webDriverConfig['close_all_sessions'] === "true") { $wdHost = sprintf( '%s://%s:%s%s', @@ -180,4 +182,20 @@ class functionalSuiteHooks extends \Codeception\GroupObject } } } + + /** + * Return the module for an action. + * + * @param string $action + * @return Module + * @throws \Exception + */ + private function getModuleForAction($action) + { + $module = $this->moduleContainer->moduleForAction($action); + if ($module === null) { + throw new TestFrameworkException('Invalid action "' . $action . '"' . PHP_EOL); + } + return $module; + } } diff --git a/dev/tests/verification/Resources/functionalSuiteUsingSecretData.txt b/dev/tests/verification/Resources/functionalSuiteUsingSecretData.txt new file mode 100644 index 000000000..1be43a544 --- /dev/null +++ b/dev/tests/verification/Resources/functionalSuiteUsingSecretData.txt @@ -0,0 +1,205 @@ +<?php + +namespace Group; + +use Facebook\WebDriver\Remote\RemoteWebDriver; +use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; +use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; +use Magento\FunctionalTestingFramework\Module\MagentoWebDriver; +use Magento\FunctionalTestingFramework\Module\MagentoAssert; +use Magento\FunctionalTestingFramework\Module\MagentoActionProxies; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Codeception\Lib\ModuleContainer; +use Codeception\Module; + +/** + * Group class is Codeception Extension which is allowed to handle to all internal events. + * This class itself can be used to listen events for test execution of one particular group. + * It may be especially useful to create fixtures data, prepare server, etc. + * + * INSTALLATION: + * + * To use this group extension, include it to "extensions" option of global Codeception config. + */ +class functionalSuiteUsingSecretData extends \Codeception\GroupObject +{ + public static $group = 'functionalSuiteUsingSecretData'; + private $testCount = 1; + private $preconditionFailure = null; + private $currentTestRun = 0; + private static $HOOK_EXECUTION_INIT = "\n/******** Beginning execution of functionalSuiteUsingSecretData suite %s block ********/\n"; + private static $HOOK_EXECUTION_END = "\n/******** Execution of functionalSuiteUsingSecretData suite %s block complete ********/\n"; + /** @var MagentoWebDriver */ + private $webDriver; + /** @var ModuleContainer */ + private $moduleContainer; + + public function _before(\Codeception\Event\TestEvent $e) + { + $this->webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); + $this->moduleContainer = $this->webDriver->getModuleContainer(); + // increment test count per execution + $this->currentTestRun++; + $this->executePreConditions(); + + if ($this->preconditionFailure != null) { + //if our preconditions fail, we need to mark all the tests as incomplete. + $e->getTest()->getMetadata()->setIncomplete("SUITE PRECONDITION FAILED:" . PHP_EOL . $this->preconditionFailure); + } + } + + private function executePreConditions() + { + if ($this->currentTestRun == 1) { + print sprintf(self::$HOOK_EXECUTION_INIT, "before"); + + try { + if ($this->webDriver->webDriver != null) { + $this->webDriver->_restart(); + } else { + $this->webDriver->_initializeSession(); + } + $cli = $this->getModuleForAction("magentoCLISecret")->magentoCLISecret($this->getModuleForAction("getSecret")->getSecret("magento/some/secret"), 60); // stepKey: cli + print($cli); // stepKey: cli + $create1Fields['someKey'] = "dataHere"; + PersistedObjectHandler::getInstance()->createEntity( + "create1", + "suite", + "SecretData", + [], + $create1Fields + ); + PersistedObjectHandler::getInstance()->createEntity( + "create2", + "suite", + "SecretData", + [] + ); + PersistedObjectHandler::getInstance()->createEntity( + "create3", + "suite", + "SecretData", + ["create1", "create2"] + ); + $this->getModuleForAction("fillSecretField")->fillSecretField("#fill", $this->getModuleForAction("getSecret")->getSecret("magento/some/secret") . "+" . $this->getModuleForAction("getSecret")->getSecret("magento/some/secret")); // stepKey: fillBefore + $this->getModuleForAction("click")->click(PersistedObjectHandler::getInstance()->retrieveEntityField('create2', 'key2', 'suite')); // stepKey: click + } catch (\Exception $exception) { + $this->preconditionFailure = $exception->getMessage(); + } + + // reset configuration and close session + $this->webDriver->_resetConfig(); + $this->webDriver->webDriver->close(); + $this->webDriver->webDriver = null; + + print sprintf(self::$HOOK_EXECUTION_END, "before"); + } + } + + public function _after(\Codeception\Event\TestEvent $e) + { + $this->executePostConditions($e); + } + + private function executePostConditions(\Codeception\Event\TestEvent $e) + { + if ($this->currentTestRun == $this->testCount) { + print sprintf(self::$HOOK_EXECUTION_INIT, "after"); + + try { + // Find out if Test in Suite failed, will cause potential failures in suite after + $cest = $e->getTest(); + + //Access private TestResultObject to find stack and if there are any errors (as opposed to failures) + $testResultObject = call_user_func(\Closure::bind( + function () use ($cest) { + return $cest->getTestResultObject(); + }, + $cest + )); + $errors = $testResultObject->errors(); + + if (!empty($errors)) { + foreach ($errors as $error) { + if ($error->failedTest()->getTestMethod() == $cest->getName()) { + // Do not attempt to run _after if failure was in the _after block + // Try to run _after but catch exceptions to prevent them from overwriting original failure. + print("LAST TEST IN SUITE FAILED, TEST AFTER MAY NOT BE SUCCESSFUL\n"); + } + } + } + if ($this->webDriver->webDriver != null) { + $this->webDriver->_restart(); + } else { + $this->webDriver->_initializeSession(); + } + PersistedObjectHandler::getInstance()->deleteEntity( + "create1", + "suite" + ); + PersistedObjectHandler::getInstance()->deleteEntity( + "create2", + "suite" + ); + PersistedObjectHandler::getInstance()->deleteEntity( + "create3", + "suite" + ); + $this->getModuleForAction("deleteEntityByUrl")->deleteEntityByUrl("deleteThis"); // stepKey: deleteThis + $this->getModuleForAction("fillSecretField")->fillSecretField("#fill", $this->getModuleForAction("getSecret")->getSecret("magento/some/secret")); // stepKey: fillAfter + $cli2 = $this->getModuleForAction("magentoCLISecret")->magentoCLISecret($this->getModuleForAction("getSecret")->getSecret("magento/some/secret") . "-some/data-" . $this->getModuleForAction("getSecret")->getSecret("magento/some/secret"), 60); // stepKey: cli2 + print($cli2); // stepKey: cli2 + } catch (\Exception $exception) { + print $exception->getMessage(); + } + + PersistedObjectHandler::getInstance()->clearSuiteObjects(); + + $this->closeSession($this->webDriver); + + print sprintf(self::$HOOK_EXECUTION_END, "after"); + } + } + + /** + * Close session method closes current session. + * If config 'close_all_sessions' is set to 'true' all sessions will be closed. + * + * return void + */ + private function closeSession(): void + { + $webDriverConfig = $this->webDriver->_getConfig(); + $this->webDriver->_closeSession(); + if (isset($webDriverConfig['close_all_sessions']) && $webDriverConfig['close_all_sessions'] === "true") { + $wdHost = sprintf( + '%s://%s:%s%s', + $webDriverConfig['protocol'], + $webDriverConfig['host'], + $webDriverConfig['port'], + $webDriverConfig['path'] + ); + $availableSessions = RemoteWebDriver::getAllSessions($wdHost); + foreach ($availableSessions as $session) { + $remoteWebDriver = RemoteWebDriver::createBySessionID($session['id'], $wdHost); + $remoteWebDriver->quit(); + } + } + } + + /** + * Return the module for an action. + * + * @param string $action + * @return Module + * @throws \Exception + */ + private function getModuleForAction($action) + { + $module = $this->moduleContainer->moduleForAction($action); + if ($module === null) { + throw new TestFrameworkException('Invalid action "' . $action . '"' . PHP_EOL); + } + return $module; + } +} diff --git a/dev/tests/verification/Resources/functionalSuiteWithComments.txt b/dev/tests/verification/Resources/functionalSuiteWithComments.txt index 6c646dd18..02b50f092 100644 --- a/dev/tests/verification/Resources/functionalSuiteWithComments.txt +++ b/dev/tests/verification/Resources/functionalSuiteWithComments.txt @@ -6,6 +6,11 @@ use Facebook\WebDriver\Remote\RemoteWebDriver; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; use Magento\FunctionalTestingFramework\Module\MagentoWebDriver; +use Magento\FunctionalTestingFramework\Module\MagentoAssert; +use Magento\FunctionalTestingFramework\Module\MagentoActionProxies; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Codeception\Lib\ModuleContainer; +use Codeception\Module; /** * Group class is Codeception Extension which is allowed to handle to all internal events. @@ -24,9 +29,15 @@ class functionalSuiteWithComments extends \Codeception\GroupObject private $currentTestRun = 0; private static $HOOK_EXECUTION_INIT = "\n/******** Beginning execution of functionalSuiteWithComments suite %s block ********/\n"; private static $HOOK_EXECUTION_END = "\n/******** Execution of functionalSuiteWithComments suite %s block complete ********/\n"; + /** @var MagentoWebDriver */ + private $webDriver; + /** @var ModuleContainer */ + private $moduleContainer; public function _before(\Codeception\Event\TestEvent $e) { + $this->webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); + $this->moduleContainer = $this->webDriver->getModuleContainer(); // increment test count per execution $this->currentTestRun++; $this->executePreConditions(); @@ -37,23 +48,19 @@ class functionalSuiteWithComments extends \Codeception\GroupObject } } - private function executePreConditions() { if ($this->currentTestRun == 1) { print sprintf(self::$HOOK_EXECUTION_INIT, "before"); - /** @var MagentoWebDriver $webDriver */ - $webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); - try { - if ($webDriver->webDriver != null) { - $webDriver->_restart(); + if ($this->webDriver->webDriver != null) { + $this->webDriver->_restart(); } else { - $webDriver->_initializeSession(); + $this->webDriver->_initializeSession(); } print("Comment in Before"); - $webDriver->amOnPage("some.url"); // stepKey: before + $this->getModuleForAction("amOnPage")->amOnPage("some.url"); // stepKey: before $createFields['someKey'] = "dataHere"; PersistedObjectHandler::getInstance()->createEntity( "create", @@ -63,18 +70,18 @@ class functionalSuiteWithComments extends \Codeception\GroupObject $createFields ); print("<click stepKey=\"comment with element\" userInput=\"helloworld\"/>"); - $webDriver->click(PersistedObjectHandler::getInstance()->retrieveEntityField('create', 'data', 'suite')); // stepKey: clickWithData + $this->getModuleForAction("click")->click(PersistedObjectHandler::getInstance()->retrieveEntityField('create', 'data', 'suite')); // stepKey: clickWithData print("Entering Action Group [AC] actionGroupWithTwoArguments"); - $webDriver->see("John", msq("uniqueData") . "John"); // stepKey: seeFirstNameAC + $this->getModuleForAction("see")->see("John", msq("uniqueData") . "John"); // stepKey: seeFirstNameAC print("Exiting Action Group [AC] actionGroupWithTwoArguments"); } catch (\Exception $exception) { $this->preconditionFailure = $exception->getMessage(); } // reset configuration and close session - $webDriver->_resetConfig(); - $webDriver->webDriver->close(); - $webDriver->webDriver = null; + $this->webDriver->_resetConfig(); + $this->webDriver->webDriver->close(); + $this->webDriver->webDriver = null; print sprintf(self::$HOOK_EXECUTION_END, "before"); } @@ -85,15 +92,11 @@ class functionalSuiteWithComments extends \Codeception\GroupObject $this->executePostConditions($e); } - private function executePostConditions(\Codeception\Event\TestEvent $e) { if ($this->currentTestRun == $this->testCount) { print sprintf(self::$HOOK_EXECUTION_INIT, "after"); - /** @var MagentoWebDriver $webDriver */ - $webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); - try { // Find out if Test in Suite failed, will cause potential failures in suite after $cest = $e->getTest(); @@ -116,10 +119,10 @@ class functionalSuiteWithComments extends \Codeception\GroupObject } } } - if ($webDriver->webDriver != null) { - $webDriver->_restart(); + if ($this->webDriver->webDriver != null) { + $this->webDriver->_restart(); } else { - $webDriver->_initializeSession(); + $this->webDriver->_initializeSession(); } print("afterBlock"); } catch (\Exception $exception) { @@ -128,7 +131,7 @@ class functionalSuiteWithComments extends \Codeception\GroupObject PersistedObjectHandler::getInstance()->clearSuiteObjects(); - $this->closeSession($webDriver); + $this->closeSession($this->webDriver); print sprintf(self::$HOOK_EXECUTION_END, "after"); } @@ -138,13 +141,12 @@ class functionalSuiteWithComments extends \Codeception\GroupObject * Close session method closes current session. * If config 'close_all_sessions' is set to 'true' all sessions will be closed. * - * @param MagentoWebDriver $webDriver * return void */ - private function closeSession(MagentoWebDriver $webDriver): void + private function closeSession(): void { - $webDriverConfig = $webDriver->_getConfig(); - $webDriver->_closeSession(); + $webDriverConfig = $this->webDriver->_getConfig(); + $this->webDriver->_closeSession(); if (isset($webDriverConfig['close_all_sessions']) && $webDriverConfig['close_all_sessions'] === "true") { $wdHost = sprintf( '%s://%s:%s%s', @@ -160,4 +162,20 @@ class functionalSuiteWithComments extends \Codeception\GroupObject } } } + + /** + * Return the module for an action. + * + * @param string $action + * @return Module + * @throws \Exception + */ + private function getModuleForAction($action) + { + $module = $this->moduleContainer->moduleForAction($action); + if ($module === null) { + throw new TestFrameworkException('Invalid action "' . $action . '"' . PHP_EOL); + } + return $module; + } } diff --git a/dev/tests/verification/TestModule/Data/PersistedReplacementData.xml b/dev/tests/verification/TestModule/Data/PersistedReplacementData.xml index 514b5eec6..7213fa6b9 100644 --- a/dev/tests/verification/TestModule/Data/PersistedReplacementData.xml +++ b/dev/tests/verification/TestModule/Data/PersistedReplacementData.xml @@ -22,4 +22,8 @@ <data key="lastName">Dane</data> <data key="mergedField">unmerged</data> </entity> + <entity name="SecretData" type="SecretData"> + <data key="key1">some/data</data> + <data key="key2">{{_CREDS.magento/some/secret}}</data> + </entity> </entities> diff --git a/dev/tests/verification/TestModule/Suite/functionalSuiteUsingSecretData.xml b/dev/tests/verification/TestModule/Suite/functionalSuiteUsingSecretData.xml new file mode 100644 index 000000000..fdb9164cb --- /dev/null +++ b/dev/tests/verification/TestModule/Suite/functionalSuiteUsingSecretData.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<suites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Suite/etc/suiteSchema.xsd"> + <suite name="functionalSuiteUsingSecretData"> + <include> + <test name="IncludeUsingSecretDataTest"/> + </include> + <before> + <magentoCLI command="{{SecretData.key2}}" stepKey="cli"/> + <createData entity="SecretData" stepKey="create1"> + <field key="someKey">dataHere</field> + </createData> + <createData entity="SecretData" stepKey="create2"/> + <createData entity="SecretData" stepKey="create3"> + <requiredEntity createDataKey="create1"/> + <requiredEntity createDataKey="create2"/> + </createData> + <fillField selector="#fill" userInput="{{SecretData.key2}}+{{SecretData.key2}}" stepKey="fillBefore"/> + <click userInput="$create2.key2$" stepKey="click"/> + </before> + <after> + <deleteData createDataKey="create1" stepKey="delete1"/> + <deleteData createDataKey="create2" stepKey="delete2"/> + <deleteData createDataKey="create3" stepKey="delete3"/> + <deleteData url="deleteThis" stepKey="deleteThis"/> + <fillField selector="#fill" userInput="{{SecretData.key2}}" stepKey="fillAfter"/> + <magentoCLI command="{{SecretData.key2}}-{{SecretData.key1}}-{{SecretData.key2}}" stepKey="cli2"/> + </after> + </suite> +</suites> diff --git a/dev/tests/verification/TestModule/Test/SampleSuiteTest/IncludeUsingSecretDataTest.xml b/dev/tests/verification/TestModule/Test/SampleSuiteTest/IncludeUsingSecretDataTest.xml new file mode 100644 index 000000000..14360e2f3 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/SampleSuiteTest/IncludeUsingSecretDataTest.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="IncludeUsingSecretDataTest"> + <createData entity="SecretData" stepKey="create"> + <field key="someKey">dataHere</field> + </createData> + <fillField selector="#fill" userInput="{{SecretData.key2}}+$create.key2$" stepKey="fill"/> + <magentoCLI command="create.key2$" stepKey="cli"/> + </test> +</tests> diff --git a/dev/tests/verification/Tests/SuiteGenerationTest.php b/dev/tests/verification/Tests/SuiteGenerationTest.php index 4a8371692..633146eef 100644 --- a/dev/tests/verification/Tests/SuiteGenerationTest.php +++ b/dev/tests/verification/Tests/SuiteGenerationTest.php @@ -388,6 +388,65 @@ public function testSuiteCommentsGeneration() ); } + /** + * Test hook groups generated during suite generation + */ + public function testSuiteGenerationCreds() + { + $groupName = 'functionalSuiteUsingSecretData'; + + $expectedContents = [ + 'IncludeUsingSecretDataTestCest.php' + ]; + + // Generate the Suite + SuiteGenerator::getInstance()->generateSuite($groupName); + + // Validate log message and add group name for later deletion + TestLoggingUtil::getInstance()->validateMockLogStatement( + 'info', + "suite generated", + ['suite' => $groupName, 'relative_path' => "_generated" . DIRECTORY_SEPARATOR . $groupName] + ); + self::$TEST_GROUPS[] = $groupName; + + // Validate Yaml file updated + $yml = Yaml::parse(file_get_contents(self::CONFIG_YML_FILE)); + $this->assertArrayHasKey($groupName, $yml['groups']); + + $suiteResultBaseDir = self::GENERATE_RESULT_DIR . + DIRECTORY_SEPARATOR . + $groupName . + DIRECTORY_SEPARATOR; + + // Validate tests have been generated + $dirContents = array_diff(scandir($suiteResultBaseDir), ['..', '.']); + + foreach ($expectedContents as $expectedFile) { + $this->assertTrue(in_array($expectedFile, $dirContents)); + } + + //assert group file created and contains correct contents + $groupFile = PROJECT_ROOT . + DIRECTORY_SEPARATOR . + "src" . + DIRECTORY_SEPARATOR . + "Magento" . + DIRECTORY_SEPARATOR . + "FunctionalTestingFramework" . + DIRECTORY_SEPARATOR . + "Group" . + DIRECTORY_SEPARATOR . + $groupName . + ".php"; + + $this->assertTrue(file_exists($groupFile)); + $this->assertFileEquals( + self::RESOURCES_PATH . DIRECTORY_SEPARATOR . $groupName . ".txt", + $groupFile + ); + } + /** * revert any changes made to config.yml * remove _generated directory From daf1e4c1464c5f195774eda215e9dd0f108b6acf Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Fri, 31 Jul 2020 11:37:27 -0500 Subject: [PATCH 497/888] MQE-2158: support using actions from multiple modules in Suites --- ...txt => ActionsInDifferentModulesSuite.txt} | 21 +++++++++++++++---- ...xml => ActionsInDifferentModulesSuite.xml} | 11 ++++++++-- ... IncludeActionsInDifferentModulesTest.xml} | 5 ++++- .../Tests/SuiteGenerationTest.php | 8 +++---- 4 files changed, 34 insertions(+), 11 deletions(-) rename dev/tests/verification/Resources/{functionalSuiteUsingSecretData.txt => ActionsInDifferentModulesSuite.txt} (82%) rename dev/tests/verification/TestModule/Suite/{functionalSuiteUsingSecretData.xml => ActionsInDifferentModulesSuite.xml} (75%) rename dev/tests/verification/TestModule/Test/SampleSuiteTest/{IncludeUsingSecretDataTest.xml => IncludeActionsInDifferentModulesTest.xml} (74%) diff --git a/dev/tests/verification/Resources/functionalSuiteUsingSecretData.txt b/dev/tests/verification/Resources/ActionsInDifferentModulesSuite.txt similarity index 82% rename from dev/tests/verification/Resources/functionalSuiteUsingSecretData.txt rename to dev/tests/verification/Resources/ActionsInDifferentModulesSuite.txt index 1be43a544..d4e1b6eb3 100644 --- a/dev/tests/verification/Resources/functionalSuiteUsingSecretData.txt +++ b/dev/tests/verification/Resources/ActionsInDifferentModulesSuite.txt @@ -21,14 +21,14 @@ use Codeception\Module; * * To use this group extension, include it to "extensions" option of global Codeception config. */ -class functionalSuiteUsingSecretData extends \Codeception\GroupObject +class ActionsInDifferentModulesSuite extends \Codeception\GroupObject { - public static $group = 'functionalSuiteUsingSecretData'; + public static $group = 'ActionsInDifferentModulesSuite'; private $testCount = 1; private $preconditionFailure = null; private $currentTestRun = 0; - private static $HOOK_EXECUTION_INIT = "\n/******** Beginning execution of functionalSuiteUsingSecretData suite %s block ********/\n"; - private static $HOOK_EXECUTION_END = "\n/******** Execution of functionalSuiteUsingSecretData suite %s block complete ********/\n"; + private static $HOOK_EXECUTION_INIT = "\n/******** Beginning execution of ActionsInDifferentModulesSuite suite %s block ********/\n"; + private static $HOOK_EXECUTION_END = "\n/******** Execution of ActionsInDifferentModulesSuite suite %s block complete ********/\n"; /** @var MagentoWebDriver */ private $webDriver; /** @var ModuleContainer */ @@ -83,6 +83,11 @@ class functionalSuiteUsingSecretData extends \Codeception\GroupObject ); $this->getModuleForAction("fillSecretField")->fillSecretField("#fill", $this->getModuleForAction("getSecret")->getSecret("magento/some/secret") . "+" . $this->getModuleForAction("getSecret")->getSecret("magento/some/secret")); // stepKey: fillBefore $this->getModuleForAction("click")->click(PersistedObjectHandler::getInstance()->retrieveEntityField('create2', 'key2', 'suite')); // stepKey: click + print("Entering Action Group [return1] ActionGroupReturningValueActionGroup"); + $grabProducts1Return1 = $this->getModuleForAction("grabMultiple")->grabMultiple("selector"); // stepKey: grabProducts1Return1 + $this->getModuleForAction("assertCount")->assertCount(1, $grabProducts1Return1); // stepKey: assertCountReturn1 + $return1 = $this->getModuleForAction("return")->return($grabProducts1Return1); // stepKey: returnProducts1Return1 + print("Exiting Action Group [return1] ActionGroupReturningValueActionGroup"); } catch (\Exception $exception) { $this->preconditionFailure = $exception->getMessage(); } @@ -133,6 +138,14 @@ class functionalSuiteUsingSecretData extends \Codeception\GroupObject } else { $this->webDriver->_initializeSession(); } + print("Entering Action Group [return2] ExtendedActionGroupReturningValueActionGroup"); + $grabProducts1Return2 = $this->getModuleForAction("grabMultiple")->grabMultiple("selector"); // stepKey: grabProducts1Return2 + $this->getModuleForAction("assertCount")->assertCount(1, $grabProducts1Return2); // stepKey: assertCountReturn2 + $return2 = $this->getModuleForAction("return")->return($grabProducts1Return2); // stepKey: returnProducts1Return2 + $grabProducts2Return2 = $this->getModuleForAction("grabMultiple")->grabMultiple("otherSelector"); // stepKey: grabProducts2Return2 + $this->getModuleForAction("assertCount")->assertCount(2, $grabProducts2Return2); // stepKey: assertSecondCountReturn2 + $return2 = $this->getModuleForAction("return")->return($grabProducts2Return2); // stepKey: returnProducts2Return2 + print("Exiting Action Group [return2] ExtendedActionGroupReturningValueActionGroup"); PersistedObjectHandler::getInstance()->deleteEntity( "create1", "suite" diff --git a/dev/tests/verification/TestModule/Suite/functionalSuiteUsingSecretData.xml b/dev/tests/verification/TestModule/Suite/ActionsInDifferentModulesSuite.xml similarity index 75% rename from dev/tests/verification/TestModule/Suite/functionalSuiteUsingSecretData.xml rename to dev/tests/verification/TestModule/Suite/ActionsInDifferentModulesSuite.xml index fdb9164cb..e3553308d 100644 --- a/dev/tests/verification/TestModule/Suite/functionalSuiteUsingSecretData.xml +++ b/dev/tests/verification/TestModule/Suite/ActionsInDifferentModulesSuite.xml @@ -7,9 +7,9 @@ --> <suites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Suite/etc/suiteSchema.xsd"> - <suite name="functionalSuiteUsingSecretData"> + <suite name="ActionsInDifferentModulesSuite"> <include> - <test name="IncludeUsingSecretDataTest"/> + <test name="IncludeActionsInDifferentModulesTest"/> </include> <before> <magentoCLI command="{{SecretData.key2}}" stepKey="cli"/> @@ -23,8 +23,15 @@ </createData> <fillField selector="#fill" userInput="{{SecretData.key2}}+{{SecretData.key2}}" stepKey="fillBefore"/> <click userInput="$create2.key2$" stepKey="click"/> + <actionGroup ref="ActionGroupReturningValueActionGroup" stepKey="return1"> + <argument name="count" value="1"/> + </actionGroup> </before> <after> + <actionGroup ref="ExtendedActionGroupReturningValueActionGroup" stepKey="return2"> + <argument name="count" value="1"/> + <argument name="otherCount" value="2"/> + </actionGroup> <deleteData createDataKey="create1" stepKey="delete1"/> <deleteData createDataKey="create2" stepKey="delete2"/> <deleteData createDataKey="create3" stepKey="delete3"/> diff --git a/dev/tests/verification/TestModule/Test/SampleSuiteTest/IncludeUsingSecretDataTest.xml b/dev/tests/verification/TestModule/Test/SampleSuiteTest/IncludeActionsInDifferentModulesTest.xml similarity index 74% rename from dev/tests/verification/TestModule/Test/SampleSuiteTest/IncludeUsingSecretDataTest.xml rename to dev/tests/verification/TestModule/Test/SampleSuiteTest/IncludeActionsInDifferentModulesTest.xml index 14360e2f3..1be662bbe 100644 --- a/dev/tests/verification/TestModule/Test/SampleSuiteTest/IncludeUsingSecretDataTest.xml +++ b/dev/tests/verification/TestModule/Test/SampleSuiteTest/IncludeActionsInDifferentModulesTest.xml @@ -7,11 +7,14 @@ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> - <test name="IncludeUsingSecretDataTest"> + <test name="IncludeActionsInDifferentModulesTest"> <createData entity="SecretData" stepKey="create"> <field key="someKey">dataHere</field> </createData> <fillField selector="#fill" userInput="{{SecretData.key2}}+$create.key2$" stepKey="fill"/> <magentoCLI command="create.key2$" stepKey="cli"/> + <actionGroup ref="ActionGroupReturningValueActionGroup" stepKey="return"> + <argument name="count" value="3"/> + </actionGroup> </test> </tests> diff --git a/dev/tests/verification/Tests/SuiteGenerationTest.php b/dev/tests/verification/Tests/SuiteGenerationTest.php index 633146eef..f37283871 100644 --- a/dev/tests/verification/Tests/SuiteGenerationTest.php +++ b/dev/tests/verification/Tests/SuiteGenerationTest.php @@ -389,14 +389,14 @@ public function testSuiteCommentsGeneration() } /** - * Test hook groups generated during suite generation + * Test suite generation with actions from different modules */ - public function testSuiteGenerationCreds() + public function testSuiteGenerationActionsInDifferentModules() { - $groupName = 'functionalSuiteUsingSecretData'; + $groupName = 'ActionsInDifferentModulesSuite'; $expectedContents = [ - 'IncludeUsingSecretDataTestCest.php' + 'IncludeActionsInDifferentModulesTestCest.php' ]; // Generate the Suite From 65298651f64258ae8b65f5265bc9867cbb5a2f13 Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Mon, 3 Aug 2020 16:51:46 -0500 Subject: [PATCH 498/888] MQE-1974: Report used deprecated metadata in Test (#772) * MQE-1974: Report used deprecated metadata in Test * MQE-1974: Report used deprecated metadata in Test * MQE-1974: Report used deprecated metadata in Test * MQE-1974: Report used deprecated metadata in Test verification tests --- .../Handlers/DataObjectHandlerTest.php | 51 ++++++++++++++ .../OperationDefinitionObjectHandlerTest.php | 67 +++++++++++++++++++ .../Page/Handlers/PageObjectHandlerTest.php | 41 ++++++++++++ .../Handlers/SectionObjectHandlerTest.php | 47 +++++++++++++ .../Util/ActionGroupObjectExtractorTest.php | 26 ++++++- .../Handlers/DataObjectHandler.php | 4 +- .../OperationDefinitionObjectHandler.php | 4 +- .../Objects/OperationDefinitionObject.php | 18 +++++ .../DataGenerator/Persist/CurlHandler.php | 1 + .../Page/Handlers/PageObjectHandler.php | 4 +- .../Page/Handlers/SectionObjectHandler.php | 4 +- .../Test/Util/ActionGroupObjectExtractor.php | 4 +- .../Util/Logger/MftfLogger.php | 10 +-- 13 files changed, 266 insertions(+), 15 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php index c9ec92ba8..9f1ca7b5c 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php @@ -13,12 +13,21 @@ use Magento\FunctionalTestingFramework\ObjectManager; use Magento\FunctionalTestingFramework\ObjectManagerFactory; use tests\unit\Util\MagentoTestCase; +use tests\unit\Util\TestLoggingUtil; /** * Class DataObjectHandlerTest */ class DataObjectHandlerTest extends MagentoTestCase { + /** + * Setup method + */ + public function setUp(): void + { + TestLoggingUtil::getInstance()->setMockLoggingUtil(); + } + // All tests share this array, feel free to add but be careful modifying or removing const PARSER_OUTPUT = [ 'entity' => [ @@ -44,6 +53,22 @@ class DataObjectHandlerTest extends MagentoTestCase ] ]; + const PARSER_OUTPUT_DEPRECATED = [ + 'entity' => [ + 'EntityOne' => [ + 'type' => 'testType', + 'data' => [ + 0 => [ + 'key' => 'testKey', + 'value' => 'testValue' + ] + ], + 'deprecated' => "deprecation message", + 'filename' => "filename.xml" + ], + ] + ]; + const PARSER_OUTPUT_WITH_EXTEND = [ 'entity' => [ 'EntityOne' => [ @@ -134,6 +159,24 @@ public function testGetAllObjects() $this->assertEquals($expected, $actual['EntityOne']); } + /** + * test deprecated data object + */ + public function testDeprecatedDataObject() + { + $this->setUpMockDataObjectHander(self::PARSER_OUTPUT_DEPRECATED); + + // Call the method under test + $actual = DataObjectHandler::getInstance()->getAllObjects(); + + //validate deprecation warning + TestLoggingUtil::getInstance()->validateMockLogStatement( + 'warning', + "DEPRECATION: The data entity 'EntityOne' is deprecated.", + ["fileName" => "filename.xml", "deprecatedMessage" => "deprecation message"] + ); + } + /** * getObject should return the expected data object if it exists */ @@ -269,4 +312,12 @@ private function setUpMockDataObjectHander($entityDataArray) 'getObjectManager' => $mockObjectManager ]); } + + /** + * clean up function runs after all tests + */ + public static function tearDownAfterClass(): void + { + TestLoggingUtil::getInstance()->clearMockLoggingUtil(); + } } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php index 9ca10c7f2..570e8d95a 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php @@ -14,12 +14,21 @@ use Magento\FunctionalTestingFramework\DataGenerator\Handlers\OperationDefinitionObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Parsers\OperationDefinitionParser; use tests\unit\Util\MagentoTestCase; +use tests\unit\Util\TestLoggingUtil; /** * Class OperationDefinitionObjectHandlerTest */ class OperationDefinitionObjectHandlerTest extends MagentoTestCase { + /** + * Setup method + */ + public function setUp(): void + { + TestLoggingUtil::getInstance()->setMockLoggingUtil(); + } + public function testGetMultipleObjects() { // Data Variables for Assertions @@ -72,6 +81,56 @@ public function testGetMultipleObjects() $this->assertArrayHasKey($operationType2 . $dataType1, $operations); } + public function testDeprecatedOperation() + { + // Data Variables for Assertions + $dataType1 = "type1"; + $operationType1 = "create"; + + /** + * Parser Output. Just one metadata with 1 field + * operationName + * createType1 + * has field + * key=id, value=integer + */ + $mockData = [OperationDefinitionObjectHandler::ENTITY_OPERATION_ROOT_TAG => [ + "testOperationName" => [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE => $dataType1, + OperationDefinitionObjectHandler::ENTITY_OPERATION_TYPE => $operationType1, + OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH => "auth", + OperationDefinitionObjectHandler::ENTITY_OPERATION_URL => "V1/Type1", + OperationDefinitionObjectHandler::ENTITY_OPERATION_METHOD => "POST", + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY => [ + 0 => [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => "id", + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => "integer" + ], + ], + OperationDefinitionObjectHandler::OBJ_DEPRECATED => 'deprecation message' + ]]]; + $this->setMockParserOutput($mockData); + + //Perform Assertions + $operationDefinitionManager = OperationDefinitionObjectHandler::getInstance(); + $operations = $operationDefinitionManager->getAllObjects(); + + $this->assertArrayHasKey($operationType1 . $dataType1, $operations); + TestLoggingUtil::getInstance()->validateMockLogStatement( + 'notice', + "NOTICE: 1 metadata operation name violations detected. See mftf.log for details.", + [] + ); + // test run time deprecation notice + $operation = $operationDefinitionManager->getOperationDefinition($operationType1, $dataType1); + $operation->logDeprecated(); + TestLoggingUtil::getInstance()->validateMockLogStatement( + 'warning', + "DEPRECATION: The operation testOperationName is deprecated.", + ['operationType' => 'create', 'deprecatedMessage' => 'deprecation message'] + ); + } + public function testObjectCreation() { // Data Variables for Assertions @@ -379,4 +438,12 @@ private function setMockParserOutput($data) $instance = AspectMock::double(ObjectManager::class, ['create' => $mockOperationParser])->make(); AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); } + + /** + * clean up function runs after all tests + */ + public static function tearDownAfterClass(): void + { + TestLoggingUtil::getInstance()->clearMockLoggingUtil(); + } } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/PageObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/PageObjectHandlerTest.php index 1a0ba5fc2..c934b680b 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/PageObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/PageObjectHandlerTest.php @@ -12,9 +12,18 @@ use Magento\FunctionalTestingFramework\Page\Handlers\PageObjectHandler; use Magento\FunctionalTestingFramework\XmlParser\PageParser; use tests\unit\Util\MagentoTestCase; +use tests\unit\Util\TestLoggingUtil; class PageObjectHandlerTest extends MagentoTestCase { + /** + * Setup method + */ + public function setUp(): void + { + TestLoggingUtil::getInstance()->setMockLoggingUtil(); + } + public function testGetPageObject() { $mockData = [ @@ -70,6 +79,30 @@ public function testGetEmptyPage() $this->addToAssertionCount(1); } + public function testDeprecatedPage() + { + $mockData = [ + "testPage1" => [ + "url" => "testURL1", + "module" => "testModule1", + "section" => [ + ], + "area" => "test", + "deprecated" => "deprecation message", + "filename" => "filename.xml" + ]]; + $this->setMockParserOutput($mockData); + + // get pages + $page = PageObjectHandler::getInstance()->getObject('testPage1'); + + TestLoggingUtil::getInstance()->validateMockLogStatement( + 'notice', + "NOTICE: 1 Page name violations detected. See mftf.log for details.", + [] + ); + } + /** * Function used to set mock for parser return and force init method to run between tests. * @@ -86,4 +119,12 @@ private function setMockParserOutput($data) $instance = AspectMock::double(ObjectManager::class, ['get' => $mockSectionParser])->make(); AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); } + + /** + * clean up function runs after all tests + */ + public static function tearDownAfterClass(): void + { + TestLoggingUtil::getInstance()->clearMockLoggingUtil(); + } } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/SectionObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/SectionObjectHandlerTest.php index b8bcf3dfb..39e26caf9 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/SectionObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/SectionObjectHandlerTest.php @@ -12,9 +12,18 @@ use Magento\FunctionalTestingFramework\Page\Handlers\SectionObjectHandler; use Magento\FunctionalTestingFramework\XmlParser\SectionParser; use tests\unit\Util\MagentoTestCase; +use tests\unit\Util\TestLoggingUtil; class SectionObjectHandlerTest extends MagentoTestCase { + /** + * Setup method + */ + public function setUp(): void + { + TestLoggingUtil::getInstance()->setMockLoggingUtil(); + } + public function testGetSectionObject() { $mockData = [ @@ -52,6 +61,36 @@ public function testGetSectionObject() $this->assertNull($invalidSection); } + public function testDeprecatedSection() + { + $mockData = [ + "testSection1" => [ + "element" => [ + "testElement" => [ + "type" => "input", + "selector" => "#element", + "deprecated" => "element deprecation message" + ] + ], + "filename" => "filename.xml", + "deprecated" => "section deprecation message" + ] + ]; + + $this->setMockParserOutput($mockData); + + // get sections + $sectionHandler = SectionObjectHandler::getInstance(); + $section = $sectionHandler->getObject("testSection1"); + + //validate deprecation warning + TestLoggingUtil::getInstance()->validateMockLogStatement( + 'notice', + "NOTICE: 1 Section name violations detected. See mftf.log for details.", + [] + ); + } + /** * Set the mock parser return value * @@ -68,4 +107,12 @@ private function setMockParserOutput($data) $instance = AspectMock::double(ObjectManager::class, ["get" => $mockSectionParser])->make(); AspectMock::double(ObjectManagerFactory::class, ["getObjectManager" => $instance]); } + + /** + * clean up function runs after all tests + */ + public static function tearDownAfterClass(): void + { + TestLoggingUtil::getInstance()->clearMockLoggingUtil(); + } } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionGroupObjectExtractorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionGroupObjectExtractorTest.php index 2c9e171d5..1fea7e848 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionGroupObjectExtractorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionGroupObjectExtractorTest.php @@ -34,23 +34,47 @@ public function testEmptyStepKey() $this->testActionGroupObjectExtractor->extractActionGroup($this->createBasicActionObjectArray("")); } + /** + * Tests deprecation message for an action group + */ + public function testDeprecationMessage() + { + $this->testActionGroupObjectExtractor->extractActionGroup( + $this->createBasicActionObjectArray( + "testDeprecatedAction1", + "actionGroup", + "filename1.xml", + "message" + ) + ); + + TestLoggingUtil::getInstance()->validateMockLogStatement( + 'warning', + "DEPRECATION: The action group 'actionGroup' is deprecated.", + ["fileName" => "filename1.xml", "deprecatedMessage" => "message"] + ); + } + /** * Utility function to return mock parser output for testing extraction into ActionObjects. * * @param string $stepKey * @param string $actionGroup * @param string $filename + * @param string $deprecated * @return array */ private function createBasicActionObjectArray( $stepKey = 'testAction1', $actionGroup = "actionGroup", - $filename = "filename.xml" + $filename = "filename.xml", + $deprecated = null ) { $baseArray = [ 'nodeName' => 'actionGroup', 'name' => $actionGroup, 'filename' => $filename, + 'deprecated' => $deprecated, $stepKey => [ "nodeName" => "sampleAction", "stepKey" => $stepKey, diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php index 5a4b42dc4..87dc6a13d 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php @@ -191,8 +191,8 @@ private function processParserOutput($parserOutput) if (array_key_exists(self::OBJ_DEPRECATED, $rawEntity)) { $deprecated = $rawEntity[self::OBJ_DEPRECATED]; LoggingUtil::getInstance()->getLogger(self::class)->deprecation( - $deprecated, - ["dataName" => $filename, "deprecatedEntity" => $deprecated] + "The data entity '{$name}' is deprecated.", + ["fileName" => $filename, "deprecatedMessage" => $deprecated] ); } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php index 2c8ab7530..eb4651b3e 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php @@ -215,8 +215,8 @@ private function initialize() if ($deprecated !== null) { LoggingUtil::getInstance()->getLogger(self::class)->deprecation( - $deprecated, - ["operationName" => $dataDefName, "deprecatedOperation" => $deprecated] + $message = "The operation {$dataDefName} is deprecated.", + ["operationType" => $operation, "deprecatedMessage" => $deprecated] ); } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/OperationDefinitionObject.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/OperationDefinitionObject.php index 67fe48300..ef1a7faa5 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/OperationDefinitionObject.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/OperationDefinitionObject.php @@ -6,6 +6,8 @@ namespace Magento\FunctionalTestingFramework\DataGenerator\Objects; +use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; + /** * Class OperationDefinitionObject * @SuppressWarnings(PHPMD) @@ -341,4 +343,20 @@ public function addQueryParams() $this->apiUrl = $this->apiUrl . $paramName . "=" . $paramValue; } } + + /** + * Function to log a referenced deprecated operation at runtime. + * + * @return void + */ + public function logDeprecated() + { + if ($this->deprecated != null) { + LoggingUtil::getInstance()->getLogger(self::class)->deprecation( + $message = "The operation {$this->name} is deprecated.", + ["operationType" => $this->operation, "deprecatedMessage" => $this->deprecated], + true + ); + } + } } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php index 362d25e75..89055b83f 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php @@ -123,6 +123,7 @@ public function executeRequest($dependentEntities) $returnRegex = $this->operationDefinition->getReturnRegex(); $returnIndex = $this->operationDefinition->getReturnIndex(); $method = $this->operationDefinition->getApiMethod(); + $this->operationDefinition->logDeprecated(); AllureHelper::addAttachmentToCurrentStep($apiUrl, 'API Endpoint'); AllureHelper::addAttachmentToCurrentStep(json_encode($headers, JSON_PRETTY_PRINT), 'Request Headers'); diff --git a/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php b/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php index 73695c182..8f4302077 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php @@ -79,8 +79,8 @@ private function __construct() if ($deprecated !== null) { LoggingUtil::getInstance()->getLogger(self::class)->deprecation( - $deprecated, - ["pageName" => $filename, "deprecatedPage" => $deprecated] + "The page '{$pageName}' is deprecated.", + ["fileName" => $filename, "deprecatedMessage" => $deprecated] ); } diff --git a/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php b/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php index 5d658bac0..6ac3456fd 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php @@ -89,8 +89,8 @@ private function __construct() $elementDeprecated = $elementData[self::OBJ_DEPRECATED] ?? null; if ($elementDeprecated !== null) { LoggingUtil::getInstance()->getLogger(ElementObject::class)->deprecation( - $elementDeprecated, - ["elementName" => $elementName, "deprecatedElement" => $elementDeprecated] + "The element '{$elementName}' is deprecated.", + ["fileName" => $filename, "deprecatedMessage" => $elementDeprecated] ); } $elements[$elementName] = new ElementObject( diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/ActionGroupObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/ActionGroupObjectExtractor.php index 618cddc09..84b960f1b 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/ActionGroupObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/ActionGroupObjectExtractor.php @@ -65,8 +65,8 @@ public function extractActionGroup($actionGroupData) if (array_key_exists(self::OBJ_DEPRECATED, $actionGroupData)) { $deprecated = $actionGroupData[self::OBJ_DEPRECATED]; LoggingUtil::getInstance()->getLogger(ActionGroupObject::class)->deprecation( - $deprecated, - ["actionGroupName" => $actionGroupData[self::FILENAME], "deprecatedActionGroup" => $deprecated] + "The action group '{$actionGroupData[self::NAME]}' is deprecated.", + ["fileName" => $actionGroupData[self::FILENAME], "deprecatedMessage" => $deprecated] ); } $actionGroupReference = $actionGroupData[self::EXTENDS_ACTION_GROUP] ?? null; diff --git a/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php b/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php index 5955235ce..880dd9736 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php +++ b/src/Magento/FunctionalTestingFramework/Util/Logger/MftfLogger.php @@ -46,12 +46,14 @@ public function __construct($name, array $handlers = [], array $processors = []) public function deprecation($message, array $context = [], $verbose = false) { $message = "DEPRECATION: " . $message; - // print during test generation - if ($this->phase === MftfApplicationConfig::GENERATION_PHASE && $verbose) { + // print during test generation including metadata + if ((array_key_exists('operationType', $context) || + $this->phase === MftfApplicationConfig::GENERATION_PHASE) && $verbose) { print ($message . json_encode($context) . "\n"); } - // suppress logging during test execution - if ($this->phase !== MftfApplicationConfig::EXECUTION_PHASE) { + // suppress logging during test execution except metadata + if (array_key_exists('operationType', $context) || + $this->phase !== MftfApplicationConfig::EXECUTION_PHASE) { parent::warning($message, $context); } } From 4126761d5b84b1508c2b8e8a5bcc284e702628c7 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Fri, 7 Aug 2020 08:50:19 -0500 Subject: [PATCH 499/888] MQE-2110: MFTF command to pause test execution --- composer.json | 1 + composer.lock | 551 +++++++++++++++++- .../Test/Handlers/TestObjectHandlerTest.php | 95 ++- docs/configuration.md | 9 + docs/test/actions.md | 2 +- etc/config/.env.example | 3 + .../Console/BaseGenerateCommand.php | 24 + .../Console/RunManifestCommand.php | 9 +- .../Console/RunTestCommand.php | 7 + .../Console/RunTestFailedCommand.php | 4 + .../Console/RunTestGroupCommand.php | 4 + .../Test/Util/TestHookObjectExtractor.php | 9 +- 12 files changed, 709 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index e1a04296f..6f8b0c2c2 100755 --- a/composer.json +++ b/composer.json @@ -24,6 +24,7 @@ "composer/composer": "^1.9", "csharpru/vault-php": "~3.5.3", "csharpru/vault-php-guzzle6-transport": "^2.0", + "hoa/console": "~3.0", "monolog/monolog": "^1.17", "mustache/mustache": "~2.5", "php-webdriver/webdriver": "^1.8.0", diff --git a/composer.lock b/composer.lock index dff4f1006..91fa2c772 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "a0516f6072ced659bf4ed7a486756bb2", + "content-hash": "98733866973fb51e11e316b98c0af563", "packages": [ { "name": "allure-framework/allure-codeception", @@ -1662,6 +1662,555 @@ ], "time": "2019-07-01T23:21:34+00:00" }, + { + "name": "hoa/consistency", + "version": "1.17.05.02", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Consistency.git", + "reference": "fd7d0adc82410507f332516faf655b6ed22e4c2f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Consistency/zipball/fd7d0adc82410507f332516faf655b6ed22e4c2f", + "reference": "fd7d0adc82410507f332516faf655b6ed22e4c2f", + "shasum": "" + }, + "require": { + "hoa/exception": "~1.0", + "php": ">=5.5.0" + }, + "require-dev": { + "hoa/stream": "~1.0", + "hoa/test": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\Consistency\\": "." + }, + "files": [ + "Prelude.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Consistency library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "autoloader", + "callable", + "consistency", + "entity", + "flex", + "keyword", + "library" + ], + "time": "2017-05-02T12:18:12+00:00" + }, + { + "name": "hoa/console", + "version": "3.17.05.02", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Console.git", + "reference": "e231fd3ea70e6d773576ae78de0bdc1daf331a66" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Console/zipball/e231fd3ea70e6d773576ae78de0bdc1daf331a66", + "reference": "e231fd3ea70e6d773576ae78de0bdc1daf331a66", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/event": "~1.0", + "hoa/exception": "~1.0", + "hoa/file": "~1.0", + "hoa/protocol": "~1.0", + "hoa/stream": "~1.0", + "hoa/ustring": "~4.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "suggest": { + "ext-pcntl": "To enable hoa://Event/Console/Window:resize.", + "hoa/dispatcher": "To use the console kit.", + "hoa/router": "To use the console kit." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\Console\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Console library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "autocompletion", + "chrome", + "cli", + "console", + "cursor", + "getoption", + "library", + "option", + "parser", + "processus", + "readline", + "terminfo", + "tput", + "window" + ], + "time": "2017-05-02T12:26:19+00:00" + }, + { + "name": "hoa/event", + "version": "1.17.01.13", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Event.git", + "reference": "6c0060dced212ffa3af0e34bb46624f990b29c54" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Event/zipball/6c0060dced212ffa3af0e34bb46624f990b29c54", + "reference": "6c0060dced212ffa3af0e34bb46624f990b29c54", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/exception": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\Event\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Event library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "event", + "library", + "listener", + "observer" + ], + "time": "2017-01-13T15:30:50+00:00" + }, + { + "name": "hoa/exception", + "version": "1.17.01.16", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Exception.git", + "reference": "091727d46420a3d7468ef0595651488bfc3a458f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Exception/zipball/091727d46420a3d7468ef0595651488bfc3a458f", + "reference": "091727d46420a3d7468ef0595651488bfc3a458f", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/event": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\Exception\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Exception library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "exception", + "library" + ], + "time": "2017-01-16T07:53:27+00:00" + }, + { + "name": "hoa/file", + "version": "1.17.07.11", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/File.git", + "reference": "35cb979b779bc54918d2f9a4e02ed6c7a1fa67ca" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/File/zipball/35cb979b779bc54918d2f9a4e02ed6c7a1fa67ca", + "reference": "35cb979b779bc54918d2f9a4e02ed6c7a1fa67ca", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/event": "~1.0", + "hoa/exception": "~1.0", + "hoa/iterator": "~2.0", + "hoa/stream": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\File\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\File library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "Socket", + "directory", + "file", + "finder", + "library", + "link", + "temporary" + ], + "time": "2017-07-11T07:42:15+00:00" + }, + { + "name": "hoa/iterator", + "version": "2.17.01.10", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Iterator.git", + "reference": "d1120ba09cb4ccd049c86d10058ab94af245f0cc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Iterator/zipball/d1120ba09cb4ccd049c86d10058ab94af245f0cc", + "reference": "d1120ba09cb4ccd049c86d10058ab94af245f0cc", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/exception": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\Iterator\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Iterator library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "iterator", + "library" + ], + "time": "2017-01-10T10:34:47+00:00" + }, + { + "name": "hoa/protocol", + "version": "1.17.01.14", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Protocol.git", + "reference": "5c2cf972151c45f373230da170ea015deecf19e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Protocol/zipball/5c2cf972151c45f373230da170ea015deecf19e2", + "reference": "5c2cf972151c45f373230da170ea015deecf19e2", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/exception": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\Protocol\\": "." + }, + "files": [ + "Wrapper.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Protocol library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "library", + "protocol", + "resource", + "stream", + "wrapper" + ], + "time": "2017-01-14T12:26:10+00:00" + }, + { + "name": "hoa/stream", + "version": "1.17.02.21", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Stream.git", + "reference": "3293cfffca2de10525df51436adf88a559151d82" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Stream/zipball/3293cfffca2de10525df51436adf88a559151d82", + "reference": "3293cfffca2de10525df51436adf88a559151d82", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/event": "~1.0", + "hoa/exception": "~1.0", + "hoa/protocol": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\Stream\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Stream library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "Context", + "bucket", + "composite", + "filter", + "in", + "library", + "out", + "protocol", + "stream", + "wrapper" + ], + "time": "2017-02-21T16:01:06+00:00" + }, + { + "name": "hoa/ustring", + "version": "4.17.01.16", + "source": { + "type": "git", + "url": "https://github.com/hoaproject/Ustring.git", + "reference": "e6326e2739178799b1fe3fdd92029f9517fa17a0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hoaproject/Ustring/zipball/e6326e2739178799b1fe3fdd92029f9517fa17a0", + "reference": "e6326e2739178799b1fe3fdd92029f9517fa17a0", + "shasum": "" + }, + "require": { + "hoa/consistency": "~1.0", + "hoa/exception": "~1.0" + }, + "require-dev": { + "hoa/test": "~2.0" + }, + "suggest": { + "ext-iconv": "ext/iconv must be present (or a third implementation) to use Hoa\\Ustring::transcode().", + "ext-intl": "To get a better Hoa\\Ustring::toAscii() and Hoa\\Ustring::compareTo()." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hoa\\Ustring\\": "." + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net" + }, + { + "name": "Hoa community", + "homepage": "https://hoa-project.net/" + } + ], + "description": "The Hoa\\Ustring library.", + "homepage": "https://hoa-project.net/", + "keywords": [ + "library", + "search", + "string", + "unicode" + ], + "time": "2017-01-16T07:08:25+00:00" + }, { "name": "jms/metadata", "version": "1.7.0", diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php index 4db2f21a4..e0fc84d4c 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php @@ -78,7 +78,7 @@ public function testGetTestObject() $expectedFailedHookObject = new TestHookObject( TestObjectExtractor::TEST_FAILED_HOOK, $testDataArrayBuilder->testName, - [$expectedFailedActionObject] + ["saveScreenshot" => $expectedFailedActionObject] ); $expectedTestActionObject = new ActionObject( @@ -278,6 +278,99 @@ private function setMockParserOutput($data) AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); } + /** + * Validate test object when ENABLE_PAUSE is set to true + * + * @throws \Exception + */ + public function testGetTestObjectWhenEnablePause() + { + // set up mock data + putenv('ENABLE_PAUSE=true'); + $testDataArrayBuilder = new TestDataArrayBuilder(); + $mockData = $testDataArrayBuilder + ->withAnnotations() + ->withFailedHook() + ->withAfterHook() + ->withBeforeHook() + ->withTestActions() + ->build(); + + $resolverMock = new MockModuleResolverBuilder(); + $resolverMock->setup(); + $this->setMockParserOutput($mockData); + + // run object handler method + $toh = TestObjectHandler::getInstance(); + $mockConfig = AspectMock::double(TestObjectHandler::class, ['initTestData' => false]); + $actualTestObject = $toh->getObject($testDataArrayBuilder->testName); + + // perform asserts + $expectedBeforeActionObject = new ActionObject( + $testDataArrayBuilder->testActionBeforeName, + $testDataArrayBuilder->testActionType, + [] + ); + $expectedAfterActionObject = new ActionObject( + $testDataArrayBuilder->testActionAfterName, + $testDataArrayBuilder->testActionType, + [] + ); + $expectedFailedActionObject1 = new ActionObject( + 'saveScreenshot', + 'saveScreenshot', + [] + ); + $expectedFailedActionObject2 = new ActionObject( + 'pauseWhenFailed', + 'pause', + [] + ); + + $expectedBeforeHookObject = new TestHookObject( + TestObjectExtractor::TEST_BEFORE_HOOK, + $testDataArrayBuilder->testName, + ["testActionBefore" => $expectedBeforeActionObject] + ); + $expectedAfterHookObject = new TestHookObject( + TestObjectExtractor::TEST_AFTER_HOOK, + $testDataArrayBuilder->testName, + ["testActionAfter" => $expectedAfterActionObject] + ); + $expectedFailedHookObject = new TestHookObject( + TestObjectExtractor::TEST_FAILED_HOOK, + $testDataArrayBuilder->testName, + [ + "saveScreenshot" => $expectedFailedActionObject1, + "pauseWhenFailed" => $expectedFailedActionObject2, + ] + ); + + $expectedTestActionObject = new ActionObject( + $testDataArrayBuilder->testTestActionName, + $testDataArrayBuilder->testActionType, + [] + ); + $expectedTestObject = new TestObject( + $testDataArrayBuilder->testName, + ["testActionInTest" => $expectedTestActionObject], + [ + 'features' => ['NO MODULE DETECTED'], + 'group' => ['test'], + 'description' => ['test_files' => '<h3>Test files</h3>', 'deprecated' => []] + ], + [ + TestObjectExtractor::TEST_BEFORE_HOOK => $expectedBeforeHookObject, + TestObjectExtractor::TEST_AFTER_HOOK => $expectedAfterHookObject, + TestObjectExtractor::TEST_FAILED_HOOK => $expectedFailedHookObject + ], + null + ); + + $this->assertEquals($expectedTestObject, $actualTestObject); + putenv('ENABLE_PAUSE'); + } + /** * After method functionality * diff --git a/docs/configuration.md b/docs/configuration.md index b16f85d8f..90111a03b 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -359,6 +359,15 @@ Global MFTF configuration for the default amount of time (in seconds) that a tes WAIT_TIMEOUT=30 ``` +### ENABLE_PAUSE + +Enables pause of test execution in any point and enter interactive shell where you will be able to try commands in action. +When pause is enabled, MFTF will generate pause() command in _failed() hook so that test will pause execution when failed. + +```conf +ENABLE_PAUSE=true +``` + <!-- Link definitions --> [`MAGENTO_CLI_COMMAND_PATH`]: #magento_cli_command_path diff --git a/docs/test/actions.md b/docs/test/actions.md index 562f6e8ff..a4e0fb44c 100644 --- a/docs/test/actions.md +++ b/docs/test/actions.md @@ -1463,7 +1463,7 @@ Attribute|Type|Use|Description ### pause -See [pause docs on codeception.com](https://codeception.com/docs/02-GettingStarted). +See [pause docs on codeception.com](https://codeception.com/docs/02-GettingStarted#Interactive-Pause). Attribute|Type|Use|Description ---|---|---|--- diff --git a/etc/config/.env.example b/etc/config/.env.example index 53b12036f..64a287adc 100644 --- a/etc/config/.env.example +++ b/etc/config/.env.example @@ -67,6 +67,9 @@ MODULE_ALLOWLIST=Magento_Framework,ConfigurableProductWishlist,ConfigurableProdu #ENABLE_BROWSER_LOG=true BROWSER_LOG_BLOCKLIST=other +#*** Uncomment and set to true to use Codeception's interactive pause functionality +#ENABLE_PAUSE=true + #*** Elastic Search version used for test ***# ELASTICSEARCH_VERSION=7 #*** End of .env ***# diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index f3becf935..29e489a63 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -25,6 +25,13 @@ class BaseGenerateCommand extends Command { const MFTF_NOTICES = "Placeholder text for MFTF notices\n"; + /** + * Enable pause() + * + * @var boolean + */ + private $enablePause = null; + /** * Console output style * @@ -218,4 +225,21 @@ protected function showMftfNotices(OutputInterface $output) $output->writeln(self::MFTF_NOTICES); } } + + /** + * Return if pause() is enabled + * + * @return boolean + */ + protected function pauseEnabled() + { + if (null === $this->enablePause) { + if (getenv('ENABLE_PAUSE') === 'true') { + $this->enablePause = true; + } else { + $this->enablePause = false; + } + } + return $this->enablePause; + } } diff --git a/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php index 37a90bb77..4e9c92d38 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php @@ -108,15 +108,18 @@ protected function execute(InputInterface $input, OutputInterface $output): int */ private function runManifestLine(string $manifestLine, OutputInterface $output) { - $codeceptionCommand = realpath(PROJECT_ROOT . "/vendor/bin/codecept") - . " run functional --verbose --steps " - . $manifestLine; + $codeceptionCommand = realpath(PROJECT_ROOT . "/vendor/bin/codecept") . " run functional --verbose --steps "; + if (getenv('ENABLE_PAUSE') === 'true') { + $codeceptionCommand .= ' --debug'; + } + $codeceptionCommand .= $manifestLine; // run the codecept command in a sub process $process = new Process($codeceptionCommand); $process->setWorkingDirectory(TESTS_BP); $process->setIdleTimeout(600); $process->setTimeout(0); + $process->setInput(STDIN); $subReturnCode = $process->run(function ($type, $buffer) use ($output) { $output->write($buffer); }); diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php index 373256cfc..c96898da8 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php @@ -137,6 +137,9 @@ private function runTests(array $tests, OutputInterface $output) ); } $fullCommand = $codeceptionCommand . $testsDirectory . $testName . ' --verbose --steps'; + if ($this->pauseEnabled()) { + $fullCommand .= ' --debug'; + } $this->returnCode = max($this->returnCode, $this->executeTestCommand($fullCommand, $output)); } } @@ -151,6 +154,9 @@ private function runTests(array $tests, OutputInterface $output) private function runTestsInSuite(array $suitesConfig, OutputInterface $output) { $codeceptionCommand = realpath(PROJECT_ROOT . '/vendor/bin/codecept') . ' run functional --verbose --steps '; + if ($this->pauseEnabled()) { + $codeceptionCommand .= ' --debug'; + } //for tests in suites, run them as a group to run before and after block foreach (array_keys($suitesConfig) as $suite) { $fullCommand = $codeceptionCommand . " -g {$suite}"; @@ -173,6 +179,7 @@ private function executeTestCommand(string $command, OutputInterface $output) $process->setWorkingDirectory(TESTS_BP); $process->setIdleTimeout(600); $process->setTimeout(0); + $process->setInput(STDIN); return $process->run(function ($type, $buffer) use ($output) { $output->write($buffer); }); diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php index c6a2d0b76..96f560f24 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php @@ -119,11 +119,15 @@ protected function execute(InputInterface $input, OutputInterface $output): int foreach ($testManifestList as $testCommand) { $codeceptionCommand = realpath(PROJECT_ROOT . '/vendor/bin/codecept') . ' run functional '; $codeceptionCommand .= $testCommand; + if ($this->pauseEnabled()) { + $codeceptionCommand .= ' --debug'; + } $process = new Process($codeceptionCommand); $process->setWorkingDirectory(TESTS_BP); $process->setIdleTimeout(600); $process->setTimeout(0); + $process->setInput(STDIN); $returnCode = max($returnCode, $process->run( function ($type, $buffer) use ($output) { $output->write($buffer); diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php index 6ea37785d..db3ea2e55 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php @@ -95,6 +95,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int } $commandString = realpath(PROJECT_ROOT . '/vendor/bin/codecept') . ' run functional --verbose --steps'; + if ($this->pauseEnabled()) { + $commandString .= ' --debug'; + } $exitCode = -1; $returnCodes = []; @@ -105,6 +108,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $process->setWorkingDirectory(TESTS_BP); $process->setIdleTimeout(600); $process->setTimeout(0); + $process->setInput(STDIN); $returnCodes[] = $process->run( function ($type, $buffer) use ($output) { diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/TestHookObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/TestHookObjectExtractor.php index c11a6e512..a68f09491 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/TestHookObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/TestHookObjectExtractor.php @@ -57,19 +57,22 @@ public function extractHook($parentName, $hookType, $testHook) /** * Creates the default failed hook object with a single saveScreenshot action. + * And a pause action when ENABLE_PAUSE is set to true. * * @param string $parentName * @return TestHookObject */ public function createDefaultFailedHook($parentName) { - - $saveScreenshotStep = [new ActionObject("saveScreenshot", "saveScreenshot", [])]; + $defaultSteps['saveScreenshot'] = new ActionObject("saveScreenshot", "saveScreenshot", []); + if (getenv('ENABLE_PAUSE') === 'true') { + $defaultSteps['pauseWhenFailed'] = new ActionObject('pauseWhenFailed', 'pause', []); + } $hook = new TestHookObject( TestObjectExtractor::TEST_FAILED_HOOK, $parentName, - $saveScreenshotStep + $defaultSteps ); return $hook; From 0dcc9fa7da86c03436e9142582a461978fff1bf6 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Fri, 7 Aug 2020 11:42:16 -0500 Subject: [PATCH 500/888] MQE-2110: MFTF command to pause test execution --- .../FunctionalTestingFramework/Console/RunManifestCommand.php | 4 +++- .../FunctionalTestingFramework/Console/RunTestCommand.php | 4 +++- .../Console/RunTestFailedCommand.php | 4 +++- .../Console/RunTestGroupCommand.php | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php index 4e9c92d38..1709726bb 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php @@ -119,7 +119,9 @@ private function runManifestLine(string $manifestLine, OutputInterface $output) $process->setWorkingDirectory(TESTS_BP); $process->setIdleTimeout(600); $process->setTimeout(0); - $process->setInput(STDIN); + if (getenv('ENABLE_PAUSE') === 'true') { + $process->setInput(STDIN); + } $subReturnCode = $process->run(function ($type, $buffer) use ($output) { $output->write($buffer); }); diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php index c96898da8..86352d5c6 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php @@ -179,7 +179,9 @@ private function executeTestCommand(string $command, OutputInterface $output) $process->setWorkingDirectory(TESTS_BP); $process->setIdleTimeout(600); $process->setTimeout(0); - $process->setInput(STDIN); + if ($this->pauseEnabled()) { + $process->setInput(STDIN); + } return $process->run(function ($type, $buffer) use ($output) { $output->write($buffer); }); diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php index 96f560f24..b9012b086 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php @@ -127,7 +127,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int $process->setWorkingDirectory(TESTS_BP); $process->setIdleTimeout(600); $process->setTimeout(0); - $process->setInput(STDIN); + if ($this->pauseEnabled()) { + $process->setInput(STDIN); + } $returnCode = max($returnCode, $process->run( function ($type, $buffer) use ($output) { $output->write($buffer); diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php index db3ea2e55..19dec6d4b 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php @@ -108,7 +108,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int $process->setWorkingDirectory(TESTS_BP); $process->setIdleTimeout(600); $process->setTimeout(0); - $process->setInput(STDIN); + if ($this->pauseEnabled()) { + $process->setInput(STDIN); + } $returnCodes[] = $process->run( function ($type, $buffer) use ($output) { From 20af7fdf70171a0b2de5a2d284e4c12e59c61c8a Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Mon, 10 Aug 2020 10:57:58 -0500 Subject: [PATCH 501/888] =?UTF-8?q?MQE-2229:=20Deprecation=20Error=20When?= =?UTF-8?q?=20Deprecated=20ActionGroup=20References=20De=E2=80=A6=20(#775)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * MQE-2229: Deprecation Error When Deprecated ActionGroup References Deprecated Element * MQE-2229: Deprecation Error When Deprecated ActionGroup References Deprecated Element Suppressed check for data entities * MQE-2229: Deprecation Error When Deprecated ActionGroup References Deprecated Element Added unit tests * MQE-2229: Deprecation Error When Deprecated ActionGroup References Deprecated Element Added ObjectHandlerUtil for mocking Handlers * MQE-2229: Deprecation Error When Deprecated ActionGroup References Deprecated Element Verification test --- .../Handlers/DataObjectHandlerTest.php | 44 +-- .../OperationDefinitionObjectHandlerTest.php | 34 +-- .../Handlers/PersistedObjectHandlerTest.php | 41 +-- .../Page/Handlers/PageObjectHandlerTest.php | 24 +- .../Handlers/SectionObjectHandlerTest.php | 22 +- .../DeprecatedEntityUsageCheckTest.php | 251 ++++++++++++++++++ .../Handlers/ActionGroupObjectHandlerTest.php | 31 +-- .../Test/Handlers/TestObjectHandlerTest.php | 30 +-- dev/tests/unit/Util/ObjectHandlerUtil.php | 145 ++++++++++ .../DeprecationCheckActionGroup.xml | 13 + .../DeprecationCheckDeprecatedActionGroup.xml | 13 + .../Data/DeprecationCheckData.xml | 14 + .../Metadata/DeprecationCheckMeta.xml | 18 ++ .../Page/DeprecationCheckPage.xml | 14 + .../Section/DeprecationCheckSection.xml | 16 ++ .../Suite/deprecationCheckSuite.xml | 16 ++ .../Test/DeprecationCheckDeprecatedTest.xml | 17 ++ .../Test/DeprecationCheckTest.xml | 17 ++ .../mftf-deprecated-entity-usage-checks.txt | 23 ++ .../DeprecationStaticCheckTest.php | 92 +++++++ .../DeprecatedEntityUsageCheck.php | 31 ++- .../StaticCheck/StaticChecksList.php | 18 ++ 22 files changed, 739 insertions(+), 185 deletions(-) create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/StaticCheck/DeprecatedEntityUsageCheckTest.php create mode 100644 dev/tests/unit/Util/ObjectHandlerUtil.php create mode 100644 dev/tests/verification/DeprecationCheckModule/ActionGroup/DeprecationCheckActionGroup.xml create mode 100644 dev/tests/verification/DeprecationCheckModule/ActionGroup/DeprecationCheckDeprecatedActionGroup.xml create mode 100644 dev/tests/verification/DeprecationCheckModule/Data/DeprecationCheckData.xml create mode 100644 dev/tests/verification/DeprecationCheckModule/Metadata/DeprecationCheckMeta.xml create mode 100644 dev/tests/verification/DeprecationCheckModule/Page/DeprecationCheckPage.xml create mode 100644 dev/tests/verification/DeprecationCheckModule/Section/DeprecationCheckSection.xml create mode 100644 dev/tests/verification/DeprecationCheckModule/Suite/deprecationCheckSuite.xml create mode 100644 dev/tests/verification/DeprecationCheckModule/Test/DeprecationCheckDeprecatedTest.xml create mode 100644 dev/tests/verification/DeprecationCheckModule/Test/DeprecationCheckTest.xml create mode 100644 dev/tests/verification/Resources/StaticChecks/mftf-deprecated-entity-usage-checks.txt create mode 100644 dev/tests/verification/Tests/StaticCheck/DeprecationStaticCheckTest.php diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php index 9f1ca7b5c..745789501 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php @@ -13,6 +13,7 @@ use Magento\FunctionalTestingFramework\ObjectManager; use Magento\FunctionalTestingFramework\ObjectManagerFactory; use tests\unit\Util\MagentoTestCase; +use tests\unit\Util\ObjectHandlerUtil; use tests\unit\Util\TestLoggingUtil; /** @@ -148,7 +149,7 @@ public function setUp(): void */ public function testGetAllObjects() { - $this->setUpMockDataObjectHander(self::PARSER_OUTPUT); + ObjectHandlerUtil::mockDataObjectHandlerWithData(self::PARSER_OUTPUT); // Call the method under test $actual = DataObjectHandler::getInstance()->getAllObjects(); @@ -164,7 +165,7 @@ public function testGetAllObjects() */ public function testDeprecatedDataObject() { - $this->setUpMockDataObjectHander(self::PARSER_OUTPUT_DEPRECATED); + ObjectHandlerUtil::mockDataObjectHandlerWithData(self::PARSER_OUTPUT_DEPRECATED); // Call the method under test $actual = DataObjectHandler::getInstance()->getAllObjects(); @@ -182,7 +183,7 @@ public function testDeprecatedDataObject() */ public function testGetObject() { - $this->setUpMockDataObjectHander(self::PARSER_OUTPUT); + ObjectHandlerUtil::mockDataObjectHandlerWithData(self::PARSER_OUTPUT); // Call the method under test $actual = DataObjectHandler::getInstance()->getObject('EntityOne'); @@ -197,7 +198,7 @@ public function testGetObject() */ public function testGetObjectNull() { - $this->setUpMockDataObjectHander(self::PARSER_OUTPUT); + ObjectHandlerUtil::mockDataObjectHandlerWithData(self::PARSER_OUTPUT); $actual = DataObjectHandler::getInstance()->getObject('h953u789h0g73t521'); // doesnt exist $this->assertNull($actual); @@ -208,7 +209,7 @@ public function testGetObjectNull() */ public function testGetAllObjectsWithDataExtends() { - $this->setUpMockDataObjectHander(self::PARSER_OUTPUT_WITH_EXTEND); + ObjectHandlerUtil::mockDataObjectHandlerWithData(self::PARSER_OUTPUT_WITH_EXTEND); // Call the method under test $actual = DataObjectHandler::getInstance()->getAllObjects(); @@ -232,7 +233,7 @@ public function testGetAllObjectsWithDataExtends() */ public function testGetObjectWithDataExtends() { - $this->setUpMockDataObjectHander(self::PARSER_OUTPUT_WITH_EXTEND); + ObjectHandlerUtil::mockDataObjectHandlerWithData(self::PARSER_OUTPUT_WITH_EXTEND); // Call the method under test $actual = DataObjectHandler::getInstance()->getObject('EntityTwo'); @@ -255,7 +256,7 @@ public function testGetObjectWithDataExtends() */ public function testGetAllObjectsWithDataExtendsItself() { - $this->setUpMockDataObjectHander(self::PARSER_OUTPUT_WITH_EXTEND_INVALID); + ObjectHandlerUtil::mockDataObjectHandlerWithData(self::PARSER_OUTPUT_WITH_EXTEND_INVALID); $this->expectException(\Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException::class); $this->expectExceptionMessage( @@ -272,7 +273,7 @@ public function testGetAllObjectsWithDataExtendsItself() */ public function testGetObjectWithDataExtendsItself() { - $this->setUpMockDataObjectHander(self::PARSER_OUTPUT_WITH_EXTEND_INVALID); + ObjectHandlerUtil::mockDataObjectHandlerWithData(self::PARSER_OUTPUT_WITH_EXTEND_INVALID); $this->expectException(\Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException::class); $this->expectExceptionMessage( @@ -286,33 +287,6 @@ public function testGetObjectWithDataExtendsItself() ); } - /** - * Set up everything required to mock DataObjectHander::getInstance() - * The first call to getInstance() uses these mocks to emulate the parser, initializing internal state - * according to the PARSER_OUTPUT value - * - * @param array $entityDataArray - */ - private function setUpMockDataObjectHander($entityDataArray) - { - // Clear DataObjectHandler singleton if already set - $property = new \ReflectionProperty(DataObjectHandler::class, "INSTANCE"); - $property->setAccessible(true); - $property->setValue(null); - - $mockDataProfileSchemaParser = AspectMock::double(DataProfileSchemaParser::class, [ - 'readDataProfiles' => $entityDataArray - ])->make(); - - $mockObjectManager = AspectMock::double(ObjectManager::class, [ - 'create' => $mockDataProfileSchemaParser - ])->make(); - - AspectMock::double(ObjectManagerFactory::class, [ - 'getObjectManager' => $mockObjectManager - ]); - } - /** * clean up function runs after all tests */ diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php index 570e8d95a..35b06a24a 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php @@ -14,6 +14,7 @@ use Magento\FunctionalTestingFramework\DataGenerator\Handlers\OperationDefinitionObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Parsers\OperationDefinitionParser; use tests\unit\Util\MagentoTestCase; +use tests\unit\Util\ObjectHandlerUtil; use tests\unit\Util\TestLoggingUtil; /** @@ -72,7 +73,7 @@ public function testGetMultipleObjects() ], ] ]]]; - $this->setMockParserOutput($mockData); + ObjectHandlerUtil::mockOperationHandlerWithData($mockData); //Perform Assertions $operationDefinitionManager = OperationDefinitionObjectHandler::getInstance(); @@ -109,7 +110,7 @@ public function testDeprecatedOperation() ], OperationDefinitionObjectHandler::OBJ_DEPRECATED => 'deprecation message' ]]]; - $this->setMockParserOutput($mockData); + ObjectHandlerUtil::mockOperationHandlerWithData($mockData); //Perform Assertions $operationDefinitionManager = OperationDefinitionObjectHandler::getInstance(); @@ -239,7 +240,7 @@ public function testObjectCreation() ); // Set up mocked data output - $this->setMockParserOutput($mockData); + ObjectHandlerUtil::mockOperationHandlerWithData($mockData); // Get Operation $operationDefinitionManager = OperationDefinitionObjectHandler::getInstance(); @@ -337,7 +338,7 @@ public function testObjectArrayCreation() ); // Set up mocked data output - $this->setMockParserOutput($mockData); + ObjectHandlerUtil::mockOperationHandlerWithData($mockData); // Get Operation $operationDefinitionManager = OperationDefinitionObjectHandler::getInstance(); @@ -405,7 +406,7 @@ public function testLooseJsonCreation() ); // Set up mocked data output - $this->setMockParserOutput($mockData); + ObjectHandlerUtil::mockOperationHandlerWithData($mockData); // get Operations $operationDefinitionManager = OperationDefinitionObjectHandler::getInstance(); @@ -416,29 +417,6 @@ public function testLooseJsonCreation() $this->assertEquals($array, $operation->getOperationMetadata()[1]); } - /** - * Function used to set mock for parser return and force init method to run between tests. - * - * @param array $data - */ - private function setMockParserOutput($data) - { - // clear Operation object handler value to inject parsed content - $property = new \ReflectionProperty( - OperationDefinitionObjectHandler::class, - 'INSTANCE' - ); - $property->setAccessible(true); - $property->setValue(null); - - $mockOperationParser = AspectMock::double( - OperationDefinitionParser::class, - ["readOperationMetadata" => $data] - )->make(); - $instance = AspectMock::double(ObjectManager::class, ['create' => $mockOperationParser])->make(); - AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); - } - /** * clean up function runs after all tests */ diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php index 870e75dcd..7e39fe216 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php @@ -16,6 +16,7 @@ use Magento\FunctionalTestingFramework\ObjectManager; use Magento\FunctionalTestingFramework\ObjectManagerFactory; use tests\unit\Util\MagentoTestCase; +use tests\unit\Util\ObjectHandlerUtil; use tests\unit\Util\TestLoggingUtil; /** @@ -84,7 +85,7 @@ public function testCreateSimpleEntity() "; // Mock Classes - $this->mockDataHandlerWithOutput($parserOutput); + ObjectHandlerUtil::mockDataObjectHandlerWithData($parserOutput); $this->mockCurlHandler($jsonResponse); $handler = PersistedObjectHandler::getInstance(); @@ -127,7 +128,7 @@ public function testDeleteSimpleEntity() "; // Mock Classes - $this->mockDataHandlerWithOutput($parserOutput); + ObjectHandlerUtil::mockDataObjectHandlerWithData($parserOutput); $this->mockCurlHandler($jsonResponse); $handler = PersistedObjectHandler::getInstance(); @@ -175,7 +176,7 @@ public function testGetSimpleEntity() "; // Mock Classes - $this->mockDataHandlerWithOutput($parserOutput); + ObjectHandlerUtil::mockDataObjectHandlerWithData($parserOutput); $this->mockCurlHandler($jsonResponse); $handler = PersistedObjectHandler::getInstance(); @@ -235,7 +236,7 @@ public function testUpdateSimpleEntity() "; // Mock Classes - $this->mockDataHandlerWithOutput($parserOutput); + ObjectHandlerUtil::mockDataObjectHandlerWithData($parserOutput); $this->mockCurlHandler($jsonResponse); $handler = PersistedObjectHandler::getInstance(); $handler->createEntity( @@ -322,7 +323,7 @@ public function testRetrieveEntityAcrossScopes() // Mock Classes and Create Entities $handler = PersistedObjectHandler::getInstance(); - $this->mockDataHandlerWithOutput($parserOutputOne); + ObjectHandlerUtil::mockDataObjectHandlerWithData($parserOutputOne); $this->mockCurlHandler($jsonReponseOne); $handler->createEntity( $entityStepKeyOne, @@ -399,7 +400,7 @@ public function testRetrieveEntityValidField($name, $key, $value, $type, $scope, // Mock Classes and Create Entities $handler = PersistedObjectHandler::getInstance(); - $this->mockDataHandlerWithOutput($parserOutputOne); + ObjectHandlerUtil::mockDataObjectHandlerWithData($parserOutputOne); $this->mockCurlHandler($jsonReponseOne); $handler->createEntity($stepKey, $scope, $name); @@ -447,8 +448,7 @@ public function testRetrieveEntityInValidField($name, $key, $value, $type, $scop // Mock Classes and Create Entities $handler = PersistedObjectHandler::getInstance(); - - $this->mockDataHandlerWithOutput($parserOutputOne); + ObjectHandlerUtil::mockDataObjectHandlerWithData($parserOutputOne); $this->mockCurlHandler($jsonReponseOne); $handler->createEntity($stepKey, $scope, $name); @@ -475,31 +475,6 @@ public static function entityDataProvider() ]; } - /** - * Mocks DataObjectHandler to use given output to create - * @param $parserOutput - * @throws \Exception - */ - public function mockDataHandlerWithOutput($parserOutput) - { - // Clear DataObjectHandler singleton if already set - $property = new \ReflectionProperty(DataObjectHandler::class, "INSTANCE"); - $property->setAccessible(true); - $property->setValue(null); - - $mockDataProfileSchemaParser = AspectMock::double(DataProfileSchemaParser::class, [ - 'readDataProfiles' => $parserOutput - ])->make(); - - $mockObjectManager = AspectMock::double(ObjectManager::class, [ - 'create' => $mockDataProfileSchemaParser - ])->make(); - - AspectMock::double(ObjectManagerFactory::class, [ - 'getObjectManager' => $mockObjectManager - ]); - } - public function mockCurlHandler($response) { AspectMock::double(CurlHandler::class, [ diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/PageObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/PageObjectHandlerTest.php index c934b680b..eb305bc4d 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/PageObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/PageObjectHandlerTest.php @@ -12,6 +12,7 @@ use Magento\FunctionalTestingFramework\Page\Handlers\PageObjectHandler; use Magento\FunctionalTestingFramework\XmlParser\PageParser; use tests\unit\Util\MagentoTestCase; +use tests\unit\Util\ObjectHandlerUtil; use tests\unit\Util\TestLoggingUtil; class PageObjectHandlerTest extends MagentoTestCase @@ -45,7 +46,7 @@ public function testGetPageObject() ], "area" => "test" ]]; - $this->setMockParserOutput($mockData); + ObjectHandlerUtil::mockPageObjectHandlerWithData($mockData); // get pages $pageHandler = PageObjectHandler::getInstance(); @@ -70,7 +71,7 @@ public function testGetEmptyPage() ], "area" => "test" ]]; - $this->setMockParserOutput($mockData); + ObjectHandlerUtil::mockPageObjectHandlerWithData($mockData); // get pages $page = PageObjectHandler::getInstance()->getObject('testPage1'); @@ -91,7 +92,7 @@ public function testDeprecatedPage() "deprecated" => "deprecation message", "filename" => "filename.xml" ]]; - $this->setMockParserOutput($mockData); + ObjectHandlerUtil::mockPageObjectHandlerWithData($mockData); // get pages $page = PageObjectHandler::getInstance()->getObject('testPage1'); @@ -103,23 +104,6 @@ public function testDeprecatedPage() ); } - /** - * Function used to set mock for parser return and force init method to run between tests. - * - * @param array $data - */ - private function setMockParserOutput($data) - { - // clear section object handler value to inject parsed content - $property = new \ReflectionProperty(PageObjectHandler::class, 'INSTANCE'); - $property->setAccessible(true); - $property->setValue(null); - - $mockSectionParser = AspectMock::double(PageParser::class, ["getData" => $data])->make(); - $instance = AspectMock::double(ObjectManager::class, ['get' => $mockSectionParser])->make(); - AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); - } - /** * clean up function runs after all tests */ diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/SectionObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/SectionObjectHandlerTest.php index 39e26caf9..69088944a 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/SectionObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/SectionObjectHandlerTest.php @@ -12,6 +12,7 @@ use Magento\FunctionalTestingFramework\Page\Handlers\SectionObjectHandler; use Magento\FunctionalTestingFramework\XmlParser\SectionParser; use tests\unit\Util\MagentoTestCase; +use tests\unit\Util\ObjectHandlerUtil; use tests\unit\Util\TestLoggingUtil; class SectionObjectHandlerTest extends MagentoTestCase @@ -46,7 +47,7 @@ public function testGetSectionObject() ] ]; - $this->setMockParserOutput($mockData); + ObjectHandlerUtil::mockSectionObjectHandlerWithData($mockData); // get sections $sectionHandler = SectionObjectHandler::getInstance(); @@ -77,7 +78,7 @@ public function testDeprecatedSection() ] ]; - $this->setMockParserOutput($mockData); + ObjectHandlerUtil::mockSectionObjectHandlerWithData($mockData); // get sections $sectionHandler = SectionObjectHandler::getInstance(); @@ -91,23 +92,6 @@ public function testDeprecatedSection() ); } - /** - * Set the mock parser return value - * - * @param array $data - */ - private function setMockParserOutput($data) - { - // clear section object handler value to inject parsed content - $property = new \ReflectionProperty(SectionObjectHandler::class, "INSTANCE"); - $property->setAccessible(true); - $property->setValue(null); - - $mockSectionParser = AspectMock::double(SectionParser::class, ["getData" => $data])->make(); - $instance = AspectMock::double(ObjectManager::class, ["get" => $mockSectionParser])->make(); - AspectMock::double(ObjectManagerFactory::class, ["getObjectManager" => $instance]); - } - /** * clean up function runs after all tests */ diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/StaticCheck/DeprecatedEntityUsageCheckTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/StaticCheck/DeprecatedEntityUsageCheckTest.php new file mode 100644 index 000000000..dc339c8a3 --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/StaticCheck/DeprecatedEntityUsageCheckTest.php @@ -0,0 +1,251 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace tests\unit\Magento\FunctionalTestFramework\StaticCheck; + +use AspectMock\Test as AspectMock; +use Magento\FunctionalTestingFramework\DataGenerator\Handlers\OperationDefinitionObjectHandler; +use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; +use Magento\FunctionalTestingFramework\Page\Objects\ElementObject; +use Magento\FunctionalTestingFramework\Page\Objects\PageObject; +use Magento\FunctionalTestingFramework\Page\Objects\SectionObject; +use Magento\FunctionalTestingFramework\StaticCheck\DeprecatedEntityUsageCheck; +use Magento\FunctionalTestingFramework\Test\Objects\TestObject; +use Symfony\Component\Console\Input\InputInterface; +use tests\unit\Util\MagentoTestCase; +use ReflectionClass; +use InvalidArgumentException; +use tests\unit\Util\ObjectHandlerUtil; + +class DeprecatedEntityUsageCheckTest extends MagentoTestCase +{ + /** @var DeprecatedEntityUsageCheck */ + private $staticCheck; + + /** @var ReflectionClass*/ + private $staticCheckClass; + + public function setUp(): void + { + $this->staticCheck = new DeprecatedEntityUsageCheck(); + $this->staticCheckClass = new \ReflectionClass($this->staticCheck); + } + + public function tearDown(): void + { + AspectMock::clean(); + } + + public function testInvalidPathOption() + { + $input = $this->getMockBuilder(InputInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $input->method('getOption') + ->with('path') + ->willReturn('/invalidPath'); + + $loadAllXmlFiles = $this->staticCheckClass->getMethod('loadAllXMLFiles'); + $loadAllXmlFiles->setAccessible(true); + + $this->expectException(InvalidArgumentException::class); + $loadAllXmlFiles->invoke($this->staticCheck, $input); + } + + public function testViolatingElementReferences() + { + //variables for assertions + $elementName = 'elementOne'; + $sectionName = 'SectionOne'; + $fileName = 'section.xml'; + + $element = new ElementObject($elementName, 'type', '#selector1', null, '41', false, 'deprecated'); + $section = new SectionObject($sectionName, [$element], $fileName); + $elementRef = $sectionName . '.' . $elementName; + $references = [$elementRef => $element, $sectionName => $section]; + $actual = $this->callViolatingReferences($references); + $expected = [ + 'Deprecated Element(s)' => [ + 0 => [ + 'name' => $elementRef, + 'file' => $fileName + ] + ] + ]; + $this->assertEquals($actual, $expected); + } + + public function testViolatingPageReferences() + { + //Page variables for assertions + $pageName = 'Page'; + $fileName = 'page.xml'; + + $page = new PageObject($pageName, '/url.html', 'Test', [], false, "test", $fileName, 'deprecated'); + $references = ['Page' => $page]; + $actual = $this->callViolatingReferences($references); + $expected = [ + 'Deprecated Page(s)' => [ + 0 => [ + 'name' => $pageName, + 'file' => $fileName + ] + ] + ]; + $this->assertEquals($actual, $expected); + } + + public function testViolatingDataReferences() + { + //Data entity variables for assertions + $entityName = 'EntityOne'; + $fileName = 'entity.xml'; + + $entity = new EntityDataObject( + $entityName, + 'testType', + ['testkey' => 'testValue'], + [], + null, + [], + null, + $fileName, + 'deprecated' + ); + $references = [$entityName => $entity]; + $actual = $this->callViolatingReferences($references); + $expected = [ + 'Deprecated Data(s)' => [ + 0 => [ + 'name' => $entityName, + 'file' => $fileName + ] + ] + ]; + $this->assertEquals($actual, $expected); + } + + public function testViolatingTestReferences() + { + // test variables for assertions + $testName = 'Test1'; + $fileName = 'test.xml'; + + $test = new TestObject($testName, [], [], [], $fileName, null, 'deprecated'); + $references = ['Test1' => $test]; + $actual = $this->callViolatingReferences($references); + $expected = [ + 'Deprecated Test(s)' => [ + 0 => [ + 'name' => $testName, + 'file' => $fileName + ] + ] + ]; + $this->assertEquals($actual, $expected); + } + + public function testViolatingMetaDataReferences() + { + // Data Variables for Assertions + $dataType1 = "type1"; + $operationType1 = "create"; + $operationType2 = "update"; + + /** + * Parser Output. + * operationName + * createType1 + * has field + * key=id, value=integer + * updateType1 + * has field + * key=id, value=integer + */ + $mockData = [OperationDefinitionObjectHandler::ENTITY_OPERATION_ROOT_TAG => [ + "testOperationName" => [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE => $dataType1, + OperationDefinitionObjectHandler::ENTITY_OPERATION_TYPE => $operationType1, + OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH => "auth", + OperationDefinitionObjectHandler::ENTITY_OPERATION_URL => "V1/Type1", + OperationDefinitionObjectHandler::ENTITY_OPERATION_METHOD => "POST", + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY => [ + 0 => [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => "id", + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => "integer" + ], + ], + OperationDefinitionObjectHandler::OBJ_DEPRECATED => 'deprecated' + ],[ + OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE => $dataType1, + OperationDefinitionObjectHandler::ENTITY_OPERATION_TYPE => $operationType2, + OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH => "auth", + OperationDefinitionObjectHandler::ENTITY_OPERATION_URL => "V1/Type1/{id}", + OperationDefinitionObjectHandler::ENTITY_OPERATION_METHOD => "PUT", + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY => [ + 0 => [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => "id", + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => "integer" + ], + ] + ]]]; + + ObjectHandlerUtil::mockOperationHandlerWithData($mockData); + $dataName = 'dataName1'; + $references = [ + $dataName => [ + $dataType1 => [ + $operationType1, + $operationType2 + ] + ] + ]; + + $expected = [ + '"'.$dataName.'" references deprecated' => [ + 0 => [ + 'name' => $dataType1, + 'file' => 'metadata xml file' + ] + ] + ]; + $property = $this->staticCheckClass->getMethod('findViolatingMetadataReferences'); + $property->setAccessible(true); + $actual = $property->invoke($this->staticCheck, $references); + $this->assertEquals($actual, $expected); + } + + public function testIsDeprecated() + { + // Test Data + $contents = '<tests> + <test name="test" deprecated="true"> + <comment userInput="input1" stepKey="key1"/> + <comment userInput="input2" stepKey="key1"/> + </test> + </tests> + '; + + $property = $this->staticCheckClass->getMethod('isDeprecated'); + $property->setAccessible(true); + $output = $property->invoke($this->staticCheck, $contents); + $this->assertTrue($output); + } + + /** + * Invoke findViolatingReferences + * @param $references + * @return mixed + * @throws \ReflectionException + */ + public function callViolatingReferences($references) + { + $property = $this->staticCheckClass->getMethod('findViolatingReferences'); + $property->setAccessible(true); + return $property->invoke($this->staticCheck, $references); + } +} diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/ActionGroupObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/ActionGroupObjectHandlerTest.php index deb08d783..71c1833ba 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/ActionGroupObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/ActionGroupObjectHandlerTest.php @@ -15,6 +15,7 @@ use tests\unit\Util\MagentoTestCase; use tests\unit\Util\ActionGroupArrayBuilder; use Magento\FunctionalTestingFramework\Test\Parsers\ActionGroupDataParser; +use tests\unit\Util\ObjectHandlerUtil; class ActionGroupObjectHandlerTest extends MagentoTestCase { @@ -34,7 +35,7 @@ public function testGetTestObjectWithInvalidExtends() ->withFilename() ->withActionObjects() ->build(); - $this->setMockParserOutput(['actionGroups' => $actionGroupOne]); + ObjectHandlerUtil::mockActionGroupObjectHandlerWithData(['actionGroups' => $actionGroupOne]); $handler = ActionGroupObjectHandler::getInstance(); @@ -68,7 +69,14 @@ public function testGetAllTestObjectsWithInvalidExtends() ->withActionObjects() ->build(); - $this->setMockParserOutput(['actionGroups' => array_merge($actionGroupOne, $actionGroupTwo)]); + ObjectHandlerUtil::mockActionGroupObjectHandlerWithData( + [ + 'actionGroups' => array_merge( + $actionGroupOne, + $actionGroupTwo + ) + ] + ); $handler = ActionGroupObjectHandler::getInstance(); @@ -76,23 +84,4 @@ public function testGetAllTestObjectsWithInvalidExtends() $this->expectExceptionMessage("Mftf Action Group can not extend from itself: " . $nameOne); $handler->getAllObjects(); } - - /** - * Function used to set mock for parser return and force init method to run between tests. - * - * @param array $data - * @throws \Exception - */ - private function setMockParserOutput($data) - { - // Clear action group object handler value to inject parsed content - $property = new \ReflectionProperty(ActionGroupObjectHandler::class, 'instance'); - $property->setAccessible(true); - $property->setValue(null); - - $mockDataParser = AspectMock::double(ActionGroupDataParser::class, ['readActionGroupData' => $data])->make(); - $instance = AspectMock::double(ObjectManager::class, ['create' => $mockDataParser]) - ->make(); // bypass the private constructor - AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); - } } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php index 4db2f21a4..897ba0ea9 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php @@ -17,6 +17,7 @@ use Magento\FunctionalTestingFramework\Test\Parsers\TestDataParser; use Magento\FunctionalTestingFramework\Test\Util\TestObjectExtractor; use tests\unit\Util\MagentoTestCase; +use tests\unit\Util\ObjectHandlerUtil; use tests\unit\Util\TestDataArrayBuilder; use tests\unit\Util\MockModuleResolverBuilder; @@ -41,7 +42,7 @@ public function testGetTestObject() $resolverMock = new MockModuleResolverBuilder(); $resolverMock->setup(); - $this->setMockParserOutput($mockData); + ObjectHandlerUtil::mockTestObjectHandlerWitData($mockData); // run object handler method $toh = TestObjectHandler::getInstance(); @@ -135,7 +136,7 @@ public function testGetTestsByGroup() $resolverMock = new MockModuleResolverBuilder(); $resolverMock->setup(); - $this->setMockParserOutput(array_merge($includeTest, $excludeTest)); + ObjectHandlerUtil::mockTestObjectHandlerWitData(array_merge($includeTest, $excludeTest)); // execute test method $toh = TestObjectHandler::getInstance(); @@ -184,7 +185,7 @@ public function testGetTestWithModuleName() $resolverMock = new MockModuleResolverBuilder(); $resolverMock->setup(['Vendor_' . $moduleExpected => $filepath]); - $this->setMockParserOutput($mockData); + ObjectHandlerUtil::mockTestObjectHandlerWitData($mockData); // Execute Test Method $toh = TestObjectHandler::getInstance(); $actualTestObject = $toh->getObject($testDataArrayBuilder->testName); @@ -212,7 +213,7 @@ public function testGetTestObjectWithInvalidExtends() ->build(); $resolverMock = new MockModuleResolverBuilder(); $resolverMock->setup(); - $this->setMockParserOutput($testOne); + ObjectHandlerUtil::mockTestObjectHandlerWitData($testOne); $toh = TestObjectHandler::getInstance(); @@ -250,7 +251,7 @@ public function testGetAllTestObjectsWithInvalidExtends() $resolverMock = new MockModuleResolverBuilder(); $resolverMock->setup(); - $this->setMockParserOutput(array_merge($testOne, $testTwo)); + ObjectHandlerUtil::mockTestObjectHandlerWitData(array_merge($testOne, $testTwo)); $toh = TestObjectHandler::getInstance(); @@ -259,25 +260,6 @@ public function testGetAllTestObjectsWithInvalidExtends() $toh->getAllObjects(); } - /** - * Function used to set mock for parser return and force init method to run between tests. - * - * @param array $data - * @throws \Exception - */ - private function setMockParserOutput($data) - { - // clear test object handler value to inject parsed content - $property = new \ReflectionProperty(TestObjectHandler::class, 'testObjectHandler'); - $property->setAccessible(true); - $property->setValue(null); - - $mockDataParser = AspectMock::double(TestDataParser::class, ['readTestData' => $data])->make(); - $instance = AspectMock::double(ObjectManager::class, ['create' => $mockDataParser]) - ->make(); // bypass the private constructor - AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); - } - /** * After method functionality * diff --git a/dev/tests/unit/Util/ObjectHandlerUtil.php b/dev/tests/unit/Util/ObjectHandlerUtil.php new file mode 100644 index 000000000..0e4543f2b --- /dev/null +++ b/dev/tests/unit/Util/ObjectHandlerUtil.php @@ -0,0 +1,145 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace tests\unit\Util; + +use AspectMock\Test as AspectMock; +use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; +use Magento\FunctionalTestingFramework\DataGenerator\Handlers\OperationDefinitionObjectHandler; +use Magento\FunctionalTestingFramework\DataGenerator\Parsers\DataProfileSchemaParser; +use Magento\FunctionalTestingFramework\DataGenerator\Parsers\OperationDefinitionParser; +use Magento\FunctionalTestingFramework\ObjectManager; +use Magento\FunctionalTestingFramework\ObjectManagerFactory; +use Magento\FunctionalTestingFramework\Page\Handlers\PageObjectHandler; +use Magento\FunctionalTestingFramework\Page\Handlers\SectionObjectHandler; +use Magento\FunctionalTestingFramework\Test\Handlers\ActionGroupObjectHandler; +use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; +use Magento\FunctionalTestingFramework\Test\Parsers\ActionGroupDataParser; +use Magento\FunctionalTestingFramework\Test\Parsers\TestDataParser; +use Magento\FunctionalTestingFramework\XmlParser\PageParser; +use Magento\FunctionalTestingFramework\XmlParser\SectionParser; + +class ObjectHandlerUtil +{ + /** + * Set up everything required to mock OperationDefinitionObjectHandler::getInstance() with $data value + * @param array $data + * @throws \Exception + */ + public static function mockOperationHandlerWithData($data) + { + // Clear OperationDefinitionObjectHandler singleton if already set + $property = new \ReflectionProperty( + OperationDefinitionObjectHandler::class, + 'INSTANCE' + ); + $property->setAccessible(true); + $property->setValue(null); + + $mockOperationParser = AspectMock::double( + OperationDefinitionParser::class, + ["readOperationMetadata" => $data] + )->make(); + $instance = AspectMock::double(ObjectManager::class, ['create' => $mockOperationParser])->make(); + AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); + } + + /** + * Set up everything required to mock DataObjectHandler::getInstance() with $data value + * + * @param array $data + */ + public static function mockDataObjectHandlerWithData($data) + { + // Clear DataObjectHandler singleton if already set + $property = new \ReflectionProperty(DataObjectHandler::class, "INSTANCE"); + $property->setAccessible(true); + $property->setValue(null); + + $mockDataProfileSchemaParser = AspectMock::double(DataProfileSchemaParser::class, [ + 'readDataProfiles' => $data + ])->make(); + + $mockObjectManager = AspectMock::double(ObjectManager::class, [ + 'create' => $mockDataProfileSchemaParser + ])->make(); + + AspectMock::double(ObjectManagerFactory::class, [ + 'getObjectManager' => $mockObjectManager + ]); + } + + /** + * Set up everything required to mock PageObjectHandler::getInstance() with $data value + * + * @param array $data + */ + public static function mockPageObjectHandlerWithData($data) + { + // clear section object handler value to inject parsed content + $property = new \ReflectionProperty(PageObjectHandler::class, 'INSTANCE'); + $property->setAccessible(true); + $property->setValue(null); + + $mockSectionParser = AspectMock::double(PageParser::class, ["getData" => $data])->make(); + $instance = AspectMock::double(ObjectManager::class, ['get' => $mockSectionParser])->make(); + AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); + } + + /** + * Set up everything required to mock SectionObjectHandler::getInstance() with $data value + * + * @param array $data + */ + public static function mockSectionObjectHandlerWithData($data) + { + // clear section object handler value to inject parsed content + $property = new \ReflectionProperty(SectionObjectHandler::class, "INSTANCE"); + $property->setAccessible(true); + $property->setValue(null); + + $mockSectionParser = AspectMock::double(SectionParser::class, ["getData" => $data])->make(); + $instance = AspectMock::double(ObjectManager::class, ["get" => $mockSectionParser])->make(); + AspectMock::double(ObjectManagerFactory::class, ["getObjectManager" => $instance]); + } + + /** + * Set up everything required to mock TestObjectHandler::getInstance() with $data value + * + * @param array $data + * @throws \Exception + */ + public static function mockTestObjectHandlerWitData($data) + { + // clear test object handler value to inject parsed content + $property = new \ReflectionProperty(TestObjectHandler::class, 'testObjectHandler'); + $property->setAccessible(true); + $property->setValue(null); + + $mockDataParser = AspectMock::double(TestDataParser::class, ['readTestData' => $data])->make(); + $instance = AspectMock::double(ObjectManager::class, ['create' => $mockDataParser]) + ->make(); // bypass the private constructor + AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); + } + + /** + * Set up everything required to mock ActionGroupObjectHandler::getInstance() with $data value + * + * @param array $data + * @throws \Exception + */ + public static function mockActionGroupObjectHandlerWithData($data) + { + // Clear action group object handler value to inject parsed content + $property = new \ReflectionProperty(ActionGroupObjectHandler::class, 'instance'); + $property->setAccessible(true); + $property->setValue(null); + + $mockDataParser = AspectMock::double(ActionGroupDataParser::class, ['readActionGroupData' => $data])->make(); + $instance = AspectMock::double(ObjectManager::class, ['create' => $mockDataParser]) + ->make(); // bypass the private constructor + AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); + } +} diff --git a/dev/tests/verification/DeprecationCheckModule/ActionGroup/DeprecationCheckActionGroup.xml b/dev/tests/verification/DeprecationCheckModule/ActionGroup/DeprecationCheckActionGroup.xml new file mode 100644 index 000000000..c83dab211 --- /dev/null +++ b/dev/tests/verification/DeprecationCheckModule/ActionGroup/DeprecationCheckActionGroup.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="DeprecationCheckActionGroup"> + <see stepKey="deprecatedSee" userInput="text" selector="{{DeprecationCheckSection.deprecationCheckElement}}" /> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/DeprecationCheckModule/ActionGroup/DeprecationCheckDeprecatedActionGroup.xml b/dev/tests/verification/DeprecationCheckModule/ActionGroup/DeprecationCheckDeprecatedActionGroup.xml new file mode 100644 index 000000000..e8412a29e --- /dev/null +++ b/dev/tests/verification/DeprecationCheckModule/ActionGroup/DeprecationCheckDeprecatedActionGroup.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="DeprecationCheckDeprecatedActionGroup" deprecated="deprecated"> + <see stepKey="deprecatedSee" userInput="text" selector="{{DeprecationCheckSection.deprecationCheckElement}}" /> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/DeprecationCheckModule/Data/DeprecationCheckData.xml b/dev/tests/verification/DeprecationCheckModule/Data/DeprecationCheckData.xml new file mode 100644 index 000000000..75a6b6678 --- /dev/null +++ b/dev/tests/verification/DeprecationCheckModule/Data/DeprecationCheckData.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="DeprecationCheckData" type="type1" deprecated="deprecated"> + <data key="field">value</data> + </entity> +</entities> diff --git a/dev/tests/verification/DeprecationCheckModule/Metadata/DeprecationCheckMeta.xml b/dev/tests/verification/DeprecationCheckModule/Metadata/DeprecationCheckMeta.xml new file mode 100644 index 000000000..757c6284b --- /dev/null +++ b/dev/tests/verification/DeprecationCheckModule/Metadata/DeprecationCheckMeta.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd"> + <operation name="DeprecationCheckMeta" dataType="type1" type="create" auth="adminFormKey" url="/V1/test" method="POST" deprecated="deprecated"> + <contentType>application/json</contentType> + <object key="category" dataType="type1"> + <field key="key1">value1</field> + <field key="key2">value2</field> + </object> + </operation> +</operations> \ No newline at end of file diff --git a/dev/tests/verification/DeprecationCheckModule/Page/DeprecationCheckPage.xml b/dev/tests/verification/DeprecationCheckModule/Page/DeprecationCheckPage.xml new file mode 100644 index 000000000..dd3f187dc --- /dev/null +++ b/dev/tests/verification/DeprecationCheckModule/Page/DeprecationCheckPage.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="DeprecationCheckPage" url="/test.html" area="storefront" module="UnknownVendor_DeprecationCheckModule" deprecated="Deprecated page"> + <section name="DeprecationCheckSection"/> + </page> +</pages> diff --git a/dev/tests/verification/DeprecationCheckModule/Section/DeprecationCheckSection.xml b/dev/tests/verification/DeprecationCheckModule/Section/DeprecationCheckSection.xml new file mode 100644 index 000000000..1837e1ef5 --- /dev/null +++ b/dev/tests/verification/DeprecationCheckModule/Section/DeprecationCheckSection.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="DeprecationCheckSection" deprecated="deprecated"> + <element name="deprecationCheckElement" type="button" selector="#elementOne" deprecated="deprecated"/> + <element name="elementTwo" type="button" selector="#elementTwo"/> + <element name="elementThree" type="button" selector="#elementThree"/> + </section> +</sections> diff --git a/dev/tests/verification/DeprecationCheckModule/Suite/deprecationCheckSuite.xml b/dev/tests/verification/DeprecationCheckModule/Suite/deprecationCheckSuite.xml new file mode 100644 index 000000000..b89ad99f6 --- /dev/null +++ b/dev/tests/verification/DeprecationCheckModule/Suite/deprecationCheckSuite.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<suites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Suite/etc/suiteSchema.xsd"> + <suite name="deprecationCheckSuite"> + <include> + <test name="DeprecationCheckDeprecatedTest"/> + <test name="DeprecationCheckTest"/> + </include> + </suite> +</suites> diff --git a/dev/tests/verification/DeprecationCheckModule/Test/DeprecationCheckDeprecatedTest.xml b/dev/tests/verification/DeprecationCheckModule/Test/DeprecationCheckDeprecatedTest.xml new file mode 100644 index 000000000..1b3ace053 --- /dev/null +++ b/dev/tests/verification/DeprecationCheckModule/Test/DeprecationCheckDeprecatedTest.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="DeprecationCheckDeprecatedTest" deprecated="deprecated"> + <createData entity="DeprecationCheckData" stepKey="deprecatedCreateData"/> + <actionGroup ref="DeprecationCheckActionGroup" stepKey="deprecationCheckActionGroup" /> + <amOnPage url="{{DeprecationCheckPage.url}}" stepKey="deprecatedAmOnPage" /> + <actionGroup ref="DeprecationCheckDeprecatedActionGroup" stepKey="deprecationCheckDeprecatedActionGroup" /> + </test> +</tests> diff --git a/dev/tests/verification/DeprecationCheckModule/Test/DeprecationCheckTest.xml b/dev/tests/verification/DeprecationCheckModule/Test/DeprecationCheckTest.xml new file mode 100644 index 000000000..1c4fc3dba --- /dev/null +++ b/dev/tests/verification/DeprecationCheckModule/Test/DeprecationCheckTest.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="DeprecationCheckTest"> + <createData entity="DeprecationCheckData" stepKey="deprecatedCreateData"/> + <actionGroup ref="DeprecationCheckActionGroup" stepKey="deprecationCheckActionGroup" /> + <amOnPage url="{{DeprecationCheckPage.url}}" stepKey="deprecatedAmOnPage" /> + <actionGroup ref="DeprecationCheckDeprecatedActionGroup" stepKey="deprecationCheckDeprecatedActionGroup" /> + </test> +</tests> diff --git a/dev/tests/verification/Resources/StaticChecks/mftf-deprecated-entity-usage-checks.txt b/dev/tests/verification/Resources/StaticChecks/mftf-deprecated-entity-usage-checks.txt new file mode 100644 index 000000000..63e025470 --- /dev/null +++ b/dev/tests/verification/Resources/StaticChecks/mftf-deprecated-entity-usage-checks.txt @@ -0,0 +1,23 @@ + +File "/verification/DeprecationCheckModule/Test/DeprecationCheckTest.xml" contains: + - Deprecated Page(s): + "DeprecationCheckPage" in /verification/DeprecationCheckModule/Page/DeprecationCheckPage.xml + - Deprecated ActionGroup(s): + "DeprecationCheckDeprecatedActionGroup" in /verification/DeprecationCheckModule/ActionGroup/DeprecationCheckDeprecatedActionGroup.xml + - Deprecated Data(s): + "DeprecationCheckData" in /verification/DeprecationCheckModule/Data/DeprecationCheckData.xml + - "DeprecationCheckData" references deprecated: + "type1" in metadata xml file + + +File "/verification/DeprecationCheckModule/ActionGroup/DeprecationCheckActionGroup.xml" contains: + - Deprecated Section(s): + "DeprecationCheckSection" in /verification/DeprecationCheckModule/Section/DeprecationCheckSection.xml + - Deprecated Element(s): + "DeprecationCheckSection.deprecationCheckElement" in /verification/DeprecationCheckModule/Section/DeprecationCheckSection.xml + + +File "/verification/DeprecationCheckModule/Suite/deprecationCheckSuite.xml" contains: + - Deprecated Test(s): + "DeprecationCheckDeprecatedTest" in /verification/DeprecationCheckModule/Test/DeprecationCheckDeprecatedTest.xml + diff --git a/dev/tests/verification/Tests/StaticCheck/DeprecationStaticCheckTest.php b/dev/tests/verification/Tests/StaticCheck/DeprecationStaticCheckTest.php new file mode 100644 index 000000000..bafe586ac --- /dev/null +++ b/dev/tests/verification/Tests/StaticCheck/DeprecationStaticCheckTest.php @@ -0,0 +1,92 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace tests\verification\Tests; + +use AspectMock\Test as AspectMock; +use Magento\FunctionalTestingFramework\StaticCheck\DeprecatedEntityUsageCheck; +use Magento\FunctionalTestingFramework\StaticCheck\StaticChecksList; +use Magento\FunctionalTestingFramework\Util\Filesystem\DirSetupUtil; +use PHPUnit\Framework\TestCase; +use Symfony\Component\Console\Input\InputInterface; + +class DeprecationStaticCheckTest extends TestCase +{ + const STATIC_RESULTS_DIR = TESTS_MODULE_PATH . + DIRECTORY_SEPARATOR . + '_output' . + DIRECTORY_SEPARATOR . + 'static-results'; + + const LOG_FILE = self::STATIC_RESULTS_DIR . + DIRECTORY_SEPARATOR . + DeprecatedEntityUsageCheck::ERROR_LOG_FILENAME . + '.txt'; + + const TEST_MODULE_PATH = TESTS_MODULE_PATH . + DIRECTORY_SEPARATOR . + 'DeprecationCheckModule'. + DIRECTORY_SEPARATOR; + + const RESOURCES_PATH = TESTS_MODULE_PATH . + DIRECTORY_SEPARATOR . + "Resources" . + DIRECTORY_SEPARATOR . + 'StaticChecks'; + + public static function setUpBeforeClass(): void + { + // remove static-results if it exists + if (file_exists(self::STATIC_RESULTS_DIR)) { + DirSetupUtil::rmdirRecursive(self::STATIC_RESULTS_DIR); + } + } + + /** + * test static-check DeprecatedEntityUsageCheck. + * + * @throws \Exception + */ + public function testDeprecatedEntityUsageCheck() + { + $staticCheck = new DeprecatedEntityUsageCheck(); + + $input = $this->mockInputInterface(self::TEST_MODULE_PATH); + AspectMock::double(StaticChecksList::class, ['getErrorFilesPath' => self::STATIC_RESULTS_DIR]); + + /** @var InputInterface $input */ + $staticCheck->execute($input); + + $this->assertTrue(file_exists(self::LOG_FILE)); + $this->assertFileEquals( + self::RESOURCES_PATH. + DIRECTORY_SEPARATOR . + DeprecatedEntityUsageCheck::ERROR_LOG_FILENAME . + ".txt", + self::LOG_FILE + ); + } + + /** + * Sets input interface + * @param $path + * @return \PHPUnit\Framework\MockObject\MockObject + */ + public function mockInputInterface($path) + { + $input = $this->getMockBuilder(InputInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $input->method('getOption') + ->with('path') + ->willReturn($path); + return $input; + } + + public function tearDown(): void + { + DirSetupUtil::rmdirRecursive(self::STATIC_RESULTS_DIR); + } +} diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/DeprecatedEntityUsageCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/DeprecatedEntityUsageCheck.php index 5da16ec6a..547e6a633 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/DeprecatedEntityUsageCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/DeprecatedEntityUsageCheck.php @@ -37,6 +37,7 @@ class DeprecatedEntityUsageCheck implements StaticCheckInterface { const EXTENDS_REGEX_PATTERN = '/extends=["\']([^\'"]*)/'; const ACTIONGROUP_REGEX_PATTERN = '/ref=["\']([^\'"]*)/'; + const DEPRECATED_REGEX_PATTERN = '/deprecated=["\']([^\'"]*)/'; const ERROR_LOG_FILENAME = 'mftf-deprecated-entity-usage-checks'; const ERROR_LOG_MESSAGE = 'MFTF Deprecated Entity Usage Check'; @@ -177,7 +178,6 @@ private function loadAllXmlFiles($input) MftfApplicationConfig::LEVEL_DEFAULT, true ); - putenv('CUSTOM_MODULE_PATHS=' . realpath($path)); $modulePaths[] = realpath($path); $includeRootPath = false; } else { @@ -225,6 +225,9 @@ private function findReferenceErrorsInActionFiles($files, $checkTestRef = false) /** @var SplFileInfo $filePath */ foreach ($files as $filePath) { $contents = file_get_contents($filePath); + if ($this->isDeprecated($contents)) { + continue; + } preg_match_all(ActionObject::ACTION_ATTRIBUTE_VARIABLE_REGEX_PATTERN, $contents, $braceReferences); preg_match_all(self::ACTIONGROUP_REGEX_PATTERN, $contents, $actionGroupReferences); preg_match_all(self::EXTENDS_REGEX_PATTERN, $contents, $extendReferences); @@ -316,6 +319,17 @@ private function findReferenceErrorsInActionFiles($files, $checkTestRef = false) return $testErrors; } + /** + * Checks if entity is deprecated in action files. + * @param string $contents + * @return boolean + */ + private function isDeprecated($contents) + { + preg_match_all(self::DEPRECATED_REGEX_PATTERN, $contents, $deprecatedEntity); + return (!empty($deprecatedEntity[1])); + } + /** * Find reference errors in a set of data files * @@ -335,6 +349,11 @@ private function findReferenceErrorsInDataFiles($files) $entities = $domDocument->getElementsByTagName('entity'); foreach ($entities as $entity) { /** @var DOMElement $entity */ + $deprecated = $entity->getAttribute('deprecated'); + // skip check if entity is deprecated + if (!empty($deprecated)) { + continue; + } $entityName = $entity->getAttribute('name'); $metadataType = $entity->getAttribute('type'); $parentEntityName = $entity->getAttribute('extends'); @@ -609,9 +628,9 @@ private function findViolatingReferences($references) $name = $key; list($section,) = explode('.', $key, 2); /** @var SectionObject $references[$section] */ - $file = $references[$section]->getFilename(); + $file = StaticChecksList::getFilePath($references[$section]->getFilename()); } else { - $file = $entity->getFilename(); + $file = StaticChecksList::getFilePath($entity->getFilename()); } $violatingReferences[$this->getSubjectFromClassType($classType)][] = [ 'name' => $name, @@ -633,16 +652,18 @@ private function setErrorOutput($violatingReferences, $path) { $testErrors = []; + $filePath = StaticChecksList::getFilePath($path->getRealPath()); + if (!empty($violatingReferences)) { // Build error output - $errorOutput = "\nFile \"{$path->getRealPath()}\" contains:\n"; + $errorOutput = "\nFile \"{$filePath}\" contains:\n"; foreach ($violatingReferences as $subject => $data) { $errorOutput .= "\t- {$subject}:\n"; foreach ($data as $item) { $errorOutput .= "\t\t\"" . $item['name'] . "\" in " . $item['file'] . "\n"; } } - $testErrors[$path->getRealPath()][] = $errorOutput; + $testErrors[$filePath][] = $errorOutput; } return $testErrors; diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php b/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php index 7cd894e00..ba2139276 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php @@ -69,4 +69,22 @@ public static function getErrorFilesPath() { return self::$errorFilesPath; } + + /** + * Return relative path to files for unit testing purposes. + * @param string $fileNames + * @return string + */ + public static function getFilePath($fileNames) + { + if (!empty($fileNames)) { + $relativeFileNames = ltrim( + str_replace(MAGENTO_BP, '', $fileNames) + ); + if (!empty($relativeFileNames)) { + return $relativeFileNames; + } + } + return $fileNames; + } } From 85d4fa6a8f29c8db4e36b7f97cb136a403154154 Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Tue, 11 Aug 2020 14:51:30 -0500 Subject: [PATCH 502/888] MQE-2212: Fix invalid behaviour MAGENTO_BACKEND_BASE_URL (#780) * MQE-2212: Fix invalid behaviour of MAGENTO_BACKEND_BASE_URL * MQE-2212: Fix invalid behaviour MAGENTO_BACKEND_BASE_URL * MQE-2212: Fix invalid behaviour MAGENTO_BACKEND_BASE_URL --- .../Resources/PageReplacementTest.txt | 4 +-- .../Module/MagentoWebDriver.php | 2 +- .../Test/Objects/ActionObject.php | 7 +++- .../Util/MftfGlobals.php | 9 ++++-- .../Util/TestGenerator.php | 32 +++++++++++++++---- 5 files changed, 40 insertions(+), 14 deletions(-) diff --git a/dev/tests/verification/Resources/PageReplacementTest.txt b/dev/tests/verification/Resources/PageReplacementTest.txt index cda119999..6f75ee096 100644 --- a/dev/tests/verification/Resources/PageReplacementTest.txt +++ b/dev/tests/verification/Resources/PageReplacementTest.txt @@ -35,8 +35,8 @@ class PageReplacementTestCest $I->amOnPage("/John/StringLiteral2.html"); // stepKey: twoParamPageStringData $I->amOnPage("/John/" . $I->retrieveEntityField('datakey', 'firstname', 'test') . ".html"); // stepKey: twoParamPageDataPersist $I->amOnPage("/" . $I->retrieveEntityField('datakey', 'firstname', 'test') . "/StringLiteral2.html"); // stepKey: twoParamPagePersistString - $I->amOnPage("/" . getenv("MAGENTO_BACKEND_NAME") . "/backend"); // stepKey: onAdminPage - $I->amOnPage("/" . getenv("MAGENTO_BACKEND_NAME") . "/StringLiteral/page.html"); // stepKey: oneParamAdminPageString + $I->amOnPage((getenv("MAGENTO_BACKEND_BASE_URL") ? rtrim(getenv("MAGENTO_BACKEND_BASE_URL"), "/") : "") . "/" . getenv("MAGENTO_BACKEND_NAME") . "/backend"); // stepKey: onAdminPage + $I->amOnPage((getenv("MAGENTO_BACKEND_BASE_URL") ? rtrim(getenv("MAGENTO_BACKEND_BASE_URL"), "/") : "") . "/" . getenv("MAGENTO_BACKEND_NAME") . "/StringLiteral/page.html"); // stepKey: oneParamAdminPageString $I->amOnUrl("http://myFullUrl.com/"); // stepKey: onExternalPage } } diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index ef57aa3f1..8886f4493 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -877,7 +877,7 @@ public function saveScreenshot() */ public function amOnPage($page) { - parent::amOnPage($page); + (0 === strpos($page, 'http')) ? parent::amOnUrl($page) : parent::amOnPage($page); $this->waitForPageLoad(); } diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php index 648471c7a..8d4e7a945 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php @@ -726,7 +726,12 @@ private function resolveParameterization($isParameterized, $replacement, $match, $resolvedReplacement = $replacement; } if (get_class($object) == PageObject::class && $object->getArea() == PageObject::ADMIN_AREA) { - $resolvedReplacement = "/{{_ENV.MAGENTO_BACKEND_NAME}}/" . $resolvedReplacement; + $urlSegments = [ + '{{_ENV.MAGENTO_BACKEND_BASE_URL}}', + '{{_ENV.MAGENTO_BACKEND_NAME}}', + $resolvedReplacement + ]; + $resolvedReplacement = implode('/', $urlSegments); } return $resolvedReplacement; } diff --git a/src/Magento/FunctionalTestingFramework/Util/MftfGlobals.php b/src/Magento/FunctionalTestingFramework/Util/MftfGlobals.php index d59df5c11..cb0f4f5ae 100644 --- a/src/Magento/FunctionalTestingFramework/Util/MftfGlobals.php +++ b/src/Magento/FunctionalTestingFramework/Util/MftfGlobals.php @@ -76,12 +76,15 @@ public static function getBackendBaseUrl($withTrailingSeparator = true) { if (!self::$backendBaseUrl) { try { + $backendName = getenv('MAGENTO_BACKEND_NAME'); $bUrl = getenv('MAGENTO_BACKEND_BASE_URL'); - if ($bUrl) { - self::$backendBaseUrl = UrlFormatter::format($bUrl, false); + if ($bUrl && $backendName) { + self::$backendBaseUrl = UrlFormatter::format( + UrlFormatter::format($bUrl) . $backendName, + false + ); } else { $baseUrl = getenv('MAGENTO_BASE_URL'); - $backendName = getenv('MAGENTO_BACKEND_NAME'); if ($baseUrl && $backendName) { self::$backendBaseUrl = UrlFormatter::format( UrlFormatter::format($baseUrl) . $backendName, diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 80056b3b9..82fb2c06a 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -2030,18 +2030,20 @@ private function resolveRuntimeReference($args, $regex, $func) $newArgs = []; foreach ($args as $key => $arg) { + $newArgs[$key] = $arg; preg_match_all($regex, $arg, $matches); if (!empty($matches[0])) { - $fullMatch = $matches[0][0]; - $refVariable = $matches[1][0]; - unset($matches); - $replacement = "{$func}(\"{$refVariable}\")"; + foreach ($matches[0] as $matchKey => $fullMatch) { + $refVariable = $matches[1][$matchKey]; - $outputArg = $this->processQuoteBreaks($fullMatch, $arg, $replacement); - $newArgs[$key] = $outputArg; + $replacement = $this->getReplacement($func, $refVariable); + + $outputArg = $this->processQuoteBreaks($fullMatch, $newArgs[$key], $replacement); + $newArgs[$key] = $outputArg; + } + unset($matches); continue; } - $newArgs[$key] = $arg; } // override passed in args for use later. @@ -2313,4 +2315,20 @@ private function parseUserInput($userInput) return $this->addUniquenessFunctionCall($userInput); } + + /** + * Supports fallback for BACKEND URL + * + * @param string $func + * @param string $refVariable + * @return string + */ + private function getReplacement($func, $refVariable): string + { + if ($refVariable === 'MAGENTO_BACKEND_BASE_URL') { + return "({$func}(\"{$refVariable}\") ? rtrim({$func}(\"{$refVariable}\"), \"/\") : \"\")"; + } + + return "{$func}(\"{$refVariable}\")"; + } } From 8e045808e778b2cf1028aed6a419e9830402396e Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 13 Aug 2020 09:34:27 -0500 Subject: [PATCH 503/888] MQE-2110: MFTF command to pause test execution --- .../Console/BaseGenerateCommand.php | 23 +++++++ .../Console/Codecept/CodeceptCommandUtil.php | 66 +++++++++++++++++++ .../Console/CodeceptRunCommand.php | 61 +++++++++++++++++ .../Console/CommandList.php | 1 + .../Console/RunManifestCommand.php | 33 ++++++---- .../Console/RunTestCommand.php | 34 +++++++--- .../Console/RunTestFailedCommand.php | 30 ++++----- .../Console/RunTestGroupCommand.php | 27 ++++---- 8 files changed, 223 insertions(+), 52 deletions(-) create mode 100644 src/Magento/FunctionalTestingFramework/Console/Codecept/CodeceptCommandUtil.php create mode 100644 src/Magento/FunctionalTestingFramework/Console/CodeceptRunCommand.php diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index 29e489a63..11ffffdae 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -14,6 +14,7 @@ use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Input\StringInput; use Symfony\Component\Console\Output\OutputInterface; use Magento\FunctionalTestingFramework\Util\Filesystem\DirSetupUtil; use Magento\FunctionalTestingFramework\Util\TestGenerator; @@ -21,9 +22,16 @@ use Magento\FunctionalTestingFramework\Suite\Handlers\SuiteObjectHandler; use Symfony\Component\Console\Style\SymfonyStyle; +/** + * Class BaseGenerateCommand + * @package Magento\FunctionalTestingFramework\Console + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class BaseGenerateCommand extends Command { const MFTF_NOTICES = "Placeholder text for MFTF notices\n"; + const CODECEPT_RUN_COMMAND = 'codecept:run functional '; /** * Enable pause() @@ -242,4 +250,19 @@ protected function pauseEnabled() } return $this->enablePause; } + + /** + * Runs the bin/mftf codecept:run command and returns exit code + * + * @param string $command + * @param OutputInterface $output + * @return integer + * @throws \Exception + */ + protected function codeceptRunTest(string $command, OutputInterface $output) + { + $input = new StringInput($command); + $command = $this->getApplication()->find('codecept:run'); + return $command->run($input, $output); + } } diff --git a/src/Magento/FunctionalTestingFramework/Console/Codecept/CodeceptCommandUtil.php b/src/Magento/FunctionalTestingFramework/Console/Codecept/CodeceptCommandUtil.php new file mode 100644 index 000000000..3992aa677 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Console/Codecept/CodeceptCommandUtil.php @@ -0,0 +1,66 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types = 1); + +namespace Magento\FunctionalTestingFramework\Console\Codecept; + +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\ArgvInput; + +class CodeceptCommandUtil +{ + const CODECEPTION_AUTOLOAD_FILE = PROJECT_ROOT . '/vendor/codeception/codeception/autoload.php'; + + /** + * Current working directory + * + * @var string + */ + private $cwd = null; + + /** + * Setup Codeception + * + * @param InputInterface $input + * @return void + */ + public function setup(InputInterface $input) + { + require_once realpath(self::CODECEPTION_AUTOLOAD_FILE); + + $tokens = preg_split('{\\s+}', $input->__toString()); + $tokens[0] = str_replace('codecept:', '', $tokens[0]); + \Closure::bind(function &(ArgvInput $input) use ($tokens) { + return $input->setTokens($tokens); + }, null, ArgvInput::class); + } + + /** + * Save Codeception working directory + * + * @return void + * @throws TestFrameworkException + */ + public function setCodeceptCwd() + { + $this->cwd = getcwd(); + chdir(FilePathFormatter::format(TESTS_BP, false)); + } + + /** + * Restore current working directory + * + * @return void + */ + public function restoreCwd() + { + if ($this->cwd) { + chdir($this->cwd); + } + } +} diff --git a/src/Magento/FunctionalTestingFramework/Console/CodeceptRunCommand.php b/src/Magento/FunctionalTestingFramework/Console/CodeceptRunCommand.php new file mode 100644 index 000000000..311b81e12 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Console/CodeceptRunCommand.php @@ -0,0 +1,61 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types = 1); + +namespace Magento\FunctionalTestingFramework\Console; + +use Codeception\Command\Run; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Magento\FunctionalTestingFramework\Console\Codecept\CodeceptCommandUtil; + +class CodeceptRunCommand extends Run +{ + /** + * Configures the current command + * + * @return void + */ + protected function configure() + { + $this->setName('codecept:run') + ->setDescription( + "Wrapper command to codecept:run. See https://codeception.com/docs/reference/Commands" + ); + + parent::configure(); + } + + /** + * Executes the current command + * + * @param InputInterface $input + * @param OutputInterface $output + * @return integer + * @throws \Exception + */ + public function execute(InputInterface $input, OutputInterface $output): int + { + $commandUtil = new CodeceptCommandUtil(); + $commandUtil->setup($input); + $commandUtil->setCodeceptCwd(); + + try { + $exitCode = parent::execute($input, $output); + } catch (\Exception $e) { + throw new TestFrameworkException( + 'Make sure cest files are generated before running bin/mftf ' + . $this->getName() + . PHP_EOL + . $e->getMessage() + ); + } + + $commandUtil->restoreCwd(); + return $exitCode; + } +} diff --git a/src/Magento/FunctionalTestingFramework/Console/CommandList.php b/src/Magento/FunctionalTestingFramework/Console/CommandList.php index f77c2c576..840e7dd86 100644 --- a/src/Magento/FunctionalTestingFramework/Console/CommandList.php +++ b/src/Magento/FunctionalTestingFramework/Console/CommandList.php @@ -30,6 +30,7 @@ public function __construct(array $commands = []) { $this->commands = [ 'build:project' => new BuildProjectCommand(), + 'codecept:run' => new CodeceptRunCommand(), 'doctor' => new DoctorCommand(), 'generate:suite' => new GenerateSuiteCommand(), 'generate:tests' => new GenerateTestsCommand(), diff --git a/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php index 1709726bb..76b92c960 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php @@ -11,6 +11,7 @@ use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\StringInput; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Process\Process; use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; @@ -103,28 +104,32 @@ protected function execute(InputInterface $input, OutputInterface $output): int * @param string $manifestLine * @param OutputInterface $output * @return void + * @throws \Exception * * @SuppressWarnings(PHPMD.UnusedLocalVariable) Need this because of the unused $type variable in the closure */ private function runManifestLine(string $manifestLine, OutputInterface $output) { - $codeceptionCommand = realpath(PROJECT_ROOT . "/vendor/bin/codecept") . " run functional --verbose --steps "; if (getenv('ENABLE_PAUSE') === 'true') { - $codeceptionCommand .= ' --debug'; + $codeceptionCommand = BaseGenerateCommand::CODECEPT_RUN_COMMAND + . '--verbose --steps --debug' . $manifestLine; + $input = new StringInput($codeceptionCommand); + $command = $this->getApplication()->find('codecept:run'); + $subReturnCode = $command->run($input, $output); + } else { + $codeceptionCommand = realpath(PROJECT_ROOT . "/vendor/bin/codecept") + . " run functional --verbose --steps " . $manifestLine; + + // run the codecept command in a sub process + $process = new Process($codeceptionCommand); + $process->setWorkingDirectory(TESTS_BP); + $process->setIdleTimeout(600); + $process->setTimeout(0); + $subReturnCode = $process->run(function ($type, $buffer) use ($output) { + $output->write($buffer); + }); } - $codeceptionCommand .= $manifestLine; - // run the codecept command in a sub process - $process = new Process($codeceptionCommand); - $process->setWorkingDirectory(TESTS_BP); - $process->setIdleTimeout(600); - $process->setTimeout(0); - if (getenv('ENABLE_PAUSE') === 'true') { - $process->setInput(STDIN); - } - $subReturnCode = $process->run(function ($type, $buffer) use ($output) { - $output->write($buffer); - }); $this->returnCode = max($this->returnCode, $subReturnCode); } diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php index 86352d5c6..502ef7c78 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php @@ -119,10 +119,16 @@ protected function execute(InputInterface $input, OutputInterface $output): int * @param OutputInterface $output * @return void * @throws TestFrameworkException + * @throws \Exception */ private function runTests(array $tests, OutputInterface $output) { - $codeceptionCommand = realpath(PROJECT_ROOT . '/vendor/bin/codecept') . ' run functional '; + if ($this->pauseEnabled()) { + $codeceptionCommand = self::CODECEPT_RUN_COMMAND; + } else { + $codeceptionCommand = realpath(PROJECT_ROOT . '/vendor/bin/codecept') . ' run functional '; + } + $testsDirectory = FilePathFormatter::format(TESTS_MODULE_PATH) . TestGenerator::GENERATED_DIR . DIRECTORY_SEPARATOR . @@ -136,11 +142,14 @@ private function runTests(array $tests, OutputInterface $output) $testName . " is not available under " . $testsDirectory ); } - $fullCommand = $codeceptionCommand . $testsDirectory . $testName . ' --verbose --steps'; + if ($this->pauseEnabled()) { - $fullCommand .= ' --debug'; + $fullCommand = $codeceptionCommand . $testsDirectory . $testName . ' --verbose --steps --debug'; + $this->returnCode = max($this->returnCode, $this->codeceptRunTest($fullCommand, $output)); + } else { + $fullCommand = $codeceptionCommand . $testsDirectory . $testName . ' --verbose --steps'; + $this->returnCode = max($this->returnCode, $this->executeTestCommand($fullCommand, $output)); } - $this->returnCode = max($this->returnCode, $this->executeTestCommand($fullCommand, $output)); } } @@ -150,17 +159,24 @@ private function runTests(array $tests, OutputInterface $output) * @param array $suitesConfig * @param OutputInterface $output * @return void + * @throws \Exception */ private function runTestsInSuite(array $suitesConfig, OutputInterface $output) { - $codeceptionCommand = realpath(PROJECT_ROOT . '/vendor/bin/codecept') . ' run functional --verbose --steps '; if ($this->pauseEnabled()) { - $codeceptionCommand .= ' --debug'; + $codeceptionCommand = self::CODECEPT_RUN_COMMAND . '--verbose --steps --debug'; + } else { + $codeceptionCommand = realpath(PROJECT_ROOT . '/vendor/bin/codecept') + . ' run functional --verbose --steps '; } //for tests in suites, run them as a group to run before and after block foreach (array_keys($suitesConfig) as $suite) { $fullCommand = $codeceptionCommand . " -g {$suite}"; - $this->returnCode = max($this->returnCode, $this->executeTestCommand($fullCommand, $output)); + if ($this->pauseEnabled()) { + $this->returnCode = max($this->returnCode, $this->codeceptRunTest($fullCommand, $output)); + } else { + $this->returnCode = max($this->returnCode, $this->executeTestCommand($fullCommand, $output)); + } } } @@ -179,9 +195,7 @@ private function executeTestCommand(string $command, OutputInterface $output) $process->setWorkingDirectory(TESTS_BP); $process->setIdleTimeout(600); $process->setTimeout(0); - if ($this->pauseEnabled()) { - $process->setInput(STDIN); - } + return $process->run(function ($type, $buffer) use ($output) { $output->write($buffer); }); diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php index b9012b086..fa48d0b72 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php @@ -117,24 +117,24 @@ protected function execute(InputInterface $input, OutputInterface $output): int $testManifestList = $this->readTestManifestFile(); $returnCode = 0; foreach ($testManifestList as $testCommand) { - $codeceptionCommand = realpath(PROJECT_ROOT . '/vendor/bin/codecept') . ' run functional '; - $codeceptionCommand .= $testCommand; if ($this->pauseEnabled()) { - $codeceptionCommand .= ' --debug'; + $codeceptionCommand = self::CODECEPT_RUN_COMMAND . $testCommand . ' --debug'; + $this->codeceptRunTest($codeceptionCommand, $output); + } else { + $codeceptionCommand = realpath(PROJECT_ROOT . '/vendor/bin/codecept') . ' run functional '; + $codeceptionCommand .= $testCommand; + + $process = new Process($codeceptionCommand); + $process->setWorkingDirectory(TESTS_BP); + $process->setIdleTimeout(600); + $process->setTimeout(0); + $returnCode = max($returnCode, $process->run( + function ($type, $buffer) use ($output) { + $output->write($buffer); + } + )); } - $process = new Process($codeceptionCommand); - $process->setWorkingDirectory(TESTS_BP); - $process->setIdleTimeout(600); - $process->setTimeout(0); - if ($this->pauseEnabled()) { - $process->setInput(STDIN); - } - $returnCode = max($returnCode, $process->run( - function ($type, $buffer) use ($output) { - $output->write($buffer); - } - )); if (file_exists($this->testsFailedFile)) { $this->failedList = array_merge( $this->failedList, diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php index 19dec6d4b..3047ba277 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php @@ -94,9 +94,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int $command->run(new ArrayInput($args), $output); } - $commandString = realpath(PROJECT_ROOT . '/vendor/bin/codecept') . ' run functional --verbose --steps'; if ($this->pauseEnabled()) { - $commandString .= ' --debug'; + $commandString = self::CODECEPT_RUN_COMMAND . '--verbose --steps --debug'; + } else { + $commandString = realpath(PROJECT_ROOT . '/vendor/bin/codecept') . ' run functional --verbose --steps'; } $exitCode = -1; @@ -104,19 +105,19 @@ protected function execute(InputInterface $input, OutputInterface $output): int foreach ($groups as $group) { $codeceptionCommandString = $commandString . " -g {$group}"; - $process = new Process($codeceptionCommandString); - $process->setWorkingDirectory(TESTS_BP); - $process->setIdleTimeout(600); - $process->setTimeout(0); if ($this->pauseEnabled()) { - $process->setInput(STDIN); + $returnCodes[] = $this->codeceptRunTest($codeceptionCommandString, $output); + } else { + $process = new Process($codeceptionCommandString); + $process->setWorkingDirectory(TESTS_BP); + $process->setIdleTimeout(600); + $process->setTimeout(0); + $returnCodes[] = $process->run( + function ($type, $buffer) use ($output) { + $output->write($buffer); + } + ); } - - $returnCodes[] = $process->run( - function ($type, $buffer) use ($output) { - $output->write($buffer); - } - ); } foreach ($returnCodes as $returnCode) { From e99db412ce7f072e3f83804c61617e1e7c82059f Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 13 Aug 2020 13:55:17 -0500 Subject: [PATCH 504/888] MQE-2110: MFTF command to pause test execution --- docs/commands/mftf.md | 25 ++++++++ docs/interactive-pause.md | 58 +++++++++++++++++++ .../Console/BaseGenerateCommand.php | 11 ++-- .../Console/CodeceptRunCommand.php | 2 +- .../Console/RunManifestCommand.php | 4 +- .../Console/RunTestCommand.php | 4 +- .../Console/RunTestFailedCommand.php | 4 +- .../Console/RunTestGroupCommand.php | 2 +- .../Module/MagentoWebDriver.php | 3 + 9 files changed, 100 insertions(+), 13 deletions(-) create mode 100644 docs/interactive-pause.md diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 3c170e5ca..5f74e5efe 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -559,6 +559,31 @@ To upgrade all test components inside the `Catalog` module: vendor/bin/mftf upgrade:tests /Users/user/magento2/app/code/Magento/Catalog/Test/Mftf/ ``` +### `codecept:run` + +MFTF wrapper command invokes `vendor/bin/codecept run`. This command runs tests in functional suite. It does not generate tests for you. You must do that first. + +#### Usage + +See https://codeception.com/docs/reference/Commands#Run + +```bash +vendor/bin/mftf codecept:run [<suite|test>] --[<option(s)>] +``` + +#### Examples + +```bash +# Run all tests in functional suite +vendor/bin/mftf codecept:run functional +# Run all tests in functional suite with options +vendor/bin/mftf codecept:run functional --verbose --steps --debug +# Run one test +vendor/bin/mftf codecept:run functional Magento/_generated/default/AdminLoginSuccessfulTestCest +# Run all tests in default group +vendor/bin/mftf codecept:run functional --verbose --steps -g default +``` + <!-- LINK DEFINITIONS --> [configuration]: ../configuration.md diff --git a/docs/interactive-pause.md b/docs/interactive-pause.md new file mode 100644 index 000000000..f5fd3597a --- /dev/null +++ b/docs/interactive-pause.md @@ -0,0 +1,58 @@ +# Interactive Pause + +It’s hard to write a complete test at once. You will need to try different commands with different arguments before you find a correct path. + +Since Codeception 3.0 you can pause execution in any point and enter interactive shell where you will be able to try commands in action. + +Now this `Interactive Pause` feature is available in MFTF and all you need to do is to set `ENABLE_PAUSE=true` in `.env`. + +Check it out at [Codeception website][] for documentation and a video to see `Interactive Pause` in action. + +In short, when a test gets to `$I->pause()` step, it stops and shows a console where you can try all available commands with auto-completion, stash commands, and save screenshot, etc. + +## Generation Time + +A `<pause>` action in xml will always be generated into php regardless if `ENABLE_PAUSE=true` is set or not. +However, when `ENABLE_PAUSE=true` is set, an additional`pause()` action will be generated in `_failed()` hook for a test, +so that the test could pause on failure at run time. + +## Execution Time + +To use `Interactive Pause` at run time, there are two types of MFTF commands to use. + +### MFTF Run Commands + +When `ENABLE_PAUSE=true` is set, the following MFTF run commands support `Interactive Pause`. + +```bash +vendor/bin/mftf run:group +``` + +```bash +vendor/bin/mftf run:test +``` + +```bash +vendor/bin/mftf run:manifest +``` + +```bash +vendor/bin/mftf run:failed +``` + +<div class="bs-callout-warning"> +Note: MFTF run command's `--debug` option is different from Codeception `--debug` mode option. +</div> + +### MFTF Codecept Run Command + +You can also use MFTF's wrapper command to run Codeception directly and activate `Interactive Pause` by passing `--debug` option. +You don't need to set `ENABLE_PAUSE=true` for this command. + +```bash +vendor/bin/mftf codecept:run --debug +``` + +## References + +[Codeception website](https://codeception.com/docs/02-GettingStarted#Interactive-Pause) \ No newline at end of file diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index 11ffffdae..44c6ceec9 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -31,7 +31,8 @@ class BaseGenerateCommand extends Command { const MFTF_NOTICES = "Placeholder text for MFTF notices\n"; - const CODECEPT_RUN_COMMAND = 'codecept:run functional '; + const CODECEPT_RUN = 'codecept:run '; + const CODECEPT_RUN_FUNCTIONAL = self::CODECEPT_RUN . 'functional '; /** * Enable pause() @@ -254,15 +255,15 @@ protected function pauseEnabled() /** * Runs the bin/mftf codecept:run command and returns exit code * - * @param string $command + * @param string $commandStr * @param OutputInterface $output * @return integer * @throws \Exception */ - protected function codeceptRunTest(string $command, OutputInterface $output) + protected function codeceptRunTest(string $commandStr, OutputInterface $output) { - $input = new StringInput($command); - $command = $this->getApplication()->find('codecept:run'); + $input = new StringInput($commandStr); + $command = $this->getApplication()->find(self::CODECEPT_RUN); return $command->run($input, $output); } } diff --git a/src/Magento/FunctionalTestingFramework/Console/CodeceptRunCommand.php b/src/Magento/FunctionalTestingFramework/Console/CodeceptRunCommand.php index 311b81e12..de16bad84 100644 --- a/src/Magento/FunctionalTestingFramework/Console/CodeceptRunCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/CodeceptRunCommand.php @@ -24,7 +24,7 @@ protected function configure() { $this->setName('codecept:run') ->setDescription( - "Wrapper command to codecept:run. See https://codeception.com/docs/reference/Commands" + "Wrapper command to vendor/bin/codecept:run. See https://codeception.com/docs/reference/Commands#Run" ); parent::configure(); diff --git a/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php index 76b92c960..89ae90888 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php @@ -111,8 +111,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int private function runManifestLine(string $manifestLine, OutputInterface $output) { if (getenv('ENABLE_PAUSE') === 'true') { - $codeceptionCommand = BaseGenerateCommand::CODECEPT_RUN_COMMAND - . '--verbose --steps --debug' . $manifestLine; + $codeceptionCommand = BaseGenerateCommand::CODECEPT_RUN_FUNCTIONAL + . '--verbose --steps --debug ' . $manifestLine; $input = new StringInput($codeceptionCommand); $command = $this->getApplication()->find('codecept:run'); $subReturnCode = $command->run($input, $output); diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php index 502ef7c78..3d99b6fad 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php @@ -124,7 +124,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int private function runTests(array $tests, OutputInterface $output) { if ($this->pauseEnabled()) { - $codeceptionCommand = self::CODECEPT_RUN_COMMAND; + $codeceptionCommand = self::CODECEPT_RUN_FUNCTIONAL; } else { $codeceptionCommand = realpath(PROJECT_ROOT . '/vendor/bin/codecept') . ' run functional '; } @@ -164,7 +164,7 @@ private function runTests(array $tests, OutputInterface $output) private function runTestsInSuite(array $suitesConfig, OutputInterface $output) { if ($this->pauseEnabled()) { - $codeceptionCommand = self::CODECEPT_RUN_COMMAND . '--verbose --steps --debug'; + $codeceptionCommand = self::CODECEPT_RUN_FUNCTIONAL . '--verbose --steps --debug'; } else { $codeceptionCommand = realpath(PROJECT_ROOT . '/vendor/bin/codecept') . ' run functional --verbose --steps '; diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php index fa48d0b72..87606d53d 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php @@ -118,8 +118,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int $returnCode = 0; foreach ($testManifestList as $testCommand) { if ($this->pauseEnabled()) { - $codeceptionCommand = self::CODECEPT_RUN_COMMAND . $testCommand . ' --debug'; - $this->codeceptRunTest($codeceptionCommand, $output); + $codeceptionCommand = self::CODECEPT_RUN_FUNCTIONAL . $testCommand . ' --debug'; + $returnCode = $this->codeceptRunTest($codeceptionCommand, $output); } else { $codeceptionCommand = realpath(PROJECT_ROOT . '/vendor/bin/codecept') . ' run functional '; $codeceptionCommand .= $testCommand; diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php index 3047ba277..896218efc 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php @@ -95,7 +95,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } if ($this->pauseEnabled()) { - $commandString = self::CODECEPT_RUN_COMMAND . '--verbose --steps --debug'; + $commandString = self::CODECEPT_RUN_FUNCTIONAL . '--verbose --steps --debug'; } else { $commandString = realpath(PROJECT_ROOT . '/vendor/bin/codecept') . ' run functional --verbose --steps'; } diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 8886f4493..859d666de 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -836,6 +836,9 @@ public function _failed(TestInterface $test, $fail) if ($this->pngReport === null && $this->htmlReport === null) { $this->saveScreenshot(); + if (getenv('ENABLE_PAUSE') === 'true') { + $this->pause(); + } } if ($this->current_test == null) { From b88849237b1f3b000703ea8a0a9183c43bc62b73 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Fri, 14 Aug 2020 09:06:28 -0500 Subject: [PATCH 505/888] MQE-2110: MFTF command to pause test execution --- docs/interactive-pause.md | 9 +++++++-- docs/test/actions.md | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/interactive-pause.md b/docs/interactive-pause.md index f5fd3597a..e7fc0f704 100644 --- a/docs/interactive-pause.md +++ b/docs/interactive-pause.md @@ -6,7 +6,7 @@ Since Codeception 3.0 you can pause execution in any point and enter interactive Now this `Interactive Pause` feature is available in MFTF and all you need to do is to set `ENABLE_PAUSE=true` in `.env`. -Check it out at [Codeception website][] for documentation and a video to see `Interactive Pause` in action. +Check [pause on codeception.com][] for documentation and a video to see `Interactive Pause` in action. In short, when a test gets to `$I->pause()` step, it stops and shows a console where you can try all available commands with auto-completion, stash commands, and save screenshot, etc. @@ -53,6 +53,11 @@ You don't need to set `ENABLE_PAUSE=true` for this command. vendor/bin/mftf codecept:run --debug ``` +<div class="bs-callout-warning"> +Note: You may want to limit the usage of this Codeception command with arguments and options for `acceptance` only +since it's what is supported by MFTF. You should also replace `acceptance` to `functional` when using this command when referring to Codeception documentation. +</div> + ## References -[Codeception website](https://codeception.com/docs/02-GettingStarted#Interactive-Pause) \ No newline at end of file +[pause on codeception.com](https://codeception.com/docs/02-GettingStarted#Interactive-Pause) \ No newline at end of file diff --git a/docs/test/actions.md b/docs/test/actions.md index a4e0fb44c..647635782 100644 --- a/docs/test/actions.md +++ b/docs/test/actions.md @@ -1463,7 +1463,7 @@ Attribute|Type|Use|Description ### pause -See [pause docs on codeception.com](https://codeception.com/docs/02-GettingStarted#Interactive-Pause). +See usage of `<pause` in [interactive-pause](../interactive-pause.md) and [pause docs on codeception.com](https://codeception.com/docs/02-GettingStarted#Interactive-Pause). Attribute|Type|Use|Description ---|---|---|--- From 1dab5ed0f30b4466207afbcc4439c8c0c9242618 Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Fri, 14 Aug 2020 11:30:31 -0500 Subject: [PATCH 506/888] Grammar and formatting --- docs/commands/mftf.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 5f74e5efe..8d1c636f2 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -561,11 +561,11 @@ vendor/bin/mftf upgrade:tests /Users/user/magento2/app/code/Magento/Catalog/Test ### `codecept:run` -MFTF wrapper command invokes `vendor/bin/codecept run`. This command runs tests in functional suite. It does not generate tests for you. You must do that first. +A MFTF wrapper command that invokes `vendor/bin/codecept run`. This command runs tests in functional suite. Tests must be generated before using this command. #### Usage -See https://codeception.com/docs/reference/Commands#Run +See the [Run Command](https://codeception.com/docs/reference/Commands#Run). ```bash vendor/bin/mftf codecept:run [<suite|test>] --[<option(s)>] From 297b2a0c6955cfb503c55b9ba1ec6d1b9010fbda Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Fri, 14 Aug 2020 11:33:02 -0500 Subject: [PATCH 507/888] grammar and formatting --- docs/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index 90111a03b..f780ac633 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -361,7 +361,7 @@ WAIT_TIMEOUT=30 ### ENABLE_PAUSE -Enables pause of test execution in any point and enter interactive shell where you will be able to try commands in action. +Enables the ability to pause test execution at any point, and enter an interactive shell where you can try commands in action. When pause is enabled, MFTF will generate pause() command in _failed() hook so that test will pause execution when failed. ```conf From 15f62b44e1a9ed9d6a3c09a766bb5edecdacaed2 Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Fri, 14 Aug 2020 11:41:11 -0500 Subject: [PATCH 508/888] Editorial pass --- docs/interactive-pause.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/docs/interactive-pause.md b/docs/interactive-pause.md index e7fc0f704..507502ee0 100644 --- a/docs/interactive-pause.md +++ b/docs/interactive-pause.md @@ -1,24 +1,24 @@ # Interactive Pause -It’s hard to write a complete test at once. You will need to try different commands with different arguments before you find a correct path. +It can be difficut to write a successful test on the first attempt. You will need to try different commands, with different arguments, before you find the correct path. -Since Codeception 3.0 you can pause execution in any point and enter interactive shell where you will be able to try commands in action. +Since Codeception 3.0, you can pause execution in any point and enter an interactive shell where you will be able to try commands in action. -Now this `Interactive Pause` feature is available in MFTF and all you need to do is to set `ENABLE_PAUSE=true` in `.env`. +Now this `Interactive Pause` feature is available in MFTF. All you need to do is to set `ENABLE_PAUSE=true` in `.env`. Check [pause on codeception.com][] for documentation and a video to see `Interactive Pause` in action. -In short, when a test gets to `$I->pause()` step, it stops and shows a console where you can try all available commands with auto-completion, stash commands, and save screenshot, etc. +In short, when a test gets to `$I->pause()` step, it stops and shows a console where you can try all available commands with auto-completion, stash commands, save screenshots, etc. ## Generation Time A `<pause>` action in xml will always be generated into php regardless if `ENABLE_PAUSE=true` is set or not. However, when `ENABLE_PAUSE=true` is set, an additional`pause()` action will be generated in `_failed()` hook for a test, -so that the test could pause on failure at run time. +so that the test may pause on failure at run time. ## Execution Time -To use `Interactive Pause` at run time, there are two types of MFTF commands to use. +To use `Interactive Pause` at run time, there are two types of MFTF commands to use: ### MFTF Run Commands @@ -47,17 +47,16 @@ Note: MFTF run command's `--debug` option is different from Codeception `--debug ### MFTF Codecept Run Command You can also use MFTF's wrapper command to run Codeception directly and activate `Interactive Pause` by passing `--debug` option. -You don't need to set `ENABLE_PAUSE=true` for this command. +You do not need to set `ENABLE_PAUSE=true` for this command. ```bash vendor/bin/mftf codecept:run --debug ``` <div class="bs-callout-warning"> -Note: You may want to limit the usage of this Codeception command with arguments and options for `acceptance` only -since it's what is supported by MFTF. You should also replace `acceptance` to `functional` when using this command when referring to Codeception documentation. +You may want to limit the usage of this Codeception command with arguments and options for `acceptance` only, since it is what is supported by MFTF. You should also change `acceptance` to `functional` when using this command when referring to Codeception documentation. </div> ## References -[pause on codeception.com](https://codeception.com/docs/02-GettingStarted#Interactive-Pause) \ No newline at end of file +[pause on codeception.com](https://codeception.com/docs/02-GettingStarted#Interactive-Pause) From 5831ac54e13caab8f5719f2c1f58ce53a8339937 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Fri, 14 Aug 2020 12:41:50 -0500 Subject: [PATCH 509/888] MQE-2110: MFTF command to pause test execution --- .../Console/BaseGenerateCommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index 44c6ceec9..525711e31 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -31,8 +31,8 @@ class BaseGenerateCommand extends Command { const MFTF_NOTICES = "Placeholder text for MFTF notices\n"; - const CODECEPT_RUN = 'codecept:run '; - const CODECEPT_RUN_FUNCTIONAL = self::CODECEPT_RUN . 'functional '; + const CODECEPT_RUN = 'codecept:run'; + const CODECEPT_RUN_FUNCTIONAL = self::CODECEPT_RUN . ' functional '; /** * Enable pause() From ba3362b5729ac1037de386e3e76dbf530bc0ea85 Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Fri, 14 Aug 2020 14:40:28 -0500 Subject: [PATCH 510/888] MQE-2242: Add static check to flag use of <pause> (#783) * MQE-2242: Add static check to flag use of <pause> * MQE-2242: Add static check to flag use of <pause> --- dev/tests/_bootstrap.php | 2 + dev/tests/util/MftfStaticTestCase.php | 49 ++++ ...tionGroupWithMultiplePausesActionGroup.xml | 18 ++ .../ActionGroupWithNoPauseActionGroup.xml | 15 ++ .../ActionGroupWithPauseActionGroup.xml | 15 ++ .../suiteWithMultiplePauseActionsSuite.xml | 28 +++ .../Suite/suiteWithPauseActionSuite.xml | 27 +++ .../Test/TestWithMultiplePauseActionsTest.xml | 30 +++ .../Test/TestWithPauseActionTest.xml | 23 ++ .../mftf-pause-action-usage-checks.txt | 30 +++ .../DeprecationStaticCheckTest.php | 46 +--- .../PauseActionStaticCheckTest.php | 51 ++++ docs/commands/mftf.md | 11 +- .../Console/StaticChecksCommand.php | 15 +- .../StaticCheck/PauseActionUsageCheck.php | 229 ++++++++++++++++++ .../StaticCheck/StaticChecksList.php | 4 +- .../Util/Script/ScriptUtil.php | 2 +- 17 files changed, 543 insertions(+), 52 deletions(-) create mode 100644 dev/tests/util/MftfStaticTestCase.php create mode 100644 dev/tests/verification/PauseCheckModule/ActionGroup/ActionGroupWithMultiplePausesActionGroup.xml create mode 100644 dev/tests/verification/PauseCheckModule/ActionGroup/ActionGroupWithNoPauseActionGroup.xml create mode 100644 dev/tests/verification/PauseCheckModule/ActionGroup/ActionGroupWithPauseActionGroup.xml create mode 100644 dev/tests/verification/PauseCheckModule/Suite/suiteWithMultiplePauseActionsSuite.xml create mode 100644 dev/tests/verification/PauseCheckModule/Suite/suiteWithPauseActionSuite.xml create mode 100644 dev/tests/verification/PauseCheckModule/Test/TestWithMultiplePauseActionsTest.xml create mode 100644 dev/tests/verification/PauseCheckModule/Test/TestWithPauseActionTest.xml create mode 100644 dev/tests/verification/Resources/StaticChecks/mftf-pause-action-usage-checks.txt create mode 100644 dev/tests/verification/Tests/StaticCheck/PauseActionStaticCheckTest.php create mode 100644 src/Magento/FunctionalTestingFramework/StaticCheck/PauseActionUsageCheck.php diff --git a/dev/tests/_bootstrap.php b/dev/tests/_bootstrap.php index 059441721..9d3750ec6 100644 --- a/dev/tests/_bootstrap.php +++ b/dev/tests/_bootstrap.php @@ -9,9 +9,11 @@ $vendorAutoloadPath = realpath(PROJECT_ROOT . '/vendor/autoload.php'); $mftfTestCasePath = realpath(PROJECT_ROOT . '/dev/tests/util/MftfTestCase.php'); +$mftfStaticTestCasePath = realpath(PROJECT_ROOT . '/dev/tests/util/MftfStaticTestCase.php'); require_once $vendorAutoloadPath; require_once $mftfTestCasePath; +require_once $mftfStaticTestCasePath; // Set up AspectMock $kernel = \AspectMock\Kernel::getInstance(); diff --git a/dev/tests/util/MftfStaticTestCase.php b/dev/tests/util/MftfStaticTestCase.php new file mode 100644 index 000000000..708561031 --- /dev/null +++ b/dev/tests/util/MftfStaticTestCase.php @@ -0,0 +1,49 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace tests\util; + +use Magento\FunctionalTestingFramework\Util\Filesystem\DirSetupUtil; +use PHPUnit\Framework\TestCase; +use Symfony\Component\Console\Input\InputInterface; + +class MftfStaticTestCase extends TestCase +{ + const STATIC_RESULTS_DIR = TESTS_MODULE_PATH . + DIRECTORY_SEPARATOR . + '_output' . + DIRECTORY_SEPARATOR . + 'static-results'; + + const RESOURCES_PATH = TESTS_MODULE_PATH . + DIRECTORY_SEPARATOR . + "Resources" . + DIRECTORY_SEPARATOR . + 'StaticChecks'; + + /** + * Sets input interface + * @param $path + * @return \PHPUnit\Framework\MockObject\MockObject + */ + public function mockInputInterface($path = null) + { + $input = $this->getMockBuilder(InputInterface::class) + ->disableOriginalConstructor() + ->getMock(); + if ($path) { + $input->method('getOption') + ->with('path') + ->willReturn($path); + } + return $input; + } + + public function tearDown(): void + { + DirSetupUtil::rmdirRecursive(self::STATIC_RESULTS_DIR); + } +} diff --git a/dev/tests/verification/PauseCheckModule/ActionGroup/ActionGroupWithMultiplePausesActionGroup.xml b/dev/tests/verification/PauseCheckModule/ActionGroup/ActionGroupWithMultiplePausesActionGroup.xml new file mode 100644 index 000000000..5e9299631 --- /dev/null +++ b/dev/tests/verification/PauseCheckModule/ActionGroup/ActionGroupWithMultiplePausesActionGroup.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="ActionGroupWithMultiplePausesActionGroup"> + <fillField selector="#foo" userInput="foo" stepKey="fillField1"/> + <pause stepKey="pauseAfterFillField1"/> + <fillField selector="#bar" userInput="bar" stepKey="fillField2"/> + <pause stepKey="pauseAfterFillField2"/> + <fillField selector="#baz" userInput="baz" stepKey="fillField3"/> + <pause stepKey="pauseAfterFillField3"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/PauseCheckModule/ActionGroup/ActionGroupWithNoPauseActionGroup.xml b/dev/tests/verification/PauseCheckModule/ActionGroup/ActionGroupWithNoPauseActionGroup.xml new file mode 100644 index 000000000..8acae47e8 --- /dev/null +++ b/dev/tests/verification/PauseCheckModule/ActionGroup/ActionGroupWithNoPauseActionGroup.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="ActionGroupWithNoPauseActionGroup"> + <fillField selector="#foo" userInput="foo" stepKey="fillField1"/> + <fillField selector="#bar" userInput="bar" stepKey="fillField2"/> + <fillField selector="#baz" userInput="baz" stepKey="fillField3"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/PauseCheckModule/ActionGroup/ActionGroupWithPauseActionGroup.xml b/dev/tests/verification/PauseCheckModule/ActionGroup/ActionGroupWithPauseActionGroup.xml new file mode 100644 index 000000000..aaef1befa --- /dev/null +++ b/dev/tests/verification/PauseCheckModule/ActionGroup/ActionGroupWithPauseActionGroup.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="ActionGroupWithPauseActionGroup"> + <fillField selector="#foo" userInput="myData1" stepKey="fillField1"/> + <fillField selector="#bar" userInput="myData2" stepKey="fillField2"/> + <pause stepKey="pauseAfterFillField2"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/PauseCheckModule/Suite/suiteWithMultiplePauseActionsSuite.xml b/dev/tests/verification/PauseCheckModule/Suite/suiteWithMultiplePauseActionsSuite.xml new file mode 100644 index 000000000..47ff1088b --- /dev/null +++ b/dev/tests/verification/PauseCheckModule/Suite/suiteWithMultiplePauseActionsSuite.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<suites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Suite/etc/suiteSchema.xsd"> + <suite name="suiteWithMultiplePauseActionsSuite"> + <include> + <group name="include" /> + </include> + <before> + <amOnPage url="some.url" stepKey="before"/> + <createData entity="SecretData" stepKey="create1"> + <field key="someKey">dataHere</field> + </createData> + <pause stepKey="pauseCreate1"/> + </before> + <after> + <deleteData createDataKey="create1" stepKey="delete1"/> + <deleteData url="deleteThis" stepKey="deleteThis"/> + <fillField selector="#fill" userInput="{{SecretData.key2}}" stepKey="fillAfter"/> + <pause stepKey="pauseFillAfter"/> + </after> + </suite> +</suites> diff --git a/dev/tests/verification/PauseCheckModule/Suite/suiteWithPauseActionSuite.xml b/dev/tests/verification/PauseCheckModule/Suite/suiteWithPauseActionSuite.xml new file mode 100644 index 000000000..71a3b5769 --- /dev/null +++ b/dev/tests/verification/PauseCheckModule/Suite/suiteWithPauseActionSuite.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<suites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Suite/etc/suiteSchema.xsd"> + <suite name="suiteWithPauseActionSuite"> + <include> + <group name="include" /> + </include> + <before> + <amOnPage url="some.url" stepKey="before"/> + <createData entity="createThis" stepKey="create"> + <field key="someKey">dataHere</field> + </createData> + <pause stepKey="pauseSuite"/> + <click stepKey="clickWithData" userInput="$create.data$"/> + <fillField selector="#foo" userInput="myData1" stepKey="fillField1"/> + </before> + <after> + <comment userInput="afterBlock" stepKey="afterBlock"/> + </after> + </suite> +</suites> diff --git a/dev/tests/verification/PauseCheckModule/Test/TestWithMultiplePauseActionsTest.xml b/dev/tests/verification/PauseCheckModule/Test/TestWithMultiplePauseActionsTest.xml new file mode 100644 index 000000000..fa47e976c --- /dev/null +++ b/dev/tests/verification/PauseCheckModule/Test/TestWithMultiplePauseActionsTest.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="TestWithMultiplePauseActionsTest"> + <annotations> + <severity value="CRITICAL"/> + <group value="functional"/> + <features value="Pause check"/> + <stories value="MQE-433"/> + </annotations> + <before> + <amOnPage url="/beforeUrl" stepKey="beforeAmOnPageKey"/> + <pause stepKey="pauseBeforeAmOnPageKey"/> + </before> + <fillField stepKey="step1" selector="#username" userInput="step1"/> + <fillField stepKey="step2" selector="#password" userInput="step2"/> + <pause stepKey="pauseAfterStep2"/> + <after> + <amOnPage url="/afterUrl" stepKey="afterAmOnPageKey"/> + <pause stepKey="pauseAfterAmOnPageKey"/> + </after> + </test> +</tests> diff --git a/dev/tests/verification/PauseCheckModule/Test/TestWithPauseActionTest.xml b/dev/tests/verification/PauseCheckModule/Test/TestWithPauseActionTest.xml new file mode 100644 index 000000000..70d0903b8 --- /dev/null +++ b/dev/tests/verification/PauseCheckModule/Test/TestWithPauseActionTest.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="TestWithPauseActionTest"> + <annotations> + <severity value="CRITICAL"/> + <group value="functional"/> + <features value="Pause check"/> + <stories value="MQE-433"/> + </annotations> + <amOnPage stepKey="step1" url="/step1"/> + <fillField stepKey="step2" selector="#username" userInput="step2"/> + <fillField stepKey="step3" selector="#password" userInput="step3"/> + <pause stepKey="pauseAfterStep3"/> + </test> +</tests> diff --git a/dev/tests/verification/Resources/StaticChecks/mftf-pause-action-usage-checks.txt b/dev/tests/verification/Resources/StaticChecks/mftf-pause-action-usage-checks.txt new file mode 100644 index 000000000..fd042a24c --- /dev/null +++ b/dev/tests/verification/Resources/StaticChecks/mftf-pause-action-usage-checks.txt @@ -0,0 +1,30 @@ + +File "/verification/PauseCheckModule/ActionGroup/ActionGroupWithMultiplePausesActionGroup.xml" +contains pause action(s): + + ActionGroupWithMultiplePausesActionGroup has pause action at stepKey(s): pauseAfterFillField1, pauseAfterFillField2, pauseAfterFillField3 + +File "/verification/PauseCheckModule/ActionGroup/ActionGroupWithPauseActionGroup.xml" +contains pause action(s): + + ActionGroupWithPauseActionGroup has pause action at stepKey(s): pauseAfterFillField2 + +File "/verification/PauseCheckModule/Test/TestWithMultiplePauseActionsTest.xml" +contains pause action(s): + + TestWithMultiplePauseActionsTest has pause action at stepKey(s): pauseBeforeAmOnPageKey, pauseAfterStep2, pauseAfterAmOnPageKey + +File "/verification/PauseCheckModule/Test/TestWithPauseActionTest.xml" +contains pause action(s): + + TestWithPauseActionTest has pause action at stepKey(s): pauseAfterStep3 + +File "/verification/PauseCheckModule/Suite/suiteWithMultiplePauseActionsSuite.xml" +contains pause action(s): + + suiteWithMultiplePauseActionsSuite has pause action at stepKey(s): pauseCreate1, pauseFillAfter + +File "/verification/PauseCheckModule/Suite/suiteWithPauseActionSuite.xml" +contains pause action(s): + + suiteWithPauseActionSuite has pause action at stepKey(s): pauseSuite diff --git a/dev/tests/verification/Tests/StaticCheck/DeprecationStaticCheckTest.php b/dev/tests/verification/Tests/StaticCheck/DeprecationStaticCheckTest.php index bafe586ac..f6aef65f6 100644 --- a/dev/tests/verification/Tests/StaticCheck/DeprecationStaticCheckTest.php +++ b/dev/tests/verification/Tests/StaticCheck/DeprecationStaticCheckTest.php @@ -8,18 +8,11 @@ use AspectMock\Test as AspectMock; use Magento\FunctionalTestingFramework\StaticCheck\DeprecatedEntityUsageCheck; use Magento\FunctionalTestingFramework\StaticCheck\StaticChecksList; -use Magento\FunctionalTestingFramework\Util\Filesystem\DirSetupUtil; -use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Input\InputInterface; +use tests\util\MftfStaticTestCase; -class DeprecationStaticCheckTest extends TestCase +class DeprecationStaticCheckTest extends MftfStaticTestCase { - const STATIC_RESULTS_DIR = TESTS_MODULE_PATH . - DIRECTORY_SEPARATOR . - '_output' . - DIRECTORY_SEPARATOR . - 'static-results'; - const LOG_FILE = self::STATIC_RESULTS_DIR . DIRECTORY_SEPARATOR . DeprecatedEntityUsageCheck::ERROR_LOG_FILENAME . @@ -30,20 +23,6 @@ class DeprecationStaticCheckTest extends TestCase 'DeprecationCheckModule'. DIRECTORY_SEPARATOR; - const RESOURCES_PATH = TESTS_MODULE_PATH . - DIRECTORY_SEPARATOR . - "Resources" . - DIRECTORY_SEPARATOR . - 'StaticChecks'; - - public static function setUpBeforeClass(): void - { - // remove static-results if it exists - if (file_exists(self::STATIC_RESULTS_DIR)) { - DirSetupUtil::rmdirRecursive(self::STATIC_RESULTS_DIR); - } - } - /** * test static-check DeprecatedEntityUsageCheck. * @@ -68,25 +47,4 @@ public function testDeprecatedEntityUsageCheck() self::LOG_FILE ); } - - /** - * Sets input interface - * @param $path - * @return \PHPUnit\Framework\MockObject\MockObject - */ - public function mockInputInterface($path) - { - $input = $this->getMockBuilder(InputInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $input->method('getOption') - ->with('path') - ->willReturn($path); - return $input; - } - - public function tearDown(): void - { - DirSetupUtil::rmdirRecursive(self::STATIC_RESULTS_DIR); - } } diff --git a/dev/tests/verification/Tests/StaticCheck/PauseActionStaticCheckTest.php b/dev/tests/verification/Tests/StaticCheck/PauseActionStaticCheckTest.php new file mode 100644 index 000000000..7c8f77c2f --- /dev/null +++ b/dev/tests/verification/Tests/StaticCheck/PauseActionStaticCheckTest.php @@ -0,0 +1,51 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace tests\verification\Tests; + +use AspectMock\Test as AspectMock; +use Magento\FunctionalTestingFramework\StaticCheck\PauseActionUsageCheck; +use Magento\FunctionalTestingFramework\StaticCheck\StaticChecksList; +use Symfony\Component\Console\Input\InputInterface; + +use tests\util\MftfStaticTestCase; + +class PauseActionStaticCheckTest extends MftfStaticTestCase +{ + const LOG_FILE = self::STATIC_RESULTS_DIR . + DIRECTORY_SEPARATOR . + PauseActionUsageCheck::ERROR_LOG_FILENAME . + '.txt'; + + const TEST_MODULE_PATH = TESTS_MODULE_PATH . + DIRECTORY_SEPARATOR . + 'PauseCheckModule'. + DIRECTORY_SEPARATOR; + + /** + * test static-check PauseActionUsageCheck. + * + * @throws \Exception + */ + public function testPauseActionUsageCheck() + { + $staticCheck = new PauseActionUsageCheck(); + + $input = $this->mockInputInterface(self::TEST_MODULE_PATH); + AspectMock::double(StaticChecksList::class, ['getErrorFilesPath' => self::STATIC_RESULTS_DIR]); + + /** @var InputInterface $input */ + $staticCheck->execute($input); + + $this->assertTrue(file_exists(self::LOG_FILE)); + $this->assertFileEquals( + self::RESOURCES_PATH. + DIRECTORY_SEPARATOR . + PauseActionUsageCheck::ERROR_LOG_FILENAME . + ".txt", + self::LOG_FILE + ); + } +} diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 3c170e5ca..0c5c86285 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -449,7 +449,7 @@ vendor/bin/mftf static-checks [<names>]... | Option | Description | |-----------------------|-----------------------------------------------------------------------------------------------------------| -| `-p, --path` | Path to a MFTF test module to run "deprecatedEntityUsage" static check script. Option is ignored by other static check scripts. +| `-p, --path` | Path to a MFTF test module to run "deprecatedEntityUsage" and "pauseActionUsage" static check scripts. Option is ignored by other static check scripts. #### Examples @@ -479,6 +479,10 @@ vendor/bin/mftf static-checks actionGroupArguments vendor/bin/mftf static-checks deprecatedEntityUsage ``` +```bash +vendor/bin/mftf static-checks pauseActionUsage +``` + ```bash vendor/bin/mftf static-checks annotations ``` @@ -487,6 +491,10 @@ vendor/bin/mftf static-checks annotations vendor/bin/mftf static-checks deprecatedEntityUsage -p path/to/mftf/test/module ``` +```bash +vendor/bin/mftf static-checks pauseActionUsage -p path/to/mftf/test/module +``` + ```bash vendor/bin/mftf static-checks testDependencies actionGroupArguments ``` @@ -499,6 +507,7 @@ vendor/bin/mftf static-checks testDependencies actionGroupArguments |`actionGroupArguments` | Checks that action groups do not have unused arguments.| |`deprecatedEntityUsage`| Checks that deprecated test entities are not being referenced.| |`annotations`| Checks various details of test annotations, such as missing annotations or duplicate annotations.| +|`pauseUsage`| Checks that pause action is not used in action groups, tests or suites.| #### Defining ruleset diff --git a/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php b/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php index fe07dbaaf..806508ef8 100644 --- a/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/StaticChecksCommand.php @@ -151,12 +151,17 @@ private function validateInput(InputInterface $input) } if ($input->getOption('path')) { - if ( (count($this->staticCheckObjects) !== 1) - || array_keys($this->staticCheckObjects)[0] !== StaticChecksList::DEPRECATED_ENTITY_USAGE_CHECK_NAME ) + if ((count($this->staticCheckObjects) !== 1) + || !in_array( + array_keys($this->staticCheckObjects)[0], + [ + StaticChecksList::DEPRECATED_ENTITY_USAGE_CHECK_NAME, + StaticChecksList::PAUSE_ACTION_USAGE_CHECK_NAME + ] + ) + ) throw new InvalidArgumentException( - '--path option can only be used for "' - . StaticChecksList::DEPRECATED_ENTITY_USAGE_CHECK_NAME - . '".' + '--path option is not supported for the command."' ); } } diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/PauseActionUsageCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/PauseActionUsageCheck.php new file mode 100644 index 000000000..e7d106bf0 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/PauseActionUsageCheck.php @@ -0,0 +1,229 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\FunctionalTestingFramework\StaticCheck; + +use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Finder\Finder; +use Exception; +use Magento\FunctionalTestingFramework\Util\Script\ScriptUtil; +use Symfony\Component\Finder\SplFileInfo; + +/** + * Class PauseActionUsageCheck + * @package Magento\FunctionalTestingFramework\StaticCheck + */ +class PauseActionUsageCheck implements StaticCheckInterface +{ + const ERROR_LOG_FILENAME = 'mftf-pause-action-usage-checks'; + const ERROR_LOG_MESSAGE = 'MFTF Pause Action Usage Check'; + + /** + * Array containing all errors found after running the execute() function. + * @var array + */ + private $errors = []; + + /** + * String representing the output summary found after running the execute() function. + * @var string + */ + private $output; + + /** + * ScriptUtil instance + * + * @var ScriptUtil + */ + private $scriptUtil; + + /** + * Test xml files to scan + * + * @var Finder|array + */ + private $testXmlFiles = []; + + /** + * Action group xml files to scan + * + * @var Finder|array + */ + private $actionGroupXmlFiles = []; + + /** + * Suite xml files to scan + * + * @var Finder|array + */ + private $suiteXmlFiles = []; + + /** + * Root suite xml files to scan + * + * @var Finder|array + */ + private $rootSuiteXmlFiles = []; + + /** + * Checks usage of pause action in action groups, tests and suites and prints out error to file. + * + * @param InputInterface $input + * @return void + * @throws Exception + */ + public function execute(InputInterface $input) + { + $this->scriptUtil = new ScriptUtil(); + $modulePaths = []; + $includeRootPath = true; + $path = $input->getOption('path'); + if ($path) { + if (!realpath($path)) { + throw new \InvalidArgumentException('Invalid --path option: ' . $path); + } + $modulePaths[] = realpath($path); + $includeRootPath = false; + } else { + $modulePaths = $this->scriptUtil->getAllModulePaths(); + } + + $this->testXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, 'Test'); + $this->actionGroupXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, 'ActionGroup'); + $this->suiteXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, 'Suite'); + if ($includeRootPath) { + $this->rootSuiteXmlFiles = $this->scriptUtil->getRootSuiteXmlFiles(); + } + $this->errors = []; + $this->errors += $this->validatePauseActionUsageInActionGroups($this->actionGroupXmlFiles); + $this->errors += $this->validatePauseActionUsageInTests($this->testXmlFiles); + $this->errors += $this->validatePauseActionUsageInSuites($this->suiteXmlFiles); + $this->errors += $this->validatePauseActionUsageInSuites($this->rootSuiteXmlFiles); + + $this->output = $this->scriptUtil->printErrorsToFile( + $this->errors, + StaticChecksList::getErrorFilesPath() . DIRECTORY_SEPARATOR . self::ERROR_LOG_FILENAME . '.txt', + self::ERROR_LOG_MESSAGE + ); + } + + /** + * Finds usages of pause action in action group files + * @param array $actionGroupXmlFiles + * @return array + */ + private function validatePauseActionUsageInActionGroups($actionGroupXmlFiles) + { + $actionGroupErrors = []; + foreach ($actionGroupXmlFiles as $filePath) { + $domDocument = new \DOMDocument(); + $domDocument->load($filePath); + $actionGroup = $domDocument->getElementsByTagName('actionGroup')->item(0); + $violatingStepKeys = $this->findViolatingPauseStepKeys($actionGroup); + $actionGroupErrors = array_merge($actionGroupErrors, $this->setErrorOutput($violatingStepKeys, $filePath)); + } + return $actionGroupErrors; + } + + /** + * Finds usages of pause action in test files + * @param array $testXmlFiles + * @return array + */ + private function validatePauseActionUsageInTests($testXmlFiles) + { + $testErrors = []; + foreach ($testXmlFiles as $filePath) { + $domDocument = new \DOMDocument(); + $domDocument->load($filePath); + $test = $domDocument->getElementsByTagName('test')->item(0); + $violatingStepKeys = $this->findViolatingPauseStepKeys($test); + $testErrors = array_merge($testErrors, $this->setErrorOutput($violatingStepKeys, $filePath)); + } + return $testErrors; + } + + /** + * Finds usages of pause action in suite files + * @param array $suiteXmlFiles + * @return array + */ + private function validatePauseActionUsageInSuites($suiteXmlFiles) + { + $suiteErrors = []; + foreach ($suiteXmlFiles as $filePath) { + $domDocument = new \DOMDocument(); + $domDocument->load($filePath); + $suite = $domDocument->getElementsByTagName('suite')->item(0); + $violatingStepKeys = $this->findViolatingPauseStepKeys($suite); + $suiteErrors = array_merge($suiteErrors, $this->setErrorOutput($violatingStepKeys, $filePath)); + } + return $suiteErrors; + } + + /** + * Finds violating pause action step keys + * @param \DomNode $entity + * @return array + */ + private function findViolatingPauseStepKeys($entity) + { + $violatingStepKeys = []; + $entityName = $entity->getAttribute('name'); + $references = $entity->getElementsByTagName('pause'); + + foreach ($references as $reference) { + $pauseStepKey = $reference->getAttribute('stepKey'); + $violatingStepKeys[$entityName][] = $pauseStepKey; + } + return $violatingStepKeys; + } + + /** + * Return array containing all errors found after running the execute() function. + * @return array + */ + public function getErrors() + { + return $this->errors; + } + + /** + * Return string of a short human readable result of the check. For example: "No errors found." + * @return string + */ + public function getOutput() + { + return $this->output; + } + + /** + * Build and return error output for pause action usages + * + * @param array $violatingReferences + * @param SplFileInfo $path + * @return mixed + */ + private function setErrorOutput($violatingReferences, $path) + { + $testErrors = []; + + $filePath = StaticChecksList::getFilePath($path->getRealPath()); + + if (!empty($violatingReferences)) { + // Build error output + $errorOutput = "\nFile \"{$filePath}\""; + $errorOutput .= "\ncontains pause action(s):\n\t\t"; + foreach ($violatingReferences as $entityName => $stepKey) { + $errorOutput .= "\n\t {$entityName} has pause action at stepKey(s): " . implode(", ", $stepKey); + } + $testErrors[$filePath][] = $errorOutput; + } + return $testErrors; + } +} diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php b/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php index ba2139276..07c52ce8c 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php @@ -17,6 +17,7 @@ class StaticChecksList implements StaticCheckListInterface { const DEPRECATED_ENTITY_USAGE_CHECK_NAME = 'deprecatedEntityUsage'; + const PAUSE_ACTION_USAGE_CHECK_NAME = 'pauseActionUsage'; const STATIC_RESULTS = 'tests' . DIRECTORY_SEPARATOR .'_output' . DIRECTORY_SEPARATOR . 'static-results'; /** @@ -45,7 +46,8 @@ public function __construct(array $checks = []) 'testDependencies' => new TestDependencyCheck(), 'actionGroupArguments' => new ActionGroupArgumentsCheck(), self::DEPRECATED_ENTITY_USAGE_CHECK_NAME => new DeprecatedEntityUsageCheck(), - 'annotations' => new AnnotationsCheck() + 'annotations' => new AnnotationsCheck(), + self::PAUSE_ACTION_USAGE_CHECK_NAME => new PauseActionUsageCheck() ] + $checks; // Static checks error files directory diff --git a/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php b/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php index 14f9c27e0..11afa5cc1 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php @@ -101,7 +101,7 @@ public function getModuleXmlFilesByScope($modulePaths, $scope) if (!realpath($modulePath . $scopePath)) { continue; } - $finder->files()->followLinks()->in($modulePath . $scopePath)->name("*.xml"); + $finder->files()->followLinks()->in($modulePath . $scopePath)->name("*.xml")->sortByName(); $found = true; } return $found ? $finder->files() : []; From 20f52038ec45000d5472237cc5bc965088a7f7c4 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Fri, 14 Aug 2020 15:23:04 -0500 Subject: [PATCH 511/888] MQE-2110: MFTF command to pause test execution --- docs/commands/mftf.md | 2 +- docs/interactive-pause.md | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 8d1c636f2..523e3e505 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -579,7 +579,7 @@ vendor/bin/mftf codecept:run functional # Run all tests in functional suite with options vendor/bin/mftf codecept:run functional --verbose --steps --debug # Run one test -vendor/bin/mftf codecept:run functional Magento/_generated/default/AdminLoginSuccessfulTestCest +vendor/bin/mftf codecept:run functional Magento/_generated/default/AdminCreateCmsPageTestCest.php --debug # Run all tests in default group vendor/bin/mftf codecept:run functional --verbose --steps -g default ``` diff --git a/docs/interactive-pause.md b/docs/interactive-pause.md index 507502ee0..2b1d2cb10 100644 --- a/docs/interactive-pause.md +++ b/docs/interactive-pause.md @@ -13,7 +13,7 @@ In short, when a test gets to `$I->pause()` step, it stops and shows a console w ## Generation Time A `<pause>` action in xml will always be generated into php regardless if `ENABLE_PAUSE=true` is set or not. -However, when `ENABLE_PAUSE=true` is set, an additional`pause()` action will be generated in `_failed()` hook for a test, +However, when `ENABLE_PAUSE=true` is set, an additional `pause()` action will be generated in `_failed()` hook for a test, so that the test may pause on failure at run time. ## Execution Time @@ -40,10 +40,6 @@ vendor/bin/mftf run:manifest vendor/bin/mftf run:failed ``` -<div class="bs-callout-warning"> -Note: MFTF run command's `--debug` option is different from Codeception `--debug` mode option. -</div> - ### MFTF Codecept Run Command You can also use MFTF's wrapper command to run Codeception directly and activate `Interactive Pause` by passing `--debug` option. @@ -54,7 +50,11 @@ vendor/bin/mftf codecept:run --debug ``` <div class="bs-callout-warning"> -You may want to limit the usage of this Codeception command with arguments and options for `acceptance` only, since it is what is supported by MFTF. You should also change `acceptance` to `functional` when using this command when referring to Codeception documentation. +Note: MFTF run command's `--debug` option is different from Codeception `--debug` mode option. +</div> + +<div class="bs-callout-warning"> +Note: You may want to limit the usage of this Codeception command with arguments and options for `acceptance` only, since it is what is supported by MFTF. You should also change `acceptance` to `functional` when using this command when referring to Codeception documentation. </div> ## References From 2ca6005d1dca71675901b66a54c6988e83093af3 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Fri, 14 Aug 2020 17:09:24 -0500 Subject: [PATCH 512/888] MQE-2110: MFTF command to pause test execution --- docs/commands/mftf.md | 4 ++++ docs/interactive-pause.md | 45 ++++++++++++++++++++++----------------- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 523e3e505..c537a9759 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -584,6 +584,10 @@ vendor/bin/mftf codecept:run functional Magento/_generated/default/AdminCreateCm vendor/bin/mftf codecept:run functional --verbose --steps -g default ``` +<div class="bs-callout-warning"> +Note: You may want to limit the usage of this Codeception command with arguments and options for `acceptance` only, since it is what is supported by MFTF. You should also change `acceptance` to `functional` when using this command when referring to Codeception documentation. +</div> + <!-- LINK DEFINITIONS --> [configuration]: ../configuration.md diff --git a/docs/interactive-pause.md b/docs/interactive-pause.md index 2b1d2cb10..85906d2a8 100644 --- a/docs/interactive-pause.md +++ b/docs/interactive-pause.md @@ -4,25 +4,15 @@ It can be difficut to write a successful test on the first attempt. You will nee Since Codeception 3.0, you can pause execution in any point and enter an interactive shell where you will be able to try commands in action. -Now this `Interactive Pause` feature is available in MFTF. All you need to do is to set `ENABLE_PAUSE=true` in `.env`. +Now this `Interactive Pause` feature is available in MFTF. All you need to do is to set `ENABLE_PAUSE` to `true` in `.env`. Check [pause on codeception.com][] for documentation and a video to see `Interactive Pause` in action. In short, when a test gets to `$I->pause()` step, it stops and shows a console where you can try all available commands with auto-completion, stash commands, save screenshots, etc. -## Generation Time +## MFTF Run Commands -A `<pause>` action in xml will always be generated into php regardless if `ENABLE_PAUSE=true` is set or not. -However, when `ENABLE_PAUSE=true` is set, an additional `pause()` action will be generated in `_failed()` hook for a test, -so that the test may pause on failure at run time. - -## Execution Time - -To use `Interactive Pause` at run time, there are two types of MFTF commands to use: - -### MFTF Run Commands - -When `ENABLE_PAUSE=true` is set, the following MFTF run commands support `Interactive Pause`. +The following MFTF run commands support `Interactive Pause` when `ENABLE_PAUSE` is set to `true`. ```bash vendor/bin/mftf run:group @@ -40,10 +30,31 @@ vendor/bin/mftf run:manifest vendor/bin/mftf run:failed ``` -### MFTF Codecept Run Command +### Use `Interactive Pause` During Test Development + +Here is a typical work flow for this use case: + +- Set `ENABLE_PAUSE` to `true` under `.env` +- Add `<pause>` action in a test where you want to stop for investigation +- Run test +- Execution should pause at <pause> action and invoke interactive console +- Try out commands in interactive console +- Resume test execution by pressing `ENTER` + +### Use `Pause` On Test Failure + +When `ENABLE_PAUSE` is set to `true`, MFTF automatically generates `pause()` action in `_failed()` hook for tests and in `_failed()` function in `MagentoWebDriver`. +This allows you to use `pause` to debug test failure for a long running test. The work flow might look like: + +- Set `ENABLE_PAUSE` to `true` under `.env` +- Run test +- Execution pauses and invokes interactive console right after test fails +- Examine and debug on the spot of failure + +## MFTF Codecept Run Command You can also use MFTF's wrapper command to run Codeception directly and activate `Interactive Pause` by passing `--debug` option. -You do not need to set `ENABLE_PAUSE=true` for this command. +You do not need to set `ENABLE_PAUSE=true` for this command if you are not using `Pause on Failure`. ```bash vendor/bin/mftf codecept:run --debug @@ -53,10 +64,6 @@ vendor/bin/mftf codecept:run --debug Note: MFTF run command's `--debug` option is different from Codeception `--debug` mode option. </div> -<div class="bs-callout-warning"> -Note: You may want to limit the usage of this Codeception command with arguments and options for `acceptance` only, since it is what is supported by MFTF. You should also change `acceptance` to `functional` when using this command when referring to Codeception documentation. -</div> - ## References [pause on codeception.com](https://codeception.com/docs/02-GettingStarted#Interactive-Pause) From d6c82cabe930b4729ae53fc1ceff6097534d2364 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Fri, 14 Aug 2020 17:19:26 -0500 Subject: [PATCH 513/888] MQE-2110: MFTF command to pause test execution --- docs/interactive-pause.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/interactive-pause.md b/docs/interactive-pause.md index 85906d2a8..25e0f7f0e 100644 --- a/docs/interactive-pause.md +++ b/docs/interactive-pause.md @@ -35,7 +35,7 @@ vendor/bin/mftf run:failed Here is a typical work flow for this use case: - Set `ENABLE_PAUSE` to `true` under `.env` -- Add `<pause>` action in a test where you want to stop for investigation +- Add <pause> action in a test where you want to pause execution for debugging - Run test - Execution should pause at <pause> action and invoke interactive console - Try out commands in interactive console @@ -54,7 +54,7 @@ This allows you to use `pause` to debug test failure for a long running test. Th ## MFTF Codecept Run Command You can also use MFTF's wrapper command to run Codeception directly and activate `Interactive Pause` by passing `--debug` option. -You do not need to set `ENABLE_PAUSE=true` for this command if you are not using `Pause on Failure`. +You do not need to set `ENABLE_PAUSE` to `true` for this command if you don't want to pause on test failure. ```bash vendor/bin/mftf codecept:run --debug From a6affde1dc05a57787f44d90427d9d44d4db4ddc Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Fri, 14 Aug 2020 20:50:06 -0500 Subject: [PATCH 514/888] MQE-2110: MFTF command to pause test execution --- docs/commands/mftf.md | 14 +++++++++++++- docs/interactive-pause.md | 8 +++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index b3365cfa0..0d74c1efb 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -585,16 +585,28 @@ vendor/bin/mftf codecept:run [<suite|test>] --[<option(s)>] ```bash # Run all tests in functional suite vendor/bin/mftf codecept:run functional +``` + +```bash # Run all tests in functional suite with options vendor/bin/mftf codecept:run functional --verbose --steps --debug +``` + +```bash # Run one test vendor/bin/mftf codecept:run functional Magento/_generated/default/AdminCreateCmsPageTestCest.php --debug +``` + +```bash # Run all tests in default group vendor/bin/mftf codecept:run functional --verbose --steps -g default ``` <div class="bs-callout-warning"> -Note: You may want to limit the usage of this Codeception command with arguments and options for `acceptance` only, since it is what is supported by MFTF. You should also change `acceptance` to `functional` when using this command when referring to Codeception documentation. +<p> +Note: You may want to limit the usage of this Codeception command with arguments and options for "acceptance" only, since it is what's supported by MFTF. +When using this command, you should change "acceptance" to "functional" when referring to Codeception documentation. +</p> </div> <!-- LINK DEFINITIONS --> diff --git a/docs/interactive-pause.md b/docs/interactive-pause.md index 25e0f7f0e..250f19936 100644 --- a/docs/interactive-pause.md +++ b/docs/interactive-pause.md @@ -61,9 +61,11 @@ vendor/bin/mftf codecept:run --debug ``` <div class="bs-callout-warning"> -Note: MFTF run command's `--debug` option is different from Codeception `--debug` mode option. +<p> +Note: MFTF command "--debug" option has different meaning than Codeception command "--debug" mode option. +</p> </div> -## References +<!-- Link definitions --> -[pause on codeception.com](https://codeception.com/docs/02-GettingStarted#Interactive-Pause) +[pause on codeception.com]: https://codeception.com/docs/02-GettingStarted#Interactive-Pause From 97a7e64e4565e46e295f445d452f387eb3db12f5 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 17 Aug 2020 14:46:25 -0500 Subject: [PATCH 515/888] MQE-2133: Make tests green for Chrome 84 --- .../Module/MagentoWebDriver.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 859d666de..3c1d8af50 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -761,19 +761,25 @@ public function dragAndDrop($source, $target, $xOffset = null, $yOffset = null) $snodes = $this->matchFirstOrFail($this->baseElement, $source); $tnodes = $this->matchFirstOrFail($this->baseElement, $target); $action = new WebDriverActions($this->webDriver); - if ($xOffset !== null || $yOffset !== null) { $targetX = intval($tnodes->getLocation()->getX() + $xOffset); $targetY = intval($tnodes->getLocation()->getY() + $yOffset); - $travelX = intval($targetX - $snodes->getLocation()->getX()); $travelY = intval($targetY - $snodes->getLocation()->getY()); $action->moveToElement($snodes); $action->clickAndHold($snodes); + // Fix Start + $action->moveByOffset(-1,-1); + $action->moveByOffset(1,1); + // Fix End $action->moveByOffset($travelX, $travelY); $action->release()->perform(); } else { $action->clickAndHold($snodes); + // Fix Start + $action->moveByOffset(-1,-1); + $action->moveByOffset(1,1); + // Fix End $action->moveToElement($tnodes); $action->release($tnodes)->perform(); } From 5d4aab2770cd1dfd75ac6f98bde3db8e6da73e6e Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 17 Aug 2020 15:01:53 -0500 Subject: [PATCH 516/888] MQE-2133: Make tests green for Chrome 84 --- .../Module/MagentoWebDriver.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 3c1d8af50..13d44a358 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -769,16 +769,16 @@ public function dragAndDrop($source, $target, $xOffset = null, $yOffset = null) $action->moveToElement($snodes); $action->clickAndHold($snodes); // Fix Start - $action->moveByOffset(-1,-1); - $action->moveByOffset(1,1); + $action->moveByOffset(-1, -1); + $action->moveByOffset(1, 1); // Fix End $action->moveByOffset($travelX, $travelY); $action->release()->perform(); } else { $action->clickAndHold($snodes); // Fix Start - $action->moveByOffset(-1,-1); - $action->moveByOffset(1,1); + $action->moveByOffset(-1, -1); + $action->moveByOffset(1, 1); // Fix End $action->moveToElement($tnodes); $action->release($tnodes)->perform(); From 9d0317b7202ebcfdc88c67c92d5e96153cf15825 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 17 Aug 2020 17:33:05 -0500 Subject: [PATCH 517/888] MQE-2270: Pausing of test during a failure is not intuitive for ENABLE_PAUSE=true --- .../Module/MagentoWebDriver.php | 25 +++++++++++++++++-- .../Test/Objects/ActionObject.php | 1 + .../Test/Util/TestHookObjectExtractor.php | 6 ++++- .../Util/TestGenerator.php | 10 ++++++++ 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 13d44a358..00e295606 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -54,7 +54,9 @@ class MagentoWebDriver extends WebDriver { use AttachmentSupport; - use Pause; + use Pause { + pause as codeceptPause; + } const MAGENTO_CRON_INTERVAL = 60; const MAGENTO_CRON_COMMAND = 'cron:run'; @@ -843,7 +845,7 @@ public function _failed(TestInterface $test, $fail) if ($this->pngReport === null && $this->htmlReport === null) { $this->saveScreenshot(); if (getenv('ENABLE_PAUSE') === 'true') { - $this->pause(); + $this->pause(true); } } @@ -1028,4 +1030,23 @@ public function switchToIFrame($locator = null) $this->webDriver->switchTo()->frame($els[0]); } } + + /** + * Invoke Codeption pause() + * + * @param boolean $pauseOnFail + * @return void + */ + public function pause($pauseOnFail = false) + { + if (!\Codeception\Util\Debug::isEnabled()) { + return; + } + + if ($pauseOnFail) { + print(PHP_EOL . "Failure encountered. Pausing execution..." . PHP_EOL . PHP_EOL); + } + + $this->codeceptPause(); + } } diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php index 8d4e7a945..8e4aa973c 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php @@ -77,6 +77,7 @@ class ActionObject const ACTION_TYPE_COMMENT = 'comment'; const ACTION_TYPE_HELPER = 'helper'; const INVISIBLE_STEP_ACTIONS = ['retrieveEntityField', 'getSecret']; + const PAUSE_ACTION_INTERNAL_ATTRIBUTE = 'pauseOnFail'; /** * The unique identifier for the action diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/TestHookObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/TestHookObjectExtractor.php index a68f09491..e9c163d31 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/TestHookObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/TestHookObjectExtractor.php @@ -66,7 +66,11 @@ public function createDefaultFailedHook($parentName) { $defaultSteps['saveScreenshot'] = new ActionObject("saveScreenshot", "saveScreenshot", []); if (getenv('ENABLE_PAUSE') === 'true') { - $defaultSteps['pauseWhenFailed'] = new ActionObject('pauseWhenFailed', 'pause', []); + $defaultSteps['pauseWhenFailed'] = new ActionObject( + 'pauseWhenFailed', + 'pause', + [ActionObject::PAUSE_ACTION_INTERNAL_ATTRIBUTE => true] + ); } $hook = new TestHookObject( diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 82fb2c06a..8caffc565 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1441,6 +1441,16 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $testSteps .= $dateGenerateCode; break; + case "pause": + $pauseAttr = $actionObject->getCustomActionAttributes( + ActionObject::PAUSE_ACTION_INTERNAL_ATTRIBUTE + ); + if ($pauseAttr) { + $testSteps .= sprintf("\t\t$%s->%s(%s);", $actor, $actionObject->getType(), 'true'); + } else { + $testSteps .= sprintf("\t\t$%s->%s();", $actor, $actionObject->getType()); + } + break; case "comment": $input = $input === null ? strtr($value, ['$' => '\$', '{' => '\{', '}' => '\}']) : $input; // Combining userInput from native XML comment and <comment/> action to fall-through 'default' case From cf562e106532553bed328cea5b4fd3b0ce96c3d2 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 18 Aug 2020 08:18:08 -0500 Subject: [PATCH 518/888] MQE-2270: Pausing of test during a failure is not intuitive for ENABLE_PAUSE=true --- .../Test/Handlers/TestObjectHandlerTest.php | 23 ++----------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php index 036656cdd..939dd496e 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php @@ -260,25 +260,6 @@ public function testGetAllTestObjectsWithInvalidExtends() $toh->getAllObjects(); } - /** - * Function used to set mock for parser return and force init method to run between tests. - * - * @param array $data - * @throws \Exception - */ - private function setMockParserOutput($data) - { - // clear test object handler value to inject parsed content - $property = new \ReflectionProperty(TestObjectHandler::class, 'testObjectHandler'); - $property->setAccessible(true); - $property->setValue(null); - - $mockDataParser = AspectMock::double(TestDataParser::class, ['readTestData' => $data])->make(); - $instance = AspectMock::double(ObjectManager::class, ['create' => $mockDataParser]) - ->make(); // bypass the private constructor - AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); - } - /** * Validate test object when ENABLE_PAUSE is set to true * @@ -299,7 +280,7 @@ public function testGetTestObjectWhenEnablePause() $resolverMock = new MockModuleResolverBuilder(); $resolverMock->setup(); - $this->setMockParserOutput($mockData); + ObjectHandlerUtil::mockTestObjectHandlerWitData($mockData); // run object handler method $toh = TestObjectHandler::getInstance(); @@ -325,7 +306,7 @@ public function testGetTestObjectWhenEnablePause() $expectedFailedActionObject2 = new ActionObject( 'pauseWhenFailed', 'pause', - [] + [ActionObject::PAUSE_ACTION_INTERNAL_ATTRIBUTE => true] ); $expectedBeforeHookObject = new TestHookObject( From 713b3333cbf411c336dc766145e8caa2b61fab38 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 18 Aug 2020 12:34:45 -0500 Subject: [PATCH 519/888] MQE-2269: Test manifest run stops at first failure encountered when ENABLE_PAUSE = true --- .../Console/BaseGenerateCommand.php | 1 + .../Console/RunManifestCommand.php | 22 ++++++++++++++----- .../Console/RunTestCommand.php | 15 +++++++++++-- .../Console/RunTestFailedCommand.php | 10 ++++++--- .../Console/RunTestGroupCommand.php | 7 ++++-- 5 files changed, 42 insertions(+), 13 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index 525711e31..401153c7b 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -33,6 +33,7 @@ class BaseGenerateCommand extends Command const MFTF_NOTICES = "Placeholder text for MFTF notices\n"; const CODECEPT_RUN = 'codecept:run'; const CODECEPT_RUN_FUNCTIONAL = self::CODECEPT_RUN . ' functional '; + const CODECEPT_RUN_OPTION_NO_EXIT = ' --no-exit '; /** * Enable pause() diff --git a/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php index 89ae90888..683be1b53 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php @@ -81,12 +81,17 @@ protected function execute(InputInterface $input, OutputInterface $output): int // Delete the Codeception failed file just in case it exists from any previous test runs $this->deleteFailedFile(); - foreach ($manifestFile as $manifestLine) { - if (empty($manifestLine)) { + for ($line = 0; $line < count($manifestFile); $line++) { + if (empty($manifestFile[$line])) { continue; } - $this->runManifestLine($manifestLine, $output); + if ($line == count($manifestFile) - 1) { + $this->runManifestLine($manifestFile[$line], $output, true); + } else { + $this->runManifestLine($manifestFile[$line], $output); + } + $this->aggregateFailed(); } @@ -103,18 +108,23 @@ protected function execute(InputInterface $input, OutputInterface $output): int * * @param string $manifestLine * @param OutputInterface $output + * @param boolean $exit * @return void * @throws \Exception * * @SuppressWarnings(PHPMD.UnusedLocalVariable) Need this because of the unused $type variable in the closure */ - private function runManifestLine(string $manifestLine, OutputInterface $output) + private function runManifestLine($manifestLine, $output, $exit = false) { if (getenv('ENABLE_PAUSE') === 'true') { $codeceptionCommand = BaseGenerateCommand::CODECEPT_RUN_FUNCTIONAL - . '--verbose --steps --debug ' . $manifestLine; + . '--verbose --steps --debug '; + if (!$exit) { + $codeceptionCommand .= BaseGenerateCommand::CODECEPT_RUN_OPTION_NO_EXIT; + } + $codeceptionCommand .= $manifestLine; $input = new StringInput($codeceptionCommand); - $command = $this->getApplication()->find('codecept:run'); + $command = $this->getApplication()->find(BaseGenerateCommand::CODECEPT_RUN); $subReturnCode = $command->run($input, $output); } else { $codeceptionCommand = realpath(PROJECT_ROOT . "/vendor/bin/codecept") diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php index 3d99b6fad..6931e8303 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php @@ -135,8 +135,8 @@ private function runTests(array $tests, OutputInterface $output) TestGenerator::DEFAULT_DIR . DIRECTORY_SEPARATOR ; - foreach ($tests as $test) { - $testName = $test . 'Cest.php'; + for ($i = 0; $i < count($tests); $i++) { + $testName = $tests[$i] . 'Cest.php'; if (!realpath($testsDirectory . $testName)) { throw new TestFrameworkException( $testName . " is not available under " . $testsDirectory @@ -145,6 +145,9 @@ private function runTests(array $tests, OutputInterface $output) if ($this->pauseEnabled()) { $fullCommand = $codeceptionCommand . $testsDirectory . $testName . ' --verbose --steps --debug'; + if ($i != count($tests) - 1) { + $fullCommand .= self::CODECEPT_RUN_OPTION_NO_EXIT; + } $this->returnCode = max($this->returnCode, $this->codeceptRunTest($fullCommand, $output)); } else { $fullCommand = $codeceptionCommand . $testsDirectory . $testName . ' --verbose --steps'; @@ -169,10 +172,18 @@ private function runTestsInSuite(array $suitesConfig, OutputInterface $output) $codeceptionCommand = realpath(PROJECT_ROOT . '/vendor/bin/codecept') . ' run functional --verbose --steps '; } + + $count = count($suitesConfig); + $index = 0; //for tests in suites, run them as a group to run before and after block foreach (array_keys($suitesConfig) as $suite) { $fullCommand = $codeceptionCommand . " -g {$suite}"; + + $index += 1; if ($this->pauseEnabled()) { + if ($index != $count) { + $fullCommand .= self::CODECEPT_RUN_OPTION_NO_EXIT; + } $this->returnCode = max($this->returnCode, $this->codeceptRunTest($fullCommand, $output)); } else { $this->returnCode = max($this->returnCode, $this->executeTestCommand($fullCommand, $output)); diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php index 87606d53d..6e6954c70 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php @@ -116,13 +116,16 @@ protected function execute(InputInterface $input, OutputInterface $output): int $testManifestList = $this->readTestManifestFile(); $returnCode = 0; - foreach ($testManifestList as $testCommand) { + for ($i = 0; $i < count($testManifestList); $i++) { if ($this->pauseEnabled()) { - $codeceptionCommand = self::CODECEPT_RUN_FUNCTIONAL . $testCommand . ' --debug'; + $codeceptionCommand = self::CODECEPT_RUN_FUNCTIONAL . $testManifestList[$i] . ' --debug '; + if ($i != count($testManifestList) - 1) { + $codeceptionCommand .= self::CODECEPT_RUN_OPTION_NO_EXIT; + } $returnCode = $this->codeceptRunTest($codeceptionCommand, $output); } else { $codeceptionCommand = realpath(PROJECT_ROOT . '/vendor/bin/codecept') . ' run functional '; - $codeceptionCommand .= $testCommand; + $codeceptionCommand .= $testManifestList[$i]; $process = new Process($codeceptionCommand); $process->setWorkingDirectory(TESTS_BP); @@ -142,6 +145,7 @@ function ($type, $buffer) use ($output) { ); } } + foreach ($this->failedList as $test) { $this->writeFailedTestToFile($test, $this->testsFailedFile); } diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php index 896218efc..53724561e 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php @@ -102,10 +102,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int $exitCode = -1; $returnCodes = []; - foreach ($groups as $group) { - $codeceptionCommandString = $commandString . " -g {$group}"; + for ($i = 0; $i < count($groups); $i++) { + $codeceptionCommandString = $commandString . ' -g ' . $groups[$i]; if ($this->pauseEnabled()) { + if ($i != count($groups) - 1) { + $codeceptionCommandString .= self::CODECEPT_RUN_OPTION_NO_EXIT; + } $returnCodes[] = $this->codeceptRunTest($codeceptionCommandString, $output); } else { $process = new Process($codeceptionCommandString); From 3f285212faa6f224798505d94a12bb8b2697a491 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 18 Aug 2020 13:22:09 -0500 Subject: [PATCH 520/888] MQE-2269: Test manifest run stops at first failure encountered when ENABLE_PAUSE = true --- .../FunctionalTestingFramework/Console/RunTestGroupCommand.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php index 53724561e..f18b9dc30 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php @@ -52,6 +52,7 @@ protected function configure() * @throws \Exception * * @SuppressWarnings(PHPMD.UnusedLocalVariable) + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ protected function execute(InputInterface $input, OutputInterface $output): int { From d14fbe59392520d719916f5979eb67341ce3bb61 Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Wed, 19 Aug 2020 11:34:51 -0500 Subject: [PATCH 521/888] MQE-2258: CHANGELOG.MD and Composer version bump (#788) * MQE-2258: CHANGELOG.MD and Composer version bump * Grammar and formatting Co-authored-by: Donald Booth <dobooth@adobe.com> --- CHANGELOG.md | 36 ++++++++++++++++++++++++++++++++++++ composer.json | 2 +- composer.lock | 6 ++++-- docs/test/actions.md | 3 ++- 4 files changed, 43 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a24b5f29..fd555ee88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,41 @@ Magento Functional Testing Framework Changelog ================================================ +3.1.0 +________ + +### Enhancements + +* Customizability + * Introduced the new `return` action that allows action groups to return a value. See the [actions page](./docs/test/actions.md#return) for details. + * Introduced new MFTF command that invokes `vendor/bin/codecept run`. See the [mftf page](./docs/commands/mftf.md#codeceptrun) for details. + +* Usability + * Introduced new action `pause`, to invoke codeception interactive pause for debugging during test execution. See the [Interactive Pause](./docs/interactive-pause.md) page for details. + * Introduced a new `.env` configuration option `ENABLE_PAUSE`, to enable the new pause feature. + +* Maintainability + * Added a new static check that checks for the usage of the `pause` action. See the [command page](./docs/commands/mftf.md#static-checks) for details. + +* Modularity + * MFTF now supports the use of actions from multiple modules within suites. + +* Traceability + * A deprecation notice is now added at test execution time for deprecated metadata usage. + +### Fixes + +* Fixed issue with suite precondition failure for `createData` with required entity. + +### GitHub Issues/Pull requests: + + * [#547](https://github.com/magento/magento2-functional-testing-framework/pull/547) -- Fix invalid behavior of MAGENTO_BACKEND_BASE_URL + * [#742](https://github.com/magento/magento2-functional-testing-framework/pull/742) -- Fix Waits In MagentoPwaWebDriver + * [#750](https://github.com/magento/magento2-functional-testing-framework/pull/750) -- Docs: Outlining the difference between Allure severity levels + * [#683](https://github.com/magento/magento2-functional-testing-framework/pull/683) -- Docs: Renamed sample test name with the correct one + * [#691](https://github.com/magento/magento2-functional-testing-framework/pull/691) -- Docs: Branch name updates + * [#678](https://github.com/magento/magento2-functional-testing-framework/pull/678) -- Docs: Command added to modify the web server rewrites configuration + * [#745](https://github.com/magento/magento2-functional-testing-framework/pull/745) -- Docs: Remove invalid sample test name + 3.0.0 --------- diff --git a/composer.json b/composer.json index 6f8b0c2c2..813ab382b 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "3.0.0", + "version": "3.1.0", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index 91fa2c772..7f7648096 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "98733866973fb51e11e316b98c0af563", + "content-hash": "278e33e2c7d183d0b7689b5a76127d29", "packages": [ { "name": "allure-framework/allure-codeception", @@ -3664,6 +3664,7 @@ "keywords": [ "tokenizer" ], + "abandoned": true, "time": "2020-02-07T06:19:00+00:00" }, { @@ -7469,5 +7470,6 @@ "ext-json": "*", "ext-openssl": "*" }, - "platform-dev": [] + "platform-dev": [], + "plugin-api-version": "1.1.0" } diff --git a/docs/test/actions.md b/docs/test/actions.md index f69ee1d66..42ecde053 100644 --- a/docs/test/actions.md +++ b/docs/test/actions.md @@ -1251,8 +1251,9 @@ Attribute|Type|Use|Description `stepKey`|string|required| A unique identifier of the action. #### Example + ```xml -<!-- Returns value of $grabInputName to the calling +<!-- Returns value of $grabInputName to the calling --> <return value="{$grabInputName}" stepKey="returnInputName"/> ``` From 0d72f3be3a24fa4ee6b23f9e011e2edf28cd1761 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Tue, 1 Sep 2020 12:25:28 -0500 Subject: [PATCH 522/888] MQE-2255: Migrate MFTF builds out of Travis --- .github/workflows/main.yml | 150 +++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 000000000..8f57e621f --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,150 @@ +# Copyright © Magento, Inc. All rights reserved. +# See COPYING.txt for license details. + +name: CI + +on: [pull_request] + +jobs: + unit-tests: + name: Unit Tests + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php-versions: ['7.3', '7.4'] + steps: + - uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@master + with: + php-version: ${{ matrix.php-versions }} + extensions: bcmath, ctype, curl, dom, gd, hash, iconv, intl, mbstring, openssl, pdo_mysql, simplexml, soap, xsl, zip + + - name: Cache Composer packages + id: composer-cache + uses: actions/cache@v2 + with: + path: vendor + key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-php- + + - name: Install dependencies + if: steps.composer-cache.outputs.cache-hit != 'true' + run: composer install --prefer-dist --no-progress --no-suggest + + - name: Run tests + run: vendor/bin/phpunit --configuration dev/tests/phpunit.xml --testsuite unit --coverage-clover clover.xml + + - name: Monitor coverage + if: github.event_name == 'pull_request' + uses: slavcodev/coverage-monitor-action@1.1.0 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + clover_file: "clover.xml" + threshold_alert: 10 + threshold_warning: 20 + + verification-tests: + name: Verification Tests + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php-versions: ['7.3', '7.4'] + steps: + - uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@master + with: + php-version: ${{ matrix.php-versions }} + extensions: bcmath, ctype, curl, dom, gd, hash, iconv, intl, mbstring, openssl, pdo_mysql, simplexml, soap, xsl, zip + + - name: Cache Composer packages + id: composer-cache + uses: actions/cache@v2 + with: + path: vendor + key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-php- + + - name: Install dependencies + if: steps.composer-cache.outputs.cache-hit != 'true' + run: composer install --prefer-dist --no-progress --no-suggest + + - name: Run tests + run: vendor/bin/phpunit --configuration dev/tests/phpunit.xml --testsuite verification + + static-tests: + name: Static Tests + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php-versions: ['7.3', '7.4'] + steps: + - uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@master + with: + php-version: ${{ matrix.php-versions }} + extensions: bcmath, ctype, curl, dom, gd, hash, iconv, intl, mbstring, openssl, pdo_mysql, simplexml, soap, xsl, zip + + - name: Cache Composer packages + id: composer-cache + uses: actions/cache@v2 + with: + path: vendor + key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-php- + + - name: Install dependencies + if: steps.composer-cache.outputs.cache-hit != 'true' + run: composer install --prefer-dist --no-progress --no-suggest + + - name: Run tests + run: bin/static-checks + + functional-tests: + name: Functional Tests + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php-versions: ['7.3', '7.4'] + + services: + chrome: + image: selenium/standalone-chrome:3.141.59-zirconium + ports: + - 4444:4444 + steps: + - uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@master + with: + php-version: ${{ matrix.php-versions }} + extensions: bcmath, ctype, curl, dom, gd, hash, iconv, intl, mbstring, openssl, pdo_mysql, simplexml, soap, xsl, zip + + - name: Cache Composer packages + id: composer-cache + uses: actions/cache@v2 + with: + path: vendor + key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-php- + + - name: Install dependencies + if: steps.composer-cache.outputs.cache-hit != 'true' + run: composer install --prefer-dist --no-progress --no-suggest + + - name: Run tests + run: bin/functional From 53b0799b00407a4eab8356c0d32f30e5c0b65d8e Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Wed, 2 Sep 2020 12:08:19 -0500 Subject: [PATCH 523/888] MQE-2255: Migrate MFTF builds out of Travis --- .github/workflows/main.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8f57e621f..b65fe5dcf 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -20,7 +20,6 @@ jobs: uses: shivammathur/setup-php@master with: php-version: ${{ matrix.php-versions }} - extensions: bcmath, ctype, curl, dom, gd, hash, iconv, intl, mbstring, openssl, pdo_mysql, simplexml, soap, xsl, zip - name: Cache Composer packages id: composer-cache From 969dbe28bba55d98d035deb5c303894f803b3639 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Wed, 2 Sep 2020 12:56:53 -0500 Subject: [PATCH 524/888] MQE-2255: Migrate MFTF builds out of Travis --- .github/workflows/main.yml | 13 ++++++++++--- .travis.yml | 18 ------------------ 2 files changed, 10 insertions(+), 21 deletions(-) delete mode 100644 .travis.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b65fe5dcf..e892f0dd0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -20,6 +20,7 @@ jobs: uses: shivammathur/setup-php@master with: php-version: ${{ matrix.php-versions }} + extensions: curl, dom, intl, json, openssl - name: Cache Composer packages id: composer-cache @@ -60,7 +61,7 @@ jobs: uses: shivammathur/setup-php@master with: php-version: ${{ matrix.php-versions }} - extensions: bcmath, ctype, curl, dom, gd, hash, iconv, intl, mbstring, openssl, pdo_mysql, simplexml, soap, xsl, zip + extensions: curl, dom, intl, json, openssl - name: Cache Composer packages id: composer-cache @@ -92,7 +93,7 @@ jobs: uses: shivammathur/setup-php@master with: php-version: ${{ matrix.php-versions }} - extensions: bcmath, ctype, curl, dom, gd, hash, iconv, intl, mbstring, openssl, pdo_mysql, simplexml, soap, xsl, zip + extensions: curl, dom, intl, json, openssl - name: Cache Composer packages id: composer-cache @@ -130,7 +131,7 @@ jobs: uses: shivammathur/setup-php@master with: php-version: ${{ matrix.php-versions }} - extensions: bcmath, ctype, curl, dom, gd, hash, iconv, intl, mbstring, openssl, pdo_mysql, simplexml, soap, xsl, zip + extensions: curl, dom, intl, json, openssl - name: Cache Composer packages id: composer-cache @@ -147,3 +148,9 @@ jobs: - name: Run tests run: bin/functional + + - name: Allure report + uses: afiore/action-allure-report@v0.1.0 + with: + results-dir: dev/tests/_output/allure-results + diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index b4dfd3717..000000000 --- a/.travis.yml +++ /dev/null @@ -1,18 +0,0 @@ -language: php -php: - - 7.3 - - 7.4 -services: - - docker -before_install: - - docker run -d -p 4444:4444 -v /dev/shm:/dev/shm selenium/standalone-chrome:3.141.59-zirconium -install: composer install --no-interaction --prefer-source -env: - matrix: - - VERIFICATION_TOOL=phpunit-checks - - VERIFICATION_TOOL=static-checks - - VERIFICATION_TOOL=functional -script: - - bin/$VERIFICATION_TOOL -after_success: - - travis_retry php vendor/bin/coveralls From f99180914e69900c84abecd97fe34471dff2e23b Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Wed, 2 Sep 2020 16:51:44 -0500 Subject: [PATCH 525/888] MQE-2255: Migrate MFTF builds out of Travis --- .github/workflows/main.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e892f0dd0..e98ab3bc5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -149,8 +149,4 @@ jobs: - name: Run tests run: bin/functional - - name: Allure report - uses: afiore/action-allure-report@v0.1.0 - with: - results-dir: dev/tests/_output/allure-results From ec8abe6ed67403d029cb4e49f309bea70a5e14f7 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Fri, 4 Sep 2020 13:17:23 -0500 Subject: [PATCH 526/888] MQE-1800: Allow generate:tests to continue running even if one test fails generation --- .../Console/BaseGenerateCommand.php | 8 ++ .../Console/GenerateSuiteCommand.php | 9 +- .../Console/GenerateTestsCommand.php | 24 +++- .../Console/RunTestCommand.php | 6 +- .../Console/RunTestFailedCommand.php | 14 +- .../Console/RunTestGroupCommand.php | 7 +- .../Suite/Handlers/SuiteObjectHandler.php | 27 +++- .../Suite/SuiteGenerator.php | 79 +++++++--- .../Suite/Util/SuiteObjectExtractor.php | 135 +++++++++++++----- .../Util/TestGenerator.php | 89 +++++++++--- 10 files changed, 305 insertions(+), 93 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index 401153c7b..93e272d04 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -49,6 +49,13 @@ class BaseGenerateCommand extends Command */ protected $ioStyle = null; + /** + * Command status + * + * @var bool + */ + protected $cmdStatus = true; + /** * Configures the base command. * @@ -111,6 +118,7 @@ protected function getTestAndSuiteConfiguration(array $tests) $testConfiguration['tests'] = null; $testConfiguration['suites'] = null; $testsReferencedInSuites = SuiteObjectHandler::getInstance()->getAllTestReferences(); + $this->cmdStatus = SuiteObjectHandler::getInstance()->parseSuccessful(); $suiteToTestPair = []; foreach($tests as $test) { diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php index 8da3493aa..547698b76 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php @@ -72,6 +72,13 @@ protected function execute(InputInterface $input, OutputInterface $output) } } - $output->writeLn("Suites Generated"); + if ($this->cmdStatus) { + $output->writeLn("Suites Generated"); + return 0; + } else { + $output->writeLn("Suite parsing error found. See mftf.log for details."); + $output->writeLn("Suites Generated"); + return 1; + } } } diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php index b76d3ab3c..561140432 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php @@ -126,20 +126,29 @@ protected function execute(InputInterface $input, OutputInterface $output) $this->removeGeneratedDirectory($output, $verbose); } + $errMessages = []; try { $testConfiguration = $this->createTestConfiguration($json, $tests); // create our manifest file here $testManifest = TestManifestFactory::makeManifest($config, $testConfiguration['suites']); - TestGenerator::getInstance(null, $testConfiguration['tests'])->createAllTestFiles($testManifest); + try { + TestGenerator::getInstance(null, $testConfiguration['tests'])->createAllTestFiles($testManifest); + } catch (\Exception $e) { + $errMessages[] = $e->getMessage(); + } if ($config == 'parallel') { /** @var ParallelTestManifest $testManifest */ $testManifest->createTestGroups($time); } - SuiteGenerator::getInstance()->generateAllSuites($testManifest); + try { + SuiteGenerator::getInstance()->generateAllSuites($testManifest); + } catch (\Exception $e) { + $errMessages[] = $e->getMessage(); + } $testManifest->generate(); } catch (\Exception $e) { @@ -152,7 +161,16 @@ protected function execute(InputInterface $input, OutputInterface $output) return 1; } - $output->writeln("Generate Tests Command Run"); + if (!empty($errMessages)) { + foreach (array_unique($errMessages) as $errMessage) { + $output->writeln($errMessage); + $output->writeln("\nGenerate Tests Command Run"); + } + return 1; + } else { + $output->writeln("\nGenerate Tests Command Run"); + return 0; + } } /** diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php index 6931e8303..6f20d1463 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php @@ -109,7 +109,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->runTestsInSuite($testConfigArray['suites'], $output); } - return $this->returnCode; + if ($this->returnCode == 0 && $this->cmdStatus) { + return 0; + } else { + return 1; + } } /** diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php index 6e6954c70..cae401314 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php @@ -99,8 +99,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int $testConfiguration = $this->getFailedTestList(); if ($testConfiguration === null) { - // no failed tests found, run is a success - return 0; + // no failed tests found + if ($this->cmdStatus) { + return 0; + } else { + return 1; + } } $command = $this->getApplication()->find('generate:tests'); @@ -150,7 +154,11 @@ function ($type, $buffer) use ($output) { $this->writeFailedTestToFile($test, $this->testsFailedFile); } - return $returnCode; + if ($returnCode == 0 && $this->cmdStatus) { + return 0; + } else { + return 1; + } } /** diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php index f18b9dc30..8975030de 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php @@ -130,6 +130,11 @@ function ($type, $buffer) use ($output) { } $exitCode = 0; } - return $exitCode; + + if ($exitCode == 0 && $this->cmdStatus) { + return 0; + } else { + return 1; + } } } diff --git a/src/Magento/FunctionalTestingFramework/Suite/Handlers/SuiteObjectHandler.php b/src/Magento/FunctionalTestingFramework/Suite/Handlers/SuiteObjectHandler.php index bbaaf4379..d78e495d8 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Handlers/SuiteObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Handlers/SuiteObjectHandler.php @@ -33,6 +33,13 @@ class SuiteObjectHandler implements ObjectHandlerInterface */ private $suiteObjects; + /** + * If suites parsing are successful + * + * @var bool + */ + private $status; + /** * Avoids instantiation of SuiteObjectHandler by new. * @return void @@ -53,7 +60,6 @@ private function __clone() * Function to enforce singleton design pattern * * @return ObjectHandlerInterface - * @throws XmlException */ public static function getInstance(): ObjectHandlerInterface { @@ -89,6 +95,16 @@ public function getAllObjects(): array return $this->suiteObjects; } + /** + * Return if there is any parsing errors + * + * @return bool + */ + public function parseSuccessful(): bool + { + return $this->status; + } + /** * Function which return all tests referenced by suites. * @@ -114,12 +130,17 @@ public function getAllTestReferences(): array * * @return void * @SuppressWarnings(PHPMD.UnusedPrivateMethod) - * @throws XmlException */ private function initSuiteData() { $suiteDataParser = ObjectManagerFactory::getObjectManager()->create(SuiteDataParser::class); $suiteObjectExtractor = new SuiteObjectExtractor(); - $this->suiteObjects = $suiteObjectExtractor->parseSuiteDataIntoObjects($suiteDataParser->readSuiteData()); + $parsedArray = $suiteObjectExtractor->parseSuiteDataIntoObjects($suiteDataParser->readSuiteData()); + $this->suiteObjects = $parsedArray['objects'] ?? []; + if (empty($this->suiteObjects)) { + $this->status = false; + } else { + $this->status = $parsedArray['status'] ?? false; + } } } diff --git a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php index b40b48ae7..2bf105b7b 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php @@ -6,6 +6,7 @@ namespace Magento\FunctionalTestingFramework\Suite; +use Magento\FunctionalTestingFramework\Exceptions\Collector\ExceptionCollector; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Exceptions\XmlException; @@ -94,27 +95,34 @@ public function generateAllSuites($testManifest) { $suites = $testManifest->getSuiteConfig(); + $exceptionCollector = new ExceptionCollector(); foreach ($suites as $suiteName => $suiteContent) { - if (empty($suiteContent)) { - LoggingUtil::getInstance()->getLogger(self::class)->notification( - "Suite '" . $suiteName . "' contains no tests and won't be generated." . PHP_EOL, - [], - true - ); - continue; - } - $firstElement = array_values($suiteContent)[0]; + try { + if (empty($suiteContent)) { + LoggingUtil::getInstance()->getLogger(self::class)->notification( + "Suite '" . $suiteName . "' contains no tests and won't be generated." . PHP_EOL, + [], + true + ); + continue; + } + $firstElement = array_values($suiteContent)[0]; - // if the first element is a string we know that we simply have an array of tests - if (is_string($firstElement)) { - $this->generateSuiteFromTest($suiteName, $suiteContent); - } + // if the first element is a string we know that we simply have an array of tests + if (is_string($firstElement)) { + $this->generateSuiteFromTest($suiteName, $suiteContent); + } - // if our first element is an array we know that we have split the suites - if (is_array($firstElement)) { - $this->generateSplitSuiteFromTest($suiteName, $suiteContent); + // if our first element is an array we know that we have split the suites + if (is_array($firstElement)) { + $this->generateSplitSuiteFromTest($suiteName, $suiteContent); + } + } catch (\Exception $e) { + $exceptionCollector->addError(self::class, $e->getMessage()); } } + // Report failure + $this->throwCollectedExceptions($exceptionCollector); } /** @@ -140,9 +148,7 @@ public function generateSuite($suiteName) * @param array $tests * @param string $originalSuiteName * @return void - * @throws TestReferenceException - * @throws XmlException - * @throws TestFrameworkException + * @throws \Exception */ private function generateSuiteFromTest($suiteName, $tests = [], $originalSuiteName = null) { @@ -152,10 +158,18 @@ private function generateSuiteFromTest($suiteName, $tests = [], $originalSuiteNa DirSetupUtil::createGroupDir($fullPath); $relevantTests = []; + $exceptionCollector = new ExceptionCollector(); if (!empty($tests)) { $this->validateTestsReferencedInSuite($suiteName, $tests, $originalSuiteName); foreach ($tests as $testName) { - $relevantTests[$testName] = TestObjectHandler::getInstance()->getObject($testName); + try { + $relevantTests[$testName] = TestObjectHandler::getInstance()->getObject($testName); + } catch (\Exception $e) { + $exceptionCollector->addError( + self::class, + "Unable to find relevant test \"{$testName}\" for suite \"{$suiteName}\"\n" . $e->getMessage() + ); + } } } else { $relevantTests = SuiteObjectHandler::getInstance()->getObject($suiteName)->getTests(); @@ -169,6 +183,8 @@ private function generateSuiteFromTest($suiteName, $tests = [], $originalSuiteNa "suite generated", ['suite' => $suiteName, 'relative_path' => $relativePath] ); + + $this->throwCollectedExceptions($exceptionCollector); } /** @@ -371,4 +387,27 @@ private static function getYamlConfigFilePath() { return FilePathFormatter::format(TESTS_BP); } + + /** + * Log error and throw collected exceptions + * + * @param ExceptionCollector $exceptionCollector + * @return void + * @throws \Exception + */ + private function throwCollectedExceptions($exceptionCollector) + { + if (!empty($exceptionCollector->getErrors())) { + foreach ($exceptionCollector->getErrors() as $file => $errorMessage) { + if (is_array($errorMessage)) { + foreach (array_unique($errorMessage) as $message) { + LoggingUtil::getInstance()->getLogger(SuiteGenerator::class)->error($message); + } + } else { + LoggingUtil::getInstance()->getLogger(SuiteGenerator::class)->error($errorMessage); + } + } + $exceptionCollector->throwException(); + } + } } diff --git a/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php index 90fbddd6e..82a154e3c 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php @@ -8,11 +8,13 @@ use Exception; use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Suite\Objects\SuiteObject; +use Magento\FunctionalTestingFramework\Suite\SuiteGenerator; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; use Magento\FunctionalTestingFramework\Test\Util\BaseObjectExtractor; use Magento\FunctionalTestingFramework\Test\Util\TestHookObjectExtractor; use Magento\FunctionalTestingFramework\Test\Util\TestObjectExtractor; +use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; use Magento\FunctionalTestingFramework\Util\ModuleResolver; use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Magento\FunctionalTestingFramework\Util\Validation\NameValidationUtil; @@ -49,8 +51,6 @@ public function __construct() * * @param array $parsedSuiteData * @return array - * @throws XmlException - * @throws \Exception * * @SuppressWarnings(PHPMD.NPathComplexity) */ @@ -63,36 +63,75 @@ public function parseSuiteDataIntoObjects($parsedSuiteData) return $suiteObjects; } + $noError = true; + $suiteSkipped = 0; foreach ($parsedSuiteData[self::SUITE_ROOT_TAG] as $parsedSuite) { if (!is_array($parsedSuite)) { // skip non array items parsed from suite (suite objects will always be arrays) continue; } - $this->validateSuiteName($parsedSuite); + try { + $this->validateSuiteName($parsedSuite); + + // extract include and exclude references + $groupTestsToInclude = $parsedSuite[self::INCLUDE_TAG_NAME] ?? []; + $groupTestsToExclude = $parsedSuite[self::EXCLUDE_TAG_NAME] ?? []; - //extract include and exclude references - $groupTestsToInclude = $parsedSuite[self::INCLUDE_TAG_NAME] ?? []; - $groupTestsToExclude = $parsedSuite[self::EXCLUDE_TAG_NAME] ?? []; + // resolve references as test objects + // continue if failed in include + $include = $this->extractTestObjectsFromSuiteRef($groupTestsToInclude); + $includeTests = $include['objects'] ?? []; + $stepError = $include['status'] ?? 0; + $includeMessage = ''; + if ($stepError != 0) { + $noError = false; + $includeMessage = strval($stepError) . " test(s) not included for suite \"" + . $parsedSuite[self::NAME] . "\"\n"; + } - //resolve references as test objects - $includeTests = $this->extractTestObjectsFromSuiteRef($groupTestsToInclude); - $excludeTests = $this->extractTestObjectsFromSuiteRef($groupTestsToExclude); + // break if failed in exclude + $exclude = $this->extractTestObjectsFromSuiteRef($groupTestsToExclude); + $excludeTests = $exclude['objects'] ?? []; + $stepError = $exclude['status'] ?? 0; + if ($stepError != 0) { + $suiteSkipped++; + $noError = false; + LoggingUtil::getInstance()->getLogger(self::class)->error( + "Unable to parse suite \"" . $parsedSuite[self::NAME] + . "\"\nFailed to exclude " . strval($stepError) . " test(s)" + ); + continue; + } - // parse any object hooks - $suiteHooks = $this->parseObjectHooks($parsedSuite); + // parse any object hooks + $suiteHooks = $this->parseObjectHooks($parsedSuite); + + // log error if suite is empty + if ($this->isSuiteEmpty($suiteHooks, $includeTests, $excludeTests)) { + $suiteSkipped++; + $noError = false; + LoggingUtil::getInstance()->getLogger(self::class)->error( + "Unable to parse suite \"" . $parsedSuite[self::NAME] . "\"\nSuite must not be empty." + ); + continue; + }; - //throw an exception if suite is empty - if ($this->isSuiteEmpty($suiteHooks, $includeTests, $excludeTests)) { - throw new XmlException(sprintf( - "Suites must not be empty. Suite: \"%s\"", - $parsedSuite[self::NAME] - )); - }; + // add all test if include tests is completely empty + if (empty($includeTests)) { + $includeTests = TestObjectHandler::getInstance()->getAllObjects(); + } - // add all test if include tests is completely empty - if (empty($includeTests)) { - $includeTests = TestObjectHandler::getInstance()->getAllObjects(); + if (!empty($includeMessage)) { + print($includeMessage); + } + } catch (\Exception $e) { + $noError = false; + $suiteSkipped++; + LoggingUtil::getInstance()->getLogger(self::class)->error( + "Unable to parse suite \"" . $parsedSuite[self::NAME] . "\"\n" . $e->getMessage() + ); + continue; } // create the new suite object @@ -104,7 +143,15 @@ public function parseSuiteDataIntoObjects($parsedSuiteData) ); } - return $suiteObjects; + if ($suiteSkipped != 0) { + print("ERROR: " . strval($suiteSkipped) + . " Suite failed to generate. See mftf.log for details."); + } + + return [ + 'status' => $noError, + 'objects' => $suiteObjects, + ]; } /** @@ -201,35 +248,45 @@ private function isSuiteEmpty($suiteHooks, $includeTests, $excludeTests) * * @param array $suiteReferences * @return array - * @throws \Exception */ private function extractTestObjectsFromSuiteRef($suiteReferences) { $testObjectList = []; + $errCount = 0; foreach ($suiteReferences as $suiteRefName => $suiteRefData) { if (!is_array($suiteRefData)) { continue; } - switch ($suiteRefData[self::NODE_NAME]) { - case self::TEST_TAG_NAME: - $testObject = TestObjectHandler::getInstance()->getObject($suiteRefData[self::NAME]); - $testObjectList[$testObject->getName()] = $testObject; - break; - case self::GROUP_TAG_NAME: - $testObjectList = $testObjectList + - TestObjectHandler::getInstance()->getTestsByGroup($suiteRefData[self::NAME]); - break; - case self::MODULE_TAG_NAME: - $testObjectList = array_merge( - $testObjectList, - $this->getTestsByModuleName($suiteRefData[self::NAME]) - ); - break; + try { + switch ($suiteRefData[self::NODE_NAME]) { + case self::TEST_TAG_NAME: + $testObject = TestObjectHandler::getInstance()->getObject($suiteRefData[self::NAME]); + $testObjectList[$testObject->getName()] = $testObject; + break; + case self::GROUP_TAG_NAME: + $testObjectList = $testObjectList + + TestObjectHandler::getInstance()->getTestsByGroup($suiteRefData[self::NAME]); + break; + case self::MODULE_TAG_NAME: + $testObjectList = array_merge( + $testObjectList, + $this->getTestsByModuleName($suiteRefData[self::NAME]) + ); + break; + } + } catch (\Exception $e) { + $errCount++; + LoggingUtil::getInstance()->getLogger(self::class)->error( + "Unable to find tests by reference \"" . $suiteRefData[self::NAME] . '"' . $e->getMessage() + ); } } - return $testObjectList; + return [ + 'status' => $errCount, + 'objects' => $testObjectList, + ]; } /** diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 8caffc565..2de60f0bd 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -11,6 +11,7 @@ use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; +use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Filter\FilterInterface; use Magento\FunctionalTestingFramework\Suite\Handlers\SuiteObjectHandler; use Magento\FunctionalTestingFramework\Test\Handlers\ActionGroupObjectHandler; @@ -20,6 +21,7 @@ use Magento\FunctionalTestingFramework\Test\Objects\TestHookObject; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; use Magento\FunctionalTestingFramework\Test\Util\BaseObjectExtractor; +use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; use Magento\FunctionalTestingFramework\Util\Manifest\BaseTestManifest; use Magento\FunctionalTestingFramework\Test\Util\ActionObjectExtractor; use Magento\FunctionalTestingFramework\Util\Filesystem\DirSetupUtil; @@ -125,6 +127,20 @@ class TestGenerator */ private $deprecationMessages = []; + /** + * Test deprecation messages. + * + * @var array + */ + private $cestPhpArray = []; + + /** + * Test deprecation messages. + * + * @var array + */ + private $notGeneratedTestsArray = []; + /** * Private constructor for Factory * @@ -239,10 +255,17 @@ public function createAllTestFiles($testManifest = null, $testsToIgnore = null) $testsToIgnore = SuiteObjectHandler::getInstance()->getAllTestReferences(); } - $testPhpArray = $this->assembleAllTestPhp($testManifest, $testsToIgnore); - foreach ($testPhpArray as $testPhpFile) { + $noError = $this->assembleAllTestPhp($testManifest, $testsToIgnore); + foreach ($this->cestPhpArray as $testPhpFile) { $this->createCestFile($testPhpFile[1], $testPhpFile[0]); } + + if (!$noError) { + throw new TestFrameworkException("ERROR: " . + strval(count($this->notGeneratedTestsArray)) + . " Test failed to generate. See mftf.log for details." + ); + } } /** @@ -319,45 +342,67 @@ private function generateInjectMethod() * * @param BaseTestManifest $testManifest * @param array $testsToIgnore - * @return array + * @return boolean + * @throws TestFrameworkException + * @throws TestReferenceException + * @throws XmlException */ private function assembleAllTestPhp($testManifest, array $testsToIgnore) { + $this->cestPhpArray = []; + $this->notGeneratedTestsArray = []; + /** @var TestObject[] $testObjects */ $testObjects = $this->loadAllTestObjects($testsToIgnore); - $cestPhpArray = []; + $filters = MftfApplicationConfig::getConfig()->getFilterList()->getFilters(); /** @var FilterInterface $filter */ foreach ($filters as $filter) { $filter->filter($testObjects); } + $removeLastTest = false; foreach ($testObjects as $test) { - // Do not generate test if it is an extended test and parent does not exist - if ($test->isSkipped() && !empty($test->getParentName())) { - try { - TestObjectHandler::getInstance()->getObject($test->getParentName()); - } catch (TestReferenceException $e) { - print("{$test->getName()} will not be generated. Parent {$e->getMessage()} \n"); - continue; + try { + // Do not generate test if it is an extended test and parent does not exist + if ($test->isSkipped() && !empty($test->getParentName())) { + try { + TestObjectHandler::getInstance()->getObject($test->getParentName()); + } catch (TestReferenceException $e) { + print("{$test->getName()} will not be generated. Parent {$e->getMessage()} \n"); + continue; + } } - } - $this->debug("<comment>Start creating test: " . $test->getCodeceptionName() . "</comment>"); - $php = $this->assembleTestPhp($test); - $cestPhpArray[] = [$test->getCodeceptionName(), $php]; + $this->debug("<comment>Start creating test: " . $test->getCodeceptionName() . "</comment>"); + $php = $this->assembleTestPhp($test); + $this->cestPhpArray[] = [$test->getCodeceptionName(), $php]; + $removeLastTest = true; - $debugInformation = $test->getDebugInformation(); - $this->debug($debugInformation); - $this->debug("<comment>Finish creating test: " . $test->getCodeceptionName() . "</comment>" . PHP_EOL); + $debugInformation = $test->getDebugInformation(); + $this->debug($debugInformation); + $this->debug("<comment>Finish creating test: " . $test->getCodeceptionName() . "</comment>" . PHP_EOL); - //write to manifest here if manifest is not null - if ($testManifest != null) { - $testManifest->addTest($test); + //write to manifest here if manifest is not null + if ($testManifest != null) { + $testManifest->addTest($test); + } + } catch (\Exception $e) { + $this->notGeneratedTestsArray[] = [$test->getName() => $e->getMessage()]; + LoggingUtil::getInstance()->getLogger(self::class)->error( + "Failed to generate {$test->getName()}\n" + ); + if ($removeLastTest) { + array_pop($this->cestPhpArray); + } } } - return $cestPhpArray; + if (empty($this->notGeneratedTestsArray)) { + return true; + } else { + return false; + } } /** From a2094bc2fa494cfa3b994451ef6b298c45d2fc14 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 10 Sep 2020 10:39:09 -0500 Subject: [PATCH 527/888] MQE-1800: Allow generate:tests to continue running even if one test fails generation --- composer.json | 2 +- .../Console/BaseGenerateCommandTest.php | 8 +- .../Suite/SuiteGeneratorTest.php | 6 +- .../Util/TestGeneratorTest.php | 7 +- dev/tests/unit/Util/TestLoggingUtil.php | 2 +- dev/tests/util/MftfTestCase.php | 22 ++ .../NotGenerateArgActionGroup.xml | 16 + .../NotGenerateCreateDataActionGroup.xml | 13 + .../NotGenerateExtendChildActionGroup.xml | 22 ++ ...rateExtendChildBadReferenceActionGroup.xml | 13 + .../NotGenerateExtendParentActionGroup.xml | 21 ++ .../NotGenerateParamsActionGroup.xml | 19 ++ .../NotGenerateSectionActionGroup.xml | 16 + .../NotGenerateMassMergeAfterActionGroup.xml | 15 + .../NotGenerateMassMergeBeforeActionGroup.xml | 15 + .../NotGenerateMergeActionGroup.xml | 18 ++ .../NotGenerateMassMergeAfterActionGroup.xml | 15 + .../NotGenerateMassMergeBeforeActionGroup.xml | 15 + .../NotGenerateMergeActionGroup.xml | 15 + .../Data/ExtendedData.xml | 18 ++ .../Suite/NotGenerateHookAfterSuite.xml | 24 ++ .../Suite/NotGenerateHookBeforeSuite.xml | 24 ++ .../Suite/PartialGenerateForIncludeSuite.xml | 20 ++ .../Suite/PartialGenerateNoExcludeSuite.xml | 18 ++ .../ActionGroupTest/NotGenerateArgTest.xml | 15 + .../NotGenerateExtendChildTest.xml | 15 + .../NotGenerateMassMergeAfterTest.xml | 13 + .../NotGenerateMassMergeBeforeTest.xml | 13 + .../ActionGroupTest/NotGenerateMergeTest.xml | 15 + .../ActionGroupTest/NotGenerateParamsTest.xml | 16 + .../NotGenerateRequiredDataTest.xml | 13 + .../NotGenerateSectionTest.xml | 15 + ...tGenerateChildExtendedBadReferenceTest.xml | 25 ++ .../NotGenerateChildExtendedMergingTest.xml | 25 ++ .../NotGenerateExtendedChildTest.xml | 19 ++ .../Test/ExtendTest/NotGenerateParentTest.xml | 26 ++ .../MergeTest/NotGenerateBasicMergeTest.xml | 25 ++ .../NotGenerateMergeMassViaInsertAfter.xml | 15 + .../NotGenerateMergeMassViaInsertBefore.xml | 15 + .../Test/NotGenerateAssertTest.xml | 24 ++ .../Test/NotGenerateBasicMergeTest.xml | 29 ++ .../Test/NotGenerateBasicXYOffsetTest.xml | 14 + .../Test/NotGenerateDataReferenceTest.xml | 14 + .../Test/NotGenerateDataReplacementTest.xml | 23 ++ .../NotGenerateMergeMassViaInsertAfter.xml | 15 + .../NotGenerateMergeMassViaInsertBefore.xml | 15 + .../Test/NotGeneratePageReplacementTest.xml | 23 ++ .../NotGenerateSectionReplacementTest.xml | 29 ++ .../Tests/ResilientGenerationTest.php | 294 ++++++++++++++++++ .../Tests/SuiteGenerationTest.php | 44 +-- .../Tests/SuiteTestReferences.php | 65 ++++ .../Console/GenerateSuiteCommand.php | 13 +- .../Console/GenerateTestsCommand.php | 2 +- .../Console/RunTestFailedCommand.php | 1 + .../Console/RunTestGroupCommand.php | 1 + .../Suite/Handlers/SuiteObjectHandler.php | 10 +- .../Suite/SuiteGenerator.php | 77 +++-- .../Suite/Util/SuiteObjectExtractor.php | 56 ++-- .../Test/Handlers/TestObjectHandler.php | 16 + .../Util/Filesystem/DirSetupUtil.php | 4 + .../Util/TestGenerator.php | 26 +- 61 files changed, 1313 insertions(+), 111 deletions(-) create mode 100644 dev/tests/verification/ResilientGenerationModule/ActionGroup/BasicActionGroup/NotGenerateArgActionGroup.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/ActionGroup/BasicActionGroup/NotGenerateCreateDataActionGroup.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/ActionGroup/BasicActionGroup/NotGenerateExtendChildActionGroup.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/ActionGroup/BasicActionGroup/NotGenerateExtendChildBadReferenceActionGroup.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/ActionGroup/BasicActionGroup/NotGenerateExtendParentActionGroup.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/ActionGroup/BasicActionGroup/NotGenerateParamsActionGroup.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/ActionGroup/BasicActionGroup/NotGenerateSectionActionGroup.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/ActionGroup/FunctionalActionGroup/NotGenerateMassMergeAfterActionGroup.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/ActionGroup/FunctionalActionGroup/NotGenerateMassMergeBeforeActionGroup.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/ActionGroup/FunctionalActionGroup/NotGenerateMergeActionGroup.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/ActionGroup/MergeFunctionalActionGroup/NotGenerateMassMergeAfterActionGroup.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/ActionGroup/MergeFunctionalActionGroup/NotGenerateMassMergeBeforeActionGroup.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/ActionGroup/MergeFunctionalActionGroup/NotGenerateMergeActionGroup.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Data/ExtendedData.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Suite/NotGenerateHookAfterSuite.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Suite/NotGenerateHookBeforeSuite.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Suite/PartialGenerateForIncludeSuite.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Suite/PartialGenerateNoExcludeSuite.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateArgTest.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateExtendChildTest.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateMassMergeAfterTest.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateMassMergeBeforeTest.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateMergeTest.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateParamsTest.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateRequiredDataTest.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateSectionTest.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/ExtendTest/NotGenerateChildExtendedBadReferenceTest.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/ExtendTest/NotGenerateChildExtendedMergingTest.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/ExtendTest/NotGenerateExtendedChildTest.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/ExtendTest/NotGenerateParentTest.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/MergeTest/NotGenerateBasicMergeTest.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/MergeTest/NotGenerateMergeMassViaInsertAfter.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/MergeTest/NotGenerateMergeMassViaInsertBefore.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/NotGenerateAssertTest.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/NotGenerateBasicMergeTest.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/NotGenerateBasicXYOffsetTest.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/NotGenerateDataReferenceTest.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/NotGenerateDataReplacementTest.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/NotGenerateMergeMassViaInsertAfter.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/NotGenerateMergeMassViaInsertBefore.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/NotGeneratePageReplacementTest.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/NotGenerateSectionReplacementTest.xml create mode 100644 dev/tests/verification/Tests/ResilientGenerationTest.php create mode 100644 dev/tests/verification/Tests/SuiteTestReferences.php diff --git a/composer.json b/composer.json index 813ab382b..92289622a 100755 --- a/composer.json +++ b/composer.json @@ -63,7 +63,7 @@ }, "autoload-dev": { "psr-4": { - "tests\\unit\\": "dev/tests/unit" + "tests\\": "dev/tests" } }, "scripts": { diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php index d2a58c0ff..ce7586eab 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php @@ -188,7 +188,13 @@ public function mockHandlers($testArray, $suiteArray) $property->setAccessible(true); $property->setValue($handler, $testArray); - AspectMock::double(SuiteObjectHandler::class, ['initSuiteData' => ''])->make(); + AspectMock::double( + SuiteObjectHandler::class, + [ + 'initSuiteData' => '', + 'parseSuccessful' => true, + ] + )->make(); $handler = SuiteObjectHandler::getInstance(); $property = new \ReflectionProperty(SuiteObjectHandler::class, 'suiteObjects'); $property->setAccessible(true); diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php index 8ac8fae37..a5832c44f 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php @@ -138,7 +138,7 @@ public function testGenerateEmptySuite() $this->setMockTestAndSuiteParserOutput($mockTestData, $mockData); // set expected error message - $this->expectExceptionMessage("Suites must not be empty. Suite: \"basicTestSuite\""); + $this->expectExceptionMessage("Suite basicTestSuite is not defined in xml or is invalid"); // parse and generate suite object with mocked data $mockSuiteGenerator = SuiteGenerator::getInstance(); @@ -180,7 +180,7 @@ public function testInvalidSuiteTestPair() $manifest = TestManifestFactory::makeManifest('default', $suiteConfig); // Set up Expected Exception - $this->expectException(TestReferenceException::class); + $this->expectException(\Exception::class); $this->expectExceptionMessageMatches('(Suite: "Suite2" Tests: "Test1")'); // parse and generate suite object with mocked data and manifest @@ -204,7 +204,7 @@ public function testNonExistentSuiteTestPair() $manifest = TestManifestFactory::makeManifest('default', $suiteConfig); // Set up Expected Exception - $this->expectException(TestReferenceException::class); + $this->expectException(\Exception::class); $this->expectExceptionMessageMatches('#Suite3 is not defined#'); // parse and generate suite object with mocked data and manifest diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php index 46bc6e346..c7ee8dffd 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php @@ -9,6 +9,7 @@ use AspectMock\Test as AspectMock; use Magento\FunctionalTestingFramework\Filter\FilterList; +use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Magento\FunctionalTestingFramework\Test\Objects\TestHookObject; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; @@ -41,13 +42,13 @@ public function testEntityException() $testObject = new TestObject("sampleTest", ["merge123" => $actionObject], [], [], "filename"); + AspectMock::double(TestObjectHandler::class, ['initTestData' => '']); + $testGeneratorObject = TestGenerator::getInstance("", ["sampleTest" => $testObject]); AspectMock::double(TestGenerator::class, ['loadAllTestObjects' => ["sampleTest" => $testObject]]); - $this->expectExceptionMessage("Could not resolve entity reference \"{{someEntity.entity}}\" " . - "in Action with stepKey \"fakeAction\".\n" . - "Exception occurred parsing action at StepKey \"fakeAction\" in Test \"sampleTest\""); + $this->expectExceptionMessage("ERROR: 1 Test failed to generate."); $testGeneratorObject->createAllTestFiles(null, []); } diff --git a/dev/tests/unit/Util/TestLoggingUtil.php b/dev/tests/unit/Util/TestLoggingUtil.php index 7becc609a..1b0bce1f9 100644 --- a/dev/tests/unit/Util/TestLoggingUtil.php +++ b/dev/tests/unit/Util/TestLoggingUtil.php @@ -93,7 +93,7 @@ public function validateMockLogStatmentRegex($type, $regex, $context) $records = $this->testLogHandler->getRecords(); $record = $records[count($records)-1]; // we assume the latest record is what requires validation $this->assertEquals(strtoupper($type), $record['level_name']); - $this->assertRegExp($regex, $record['message']); + $this->assertMatchesRegularExpression($regex, $record['message']); $this->assertEquals($context, $record['context']); } diff --git a/dev/tests/util/MftfTestCase.php b/dev/tests/util/MftfTestCase.php index 8bfa1009f..ae9e4dd79 100644 --- a/dev/tests/util/MftfTestCase.php +++ b/dev/tests/util/MftfTestCase.php @@ -80,6 +80,28 @@ public function validateSchemaErrorWithTest($fileContents, $objectType ,$expecte } } + /** + * Asserts that the given callback throws the given exception + * + * @param string $expectClass + * @param array $expectedMessages + * @param callable $callback + */ + protected function assertExceptionRegex(string $expectClass, array $expectedMessages, callable $callback) + { + try { + $callback(); + } catch (\Throwable $exception) { + $this->assertInstanceOf($expectClass, $exception, 'An invalid exception was thrown.'); + foreach ($expectedMessages as $expectedMessage) { + $this->assertMatchesRegularExpression($expectedMessage, $exception->getMessage()); + } + return; + } + + $this->fail('No exception was thrown.'); + } + /** * Clears test handler and object manager to force recollection of test data * diff --git a/dev/tests/verification/ResilientGenerationModule/ActionGroup/BasicActionGroup/NotGenerateArgActionGroup.xml b/dev/tests/verification/ResilientGenerationModule/ActionGroup/BasicActionGroup/NotGenerateArgActionGroup.xml new file mode 100644 index 000000000..5d0246b08 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/ActionGroup/BasicActionGroup/NotGenerateArgActionGroup.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="NotGenerateArgActionGroup"> + <arguments> + <argument name="someArgument" defaultValue="ReplacementPerson"/> + </arguments> + <see selector="{{SampleSection.threeParamElement(someArgument.firstname, someArgument.lastname, 'test')}}" userInput="{{someArgument.lastname}}" stepKey="seeLastName" /> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/ResilientGenerationModule/ActionGroup/BasicActionGroup/NotGenerateCreateDataActionGroup.xml b/dev/tests/verification/ResilientGenerationModule/ActionGroup/BasicActionGroup/NotGenerateCreateDataActionGroup.xml new file mode 100644 index 000000000..580c9081c --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/ActionGroup/BasicActionGroup/NotGenerateCreateDataActionGroup.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="NotGenerateCreateDataActionGroup"> + <createData entity="NotExtendParentData" stepKey="createData"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/ResilientGenerationModule/ActionGroup/BasicActionGroup/NotGenerateExtendChildActionGroup.xml b/dev/tests/verification/ResilientGenerationModule/ActionGroup/BasicActionGroup/NotGenerateExtendChildActionGroup.xml new file mode 100644 index 000000000..9566ad170 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/ActionGroup/BasicActionGroup/NotGenerateExtendChildActionGroup.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="NotGenerateExtendChildActionGroup" extends="NotGenerateExtendParentActionGroup"> + <arguments> + <argument name="otherCount" type="string"/> + </arguments> + <grabMultiple selector="notASelector" stepKey="grabProducts"/> + <comment userInput="New Input After" stepKey="afterGrabProducts" after="grabProducts"/> + <comment userInput="New Input Before" stepKey="beforeGrabProducts" before="grabProducts"/> + <assertCount stepKey="assertSecondCount"> + <expectedResult type="int">{{otherCount}}</expectedResult> + <actualResult type="variable">grabProducts</actualResult> + </assertCount> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/ResilientGenerationModule/ActionGroup/BasicActionGroup/NotGenerateExtendChildBadReferenceActionGroup.xml b/dev/tests/verification/ResilientGenerationModule/ActionGroup/BasicActionGroup/NotGenerateExtendChildBadReferenceActionGroup.xml new file mode 100644 index 000000000..4896c239f --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/ActionGroup/BasicActionGroup/NotGenerateExtendChildBadReferenceActionGroup.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="NotGenerateExtendChildBadReferenceActionGroup" extends="extendBasicActionGroup"> + <fillField stepKey="fill" selector="$name" userInput="$$N.N$$"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/ResilientGenerationModule/ActionGroup/BasicActionGroup/NotGenerateExtendParentActionGroup.xml b/dev/tests/verification/ResilientGenerationModule/ActionGroup/BasicActionGroup/NotGenerateExtendParentActionGroup.xml new file mode 100644 index 000000000..5e3cfaa54 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/ActionGroup/BasicActionGroup/NotGenerateExtendParentActionGroup.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="NotGenerateExtendParentActionGroup"> + <arguments> + <argument name="count" type="string"/> + </arguments> + <grabMultiple selector="selector" stepKey="grabProducts"/> + <assertCount stepKey="assertCount"> + <expectedResult type="int">{{count}}</expectedResult> + <actualResult type="variable">grabProducts</actualResult> + </assertCount> + <click stepKey="click" userInput="{{N.N}}" selector="#name"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/ResilientGenerationModule/ActionGroup/BasicActionGroup/NotGenerateParamsActionGroup.xml b/dev/tests/verification/ResilientGenerationModule/ActionGroup/BasicActionGroup/NotGenerateParamsActionGroup.xml new file mode 100644 index 000000000..29ebba5f7 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/ActionGroup/BasicActionGroup/NotGenerateParamsActionGroup.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="NotGenerateParamsActionGroup"> + <arguments> + <argument name="param" type="entity"/> + <argument name="param2" type="entity" defaultValue="simpleParamData"/> + </arguments> + <click selector="{{SampleSection.twoParamElement({$testVariable2}, param.firstname)}}" stepKey="click1"/> + <click selector="{{SampleSection.threeParamElement(param.lastname, param2.uniqueNamePre, {$testVariable})}}" stepKey="click2"/> + <seeElement selector="{{SampleSection.fourParamElement(param.middlename, {$testVariable}, {$testVariable2}, $$createSimpleData.name$$)}}" stepKey="see1"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/ResilientGenerationModule/ActionGroup/BasicActionGroup/NotGenerateSectionActionGroup.xml b/dev/tests/verification/ResilientGenerationModule/ActionGroup/BasicActionGroup/NotGenerateSectionActionGroup.xml new file mode 100644 index 000000000..81a4d4c8d --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/ActionGroup/BasicActionGroup/NotGenerateSectionActionGroup.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="NotGenerateSectionActionGroup"> + <arguments> + <argument name="section" defaultValue="SampleSection"/> + </arguments> + <executeJS function="{{section.oneParamElement('full-width')}}" stepKey="keyone"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/ResilientGenerationModule/ActionGroup/FunctionalActionGroup/NotGenerateMassMergeAfterActionGroup.xml b/dev/tests/verification/ResilientGenerationModule/ActionGroup/FunctionalActionGroup/NotGenerateMassMergeAfterActionGroup.xml new file mode 100644 index 000000000..5fc49e0b3 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/ActionGroup/FunctionalActionGroup/NotGenerateMassMergeAfterActionGroup.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="NotGenerateMassMergeAfter"> + <fillField selector="#foo" userInput="foo" stepKey="fillField1"/> + <fillField selector="#bar" userInput="bar" stepKey="fillField2"/> + <fillField selector="#baz" userInput="baz" stepKey="fillField3"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/ResilientGenerationModule/ActionGroup/FunctionalActionGroup/NotGenerateMassMergeBeforeActionGroup.xml b/dev/tests/verification/ResilientGenerationModule/ActionGroup/FunctionalActionGroup/NotGenerateMassMergeBeforeActionGroup.xml new file mode 100644 index 000000000..23352d61e --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/ActionGroup/FunctionalActionGroup/NotGenerateMassMergeBeforeActionGroup.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="NotGenerateMassMergeBefore"> + <fillField selector="#foo" userInput="foo" stepKey="fillField1"/> + <fillField selector="#bar" userInput="bar" stepKey="fillField2"/> + <fillField selector="#baz" userInput="baz" stepKey="fillField3"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/ResilientGenerationModule/ActionGroup/FunctionalActionGroup/NotGenerateMergeActionGroup.xml b/dev/tests/verification/ResilientGenerationModule/ActionGroup/FunctionalActionGroup/NotGenerateMergeActionGroup.xml new file mode 100644 index 000000000..6796df94e --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/ActionGroup/FunctionalActionGroup/NotGenerateMergeActionGroup.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="NotGenerateMergeActionGroup"> + <arguments> + <argument name="myArg"/> + </arguments> + <fillField stepKey="deleteMe" userInput="Please delete me" selector="#delete" /> + <see selector="{{SampleSectionN.oneParamElement(myArg.firstname)}}" stepKey="see1"/> + <amOnPage url="{{SamplePage.url(myArg.firstname,myArg.lastname)}}" stepKey="amOnPage1"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/ResilientGenerationModule/ActionGroup/MergeFunctionalActionGroup/NotGenerateMassMergeAfterActionGroup.xml b/dev/tests/verification/ResilientGenerationModule/ActionGroup/MergeFunctionalActionGroup/NotGenerateMassMergeAfterActionGroup.xml new file mode 100644 index 000000000..18d4332ac --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/ActionGroup/MergeFunctionalActionGroup/NotGenerateMassMergeAfterActionGroup.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="NotGenerateMassMergeAfter" insertAfter="NfillField2"> + <click stepKey="mergeAfterBar" selector="#foo2"/> + <click stepKey="mergeAfterFoo2" selector="#bar2"/> + <click stepKey="mergeAfterBar2" selector="#baz2"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/ResilientGenerationModule/ActionGroup/MergeFunctionalActionGroup/NotGenerateMassMergeBeforeActionGroup.xml b/dev/tests/verification/ResilientGenerationModule/ActionGroup/MergeFunctionalActionGroup/NotGenerateMassMergeBeforeActionGroup.xml new file mode 100644 index 000000000..07166d1fb --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/ActionGroup/MergeFunctionalActionGroup/NotGenerateMassMergeBeforeActionGroup.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="NotGenerateMassMergeBefore" insertBefore="fillField2N"> + <click stepKey="mergeBeforeBar" selector="#foo2"/> + <click stepKey="mergeAfterFoo2" selector="#bar2"/> + <click stepKey="mergeAfterBar2" selector="#baz2"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/ResilientGenerationModule/ActionGroup/MergeFunctionalActionGroup/NotGenerateMergeActionGroup.xml b/dev/tests/verification/ResilientGenerationModule/ActionGroup/MergeFunctionalActionGroup/NotGenerateMergeActionGroup.xml new file mode 100644 index 000000000..964a40a74 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/ActionGroup/MergeFunctionalActionGroup/NotGenerateMergeActionGroup.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="NotGenerateMergeActionGroup"> + <see stepKey="myMergedSeeElement" selector=".merge .{{myArg.firstname}}" before="see1"/> + <click stepKey="myMergedClick" selector=".merge .{{myArg.lastNname}}" after="amOnPage1"/> + <remove keyForRemoval="deleteMe"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/verification/ResilientGenerationModule/Data/ExtendedData.xml b/dev/tests/verification/ResilientGenerationModule/Data/ExtendedData.xml new file mode 100644 index 000000000..59243531e --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Data/ExtendedData.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="NotExtendParentData" extends="NparentData"> + <data key="name">otherName</data> + <data key="nameExtend">extendName</data> + <data key="uniqueNamePost">item</data> + <data key="anotherUniqueNamePre" unique="suffix">postnameExtend</data> + <requiredEntity type="item">value</requiredEntity> + </entity> +</entities> diff --git a/dev/tests/verification/ResilientGenerationModule/Suite/NotGenerateHookAfterSuite.xml b/dev/tests/verification/ResilientGenerationModule/Suite/NotGenerateHookAfterSuite.xml new file mode 100644 index 000000000..96054071e --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Suite/NotGenerateHookAfterSuite.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<suites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Suite/etc/suiteSchema.xsd"> + <suite name="NotGenerateHookAfterSuite"> + <include> + <test name="IncludeTest"/> + </include> + <before> + <amOnPage url="some.url" stepKey="before"/> + </before> + <after> + <actionGroup ref="actionGroupWithTwoArgumentsN" stepKey="AC"> + <argument name="somePerson" value="simpleData"/> + <argument name="anotherPerson" value="uniqueData"/> + </actionGroup> + </after> + </suite> +</suites> diff --git a/dev/tests/verification/ResilientGenerationModule/Suite/NotGenerateHookBeforeSuite.xml b/dev/tests/verification/ResilientGenerationModule/Suite/NotGenerateHookBeforeSuite.xml new file mode 100644 index 000000000..36e046114 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Suite/NotGenerateHookBeforeSuite.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<suites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Suite/etc/suiteSchema.xsd"> + <suite name="NotGenerateHookBeforeSuite"> + <include> + <test name="IncludeTest"/> + </include> + <before> + <actionGroup ref="actionGroupWithTwoArgumentsN" stepKey="AC"> + <argument name="somePerson" value="simpleData"/> + <argument name="anotherPerson" value="uniqueData"/> + </actionGroup> + </before> + <after> + <amOnPage url="some.url" stepKey="after"/> + </after> + </suite> +</suites> diff --git a/dev/tests/verification/ResilientGenerationModule/Suite/PartialGenerateForIncludeSuite.xml b/dev/tests/verification/ResilientGenerationModule/Suite/PartialGenerateForIncludeSuite.xml new file mode 100644 index 000000000..7e9f3d76c --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Suite/PartialGenerateForIncludeSuite.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<suites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Suite/etc/suiteSchema.xsd"> + <suite name="PartialGenerateForIncludeSuite"> + <include> + <test name="IncludeTest"/> + <group name = "N" /> + <test name="NotGenerateDataReferenceTest"/> + </include> + <exclude> + <test name="ExcludeTest2"/> + </exclude> + </suite> +</suites> diff --git a/dev/tests/verification/ResilientGenerationModule/Suite/PartialGenerateNoExcludeSuite.xml b/dev/tests/verification/ResilientGenerationModule/Suite/PartialGenerateNoExcludeSuite.xml new file mode 100644 index 000000000..cde48cbbb --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Suite/PartialGenerateNoExcludeSuite.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<suites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Suite/etc/suiteSchema.xsd"> + <suite name="PartialGenerateNoExcludeSuite"> + <include> + <test name="IncludeTest"/> + </include> + <exclude> + <test name="NotGenerateDataReferenceTest"/> + </exclude> + </suite> +</suites> diff --git a/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateArgTest.xml b/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateArgTest.xml new file mode 100644 index 000000000..8b98a9a19 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateArgTest.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateArgTest"> + <actionGroup ref="NotGenerateArgActionGroup" stepKey="actionGroup"> + <argument name="someArgument" value="N"/> + </actionGroup> + </test> +</tests> diff --git a/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateExtendChildTest.xml b/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateExtendChildTest.xml new file mode 100644 index 000000000..9f9d022f6 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateExtendChildTest.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateExtendChildTest"> + <actionGroup ref="NotGenerateExtendChildActionGroup" stepKey="actionGroup"> + <argument name="otherCount" value="2"/> + </actionGroup> + </test> +</tests> diff --git a/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateMassMergeAfterTest.xml b/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateMassMergeAfterTest.xml new file mode 100644 index 000000000..ed3f31a79 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateMassMergeAfterTest.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateMassMergeAferTest"> + <actionGroup ref="NotGenerateMassMergeAfter" stepKey="actionGroup"/> + </test> +</tests> diff --git a/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateMassMergeBeforeTest.xml b/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateMassMergeBeforeTest.xml new file mode 100644 index 000000000..1046138b4 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateMassMergeBeforeTest.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateMassMergeBeforeTest"> + <actionGroup ref="NotGenerateMassMergeBefore" stepKey="actionGroup"/> + </test> +</tests> diff --git a/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateMergeTest.xml b/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateMergeTest.xml new file mode 100644 index 000000000..7fa4684e0 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateMergeTest.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateMergeTest"> + <actionGroup ref="NotGenerateMergeActionGroup" stepKey="actionGroup"> + <argument name="myArg" value="N"/> + </actionGroup> + </test> +</tests> diff --git a/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateParamsTest.xml b/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateParamsTest.xml new file mode 100644 index 000000000..3704ba695 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateParamsTest.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateParamsTest"> + <actionGroup ref="NotGenerateParamsActionGroup" stepKey="actionGroup"> + <argument name="param" value="n"/> + <argument name="param2" value="o"/> + </actionGroup> + </test> +</tests> diff --git a/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateRequiredDataTest.xml b/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateRequiredDataTest.xml new file mode 100644 index 000000000..93da0c5ce --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateRequiredDataTest.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateRequiredDataTest"> + <actionGroup ref="NotGenerateRequiredDataActionGroup" stepKey="actionGroup"/> + </test> +</tests> diff --git a/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateSectionTest.xml b/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateSectionTest.xml new file mode 100644 index 000000000..3d7499b8b --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateSectionTest.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateSectionTest"> + <actionGroup ref="NotGenerateSectionActionGroup" stepKey="actionGroup"> + <argument name="section" value="N"/> + </actionGroup> + </test> +</tests> diff --git a/dev/tests/verification/ResilientGenerationModule/Test/ExtendTest/NotGenerateChildExtendedBadReferenceTest.xml b/dev/tests/verification/ResilientGenerationModule/Test/ExtendTest/NotGenerateChildExtendedBadReferenceTest.xml new file mode 100644 index 000000000..45e1177f1 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/ExtendTest/NotGenerateChildExtendedBadReferenceTest.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateChildExtendedBadReferenceTest" extends="ParentExtendedTest"> + <annotations> + <severity value="MINOR"/> + <title value="NotGenerateChildExtendedBadReferenceTest"/> + <features value="Child"/> + <stories value="Child"/> + </annotations> + <before> + <amOnPage url="/firstUrl" stepKey="firstBeforeAmOnPageKey" before="beforeAmOnPageKey"/> + <amOnPage url="/lastUrl" stepKey="lastBefore" after="beforeAmOnPageKey"/> + </before> + <comment stepKey="lastStepKey" userInput="Last Comment"/> + <comment stepKey="beforeBasicCommentWithNoData" userInput="{{N.N}}" before="basicCommentWithNoData"/> + <comment stepKey="afterBasicCommentWithNoData" userInput="After Comment" after="basicCommentWithNoData"/> + </test> +</tests> diff --git a/dev/tests/verification/ResilientGenerationModule/Test/ExtendTest/NotGenerateChildExtendedMergingTest.xml b/dev/tests/verification/ResilientGenerationModule/Test/ExtendTest/NotGenerateChildExtendedMergingTest.xml new file mode 100644 index 000000000..61f15a31a --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/ExtendTest/NotGenerateChildExtendedMergingTest.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateChildExtendedMergingTest" extends="ParentExtendedTest"> + <annotations> + <severity value="MINOR"/> + <title value="NotGenerateChildExtendedTestMerging"/> + <features value="Child"/> + <stories value="Child"/> + </annotations> + <before> + <amOnPage url="/firstUrl" stepKey="firstBeforeAmOnPageKey" before="beforeAmOnPageKey"/> + <amOnPage url="/lastUrl" stepKey="lastBefore" after="beforeAmOnPageKeyN"/> + </before> + <comment stepKey="lastStepKey" userInput="Last Comment"/> + <comment stepKey="beforeBasicCommentWithNoData" userInput="Before Comment" before="basicCommentWithNoData"/> + <comment stepKey="afterBasicCommentWithNoData" userInput="After Comment" after="basicCommentWithNoData"/> + </test> +</tests> diff --git a/dev/tests/verification/ResilientGenerationModule/Test/ExtendTest/NotGenerateExtendedChildTest.xml b/dev/tests/verification/ResilientGenerationModule/Test/ExtendTest/NotGenerateExtendedChildTest.xml new file mode 100644 index 000000000..75154b83d --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/ExtendTest/NotGenerateExtendedChildTest.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateExtendedChildTest" extends="NotGenerateParentTest"> + <annotations> + <severity value="MINOR"/> + <title value="NotGenerateExtendedChildTest"/> + <features value="NotGenerateExtendedChildTest"/> + <stories value="NotGenerateExtendedChildTest"/> + </annotations> + <comment stepKey="basicCommentWithNoData" userInput="Different Input"/> + </test> +</tests> diff --git a/dev/tests/verification/ResilientGenerationModule/Test/ExtendTest/NotGenerateParentTest.xml b/dev/tests/verification/ResilientGenerationModule/Test/ExtendTest/NotGenerateParentTest.xml new file mode 100644 index 000000000..0735ad13a --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/ExtendTest/NotGenerateParentTest.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateParentTest"> + <annotations> + <severity value="AVERAGE"/> + <title value="NotGenerateParentTest"/> + <features value="NotGenerateParentTest"/> + <stories value="NotGenerateParentTest"/> + </annotations> + <before> + <amOnPage url="{{NOTaPAGE.url}}" stepKey="beforeAmOnPageKey"/> + </before> + <after> + <amOnPage url="/afterUrl" stepKey="afterAmOnPageKey"/> + </after> + <comment stepKey="basicCommentWithNoData" userInput="Parent Comment"/> + <amOnPage url="/url/in/parent" stepKey="amOnPageInParent"/> + </test> +</tests> diff --git a/dev/tests/verification/ResilientGenerationModule/Test/MergeTest/NotGenerateBasicMergeTest.xml b/dev/tests/verification/ResilientGenerationModule/Test/MergeTest/NotGenerateBasicMergeTest.xml new file mode 100644 index 000000000..a2f68271c --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/MergeTest/NotGenerateBasicMergeTest.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateBasicMergeTest"> + <before> + <see stepKey="before2" selector="#before2" after="before1N"/> + </before> + <after> + <amOnPage url="/afterUrl1" stepKey="after1"/> + </after> + <click stepKey="step7Merge" selector="{{SampleSection.oneParamElement(DefaultPerson.firstname)}} .step7Merge" after="step6Merge"/> + <click stepKey="step2" selector="#step2" after="step1NNN"/> + <click stepKey="step4" selector="#step4" before="step5"/> + <remove keyForRemoval="step6"/> + <click stepKey="step6Merge" selector="#step6Merged" after="step5"/> + <click stepKey="step10" selector="#step10MergedInResult"/> + <actionGroup ref="FunctionalActionGroupWithData" stepKey="step8Merge" after="step7MergeNNN"/> + </test> +</tests> diff --git a/dev/tests/verification/ResilientGenerationModule/Test/MergeTest/NotGenerateMergeMassViaInsertAfter.xml b/dev/tests/verification/ResilientGenerationModule/Test/MergeTest/NotGenerateMergeMassViaInsertAfter.xml new file mode 100644 index 000000000..1bde12ac5 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/MergeTest/NotGenerateMergeMassViaInsertAfter.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateMergeMassViaInsertAfter" insertAfter="fillField2N"> + <click stepKey="clickOne" selector="#mergeOne"/> + <click stepKey="clickTwo" selector="#mergeTwo"/> + <click stepKey="clickThree" selector="#mergeThree"/> + </test> +</tests> diff --git a/dev/tests/verification/ResilientGenerationModule/Test/MergeTest/NotGenerateMergeMassViaInsertBefore.xml b/dev/tests/verification/ResilientGenerationModule/Test/MergeTest/NotGenerateMergeMassViaInsertBefore.xml new file mode 100644 index 000000000..fba36fa01 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/MergeTest/NotGenerateMergeMassViaInsertBefore.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateMergeMassViaInsertBefore" insertBefore="fillField2N"> + <click stepKey="clickOne" selector="#mergeOne"/> + <click stepKey="clickTwo" selector="#mergeTwo"/> + <click stepKey="clickThree" selector="#mergeThree"/> + </test> +</tests> diff --git a/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateAssertTest.xml b/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateAssertTest.xml new file mode 100644 index 000000000..77368f232 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateAssertTest.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateAssertTest"> + <before> + <createData entity="ReplacementPerson" stepKey="createData1"/> + </before> + <createData entity="UniquePerson" stepKey="createData2"/> + <grabTextFrom selector=".copyright>span" stepKey="grabTextFrom1"/> + + <!-- assert entity resolution --> + <assertEquals stepKey="assertEqualsEntity" message="pass"> + <expectedResult type="string">{{simpleData.firstnameN}}</expectedResult> + <actualResult type="string">{{simpleData.lastname}}</actualResult> + </assertEquals> + </test> +</tests> diff --git a/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateBasicMergeTest.xml b/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateBasicMergeTest.xml new file mode 100644 index 000000000..7344b4f42 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateBasicMergeTest.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateBasicMergeTest"> + <annotations> + <severity value="CRITICAL"/> + <title value="NotGenerateBasicMergeTest"/> + <features value="Merge Functional Cest"/> + <stories value="MQE-433"/> + </annotations> + <before> + <amOnPage url="/beforeUrl" stepKey="before1"/> + </before> + <after> + <amOnPage url="/afterUrl" stepKey="after1"/> + </after> + <amOnPage stepKey="step1" url="/step1"/> + <fillField stepKey="step3" selector="#username" userInput="step3"/> + <fillField stepKey="step5" selector="#password" userInput="step5"/> + <click stepKey="step6" selector=".step6"/> + <click stepKey="step10" selector="#step10ShouldNotInResult"/> + </test> +</tests> diff --git a/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateBasicXYOffsetTest.xml b/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateBasicXYOffsetTest.xml new file mode 100644 index 000000000..5fee83988 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateBasicXYOffsetTest.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateBasicXYOffsetTest"> + <clickWithLeftButton selector="{{SampleSection.simpleElement}}{{SampleSection.simpleElementOneParam(offset.x)}}" x="{{offsetN.x}}" y="{{offset.y}}" stepKey="clickWithLeftButtonKeyXY1" /> + <clickWithRightButton selector="{{SampleSection.simpleElementOneParam('4123')}}{{SampleSection.simpleElement}}" x="{{offset.x}}" y="{{offset.yN}}" stepKey="clickWithRightButtonKeyXY1" /> + </test> +</tests> diff --git a/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateDataReferenceTest.xml b/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateDataReferenceTest.xml new file mode 100644 index 000000000..be05ca994 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateDataReferenceTest.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateDataReferenceTest"> + <fillField stepKey="fill" userInput="{{NotExtendParentData.name}}" selector="#name"/> + </test> +</tests> diff --git a/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateDataReplacementTest.xml b/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateDataReplacementTest.xml new file mode 100644 index 000000000..efab25f7e --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateDataReplacementTest.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateDataReplacementTest"> + <fillField stepKey="inputReplace" selector="#selector" userInput="StringBefore {{simpleDataN.firstname}} StringAfter"/> + <seeCurrentUrlMatches stepKey="seeInRegex" regex="~\/{{simpleData.Nfirstname}}~i"/> + <fillField stepKey="selectorReplace" selector="#{{simpleData.Nfirstname}}" userInput="input"/> + <dragAndDrop stepKey="selector12Replace" selector1="#{{simpleData.Nfirstname}}" selector2="{{NsimpleData.lastname}}"/> + <conditionalClick stepKey="dependentSelectorReplace" dependentSelector="#{{simpleData.Nfirstname}}" selector="{{simpleDataN.lastname}}" visible="true"/> + <amOnUrl stepKey="urlReplace" url="{{simpleData.firstnameN}}.html"/> + <searchAndMultiSelectOption stepKey="parameterArrayReplacement" selector="#selector" parameterArray="[{{simpleData.firstnameN}}, {{NsimpleData.lastname}}]"/> + + <seeInPageSource html="StringBefore {{simpleData.Nfirstname}} StringAfter" stepKey="htmlReplace1"/> + <seeInPageSource html="#{{simpleDataN.firstname}}" stepKey="htmlReplace2"/> + </test> +</tests> \ No newline at end of file diff --git a/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateMergeMassViaInsertAfter.xml b/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateMergeMassViaInsertAfter.xml new file mode 100644 index 000000000..1f2bae414 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateMergeMassViaInsertAfter.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateMergeMassViaInsertAfter"> + <fillField selector="#foo" userInput="foo" stepKey="fillField1"/> + <fillField selector="#bar" userInput="bar" stepKey="fillField2"/> + <fillField selector="#baz" userInput="baz" stepKey="fillField3"/> + </test> +</tests> diff --git a/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateMergeMassViaInsertBefore.xml b/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateMergeMassViaInsertBefore.xml new file mode 100644 index 000000000..ceb7f2e81 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateMergeMassViaInsertBefore.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateMergeMassViaInsertBefore"> + <fillField selector="#foo" userInput="foo" stepKey="fillField1"/> + <fillField selector="#bar" userInput="bar" stepKey="fillField2"/> + <fillField selector="#baz" userInput="baz" stepKey="fillField3"/> + </test> +</tests> diff --git a/dev/tests/verification/ResilientGenerationModule/Test/NotGeneratePageReplacementTest.xml b/dev/tests/verification/ResilientGenerationModule/Test/NotGeneratePageReplacementTest.xml new file mode 100644 index 000000000..1a4a61336 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/NotGeneratePageReplacementTest.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGeneratePageReplacementTest"> + <createData entity="simpleData" stepKey="datakey"/> + <amOnPage stepKey="noParamPage" url="{{NoParamPageN.url}}"/> + <amOnPage stepKey="noParamPageN" url="{{NoParamPage.urlN}}"/> + <amOnPage stepKey="oneParamPageString" url="{{OneParamPage.url('StringLiteral', 'N')}}"/> + <amOnPage stepKey="oneParamPageData" url="{{OneParamPage.url(simpleDataN.firstname)}}"/> + <amOnPage stepKey="oneParamPagePersist" url="{{OneParamPage.url($datakey.firstnameN$)}}"/> + <amOnPage stepKey="twoParamPageString" url="{{TwoParamPage.url('StringLiteral1')}}"/> + <amOnPage stepKey="twoParamPageStringData" url="{{TwoParamPage.url(simpleData.firstnameN, 'StringLiteral2')}}"/> + <amOnPage stepKey="twoParamPageDataPersist" url="{{TwoParamPage.url(simpleData.firstname, $datakey.firstnameN$)}}"/> + <amOnPage stepKey="twoParamPagePersistString" url="{{TwoParamPage.url($datakey.firstnameN$, 'StringLiteral2')}}"/> + </test> +</tests> \ No newline at end of file diff --git a/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateSectionReplacementTest.xml b/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateSectionReplacementTest.xml new file mode 100644 index 000000000..ea527d49f --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateSectionReplacementTest.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateSectionReplacementTest"> + <click stepKey="selectorReplace" selector="{{SampleSectionN.simpleElement}}"/> + <click stepKey="selectorReplaceTimeout" selector="{{SampleSection.timeoutElementN}}"/> + + <click stepKey="selectorReplaceOneParam" selector="{{SampleSection.oneParamElement('stringLiteral', 'N')}}"/> + <click stepKey="selectorReplaceTwoParam" selector="{{SampleSection.twoParamElement('stringLiteral1')}}"/> + + <click stepKey="selectorReplaceThreeParamDataRef" selector="{{SampleSection.threeParamElement(simpleData.firstname, simpleDataN.lastname, simpleData.middlename)}}"/> + <click stepKey="selectorReplaceThreeParamOneDupeDataRef" selector="{{SampleSection.threeOneDuplicateParamElement(simpleData.firstname, simpleData.lastname, simpleData.Nmiddlename)}}"/> + + <click stepKey="selectorReplaceOneParamVariable" selector="{{SampleSection.oneParamElement({$dataN})}}"/> + + <click stepKey="selectorReplaceThreeParamMixed1" selector="{{SampleSection.threeParamElement('stringLiteral1', $createdData.Nfirstname$, simpleData.firstname)}}"/> + <click stepKey="selectorReplaceThreeParamMixed2" selector="{{SampleSection.threeParamElement('stringLiteral1', $NcreatedData.firstname$, {$data})}}"/> + + <click stepKey="selectorReplaceTwoParamElements" selector="{{SampleSection.oneParamElement('1')}}{{SampleSectionN.oneParamElement('2')}}"/> + <click stepKey="selectorReplaceTwoParamMixedTypes" selector="{{SampleSection.oneParamElement('1')}}{{SampleSection.oneParamElementN({$data})}}"/> + </test> +</tests> diff --git a/dev/tests/verification/Tests/ResilientGenerationTest.php b/dev/tests/verification/Tests/ResilientGenerationTest.php new file mode 100644 index 000000000..418dfee12 --- /dev/null +++ b/dev/tests/verification/Tests/ResilientGenerationTest.php @@ -0,0 +1,294 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace tests\verification\Tests; + +use Magento\FunctionalTestingFramework\Suite\Handlers\SuiteObjectHandler; +use Magento\FunctionalTestingFramework\Suite\SuiteGenerator; +use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; +use Magento\FunctionalTestingFramework\Util\Filesystem\DirSetupUtil; +use Magento\FunctionalTestingFramework\Util\Manifest\TestManifestFactory; +use Magento\FunctionalTestingFramework\Util\TestGenerator; +use Symfony\Component\Yaml\Yaml; +use tests\unit\Util\TestLoggingUtil; +use tests\util\MftfTestCase; + +class ResilientGenerationTest extends MftfTestCase +{ + const RESOURCES_DIR = TESTS_BP . DIRECTORY_SEPARATOR . 'verification' . DIRECTORY_SEPARATOR . 'Resources'; + const CONFIG_YML_FILE = TESTS_BP . DIRECTORY_SEPARATOR . SuiteGenerator::YAML_CODECEPTION_CONFIG_FILENAME; + const GENERATE_RESULT_DIR = TESTS_BP . + DIRECTORY_SEPARATOR . + "verification" . + DIRECTORY_SEPARATOR . + "_generated" . + DIRECTORY_SEPARATOR; + + /** + * Exception group names and log messages + * + * @var string[][] + */ + private static $exceptionGrpLogs = [ + 'PartialGenerateForIncludeSuite' => [ + '/Failed to generate tests for suite "PartialGenerateForIncludeSuite"/' + ], + 'NotGenerateHookBeforeSuite' => [ + '/Suite NotGenerateHookBeforeSuite is not defined in xml or is invalid./' + ], + 'NotGenerateHookAfterSuite' => [ + '/Suite NotGenerateHookAfterSuite is not defined in xml or is invalid./' + ] + ]; + + /** + * Set up for testing + */ + public static function setUpBeforeClass(): void + { + // destroy _generated if it exists + if (file_exists(self::GENERATE_RESULT_DIR)) { + DirSetupUtil::rmdirRecursive(self::GENERATE_RESULT_DIR); + } + } + + public function setUp(): void + { + // copy config yml file to test dir + $fileSystem = new \Symfony\Component\Filesystem\Filesystem(); + $fileSystem->copy( + realpath( + FW_BP + . DIRECTORY_SEPARATOR + . 'etc' + . DIRECTORY_SEPARATOR + . 'config' + . DIRECTORY_SEPARATOR + . 'codeception.dist.yml' + ), + self::CONFIG_YML_FILE + ); + + TestLoggingUtil::getInstance()->setMockLoggingUtil(); + + $property = new \ReflectionProperty(SuiteGenerator::class, "instance"); + $property->setAccessible(true); + $property->setValue(null); + + $property = new \ReflectionProperty(DirSetupUtil::class, "DIR_CONTEXT"); + $property->setAccessible(true); + $property->setValue([]); + + $property = new \ReflectionProperty(SuiteObjectHandler::class, "instance"); + $property->setAccessible(true); + $property->setValue(null); + + $property = new \ReflectionProperty(TestObjectHandler::class, "testObjectHandler"); + $property->setAccessible(true); + $property->setValue(null); + } + + /** + * Test resilient generate all tests + */ + public function testGenerateAllTests() + { + $exceptionMessage = '/ERROR: 21 Test failed to generate./'; + + $testManifest = TestManifestFactory::makeManifest('default', []); + // Validate exception is thrown + $this->assertExceptionRegex( + \Exception::class, + [$exceptionMessage], + function () use ($testManifest) { + TestGenerator::getInstance(null, [])->createAllTestFiles($testManifest); + } + ); + + // Validate tests have been generated + $dirContents = array_diff( + scandir(self::GENERATE_RESULT_DIR . DIRECTORY_SEPARATOR . 'default'), + ['..', '.'] + ); + + foreach ($dirContents as $dirContent) { + $this->assertStringStartsNotWith( + 'NotGenerate', + $dirContent, + "string {$dirContent} should not contains \"NotGenerate\"" + ); + } + + // Validate log message + TestLoggingUtil::getInstance()->validateMockLogStatmentRegex( + 'error', + $exceptionMessage, + [] + ); + } + + /** + * Test resilient generate all suites + */ + public function testGenerateAllSuites() + { + $testManifest = TestManifestFactory::makeManifest('', []); + + // Validate exception is thrown + $exceptionMessage = '/' + . preg_quote( + 'Failed to generate tests for suite "PartialGenerateForIncludeSuite"' + ) + . '/'; + $this->assertExceptionRegex( + \Exception::class, + [$exceptionMessage], + function () use ($testManifest) { + SuiteGenerator::getInstance()->generateAllSuites($testManifest); + } + ); + + foreach (SuiteTestReferences::$data as $groupName => $expectedContents) { + if (substr($groupName, 0, 11) != 'NotGenerate') { + // Validate Yaml file updated + $yml = Yaml::parse(file_get_contents(self::CONFIG_YML_FILE)); + $this->assertArrayHasKey($groupName, $yml['groups']); + + $suiteResultBaseDir = self::GENERATE_RESULT_DIR . + DIRECTORY_SEPARATOR . + $groupName . + DIRECTORY_SEPARATOR; + + // Validate suite and tests have been generated + $dirContents = array_diff(scandir($suiteResultBaseDir), ['..', '.']); + + foreach ($expectedContents as $expectedFile) { + $this->assertTrue(in_array($expectedFile, $dirContents)); + } + } else { + $dirContents = array_diff(scandir(self::GENERATE_RESULT_DIR), ['..', '.']); + + // Validate suite is not generated + $this->assertFalse(in_array($groupName, $dirContents)); + } + } + + // Validate log message + TestLoggingUtil::getInstance()->validateMockLogStatmentRegex( + 'error', + $exceptionMessage, + [] + ); + } + + /** + * Test resilient generate some suites + */ + public function testGenerateSomeSuites() + { + $suites = [ + 'PartialGenerateForIncludeSuite', + 'PartialGenerateNoExcludeSuite', + 'NotGenerateHookBeforeSuite', + 'NotGenerateHookAfterSuite', + ]; + + foreach ($suites as $groupName) { + $expectedContents = SuiteTestReferences::$data[$groupName]; + if (!in_array($groupName, array_keys(self::$exceptionGrpLogs))) { + SuiteGenerator::getInstance()->generateSuite($groupName); + } else { + // Validate exception is thrown + $this->assertExceptionRegex( + \Exception::class, + self::$exceptionGrpLogs[$groupName], + function () use ($groupName) { + SuiteGenerator::getInstance()->generateSuite($groupName); + } + ); + } + + if (substr($groupName, 0, 11) != 'NotGenerate') { + // Validate Yaml file updated + $yml = Yaml::parse(file_get_contents(self::CONFIG_YML_FILE)); + $this->assertArrayHasKey($groupName, $yml['groups']); + + $suiteResultBaseDir = self::GENERATE_RESULT_DIR . + DIRECTORY_SEPARATOR . + $groupName . + DIRECTORY_SEPARATOR; + + // Validate tests have been generated + $dirContents = array_diff(scandir($suiteResultBaseDir), ['..', '.']); + + foreach ($expectedContents as $expectedFile) { + $this->assertTrue(in_array($expectedFile, $dirContents)); + } + } else { + $dirContents = array_diff(scandir(self::GENERATE_RESULT_DIR), ['..', '.']); + + // Validate suite is not generated + $this->assertFalse(in_array($groupName, $dirContents)); + } + + // Validate log message + if (substr($groupName, 0, 11) != 'NotGenerate' + && !in_array($groupName, array_keys(self::$exceptionGrpLogs))) { + $type = 'info'; + $message = '/suite generated/'; + $context = [ + 'suite' => $groupName, + 'relative_path' => "_generated" . DIRECTORY_SEPARATOR . $groupName + ]; + } else { + $type = 'error'; + $message = self::$exceptionGrpLogs[$groupName][0]; + $context = []; + } + TestLoggingUtil::getInstance()->validateMockLogStatmentRegex($type, $message, $context); + } + } + + /** + * + * revert any changes made to config.yml + * remove _generated directory + */ + public function tearDown(): void + { + DirSetupUtil::rmdirRecursive(self::GENERATE_RESULT_DIR); + + // delete config yml file from test dir + $fileSystem = new \Symfony\Component\Filesystem\Filesystem(); + $fileSystem->remove( + self::CONFIG_YML_FILE + ); + + $property = new \ReflectionProperty(SuiteGenerator::class, "instance"); + $property->setAccessible(true); + $property->setValue(null); + + $property = new \ReflectionProperty(DirSetupUtil::class, "DIR_CONTEXT"); + $property->setAccessible(true); + $property->setValue([]); + + $property = new \ReflectionProperty(SuiteObjectHandler::class, "instance"); + $property->setAccessible(true); + $property->setValue(null); + + $property = new \ReflectionProperty(TestObjectHandler::class, "testObjectHandler"); + $property->setAccessible(true); + $property->setValue(null); + } + + /** + * Remove yml if created during tests and did not exist before + */ + public static function tearDownAfterClass(): void + { + TestLoggingUtil::getInstance()->clearMockLoggingUtil(); + } +} diff --git a/dev/tests/verification/Tests/SuiteGenerationTest.php b/dev/tests/verification/Tests/SuiteGenerationTest.php index f37283871..064b4d3b0 100644 --- a/dev/tests/verification/Tests/SuiteGenerationTest.php +++ b/dev/tests/verification/Tests/SuiteGenerationTest.php @@ -13,7 +13,6 @@ use Magento\FunctionalTestingFramework\Util\Manifest\ParallelTestManifest; use Magento\FunctionalTestingFramework\Util\Manifest\TestManifestFactory; use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; -use PHPUnit\Util\Filesystem; use Symfony\Component\Yaml\Yaml; use tests\unit\Util\TestLoggingUtil; use tests\util\MftfTestCase; @@ -74,12 +73,7 @@ public function testSuiteGeneration1() { $groupName = 'functionalSuite1'; - $expectedContents = [ - 'additionalTestCest.php', - 'additionalIncludeTest2Cest.php', - 'IncludeTest2Cest.php', - 'IncludeTestCest.php' - ]; + $expectedContents = SuiteTestReferences::$data[$groupName]; // Generate the Suite SuiteGenerator::getInstance()->generateSuite($groupName); @@ -124,12 +118,7 @@ public function testSuiteGenerationParallel() 'functionalSuite1_3_G' ]; - $expectedContents = [ - 'additionalTestCest.php', - 'additionalIncludeTest2Cest.php', - 'IncludeTest2Cest.php', - 'IncludeTestCest.php' - ]; + $expectedContents = SuiteTestReferences::$data[$groupName]; //createParallelManifest /** @var ParallelTestManifest $parallelManifest */ @@ -175,9 +164,7 @@ public function testSuiteGenerationHooks() { $groupName = 'functionalSuiteHooks'; - $expectedContents = [ - 'IncludeTestCest.php' - ]; + $expectedContents = SuiteTestReferences::$data[$groupName]; // Generate the Suite SuiteGenerator::getInstance()->generateSuite($groupName); @@ -235,12 +222,7 @@ public function testSuiteGenerationSingleRun() //using functionalSuite2 to avoid directory caching $groupName = 'functionalSuite2'; - $expectedContents = [ - 'additionalTestCest.php', - 'additionalIncludeTest2Cest.php', - 'IncludeTest2Cest.php', - 'IncludeTestCest.php' - ]; + $expectedContents = SuiteTestReferences::$data[$groupName]; //createParallelManifest /** @var DefaultTestManifest $parallelManifest */ @@ -294,9 +276,7 @@ public function testSuiteGenerationWithExtends() { $groupName = 'suiteExtends'; - $expectedFileNames = [ - 'ExtendedChildTestInSuiteCest' - ]; + $expectedFileNames = SuiteTestReferences::$data[$groupName]; // Generate the Suite SuiteGenerator::getInstance()->generateSuite($groupName); @@ -321,10 +301,10 @@ public function testSuiteGenerationWithExtends() $dirContents = array_diff(scandir($suiteResultBaseDir), ['..', '.']); foreach ($expectedFileNames as $expectedFileName) { - $this->assertTrue(in_array($expectedFileName . ".php", $dirContents)); + $this->assertTrue(in_array($expectedFileName, $dirContents)); $this->assertFileEquals( - self::RESOURCES_PATH . DIRECTORY_SEPARATOR . $expectedFileName . ".txt", - $suiteResultBaseDir . $expectedFileName . ".php" + self::RESOURCES_PATH . DIRECTORY_SEPARATOR . substr($expectedFileName, 0, strlen($expectedFileName)-4) . ".txt", + $suiteResultBaseDir . $expectedFileName ); } } @@ -336,9 +316,7 @@ public function testSuiteCommentsGeneration() { $groupName = 'functionalSuiteWithComments'; - $expectedContents = [ - 'IncludeTestCest.php' - ]; + $expectedContents = SuiteTestReferences::$data[$groupName]; // Generate the Suite SuiteGenerator::getInstance()->generateSuite($groupName); @@ -395,9 +373,7 @@ public function testSuiteGenerationActionsInDifferentModules() { $groupName = 'ActionsInDifferentModulesSuite'; - $expectedContents = [ - 'IncludeActionsInDifferentModulesTestCest.php' - ]; + $expectedContents = SuiteTestReferences::$data[$groupName]; // Generate the Suite SuiteGenerator::getInstance()->generateSuite($groupName); diff --git a/dev/tests/verification/Tests/SuiteTestReferences.php b/dev/tests/verification/Tests/SuiteTestReferences.php new file mode 100644 index 000000000..800285528 --- /dev/null +++ b/dev/tests/verification/Tests/SuiteTestReferences.php @@ -0,0 +1,65 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace tests\verification\Tests; + +class SuiteTestReferences +{ + /** + * Array of suite to tests that the suite contains + * + * @var array + */ + public static $data = [ + 'functionalSuite1' => [ + 'additionalTestCest.php', + 'additionalIncludeTest2Cest.php', + 'IncludeTest2Cest.php', + 'IncludeTestCest.php' + ], + 'functionalSuiteHooks' => [ + 'IncludeTestCest.php' + ], + 'functionalSuite2' => [ + 'additionalTestCest.php', + 'additionalIncludeTest2Cest.php', + 'IncludeTest2Cest.php', + 'IncludeTestCest.php' + ], + 'suiteExtends' => [ + 'ExtendedChildTestInSuiteCest.php' + ], + 'functionalSuiteWithComments' => [ + 'IncludeTestCest.php' + ], + 'ActionsInDifferentModulesSuite' => [ + 'IncludeActionsInDifferentModulesTestCest.php' + ], + 'suiteWithMultiplePauseActionsSuite' => [ + 'additionalTestCest.php', + 'ExcludeTest2Cest.php', + 'IncludeTest2Cest.php' + ], + 'suiteWithPauseActionSuite' => [ + 'additionalTestCest.php', + 'ExcludeTest2Cest.php', + 'IncludeTest2Cest.php' + ], + 'PartialGenerateForIncludeSuite' => [ + 'IncludeTestCest.php' + ], + 'PartialGenerateNoExcludeSuite' => [ + 'IncludeTestCest.php' + ], + 'NotGenerateHookBeforeSuite' => [ + ], + 'NotGenerateHookAfterSuite' => [ + ], + 'deprecationCheckSuite' => [ + 'DeprecationCheckDeprecatedTestCest.php', + 'DeprecationCheckTestCest.php' + ], + ]; +} diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php index 547698b76..0f776d113 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php @@ -65,19 +65,20 @@ protected function execute(InputInterface $input, OutputInterface $output) $suites = $input->getArgument('suites'); + $errMessages = []; foreach ($suites as $suite) { - SuiteGenerator::getInstance()->generateSuite($suite); - if ($output->isVerbose()) { - $output->writeLn("suite $suite generated"); + try { + SuiteGenerator::getInstance()->generateSuite($suite); + } catch (\Exception $e) { + $errMessages[] = $e->getMessage(); } } - if ($this->cmdStatus) { + if ($this->cmdStatus && empty($errMessages)) { $output->writeLn("Suites Generated"); return 0; } else { - $output->writeLn("Suite parsing error found. See mftf.log for details."); - $output->writeLn("Suites Generated"); + $output->writeLn("Suites Generated (with failures)"); return 1; } } diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php index 561140432..d8494fee3 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php @@ -164,7 +164,7 @@ protected function execute(InputInterface $input, OutputInterface $output) if (!empty($errMessages)) { foreach (array_unique($errMessages) as $errMessage) { $output->writeln($errMessage); - $output->writeln("\nGenerate Tests Command Run"); + $output->writeln("\nGenerate Tests Command Run (with failures)"); } return 1; } else { diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php index cae401314..040fe6b6b 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php @@ -66,6 +66,7 @@ protected function configure() * * @SuppressWarnings(PHPMD.UnusedLocalVariable) * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ protected function execute(InputInterface $input, OutputInterface $output): int { diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php index 8975030de..b23938d1f 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php @@ -53,6 +53,7 @@ protected function configure() * * @SuppressWarnings(PHPMD.UnusedLocalVariable) * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) */ protected function execute(InputInterface $input, OutputInterface $output): int { diff --git a/src/Magento/FunctionalTestingFramework/Suite/Handlers/SuiteObjectHandler.php b/src/Magento/FunctionalTestingFramework/Suite/Handlers/SuiteObjectHandler.php index d78e495d8..fb058efa5 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Handlers/SuiteObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Handlers/SuiteObjectHandler.php @@ -36,7 +36,7 @@ class SuiteObjectHandler implements ObjectHandlerInterface /** * If suites parsing are successful * - * @var bool + * @var boolean */ private $status; @@ -80,7 +80,9 @@ public static function getInstance(): ObjectHandlerInterface public function getObject($objectName): SuiteObject { if (!array_key_exists($objectName, $this->suiteObjects)) { - throw new TestReferenceException("Suite ${objectName} is not defined in xml."); + throw new TestReferenceException( + "Suite ${objectName} is not defined in xml or is invalid." + ); } return $this->suiteObjects[$objectName]; } @@ -98,9 +100,9 @@ public function getAllObjects(): array /** * Return if there is any parsing errors * - * @return bool + * @return boolean */ - public function parseSuccessful(): bool + public function parseSuccessful() { return $this->status; } diff --git a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php index 2bf105b7b..5e6dd2f31 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php @@ -20,6 +20,7 @@ use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Magento\FunctionalTestingFramework\Util\TestGenerator; use Symfony\Component\Yaml\Yaml; +use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; /** * Class SuiteGenerator @@ -118,7 +119,7 @@ public function generateAllSuites($testManifest) $this->generateSplitSuiteFromTest($suiteName, $suiteContent); } } catch (\Exception $e) { - $exceptionCollector->addError(self::class, $e->getMessage()); + $exceptionCollector->addError(self::class, self::class . ': ' . $e->getMessage()); } } // Report failure @@ -149,6 +150,8 @@ public function generateSuite($suiteName) * @param string $originalSuiteName * @return void * @throws \Exception + * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ private function generateSuiteFromTest($suiteName, $tests = [], $originalSuiteName = null) { @@ -156,33 +159,57 @@ private function generateSuiteFromTest($suiteName, $tests = [], $originalSuiteNa $fullPath = FilePathFormatter::format(TESTS_MODULE_PATH) . $relativePath . DIRECTORY_SEPARATOR; DirSetupUtil::createGroupDir($fullPath); - - $relevantTests = []; $exceptionCollector = new ExceptionCollector(); - if (!empty($tests)) { - $this->validateTestsReferencedInSuite($suiteName, $tests, $originalSuiteName); - foreach ($tests as $testName) { - try { - $relevantTests[$testName] = TestObjectHandler::getInstance()->getObject($testName); - } catch (\Exception $e) { - $exceptionCollector->addError( - self::class, - "Unable to find relevant test \"{$testName}\" for suite \"{$suiteName}\"\n" . $e->getMessage() - ); + try { + $relevantTests = []; + if (!empty($tests)) { + $this->validateTestsReferencedInSuite($suiteName, $tests, $originalSuiteName); + foreach ($tests as $testName) { + try { + $relevantTests[$testName] = TestObjectHandler::getInstance()->getObject($testName); + } catch (\Exception $e) { + $exceptionCollector->addError( + self::class, + "Unable to find relevant test \"{$testName}\" for suite \"{$suiteName}\"" + ); + } } + } else { + $relevantTests = SuiteObjectHandler::getInstance()->getObject($suiteName)->getTests(); } - } else { - $relevantTests = SuiteObjectHandler::getInstance()->getObject($suiteName)->getTests(); - } - $this->generateRelevantGroupTests($suiteName, $relevantTests); - $groupNamespace = $this->generateGroupFile($suiteName, $relevantTests, $originalSuiteName); + if (empty($relevantTests)) { + $exceptionCollector->reset(); + throw new TestFrameworkException("No relevant test found for suite \"{$suiteName}\""); + } - $this->appendEntriesToConfig($suiteName, $fullPath, $groupNamespace); - LoggingUtil::getInstance()->getLogger(SuiteGenerator::class)->info( - "suite generated", - ['suite' => $suiteName, 'relative_path' => $relativePath] - ); + try { + $this->generateRelevantGroupTests($suiteName, $relevantTests); + } catch (\Exception $e) { + $exceptionCollector->addError( + self::class, + "Failed to generate tests for suite \"{$suiteName}\"" + ); + } + + $groupNamespace = $this->generateGroupFile($suiteName, $relevantTests, $originalSuiteName); + + $this->appendEntriesToConfig($suiteName, $fullPath, $groupNamespace); + + if (MftfApplicationConfig::getConfig()->verboseEnabled() + && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { + print("suite {$suiteName} generated\n"); + } + LoggingUtil::getInstance()->getLogger(self::class)->info( + "suite generated", + ['suite' => $suiteName, 'relative_path' => $relativePath] + ); + } catch (\Exception $e) { + if (file_exists($fullPath)) { + DirSetupUtil::rmdirRecursive($fullPath); + } + $exceptionCollector->addError(self::class, $e->getMessage()); + } $this->throwCollectedExceptions($exceptionCollector); } @@ -401,10 +428,10 @@ private function throwCollectedExceptions($exceptionCollector) foreach ($exceptionCollector->getErrors() as $file => $errorMessage) { if (is_array($errorMessage)) { foreach (array_unique($errorMessage) as $message) { - LoggingUtil::getInstance()->getLogger(SuiteGenerator::class)->error($message); + LoggingUtil::getInstance()->getLogger(self::class)->error(trim($message)); } } else { - LoggingUtil::getInstance()->getLogger(SuiteGenerator::class)->error($errorMessage); + LoggingUtil::getInstance()->getLogger(self::class)->error(trim($errorMessage)); } } $exceptionCollector->throwException(); diff --git a/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php index 82a154e3c..72193aaa5 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php @@ -8,18 +8,16 @@ use Exception; use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Suite\Objects\SuiteObject; -use Magento\FunctionalTestingFramework\Suite\SuiteGenerator; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; use Magento\FunctionalTestingFramework\Test\Util\BaseObjectExtractor; use Magento\FunctionalTestingFramework\Test\Util\TestHookObjectExtractor; use Magento\FunctionalTestingFramework\Test\Util\TestObjectExtractor; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; -use Magento\FunctionalTestingFramework\Util\ModuleResolver; -use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Magento\FunctionalTestingFramework\Util\Validation\NameValidationUtil; -use Symfony\Component\Finder\Finder; use Magento\FunctionalTestingFramework\Util\ModulePathExtractor; +use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; +use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; class SuiteObjectExtractor extends BaseObjectExtractor { @@ -53,6 +51,7 @@ public function __construct() * @return array * * @SuppressWarnings(PHPMD.NPathComplexity) + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function parseSuiteDataIntoObjects($parsedSuiteData) { @@ -87,22 +86,12 @@ public function parseSuiteDataIntoObjects($parsedSuiteData) if ($stepError != 0) { $noError = false; $includeMessage = strval($stepError) . " test(s) not included for suite \"" - . $parsedSuite[self::NAME] . "\"\n"; + . $parsedSuite[self::NAME] . "\""; } - // break if failed in exclude + // it's ok if failed in exclude $exclude = $this->extractTestObjectsFromSuiteRef($groupTestsToExclude); $excludeTests = $exclude['objects'] ?? []; - $stepError = $exclude['status'] ?? 0; - if ($stepError != 0) { - $suiteSkipped++; - $noError = false; - LoggingUtil::getInstance()->getLogger(self::class)->error( - "Unable to parse suite \"" . $parsedSuite[self::NAME] - . "\"\nFailed to exclude " . strval($stepError) . " test(s)" - ); - continue; - } // parse any object hooks $suiteHooks = $this->parseObjectHooks($parsedSuite); @@ -122,15 +111,20 @@ public function parseSuiteDataIntoObjects($parsedSuiteData) $includeTests = TestObjectHandler::getInstance()->getAllObjects(); } - if (!empty($includeMessage)) { + if (!empty($includeMessage) + && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { print($includeMessage); + LoggingUtil::getInstance()->getLogger(self::class)->error($includeMessage); } } catch (\Exception $e) { $noError = false; $suiteSkipped++; - LoggingUtil::getInstance()->getLogger(self::class)->error( - "Unable to parse suite \"" . $parsedSuite[self::NAME] . "\"\n" . $e->getMessage() - ); + if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { + print("Unable to parse suite \"" . $parsedSuite[self::NAME] . "\""); + LoggingUtil::getInstance()->getLogger(self::class)->error( + "Unable to parse suite \"" . $parsedSuite[self::NAME] . "\"\n" . $e->getMessage() + ); + } continue; } @@ -143,9 +137,13 @@ public function parseSuiteDataIntoObjects($parsedSuiteData) ); } - if ($suiteSkipped != 0) { + if ($suiteSkipped != 0 + && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { print("ERROR: " . strval($suiteSkipped) . " Suite failed to generate. See mftf.log for details."); + LoggingUtil::getInstance()->getLogger(self::class)->error( + "ERROR: " . strval($suiteSkipped) . " Suite failed to generate." + ); } return [ @@ -191,24 +189,32 @@ private function validateSuiteName($parsedSuite) * @param array $parsedSuite * @return array * @throws XmlException + * @throws TestReferenceException */ private function parseObjectHooks($parsedSuite) { $suiteHooks = []; if (array_key_exists(TestObjectExtractor::TEST_BEFORE_HOOK, $parsedSuite)) { - $suiteHooks[TestObjectExtractor::TEST_BEFORE_HOOK] = $this->testHookObjectExtractor->extractHook( + $hookObject = $this->testHookObjectExtractor->extractHook( $parsedSuite[self::NAME], TestObjectExtractor::TEST_BEFORE_HOOK, $parsedSuite[TestObjectExtractor::TEST_BEFORE_HOOK] ); + // Validate hook actions + $hookObject->getActions(); + $suiteHooks[TestObjectExtractor::TEST_BEFORE_HOOK] = $hookObject; } + if (array_key_exists(TestObjectExtractor::TEST_AFTER_HOOK, $parsedSuite)) { - $suiteHooks[TestObjectExtractor::TEST_AFTER_HOOK] = $this->testHookObjectExtractor->extractHook( + $hookObject = $this->testHookObjectExtractor->extractHook( $parsedSuite[self::NAME], TestObjectExtractor::TEST_AFTER_HOOK, $parsedSuite[TestObjectExtractor::TEST_AFTER_HOOK] ); + // Validate hook actions + $hookObject->getActions(); + $suiteHooks[TestObjectExtractor::TEST_AFTER_HOOK] = $hookObject; } if (count($suiteHooks) == 1) { @@ -278,14 +284,14 @@ private function extractTestObjectsFromSuiteRef($suiteReferences) } catch (\Exception $e) { $errCount++; LoggingUtil::getInstance()->getLogger(self::class)->error( - "Unable to find tests by reference \"" . $suiteRefData[self::NAME] . '"' . $e->getMessage() + "Unable to find tests by reference for suite \"" . $suiteRefData[self::NAME] . '"' ); } } return [ 'status' => $errCount, - 'objects' => $testObjectList, + 'objects' => $testObjectList ]; } diff --git a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php index 6ad9762af..9c2f24a77 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php @@ -122,6 +122,22 @@ public function getTestsByGroup($groupName) return $relevantTests; } + /** + * Sanitize test objects + * + * @param array $testsToRemove + * @return void + */ + public function sanitizeTests($testsToRemove) + { + foreach ($testsToRemove as $name) { + unset($this->tests[$name]); + LoggingUtil::getInstance()->getLogger(self::class)->error( + "Failed to parse and removed test object {$name}." + ); + } + } + /** * This method reads all Test.xml files into objects and stores them in an array for future access. * diff --git a/src/Magento/FunctionalTestingFramework/Util/Filesystem/DirSetupUtil.php b/src/Magento/FunctionalTestingFramework/Util/Filesystem/DirSetupUtil.php index 9f0036629..120b74ac3 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Filesystem/DirSetupUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/Filesystem/DirSetupUtil.php @@ -49,6 +49,10 @@ public static function createGroupDir($fullPath) */ public static function rmdirRecursive($directory) { + if (!is_dir($directory)) { + return; + } + $it = new RecursiveDirectoryIterator($directory, FilesystemIterator::SKIP_DOTS); while ($it->valid()) { diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 2de60f0bd..b994d5e53 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -222,6 +222,7 @@ private function loadAllTestObjects($testsToIgnore) */ private function createCestFile(string $testPhp, string $filename) { + DirSetupUtil::createGroupDir($this->exportDirectory); $exportFilePath = $this->exportDirectory . DIRECTORY_SEPARATOR . $filename . ".php"; $file = fopen($exportFilePath, 'w'); @@ -261,9 +262,10 @@ public function createAllTestFiles($testManifest = null, $testsToIgnore = null) } if (!$noError) { - throw new TestFrameworkException("ERROR: " . - strval(count($this->notGeneratedTestsArray)) - . " Test failed to generate. See mftf.log for details." + throw new TestFrameworkException( + "ERROR: " + . strval(count($this->notGeneratedTestsArray)) + . " Test failed to generate." ); } } @@ -361,15 +363,23 @@ private function assembleAllTestPhp($testManifest, array $testsToIgnore) $filter->filter($testObjects); } - $removeLastTest = false; foreach ($testObjects as $test) { try { + // Reset flag for new test + $removeLastTest = false; + // Do not generate test if it is an extended test and parent does not exist if ($test->isSkipped() && !empty($test->getParentName())) { try { TestObjectHandler::getInstance()->getObject($test->getParentName()); } catch (TestReferenceException $e) { - print("{$test->getName()} will not be generated. Parent {$e->getMessage()} \n"); + TestObjectHandler::getInstance()->sanitizeTests([$test->getName()]); + if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { + print("{$test->getName()} will not be generated. Parent {$e->getMessage()} \n"); + LoggingUtil::getInstance()->getLogger(self::class)->info( + "{$test->getName()} will not be generated. Parent does not exist." + ); + } continue; } } @@ -377,24 +387,26 @@ private function assembleAllTestPhp($testManifest, array $testsToIgnore) $this->debug("<comment>Start creating test: " . $test->getCodeceptionName() . "</comment>"); $php = $this->assembleTestPhp($test); $this->cestPhpArray[] = [$test->getCodeceptionName(), $php]; + // Set flag in case something goes wrong $removeLastTest = true; $debugInformation = $test->getDebugInformation(); $this->debug($debugInformation); $this->debug("<comment>Finish creating test: " . $test->getCodeceptionName() . "</comment>" . PHP_EOL); - //write to manifest here if manifest is not null + // Write to manifest here if manifest is not null if ($testManifest != null) { $testManifest->addTest($test); } } catch (\Exception $e) { $this->notGeneratedTestsArray[] = [$test->getName() => $e->getMessage()]; LoggingUtil::getInstance()->getLogger(self::class)->error( - "Failed to generate {$test->getName()}\n" + "Failed to generate {$test->getName()}" ); if ($removeLastTest) { array_pop($this->cestPhpArray); } + TestObjectHandler::getInstance()->sanitizeTests([$test->getName()]); } } From c1948e9266ca181fd7a378dd9d5e574419b65cb3 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 10 Sep 2020 12:31:38 -0500 Subject: [PATCH 528/888] MQE-1800: Allow generate:tests to continue running even if one test fails generation --- bin/functional | 1 + dev/tests/verification/Tests/SuiteGenerationTest.php | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/bin/functional b/bin/functional index 97501e018..63bb41197 100755 --- a/bin/functional +++ b/bin/functional @@ -7,5 +7,6 @@ echo "===============================" echo " EXECUTE Functional Tests " echo "===============================" bin/mftf build:project +bin/mftf run:test DeprecatedDevDocsTest -f bin/mftf run:test DevDocsTest -f bin/mftf run:test FormatCurrencyTest -f \ No newline at end of file diff --git a/dev/tests/verification/Tests/SuiteGenerationTest.php b/dev/tests/verification/Tests/SuiteGenerationTest.php index 064b4d3b0..f21e91f78 100644 --- a/dev/tests/verification/Tests/SuiteGenerationTest.php +++ b/dev/tests/verification/Tests/SuiteGenerationTest.php @@ -303,7 +303,9 @@ public function testSuiteGenerationWithExtends() foreach ($expectedFileNames as $expectedFileName) { $this->assertTrue(in_array($expectedFileName, $dirContents)); $this->assertFileEquals( - self::RESOURCES_PATH . DIRECTORY_SEPARATOR . substr($expectedFileName, 0, strlen($expectedFileName)-4) . ".txt", + self::RESOURCES_PATH . DIRECTORY_SEPARATOR + . substr($expectedFileName, 0, strlen($expectedFileName)-4) + . ".txt", $suiteResultBaseDir . $expectedFileName ); } From fca945b6ec093d2324a80ad1d9b154906ba4c928 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 10 Sep 2020 12:43:42 -0500 Subject: [PATCH 529/888] MQE-1800: Allow generate:tests to continue running even if one test fails generation --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e98ab3bc5..4554d09e6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -73,7 +73,7 @@ jobs: ${{ runner.os }}-php- - name: Install dependencies - if: steps.composer-cache.outputs.cache-hit != 'true' + #if: steps.composer-cache.outputs.cache-hit != 'true' run: composer install --prefer-dist --no-progress --no-suggest - name: Run tests From d6a4e8b90d319690112d39e4438f0fd2452281b0 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 10 Sep 2020 16:56:09 -0500 Subject: [PATCH 530/888] MQE-1800: Allow generate:tests to continue running even if one test fails generation --- .../Config/Reader/Filesystem.php | 3 +- .../Console/GenerateSuiteCommand.php | 29 ++++++++- .../Console/GenerateTestsCommand.php | 62 ++++++++++++++----- .../Exceptions/FastFailException.php | 54 ++++++++++++++++ .../Suite/SuiteGenerator.php | 9 +++ .../Suite/Util/SuiteObjectExtractor.php | 22 +++++-- .../Util/TestGenerator.php | 4 ++ 7 files changed, 158 insertions(+), 25 deletions(-) create mode 100644 src/Magento/FunctionalTestingFramework/Exceptions/FastFailException.php diff --git a/src/Magento/FunctionalTestingFramework/Config/Reader/Filesystem.php b/src/Magento/FunctionalTestingFramework/Config/Reader/Filesystem.php index ab7d64ea9..8f3fd5200 100644 --- a/src/Magento/FunctionalTestingFramework/Config/Reader/Filesystem.php +++ b/src/Magento/FunctionalTestingFramework/Config/Reader/Filesystem.php @@ -6,6 +6,7 @@ namespace Magento\FunctionalTestingFramework\Config\Reader; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Exceptions\FastFailException; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; /** @@ -240,7 +241,7 @@ protected function validateSchema($configMerger, $filename = null) true ); } - throw new \Exception("Schema validation errors found in xml file(s)" . $filename); + throw new FastFailException("Schema validation errors found in xml file(s)" . $filename); } } } diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php index 0f776d113..687e6dba9 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php @@ -8,6 +8,7 @@ namespace Magento\FunctionalTestingFramework\Console; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Exceptions\FastFailException; use Magento\FunctionalTestingFramework\Suite\SuiteGenerator; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -43,6 +44,7 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output) { + $this->setIOStyle($input, $output); $force = $input->getOption('force'); $debug = $input->getOption('debug') ?? MftfApplicationConfig::LEVEL_DEVELOPER; // for backward compatibility $remove = $input->getOption('remove'); @@ -69,17 +71,40 @@ protected function execute(InputInterface $input, OutputInterface $output) foreach ($suites as $suite) { try { SuiteGenerator::getInstance()->generateSuite($suite); + } catch (FastFailException $e) { + throw $e; } catch (\Exception $e) { $errMessages[] = $e->getMessage(); } } if ($this->cmdStatus && empty($errMessages)) { - $output->writeLn("Suites Generated"); + $this->ioStyle->text("Suites Generated" . PHP_EOL); return 0; } else { - $output->writeLn("Suites Generated (with failures)"); + $this->printMessages($errMessages); + $this->ioStyle->text("Suites Generated (with failures)" . PHP_EOL); return 1; } } + + /** + * Print messages to console + * + * @param string[] $errMessages + * @return void + */ + private function printMessages($errMessages) + { + if (empty($errMessages)) { + return; + } + + // Print error + foreach (array_unique($errMessages) as $errMessage) { + if (!empty(trim($errMessage))) { + $this->ioStyle->error(trim($errMessage)); + } + } + } } diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php index d8494fee3..ab616ea74 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php @@ -8,6 +8,7 @@ namespace Magento\FunctionalTestingFramework\Console; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Exceptions\FastFailException; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Suite\SuiteGenerator; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; @@ -135,6 +136,8 @@ protected function execute(InputInterface $input, OutputInterface $output) try { TestGenerator::getInstance(null, $testConfiguration['tests'])->createAllTestFiles($testManifest); + } catch (FastFailException $e) { + throw $e; } catch (\Exception $e) { $errMessages[] = $e->getMessage(); } @@ -146,31 +149,27 @@ protected function execute(InputInterface $input, OutputInterface $output) try { SuiteGenerator::getInstance()->generateAllSuites($testManifest); + } catch (FastFailException $e) { + throw $e; } catch (\Exception $e) { $errMessages[] = $e->getMessage(); } $testManifest->generate(); - } catch (\Exception $e) { - $message = $e->getMessage() . PHP_EOL; - $message .= !empty($filters) ? 'Filter(s): ' . implode(', ', $filters) . PHP_EOL : ''; - $message .= !empty($tests) ? 'Test name(s): ' . implode(', ', $tests) . PHP_EOL : ''; - $message .= !empty($json) && empty($tests) ? 'Test configuration: ' . $json . PHP_EOL : ''; - $this->ioStyle->note($message); - return 1; - } + if (empty($errMessages)) { + $this->ioStyle->text("Generate Tests Command Run" . PHP_EOL); - if (!empty($errMessages)) { - foreach (array_unique($errMessages) as $errMessage) { - $output->writeln($errMessage); - $output->writeln("\nGenerate Tests Command Run (with failures)"); + return 0; } - return 1; - } else { - $output->writeln("\nGenerate Tests Command Run"); - return 0; + } catch (\Exception $e) { + $errMessages[] = $e->getMessage(); } + + $this->printMessages($errMessages, $tests, $filters, $json); + $this->ioStyle->text("Generate Tests Command Run (with failures)". PHP_EOL); + + return 1; } /** @@ -228,4 +227,35 @@ private function parseTestsConfigJson($json, array $testConfiguration) $jsonTestConfiguration['suites'] = $testConfigArray['suites'] ?? null; return $jsonTestConfiguration; } + + /** + * Print messages to console + * + * @param array $errMessages + * @param array $tests + * @param array $filters + * @param string $json + * @return void + */ + private function printMessages($errMessages, $tests, $filters, $json) + { + if (empty($errMessages)) { + return; + } + + // Print error + foreach (array_unique($errMessages) as $errMessage) { + if (!empty(trim($errMessage))) { + $this->ioStyle->error(trim($errMessage)); + } + } + + // Print notice + $message = !empty($filters) ? 'Filter(s): ' . implode(', ', $filters) . PHP_EOL : ''; + $message .= !empty($tests) ? 'Test name(s): ' . implode(', ', $tests) . PHP_EOL : ''; + $message .= !empty($json) && empty($tests) ? 'Test configuration: ' . $json . PHP_EOL : ''; + if (!empty($message)) { + $this->ioStyle->note($message); + } + } } diff --git a/src/Magento/FunctionalTestingFramework/Exceptions/FastFailException.php b/src/Magento/FunctionalTestingFramework/Exceptions/FastFailException.php new file mode 100644 index 000000000..70d84dff2 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Exceptions/FastFailException.php @@ -0,0 +1,54 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\FunctionalTestingFramework\Exceptions; + +use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; + +/** + * Class FastFailException + * + * This exception type should not be caught and should allow fast fail of current execution + */ +class FastFailException extends \Exception +{ + /** + * Exception context + * + * @var array + */ + protected $context; + + /** + * FastFailException constructor + * + * @param string $message + * @param array $context + * + * @SuppressWarnings(PHPMD.UnusedLocalVariable) + */ + public function __construct($message, $context = []) + { + list($childClass, $callingClass) = debug_backtrace(false, 2); + LoggingUtil::getInstance()->getLogger($callingClass['class'])->error( + $message, + $context + ); + + $this->context = $context; + parent::__construct($message); + } + + /** + * Return exception context + * + * @return array + */ + public function getContext() + { + return $this->context; + } +} diff --git a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php index 5e6dd2f31..f6af4d835 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php @@ -7,6 +7,7 @@ namespace Magento\FunctionalTestingFramework\Suite; use Magento\FunctionalTestingFramework\Exceptions\Collector\ExceptionCollector; +use Magento\FunctionalTestingFramework\Exceptions\FastFailException; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Exceptions\XmlException; @@ -118,6 +119,8 @@ public function generateAllSuites($testManifest) if (is_array($firstElement)) { $this->generateSplitSuiteFromTest($suiteName, $suiteContent); } + } catch (FastFailException $e) { + throw $e; } catch (\Exception $e) { $exceptionCollector->addError(self::class, self::class . ': ' . $e->getMessage()); } @@ -167,6 +170,8 @@ private function generateSuiteFromTest($suiteName, $tests = [], $originalSuiteNa foreach ($tests as $testName) { try { $relevantTests[$testName] = TestObjectHandler::getInstance()->getObject($testName); + } catch (FastFailException $e) { + throw $e; } catch (\Exception $e) { $exceptionCollector->addError( self::class, @@ -185,6 +190,8 @@ private function generateSuiteFromTest($suiteName, $tests = [], $originalSuiteNa try { $this->generateRelevantGroupTests($suiteName, $relevantTests); + } catch (FastFailException $e) { + throw $e; } catch (\Exception $e) { $exceptionCollector->addError( self::class, @@ -204,6 +211,8 @@ private function generateSuiteFromTest($suiteName, $tests = [], $originalSuiteNa "suite generated", ['suite' => $suiteName, 'relative_path' => $relativePath] ); + } catch (FastFailException $e) { + throw $e; } catch (\Exception $e) { if (file_exists($fullPath)) { DirSetupUtil::rmdirRecursive($fullPath); diff --git a/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php index 72193aaa5..4f81946d7 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php @@ -6,6 +6,7 @@ namespace Magento\FunctionalTestingFramework\Suite\Util; use Exception; +use Magento\FunctionalTestingFramework\Exceptions\FastFailException; use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Suite\Objects\SuiteObject; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; @@ -19,6 +20,12 @@ use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +/** + * Class SuiteObjectExtractor + * @package Magento\FunctionalTestingFramework\Suite\Util + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class SuiteObjectExtractor extends BaseObjectExtractor { const SUITE_ROOT_TAG = 'suites'; @@ -70,9 +77,8 @@ public function parseSuiteDataIntoObjects($parsedSuiteData) continue; } + $this->validateSuiteName($parsedSuite); try { - $this->validateSuiteName($parsedSuite); - // extract include and exclude references $groupTestsToInclude = $parsedSuite[self::INCLUDE_TAG_NAME] ?? []; $groupTestsToExclude = $parsedSuite[self::EXCLUDE_TAG_NAME] ?? []; @@ -116,11 +122,13 @@ public function parseSuiteDataIntoObjects($parsedSuiteData) print($includeMessage); LoggingUtil::getInstance()->getLogger(self::class)->error($includeMessage); } + } catch (FastFailException $e) { + throw $e; } catch (\Exception $e) { $noError = false; $suiteSkipped++; if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { - print("Unable to parse suite \"" . $parsedSuite[self::NAME] . "\""); + print("Unable to parse suite \"" . $parsedSuite[self::NAME] . "\"\n"); LoggingUtil::getInstance()->getLogger(self::class)->error( "Unable to parse suite \"" . $parsedSuite[self::NAME] . "\"\n" . $e->getMessage() ); @@ -159,14 +167,14 @@ public function parseSuiteDataIntoObjects($parsedSuiteData) * * @param array $parsedSuite * @return void - * @throws XmlException + * @throws FastFailException */ private function validateSuiteName($parsedSuite) { //check if name used is using special char or the "default" reserved name NameValidationUtil::validateName($parsedSuite[self::NAME], 'Suite'); if ($parsedSuite[self::NAME] == 'default') { - throw new XmlException("A Suite can not have the name \"default\""); + throw new FastFailException("A Suite can not have the name \"default\""); } $suiteName = $parsedSuite[self::NAME]; @@ -179,7 +187,7 @@ private function validateSuiteName($parsedSuite) } $exceptionmessage = "\"Suite names and Group names can not have the same value. \t\n" . "Suite: \"{$suiteName}\" also exists as a group annotation in: \n{$testGroupConflictsFileNames}"; - throw new XmlException($exceptionmessage); + throw new FastFailException($exceptionmessage); } } @@ -281,6 +289,8 @@ private function extractTestObjectsFromSuiteRef($suiteReferences) ); break; } + } catch (FastFailException $e) { + throw $e; } catch (\Exception $e) { $errCount++; LoggingUtil::getInstance()->getLogger(self::class)->error( diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index b994d5e53..a2a7709a1 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -9,6 +9,7 @@ use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; +use Magento\FunctionalTestingFramework\Exceptions\FastFailException; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Exceptions\XmlException; @@ -348,6 +349,7 @@ private function generateInjectMethod() * @throws TestFrameworkException * @throws TestReferenceException * @throws XmlException + * @throws FastFailException */ private function assembleAllTestPhp($testManifest, array $testsToIgnore) { @@ -398,6 +400,8 @@ private function assembleAllTestPhp($testManifest, array $testsToIgnore) if ($testManifest != null) { $testManifest->addTest($test); } + } catch (FastFailException $e) { + throw $e; } catch (\Exception $e) { $this->notGeneratedTestsArray[] = [$test->getName() => $e->getMessage()]; LoggingUtil::getInstance()->getLogger(self::class)->error( From 29ba6db9c0823f5a379c77d37bc3c9fcf32b1fec Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 10 Sep 2020 17:41:56 -0500 Subject: [PATCH 531/888] MQE-1800: Allow generate:tests to continue running even if one test fails generation --- .../FunctionalTestingFramework/Console/RunTestCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php index 6f20d1463..9cf8749d5 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php @@ -112,7 +112,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int if ($this->returnCode == 0 && $this->cmdStatus) { return 0; } else { - return 1; + return 0; } } From 1e4a448cebc7f946468b505af1da7e15c63ac845 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 10 Sep 2020 18:33:23 -0500 Subject: [PATCH 532/888] MQE-1800: Allow generate:tests to continue running even if one test fails generation --- .../FunctionalTestingFramework/Console/RunTestCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php index 9cf8749d5..6f20d1463 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php @@ -112,7 +112,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int if ($this->returnCode == 0 && $this->cmdStatus) { return 0; } else { - return 0; + return 1; } } From 650e2cb190ebba119c89febc11f09dc2d25310dc Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 14 Sep 2020 13:04:26 -0500 Subject: [PATCH 533/888] MQE-1800: Allow generate:tests to continue running even if one test fails generation --- .../Suite/SuiteGeneratorTest.php | 29 +- .../Test/Handlers/TestObjectHandlerTest.php | 18 +- .../Test/Util/AnnotationExtractorTest.php | 19 +- .../Util/GenerationErrorHandlerTest.php | 273 ++++++++++++++++++ .../Util/TestGeneratorTest.php | 19 +- .../Tests/ResilientGenerationTest.php | 43 +-- .../Console/BaseGenerateCommand.php | 15 +- .../Console/GenerateSuiteCommand.php | 36 +-- .../Console/GenerateTestsCommand.php | 96 +++--- .../Console/RunTestCommand.php | 6 +- .../Console/RunTestFailedCommand.php | 15 +- .../Console/RunTestGroupCommand.php | 8 +- .../Suite/Handlers/SuiteObjectHandler.php | 33 +-- .../Suite/Objects/SuiteObject.php | 4 +- .../Suite/SuiteGenerator.php | 10 +- .../Suite/Util/SuiteObjectExtractor.php | 75 +++-- .../Test/Handlers/TestObjectHandler.php | 100 +++++-- .../Test/Util/AnnotationExtractor.php | 51 +++- .../Test/Util/ObjectExtensionUtil.php | 4 +- .../Test/Util/TestHookObjectExtractor.php | 5 +- .../Test/Util/TestObjectExtractor.php | 5 +- .../Util/GenerationErrorHandler.php | 125 ++++++++ .../Util/Logger/LoggingUtil.php | 5 +- .../Util/TestGenerator.php | 67 ++--- .../Util/Validation/NameValidationUtil.php | 10 +- 25 files changed, 744 insertions(+), 327 deletions(-) create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/Util/GenerationErrorHandlerTest.php create mode 100644 src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php index a5832c44f..f296013ab 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php @@ -16,6 +16,7 @@ use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; use Magento\FunctionalTestingFramework\Test\Util\TestObjectExtractor; use Magento\FunctionalTestingFramework\Test\Parsers\TestDataParser; +use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; use Magento\FunctionalTestingFramework\Util\Manifest\DefaultTestManifest; use tests\unit\Util\MagentoTestCase; use Magento\FunctionalTestingFramework\Util\Manifest\TestManifestFactory; @@ -179,13 +180,15 @@ public function testInvalidSuiteTestPair() $suiteConfig = ['Suite2' => ['Test1']]; $manifest = TestManifestFactory::makeManifest('default', $suiteConfig); - // Set up Expected Exception - $this->expectException(\Exception::class); - $this->expectExceptionMessageMatches('(Suite: "Suite2" Tests: "Test1")'); - // parse and generate suite object with mocked data and manifest $mockSuiteGenerator = SuiteGenerator::getInstance(); $mockSuiteGenerator->generateAllSuites($manifest); + + // assert that no exception for generateAllSuites and suite generation error is stored in GenerationErrorHandler + $errMessage = 'Cannot reference tests which are not declared as part of suite (Suite: "Suite2" Tests: "Test1")'; + TestLoggingUtil::getInstance()->validateMockLogStatement('error', $errMessage, []); + $suiteErrors = GenerationErrorHandler::getInstance()->getErrorsByType('suite'); + $this->assertArrayHasKey('Suite2', $suiteErrors); } public function testNonExistentSuiteTestPair() @@ -203,13 +206,15 @@ public function testNonExistentSuiteTestPair() $suiteConfig = ['Suite3' => ['Test1']]; $manifest = TestManifestFactory::makeManifest('default', $suiteConfig); - // Set up Expected Exception - $this->expectException(\Exception::class); - $this->expectExceptionMessageMatches('#Suite3 is not defined#'); - // parse and generate suite object with mocked data and manifest $mockSuiteGenerator = SuiteGenerator::getInstance(); $mockSuiteGenerator->generateAllSuites($manifest); + + // assert that no exception for generateAllSuites and suite generation error is stored in GenerationErrorHandler + $errMessage = 'Suite Suite3 is not defined in xml or is invalid.'; + TestLoggingUtil::getInstance()->validateMockLogStatement('error', $errMessage, []); + $suiteErrors = GenerationErrorHandler::getInstance()->getErrorsByType('suite'); + $this->assertArrayHasKey('Suite3', $suiteErrors); } /** @@ -271,6 +276,14 @@ private function setMockTestAndSuiteParserOutput($testData, $suiteData) $property->setValue($instance, $instance); } + /** + * clean up function runs after each test + */ + public function tearDown(): void + { + GenerationErrorHandler::getInstance()->reset(); + } + /** * clean up function runs after all tests */ diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php index 939dd496e..f05277b82 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php @@ -20,9 +20,16 @@ use tests\unit\Util\ObjectHandlerUtil; use tests\unit\Util\TestDataArrayBuilder; use tests\unit\Util\MockModuleResolverBuilder; +use tests\unit\Util\TestLoggingUtil; +use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; class TestObjectHandlerTest extends MagentoTestCase { + public function setUp(): void + { + TestLoggingUtil::getInstance()->setMockLoggingUtil(); + } + /** * Basic test to validate array => test object conversion. * @@ -254,10 +261,13 @@ public function testGetAllTestObjectsWithInvalidExtends() ObjectHandlerUtil::mockTestObjectHandlerWitData(array_merge($testOne, $testTwo)); $toh = TestObjectHandler::getInstance(); - - $this->expectException(\Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException::class); - $this->expectExceptionMessage("Mftf Test can not extend from itself: " . "testOne"); $toh->getAllObjects(); + + // assert that no exception for getAllObjects and test generation error is stored in GenerationErrorHandler + $errorMessage = '/' . preg_quote("Mftf Test can not extend from itself: " . "testOne") . '/'; + TestLoggingUtil::getInstance()->validateMockLogStatmentRegex('error', $errorMessage, []); + $testErrors = GenerationErrorHandler::getInstance()->getErrorsByType('test'); + $this->assertArrayHasKey('testOne', $testErrors); } /** @@ -360,6 +370,8 @@ public function testGetTestObjectWhenEnablePause() */ public function tearDown(): void { + TestLoggingUtil::getInstance()->clearMockLoggingUtil(); AspectMock::clean(); + parent::tearDownAfterClass(); } } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/AnnotationExtractorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/AnnotationExtractorTest.php index bfb108ce8..3e3c44429 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/AnnotationExtractorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/AnnotationExtractorTest.php @@ -12,6 +12,7 @@ use Monolog\Logger; use PHPUnit\Framework\TestCase; use tests\unit\Util\TestLoggingUtil; +use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; class AnnotationExtractorTest extends TestCase { @@ -195,14 +196,20 @@ public function testTestCaseIdUniqueness() $extractor = new AnnotationExtractor(); $extractor->extractAnnotations($firstTestAnnotation, "firstTest"); $extractor->extractAnnotations($secondTestannotation, "secondTest"); + $extractor->validateTestCaseIdTitleUniqueness(); - //Expect Exception - $this->expectException(\Magento\FunctionalTestingFramework\Exceptions\XmlException::class); - $this->expectExceptionMessage("TestCaseId and Title pairs must be unique:\n\n" . - "TestCaseId: 'MQE-0001' Title: 'TEST TITLE' in Tests 'firstTest', 'secondTest'"); + // assert that no exception for validateTestCaseIdTitleUniqueness + // and validation error is stored in GenerationErrorHandler + $errorMessage = '/' . preg_quote("TestCaseId and Title pairs is not unique in Tests 'firstTest', 'secondTest'") . '/'; + TestLoggingUtil::getInstance()->validateMockLogStatmentRegex('error', $errorMessage, []); + $testErrors = GenerationErrorHandler::getInstance()->getErrorsByType('test'); + $this->assertArrayHasKey('firstTest', $testErrors); + $this->assertArrayHasKey('secondTest', $testErrors); + } - //Trigger Exception - $extractor->validateTestCaseIdTitleUniqueness(); + public function tearDown(): void + { + GenerationErrorHandler::getInstance()->reset(); } /** diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/GenerationErrorHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/GenerationErrorHandlerTest.php new file mode 100644 index 000000000..630583567 --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/GenerationErrorHandlerTest.php @@ -0,0 +1,273 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace tests\unit\Magento\FunctionalTestFramework\Util; + +use AspectMock\Test as AspectMock; +use tests\unit\Util\MagentoTestCase; +use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; +use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; + +/** + * Class GenerationErrorHandlerTest + */ +class GenerationErrorHandlerTest extends MagentoTestCase +{ + /** + * Test get errors when all errors are distinct + */ + public function testGetDistinctErrors() + { + AspectMock::double( + MftfApplicationConfig::class, + ['getPhase' => MftfApplicationConfig::GENERATION_PHASE] + ); + + $expectedAllErrors = [ + 'test' => [ + 'Sameple1Test' => [ + 'message' => 'TestError1', + 'generated' => false, + ], + 'Sameple2Test' => [ + 'message' => 'TestError2', + 'generated' => true, + ] + ], + 'suite' => [ + 'Sameple1Suite' => [ + 'message' => 'SuiteError1', + 'generated' => false, + ], + ] + ]; + + $expectedTestErrors = [ + 'Sameple1Test' => [ + 'message' => 'TestError1', + 'generated' => false, + ], + 'Sameple2Test' => [ + 'message' => 'TestError2', + 'generated' => true, + ] + ]; + + $expectedSuiteErrors = [ + 'Sameple1Suite' => [ + 'message' => 'SuiteError1', + 'generated' => false, + ], + ]; + + GenerationErrorHandler::getInstance()->addError('test', 'Sameple1Test', 'TestError1'); + GenerationErrorHandler::getInstance()->addError('test', 'Sameple2Test', 'TestError2', true); + GenerationErrorHandler::getInstance()->addError('suite', 'Sameple1Suite', 'SuiteError1'); + + // Assert getAllErrors + $this->assertEquals($expectedAllErrors, GenerationErrorHandler::getInstance()->getAllErrors()); + // Assert getErrorsByType + $this->assertEquals($expectedTestErrors, GenerationErrorHandler::getInstance()->getErrorsByType('test')); + $this->assertEquals($expectedSuiteErrors, GenerationErrorHandler::getInstance()->getErrorsByType('suite')); + } + + /** + * Test get errors when some errors have the same key + */ + public function testGetErrorsWithSameKey() + { + AspectMock::double( + MftfApplicationConfig::class, + ['getPhase' => MftfApplicationConfig::GENERATION_PHASE] + ); + + $expectedAllErrors = [ + 'test' => [ + 'Sameple1Test' => [ + 'message' => [ + 0 => 'TestError1', + 1 => 'TestError3' + ], + 'generated' => [ + 0 => false, + 1 => true + ], + ], + 'Sameple2Test' => [ + 'message' => 'TestError2', + 'generated' => true, + ], + ], + 'suite' => [ + 'Sameple1Suite' => [ + 'message' => [ + 0 => 'SuiteError1', + 1 => 'SuiteError2', + ], + 'generated' => [ + 0 => false, + 1 => false, + ], + ], + ], + ]; + + $expectedTestErrors = [ + 'Sameple1Test' => [ + 'message' => [ + 0 => 'TestError1', + 1 => 'TestError3' + ], + 'generated' => [ + 0 => false, + 1 => true + ], + ], + 'Sameple2Test' => [ + 'message' => 'TestError2', + 'generated' => true, + ], + ]; + + $expectedSuiteErrors = [ + 'Sameple1Suite' => [ + 'message' => [ + 0 => 'SuiteError1', + 1 => 'SuiteError2', + ], + 'generated' => [ + 0 => false, + 1 => false, + ], + ], + ]; + + GenerationErrorHandler::getInstance()->addError('test', 'Sameple1Test', 'TestError1'); + GenerationErrorHandler::getInstance()->addError('suite', 'Sameple1Suite', 'SuiteError1'); + GenerationErrorHandler::getInstance()->addError('test', 'Sameple2Test', 'TestError2', true); + GenerationErrorHandler::getInstance()->addError('suite', 'Sameple1Suite', 'SuiteError2'); + GenerationErrorHandler::getInstance()->addError('test', 'Sameple1Test', 'TestError3', true); + + // Assert getAllErrors + $this->assertEquals($expectedAllErrors, GenerationErrorHandler::getInstance()->getAllErrors()); + // Assert getErrorsByType + $this->assertEquals($expectedTestErrors, GenerationErrorHandler::getInstance()->getErrorsByType('test')); + $this->assertEquals($expectedSuiteErrors, GenerationErrorHandler::getInstance()->getErrorsByType('suite')); + } + + /** + * Test get errors when some errors are duplicate + */ + public function testGetAllErrorsDuplicate() + { + AspectMock::double( + MftfApplicationConfig::class, + ['getPhase' => MftfApplicationConfig::GENERATION_PHASE] + ); + + $expectedAllErrors = [ + 'test' => [ + 'Sameple1Test' => [ + 'message' => [ + 0 => 'TestError1', + 1 => 'TestError1' + ], + 'generated' => [ + 0 => false, + 1 => false + ], + ], + 'Sameple2Test' => [ + 'message' => 'TestError2', + 'generated' => true, + ], + ], + 'suite' => [ + 'Sameple1Suite' => [ + 'message' => [ + 0 => 'SuiteError1', + 1 => 'SuiteError2', + ], + 'generated' => [ + 0 => false, + 1 => false, + ], + ], + ], + ]; + + $expectedTestErrors = [ + 'Sameple1Test' => [ + 'message' => [ + 0 => 'TestError1', + 1 => 'TestError1' + ], + 'generated' => [ + 0 => false, + 1 => false + ], + ], + 'Sameple2Test' => [ + 'message' => 'TestError2', + 'generated' => true, + ], + ]; + + $expectedSuiteErrors = [ + 'Sameple1Suite' => [ + 'message' => [ + 0 => 'SuiteError1', + 1 => 'SuiteError2', + ], + 'generated' => [ + 0 => false, + 1 => false, + ], + ], + ]; + + GenerationErrorHandler::getInstance()->addError('test', 'Sameple1Test', 'TestError1'); + GenerationErrorHandler::getInstance()->addError('suite', 'Sameple1Suite', 'SuiteError1'); + GenerationErrorHandler::getInstance()->addError('test', 'Sameple2Test', 'TestError2', true); + GenerationErrorHandler::getInstance()->addError('suite', 'Sameple1Suite', 'SuiteError2'); + GenerationErrorHandler::getInstance()->addError('test', 'Sameple1Test', 'TestError1'); + + // Assert getAllErrors + $this->assertEquals($expectedAllErrors, GenerationErrorHandler::getInstance()->getAllErrors()); + // Assert getErrorsByType + $this->assertEquals($expectedTestErrors, GenerationErrorHandler::getInstance()->getErrorsByType('test')); + $this->assertEquals($expectedSuiteErrors, GenerationErrorHandler::getInstance()->getErrorsByType('suite')); + } + + /** + * Test reset + */ + public function testResetError() + { + AspectMock::double( + MftfApplicationConfig::class, + ['getPhase' => MftfApplicationConfig::GENERATION_PHASE] + ); + + GenerationErrorHandler::getInstance()->addError('something', 'some', 'error'); + GenerationErrorHandler::getInstance()->addError('otherthing', 'other', 'error'); + GenerationErrorHandler::getInstance()->reset(); + + // Assert getAllErrors + $this->assertEquals([], GenerationErrorHandler::getInstance()->getAllErrors()); + // Assert getErrorsByType + $this->assertEquals([], GenerationErrorHandler::getInstance()->getErrorsByType('something')); + $this->assertEquals([], GenerationErrorHandler::getInstance()->getErrorsByType('otherthing')); + $this->assertEquals([], GenerationErrorHandler::getInstance()->getErrorsByType('nothing')); + } + + public function tearDown(): void + { + $property = new \ReflectionProperty(GenerationErrorHandler::class, 'instance'); + $property->setAccessible(true); + $property->setValue(null); + } +} diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php index c7ee8dffd..8817d89c7 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php @@ -16,9 +16,19 @@ use tests\unit\Util\MagentoTestCase; use Magento\FunctionalTestingFramework\Util\TestGenerator; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use tests\unit\Util\TestLoggingUtil; +use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; class TestGeneratorTest extends MagentoTestCase { + /** + * Before method functionality + */ + public function setUp(): void + { + TestLoggingUtil::getInstance()->setMockLoggingUtil(); + } + /** * After method functionality * @@ -27,6 +37,7 @@ class TestGeneratorTest extends MagentoTestCase public function tearDown(): void { AspectMock::clean(); + GenerationErrorHandler::getInstance()->reset(); } /** @@ -48,9 +59,13 @@ public function testEntityException() AspectMock::double(TestGenerator::class, ['loadAllTestObjects' => ["sampleTest" => $testObject]]); - $this->expectExceptionMessage("ERROR: 1 Test failed to generate."); - $testGeneratorObject->createAllTestFiles(null, []); + + // assert that no exception for createAllTestFiles and generation error is stored in GenerationErrorHandler + $errorMessage = '/' . preg_quote("Removed invalid test object sampleTest") . '/'; + TestLoggingUtil::getInstance()->validateMockLogStatmentRegex('error', $errorMessage, []); + $testErrors = GenerationErrorHandler::getInstance()->getErrorsByType('test'); + $this->assertArrayHasKey('sampleTest', $testErrors); } /** diff --git a/dev/tests/verification/Tests/ResilientGenerationTest.php b/dev/tests/verification/Tests/ResilientGenerationTest.php index 418dfee12..e7df5260d 100644 --- a/dev/tests/verification/Tests/ResilientGenerationTest.php +++ b/dev/tests/verification/Tests/ResilientGenerationTest.php @@ -33,9 +33,6 @@ class ResilientGenerationTest extends MftfTestCase * @var string[][] */ private static $exceptionGrpLogs = [ - 'PartialGenerateForIncludeSuite' => [ - '/Failed to generate tests for suite "PartialGenerateForIncludeSuite"/' - ], 'NotGenerateHookBeforeSuite' => [ '/Suite NotGenerateHookBeforeSuite is not defined in xml or is invalid./' ], @@ -96,17 +93,8 @@ public function setUp(): void */ public function testGenerateAllTests() { - $exceptionMessage = '/ERROR: 21 Test failed to generate./'; - $testManifest = TestManifestFactory::makeManifest('default', []); - // Validate exception is thrown - $this->assertExceptionRegex( - \Exception::class, - [$exceptionMessage], - function () use ($testManifest) { - TestGenerator::getInstance(null, [])->createAllTestFiles($testManifest); - } - ); + TestGenerator::getInstance(null, [])->createAllTestFiles($testManifest); // Validate tests have been generated $dirContents = array_diff( @@ -121,13 +109,6 @@ function () use ($testManifest) { "string {$dirContent} should not contains \"NotGenerate\"" ); } - - // Validate log message - TestLoggingUtil::getInstance()->validateMockLogStatmentRegex( - 'error', - $exceptionMessage, - [] - ); } /** @@ -136,20 +117,7 @@ function () use ($testManifest) { public function testGenerateAllSuites() { $testManifest = TestManifestFactory::makeManifest('', []); - - // Validate exception is thrown - $exceptionMessage = '/' - . preg_quote( - 'Failed to generate tests for suite "PartialGenerateForIncludeSuite"' - ) - . '/'; - $this->assertExceptionRegex( - \Exception::class, - [$exceptionMessage], - function () use ($testManifest) { - SuiteGenerator::getInstance()->generateAllSuites($testManifest); - } - ); + SuiteGenerator::getInstance()->generateAllSuites($testManifest); foreach (SuiteTestReferences::$data as $groupName => $expectedContents) { if (substr($groupName, 0, 11) != 'NotGenerate') { @@ -175,13 +143,6 @@ function () use ($testManifest) { $this->assertFalse(in_array($groupName, $dirContents)); } } - - // Validate log message - TestLoggingUtil::getInstance()->validateMockLogStatmentRegex( - 'error', - $exceptionMessage, - [] - ); } /** diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index 93e272d04..f6a4ff4a5 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -8,7 +8,9 @@ namespace Magento\FunctionalTestingFramework\Console; +use Magento\FunctionalTestingFramework\Exceptions\FastFailException; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Symfony\Component\Console\Command\Command; @@ -49,13 +51,6 @@ class BaseGenerateCommand extends Command */ protected $ioStyle = null; - /** - * Command status - * - * @var bool - */ - protected $cmdStatus = true; - /** * Configures the base command. * @@ -111,14 +106,13 @@ protected function removeGeneratedDirectory(OutputInterface $output, bool $verbo * Returns an array of test configuration to be used as an argument for generation of tests * @param array $tests * @return false|string - * @throws \Magento\FunctionalTestingFramework\Exceptions\XmlException + * @throws FastFailException */ protected function getTestAndSuiteConfiguration(array $tests) { $testConfiguration['tests'] = null; $testConfiguration['suites'] = null; $testsReferencedInSuites = SuiteObjectHandler::getInstance()->getAllTestReferences(); - $this->cmdStatus = SuiteObjectHandler::getInstance()->parseSuccessful(); $suiteToTestPair = []; foreach($tests as $test) { @@ -150,7 +144,8 @@ protected function getTestAndSuiteConfiguration(array $tests) * Returns an array of test configuration to be used as an argument for generation of tests * This function uses group or suite names for generation * @return false|string - * @throws \Magento\FunctionalTestingFramework\Exceptions\XmlException + * @throws FastFailException + * @throws TestFrameworkException */ protected function getGroupAndSuiteConfiguration(array $groupOrSuiteNames) { diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php index 687e6dba9..10e245a79 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php @@ -10,6 +10,7 @@ use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\Exceptions\FastFailException; use Magento\FunctionalTestingFramework\Suite\SuiteGenerator; +use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -44,7 +45,6 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output) { - $this->setIOStyle($input, $output); $force = $input->getOption('force'); $debug = $input->getOption('debug') ?? MftfApplicationConfig::LEVEL_DEVELOPER; // for backward compatibility $remove = $input->getOption('remove'); @@ -67,44 +67,26 @@ protected function execute(InputInterface $input, OutputInterface $output) $suites = $input->getArgument('suites'); - $errMessages = []; foreach ($suites as $suite) { try { SuiteGenerator::getInstance()->generateSuite($suite); + if ($output->isVerbose()) { + $output->writeLn("suite $suite generated"); + } } catch (FastFailException $e) { throw $e; } catch (\Exception $e) { - $errMessages[] = $e->getMessage(); } } - if ($this->cmdStatus && empty($errMessages)) { - $this->ioStyle->text("Suites Generated" . PHP_EOL); + if (empty(GenerationErrorHandler::getInstance()->getAllErrors())) { + $output->writeln("Suites Generated"); return 0; } else { - $this->printMessages($errMessages); - $this->ioStyle->text("Suites Generated (with failures)" . PHP_EOL); + GenerationErrorHandler::getInstance()->printErrorSummary(); + GenerationErrorHandler::getInstance()->reset(); + $output->writeln("Suites Generated (with failures)"); return 1; } } - - /** - * Print messages to console - * - * @param string[] $errMessages - * @return void - */ - private function printMessages($errMessages) - { - if (empty($errMessages)) { - return; - } - - // Print error - foreach (array_unique($errMessages) as $errMessage) { - if (!empty(trim($errMessage))) { - $this->ioStyle->error(trim($errMessage)); - } - } - } } diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php index ab616ea74..8a6bc60de 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php @@ -10,8 +10,11 @@ use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\Exceptions\FastFailException; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Suite\SuiteGenerator; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; +use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; +use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; use Magento\FunctionalTestingFramework\Util\Manifest\ParallelTestManifest; use Magento\FunctionalTestingFramework\Util\Manifest\TestManifestFactory; use Magento\FunctionalTestingFramework\Util\TestGenerator; @@ -73,8 +76,7 @@ protected function configure() * @param OutputInterface $output * @return void|integer * @throws TestFrameworkException - * @throws \Magento\FunctionalTestingFramework\Exceptions\TestReferenceException - * @throws \Magento\FunctionalTestingFramework\Exceptions\XmlException + * @throws FastFailException */ protected function execute(InputInterface $input, OutputInterface $output) { @@ -127,7 +129,6 @@ protected function execute(InputInterface $input, OutputInterface $output) $this->removeGeneratedDirectory($output, $verbose); } - $errMessages = []; try { $testConfiguration = $this->createTestConfiguration($json, $tests); @@ -139,7 +140,6 @@ protected function execute(InputInterface $input, OutputInterface $output) } catch (FastFailException $e) { throw $e; } catch (\Exception $e) { - $errMessages[] = $e->getMessage(); } if ($config == 'parallel') { @@ -147,29 +147,31 @@ protected function execute(InputInterface $input, OutputInterface $output) $testManifest->createTestGroups($time); } - try { - SuiteGenerator::getInstance()->generateAllSuites($testManifest); - } catch (FastFailException $e) { - throw $e; - } catch (\Exception $e) { - $errMessages[] = $e->getMessage(); - } + SuiteGenerator::getInstance()->generateAllSuites($testManifest); $testManifest->generate(); - - if (empty($errMessages)) { - $this->ioStyle->text("Generate Tests Command Run" . PHP_EOL); - - return 0; - } } catch (\Exception $e) { - $errMessages[] = $e->getMessage(); - } + if (!empty(GenerationErrorHandler::getInstance()->getAllErrors())) { + GenerationErrorHandler::getInstance()->printErrorSummary(); + } + $message = $e->getMessage() . PHP_EOL; + $message .= !empty($filters) ? 'Filter(s): ' . implode(', ', $filters) . PHP_EOL : ''; + $message .= !empty($tests) ? 'Test name(s): ' . implode(', ', $tests) . PHP_EOL : ''; + $message .= !empty($json) && empty($tests) ? 'Test configuration: ' . $json . PHP_EOL : ''; + $this->ioStyle->note($message); - $this->printMessages($errMessages, $tests, $filters, $json); - $this->ioStyle->text("Generate Tests Command Run (with failures)". PHP_EOL); + return 1; + } - return 1; + if (empty(GenerationErrorHandler::getInstance()->getAllErrors())) { + $output->writeln("Generate Tests Command Run"); + return 0; + } else { + GenerationErrorHandler::getInstance()->printErrorSummary(); + GenerationErrorHandler::getInstance()->reset(); + $output->writeln("Generate Tests Command Run (with failures)"); + return 1; + } } /** @@ -178,8 +180,8 @@ protected function execute(InputInterface $input, OutputInterface $output) * @param string $json * @param array $tests * @return array - * @throws \Magento\FunctionalTestingFramework\Exceptions\TestReferenceException - * @throws \Magento\FunctionalTestingFramework\Exceptions\XmlException + * @throws FastFailException + * @throws TestFrameworkException */ private function createTestConfiguration( $json, @@ -196,7 +198,20 @@ private function createTestConfiguration( $testObjects = []; foreach ($testConfiguration['tests'] as $test) { - $testObjects[$test] = TestObjectHandler::getInstance()->getObject($test); + try { + $testObjects[$test] = TestObjectHandler::getInstance()->getObject($test); + } catch (TestReferenceException $e) { + $message = "Unable to find test {$test} from test configuration"; + LoggingUtil::getInstance()->getLogger(self::class)->error( + $message. PHP_EOL . $e->getMessage() + ); + if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { + print($message . PHP_EOL); + } + if (MftfApplicationConfig::getConfig()->getPhase() != MftfApplicationConfig::EXECUTION_PHASE) { + GenerationErrorHandler::getInstance()->addError('test', $test, $message); + } + } } $testConfiguration['tests'] = $testObjects; @@ -227,35 +242,4 @@ private function parseTestsConfigJson($json, array $testConfiguration) $jsonTestConfiguration['suites'] = $testConfigArray['suites'] ?? null; return $jsonTestConfiguration; } - - /** - * Print messages to console - * - * @param array $errMessages - * @param array $tests - * @param array $filters - * @param string $json - * @return void - */ - private function printMessages($errMessages, $tests, $filters, $json) - { - if (empty($errMessages)) { - return; - } - - // Print error - foreach (array_unique($errMessages) as $errMessage) { - if (!empty(trim($errMessage))) { - $this->ioStyle->error(trim($errMessage)); - } - } - - // Print notice - $message = !empty($filters) ? 'Filter(s): ' . implode(', ', $filters) . PHP_EOL : ''; - $message .= !empty($tests) ? 'Test name(s): ' . implode(', ', $tests) . PHP_EOL : ''; - $message .= !empty($json) && empty($tests) ? 'Test configuration: ' . $json . PHP_EOL : ''; - if (!empty($message)) { - $this->ioStyle->note($message); - } - } } diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php index 6f20d1463..6931e8303 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php @@ -109,11 +109,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->runTestsInSuite($testConfigArray['suites'], $output); } - if ($this->returnCode == 0 && $this->cmdStatus) { - return 0; - } else { - return 1; - } + return $this->returnCode; } /** diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php index 040fe6b6b..6e6954c70 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php @@ -66,7 +66,6 @@ protected function configure() * * @SuppressWarnings(PHPMD.UnusedLocalVariable) * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ protected function execute(InputInterface $input, OutputInterface $output): int { @@ -100,12 +99,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int $testConfiguration = $this->getFailedTestList(); if ($testConfiguration === null) { - // no failed tests found - if ($this->cmdStatus) { - return 0; - } else { - return 1; - } + // no failed tests found, run is a success + return 0; } $command = $this->getApplication()->find('generate:tests'); @@ -155,11 +150,7 @@ function ($type, $buffer) use ($output) { $this->writeFailedTestToFile($test, $this->testsFailedFile); } - if ($returnCode == 0 && $this->cmdStatus) { - return 0; - } else { - return 1; - } + return $returnCode; } /** diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php index b23938d1f..f18b9dc30 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php @@ -53,7 +53,6 @@ protected function configure() * * @SuppressWarnings(PHPMD.UnusedLocalVariable) * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.NPathComplexity) */ protected function execute(InputInterface $input, OutputInterface $output): int { @@ -131,11 +130,6 @@ function ($type, $buffer) use ($output) { } $exitCode = 0; } - - if ($exitCode == 0 && $this->cmdStatus) { - return 0; - } else { - return 1; - } + return $exitCode; } } diff --git a/src/Magento/FunctionalTestingFramework/Suite/Handlers/SuiteObjectHandler.php b/src/Magento/FunctionalTestingFramework/Suite/Handlers/SuiteObjectHandler.php index fb058efa5..5f21e08e1 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Handlers/SuiteObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Handlers/SuiteObjectHandler.php @@ -5,6 +5,9 @@ */ namespace Magento\FunctionalTestingFramework\Suite\Handlers; +use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Exceptions\FastFailException; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\ObjectManager\ObjectHandlerInterface; @@ -13,6 +16,8 @@ use Magento\FunctionalTestingFramework\Suite\Parsers\SuiteDataParser; use Magento\FunctionalTestingFramework\Suite\Util\SuiteObjectExtractor; use Magento\FunctionalTestingFramework\Test\Util\ObjectExtractor; +use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; +use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; /** * Class SuiteObjectHandler @@ -33,13 +38,6 @@ class SuiteObjectHandler implements ObjectHandlerInterface */ private $suiteObjects; - /** - * If suites parsing are successful - * - * @var boolean - */ - private $status; - /** * Avoids instantiation of SuiteObjectHandler by new. * @return void @@ -60,6 +58,7 @@ private function __clone() * Function to enforce singleton design pattern * * @return ObjectHandlerInterface + * @throws FastFailException */ public static function getInstance(): ObjectHandlerInterface { @@ -97,20 +96,11 @@ public function getAllObjects(): array return $this->suiteObjects; } - /** - * Return if there is any parsing errors - * - * @return boolean - */ - public function parseSuccessful() - { - return $this->status; - } - /** * Function which return all tests referenced by suites. * * @return array + * @throws TestFrameworkException */ public function getAllTestReferences(): array { @@ -132,17 +122,12 @@ public function getAllTestReferences(): array * * @return void * @SuppressWarnings(PHPMD.UnusedPrivateMethod) + * @throws FastFailException */ private function initSuiteData() { $suiteDataParser = ObjectManagerFactory::getObjectManager()->create(SuiteDataParser::class); $suiteObjectExtractor = new SuiteObjectExtractor(); - $parsedArray = $suiteObjectExtractor->parseSuiteDataIntoObjects($suiteDataParser->readSuiteData()); - $this->suiteObjects = $parsedArray['objects'] ?? []; - if (empty($this->suiteObjects)) { - $this->status = false; - } else { - $this->status = $parsedArray['status'] ?? false; - } + $this->suiteObjects = $suiteObjectExtractor->parseSuiteDataIntoObjects($suiteDataParser->readSuiteData()); } } diff --git a/src/Magento/FunctionalTestingFramework/Suite/Objects/SuiteObject.php b/src/Magento/FunctionalTestingFramework/Suite/Objects/SuiteObject.php index 64820cf09..57d5c11f0 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Objects/SuiteObject.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Objects/SuiteObject.php @@ -6,6 +6,7 @@ namespace Magento\FunctionalTestingFramework\Suite\Objects; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Filter\FilterInterface; use Magento\FunctionalTestingFramework\Test\Objects\TestHookObject; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; @@ -82,6 +83,7 @@ public function getName() * Returns an array of Test Objects based on specifications in exclude and include arrays. * * @return array + * @throws TestFrameworkException */ public function getTests() { @@ -96,7 +98,7 @@ public function getTests() * @param TestObject[] $includeTests * @param TestObject[] $excludeTests * @return TestObject[] - * @throws \Exception + * @throws TestFrameworkException */ private function resolveTests($includeTests, $excludeTests) { diff --git a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php index f6af4d835..4b05c2c9d 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php @@ -16,6 +16,7 @@ use Magento\FunctionalTestingFramework\Suite\Objects\SuiteObject; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; use Magento\FunctionalTestingFramework\Util\Filesystem\DirSetupUtil; +use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; use Magento\FunctionalTestingFramework\Util\Manifest\BaseTestManifest; use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; @@ -91,18 +92,17 @@ public static function getInstance(): SuiteGenerator * * @param BaseTestManifest $testManifest * @return void - * @throws \Exception + * @throws FastFailException */ public function generateAllSuites($testManifest) { $suites = $testManifest->getSuiteConfig(); - $exceptionCollector = new ExceptionCollector(); foreach ($suites as $suiteName => $suiteContent) { try { if (empty($suiteContent)) { LoggingUtil::getInstance()->getLogger(self::class)->notification( - "Suite '" . $suiteName . "' contains no tests and won't be generated." . PHP_EOL, + "NOTICE: Suite '" . $suiteName . "' contains no tests and won't be generated." . PHP_EOL, [], true ); @@ -122,11 +122,8 @@ public function generateAllSuites($testManifest) } catch (FastFailException $e) { throw $e; } catch (\Exception $e) { - $exceptionCollector->addError(self::class, self::class . ': ' . $e->getMessage()); } } - // Report failure - $this->throwCollectedExceptions($exceptionCollector); } /** @@ -218,6 +215,7 @@ private function generateSuiteFromTest($suiteName, $tests = [], $originalSuiteNa DirSetupUtil::rmdirRecursive($fullPath); } $exceptionCollector->addError(self::class, $e->getMessage()); + GenerationErrorHandler::getInstance()->addError('suite', $suiteName, self::class . ': ' . $e->getMessage()); } $this->throwCollectedExceptions($exceptionCollector); diff --git a/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php index 4f81946d7..b3696b30c 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php @@ -7,6 +7,7 @@ use Exception; use Magento\FunctionalTestingFramework\Exceptions\FastFailException; +use Magento\FunctionalTestingFramework\Exceptions\GenerationErrorCollector; use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Suite\Objects\SuiteObject; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; @@ -14,6 +15,7 @@ use Magento\FunctionalTestingFramework\Test\Util\BaseObjectExtractor; use Magento\FunctionalTestingFramework\Test\Util\TestHookObjectExtractor; use Magento\FunctionalTestingFramework\Test\Util\TestObjectExtractor; +use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; use Magento\FunctionalTestingFramework\Util\Validation\NameValidationUtil; use Magento\FunctionalTestingFramework\Util\ModulePathExtractor; @@ -56,9 +58,11 @@ public function __construct() * * @param array $parsedSuiteData * @return array + * @throws FastFailException * * @SuppressWarnings(PHPMD.NPathComplexity) * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ public function parseSuiteDataIntoObjects($parsedSuiteData) { @@ -69,8 +73,6 @@ public function parseSuiteDataIntoObjects($parsedSuiteData) return $suiteObjects; } - $noError = true; - $suiteSkipped = 0; foreach ($parsedSuiteData[self::SUITE_ROOT_TAG] as $parsedSuite) { if (!is_array($parsedSuite)) { // skip non array items parsed from suite (suite objects will always be arrays) @@ -78,6 +80,7 @@ public function parseSuiteDataIntoObjects($parsedSuiteData) } $this->validateSuiteName($parsedSuite); + try { // extract include and exclude references $groupTestsToInclude = $parsedSuite[self::INCLUDE_TAG_NAME] ?? []; @@ -90,9 +93,8 @@ public function parseSuiteDataIntoObjects($parsedSuiteData) $stepError = $include['status'] ?? 0; $includeMessage = ''; if ($stepError != 0) { - $noError = false; - $includeMessage = strval($stepError) . " test(s) not included for suite \"" - . $parsedSuite[self::NAME] . "\""; + $includeMessage = "ERROR: " . strval($stepError) . " test(s) not included for suite " + . $parsedSuite[self::NAME]; } // it's ok if failed in exclude @@ -104,11 +106,16 @@ public function parseSuiteDataIntoObjects($parsedSuiteData) // log error if suite is empty if ($this->isSuiteEmpty($suiteHooks, $includeTests, $excludeTests)) { - $suiteSkipped++; - $noError = false; LoggingUtil::getInstance()->getLogger(self::class)->error( - "Unable to parse suite \"" . $parsedSuite[self::NAME] . "\"\nSuite must not be empty." + "Unable to parse suite " . $parsedSuite[self::NAME] . ". Suite must not be empty." ); + if (MftfApplicationConfig::getConfig()->getPhase() != MftfApplicationConfig::EXECUTION_PHASE) { + GenerationErrorHandler::getInstance()->addError( + 'suite', + $parsedSuite[self::NAME], + self::class . ': ' . 'Suite must not be empty.' + ); + } continue; }; @@ -117,20 +124,34 @@ public function parseSuiteDataIntoObjects($parsedSuiteData) $includeTests = TestObjectHandler::getInstance()->getAllObjects(); } - if (!empty($includeMessage) - && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { - print($includeMessage); + if (!empty($includeMessage)) { LoggingUtil::getInstance()->getLogger(self::class)->error($includeMessage); + if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { + print($includeMessage); + } + if (MftfApplicationConfig::getConfig()->getPhase() != MftfApplicationConfig::EXECUTION_PHASE) { + GenerationErrorHandler::getInstance()->addError( + 'suite', + $parsedSuite[self::NAME], + self::class . ': ' . $includeMessage, + true + ); + } } } catch (FastFailException $e) { throw $e; } catch (\Exception $e) { - $noError = false; - $suiteSkipped++; + LoggingUtil::getInstance()->getLogger(self::class)->error( + "Unable to parse suite " . $parsedSuite[self::NAME] . "\n" . $e->getMessage() + ); if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { - print("Unable to parse suite \"" . $parsedSuite[self::NAME] . "\"\n"); - LoggingUtil::getInstance()->getLogger(self::class)->error( - "Unable to parse suite \"" . $parsedSuite[self::NAME] . "\"\n" . $e->getMessage() + print("ERROR: Unable to parse suite " . $parsedSuite[self::NAME] . "\n"); + } + if (MftfApplicationConfig::getConfig()->getPhase() != MftfApplicationConfig::EXECUTION_PHASE) { + GenerationErrorHandler::getInstance()->addError( + 'suite', + $parsedSuite[self::NAME], + self::class . ': Unable to parse suite ' . $e->getMessage() ); } continue; @@ -145,19 +166,7 @@ public function parseSuiteDataIntoObjects($parsedSuiteData) ); } - if ($suiteSkipped != 0 - && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { - print("ERROR: " . strval($suiteSkipped) - . " Suite failed to generate. See mftf.log for details."); - LoggingUtil::getInstance()->getLogger(self::class)->error( - "ERROR: " . strval($suiteSkipped) . " Suite failed to generate." - ); - } - - return [ - 'status' => $noError, - 'objects' => $suiteObjects, - ]; + return $suiteObjects; } /** @@ -262,6 +271,7 @@ private function isSuiteEmpty($suiteHooks, $includeTests, $excludeTests) * * @param array $suiteReferences * @return array + * @throws FastFailException */ private function extractTestObjectsFromSuiteRef($suiteReferences) { @@ -294,7 +304,12 @@ private function extractTestObjectsFromSuiteRef($suiteReferences) } catch (\Exception $e) { $errCount++; LoggingUtil::getInstance()->getLogger(self::class)->error( - "Unable to find tests by reference for suite \"" . $suiteRefData[self::NAME] . '"' + "Unable to find <" + . $suiteRefData[self::NODE_NAME] + . "> reference " + . $suiteRefData[self::NAME] + . " for suite " + . $suiteRefData[self::NAME] ); } } diff --git a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php index 9c2f24a77..334696b06 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php @@ -5,7 +5,8 @@ */ namespace Magento\FunctionalTestingFramework\Test\Handlers; -use Magento\FunctionalTestingFramework\Exceptions\Collector\ExceptionCollector; +use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Exceptions\FastFailException; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Exceptions\XmlException; @@ -15,11 +16,14 @@ use Magento\FunctionalTestingFramework\Test\Parsers\TestDataParser; use Magento\FunctionalTestingFramework\Test\Util\ObjectExtensionUtil; use Magento\FunctionalTestingFramework\Test\Util\TestObjectExtractor; +use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; use Magento\FunctionalTestingFramework\Util\Validation\NameValidationUtil; /** * Class TestObjectHandler + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class TestObjectHandler implements ObjectHandlerInterface { @@ -51,7 +55,8 @@ class TestObjectHandler implements ObjectHandlerInterface * Singleton method to return TestObjectHandler. * * @return TestObjectHandler - * @throws XmlException + * @throws FastFailException + * @throws TestFrameworkException */ public static function getInstance($validateAnnotations = true) { @@ -92,12 +97,32 @@ public function getObject($testName) * Returns all tests parsed from xml indexed by testName. * * @return array + * @throws FastFailException + * @throws TestFrameworkException */ public function getAllObjects() { $testObjects = []; foreach ($this->tests as $testName => $test) { - $testObjects[$testName] = $this->extendTest($test); + try { + $testObjects[$testName] = $this->extendTest($test); + } catch (FastFailException $exception) { + throw $exception; + } catch (\Exception $exception) { + LoggingUtil::getInstance()->getLogger(self::class)->error( + "Unable to create test " . $testName . "\n" . $exception->getMessage() + ); + if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { + print("ERROR: Unable to create test " . $testName . "\n" . $exception->getMessage()); + } + if (MftfApplicationConfig::getConfig()->getPhase() != MftfApplicationConfig::EXECUTION_PHASE) { + GenerationErrorHandler::getInstance()->addError( + 'test', + $testName, + self::class . ': Unable to create test ' . $exception->getMessage() + ); + } + } } return $testObjects; } @@ -107,15 +132,36 @@ public function getAllObjects() * * @param string $groupName * @return TestObject[] + * @throws FastFailException + * @throws TestFrameworkException */ public function getTestsByGroup($groupName) { $relevantTests = []; foreach ($this->tests as $test) { - /** @var TestObject $test */ - if (in_array($groupName, $test->getAnnotationByName('group'))) { - $relevantTests[$test->getName()] = $this->extendTest($test); - continue; + try { + /** @var TestObject $test */ + if (in_array($groupName, $test->getAnnotationByName('group'))) { + $relevantTests[$test->getName()] = $this->extendTest($test); + } + } catch (FastFailException $exception) { + throw $exception; + } catch (\Exception $exception) { + $message = "Unable to reference test " + . $test->getName() + . " for group {$groupName}\n" + . $exception->getMessage(); + LoggingUtil::getInstance()->getLogger(self::class)->error($message); + if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { + print('ERROR: ' . $message); + } + if (MftfApplicationConfig::getConfig()->getPhase() != MftfApplicationConfig::EXECUTION_PHASE) { + GenerationErrorHandler::getInstance()->addError( + 'test', + $test->getName(), + self::class . ': ' . $message + ); + } } } @@ -133,7 +179,7 @@ public function sanitizeTests($testsToRemove) foreach ($testsToRemove as $name) { unset($this->tests[$name]); LoggingUtil::getInstance()->getLogger(self::class)->error( - "Failed to parse and removed test object {$name}." + "Removed invalid test object {$name}" ); } } @@ -143,7 +189,8 @@ public function sanitizeTests($testsToRemove) * * @return void * @SuppressWarnings(PHPMD.UnusedPrivateMethod) - * @throws XmlException + * @throws FastFailException + * @throws TestFrameworkException */ private function initTestData($validateAnnotations = true) { @@ -157,21 +204,33 @@ private function initTestData($validateAnnotations = true) return; } - $exceptionCollector = new ExceptionCollector(); $testNameValidator = new NameValidationUtil(); foreach ($parsedTestArray as $testName => $testData) { - $filename = $testData[TestObjectHandler::TEST_FILENAME_ATTRIBUTE]; - $testNameValidator->validatePascalCase($testName, NameValidationUtil::TEST_NAME, $filename); - if (!is_array($testData)) { - continue; - } try { + $filename = $testData[TestObjectHandler::TEST_FILENAME_ATTRIBUTE]; + $testNameValidator->validatePascalCase($testName, NameValidationUtil::TEST_NAME, $filename); + if (!is_array($testData)) { + continue; + } $this->tests[$testName] = $testObjectExtractor->extractTestData($testData, $validateAnnotations); - } catch (XmlException $exception) { - $exceptionCollector->addError(self::class, $exception->getMessage()); + } catch (FastFailException $exception) { + throw $exception; + } catch (\Exception $exception) { + LoggingUtil::getInstance()->getLogger(self::class)->error( + "Unable to parse test " . $testName . "\n" . $exception->getMessage() + ); + if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { + print("ERROR: Unable to parse test " . $testName . "\n"); + } + if (MftfApplicationConfig::getConfig()->getPhase() != MftfApplicationConfig::EXECUTION_PHASE) { + GenerationErrorHandler::getInstance()->addError( + 'test', + $testName, + self::class . ': Unable to parse test ' . $exception->getMessage() + ); + } } } - $exceptionCollector->throwException(); $testNameValidator->summarize(NameValidationUtil::TEST_NAME); if ($validateAnnotations) { $testObjectExtractor->getAnnotationExtractor()->validateStoryTitleUniqueness(); @@ -185,12 +244,15 @@ private function initTestData($validateAnnotations = true) * @param TestObject $testObject * @return TestObject * @throws TestFrameworkException + * @throws XmlException */ private function extendTest($testObject) { if ($testObject->getParentName() !== null) { if ($testObject->getParentName() == $testObject->getName()) { - throw new TestFrameworkException("Mftf Test can not extend from itself: " . $testObject->getName()); + throw new TestFrameworkException( + "Mftf Test can not extend from itself: " . $testObject->getName() + ); } return $this->extendUtil->extendTest($testObject); } diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php index 46adb7ce2..39016ab64 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php @@ -7,8 +7,10 @@ namespace Magento\FunctionalTestingFramework\Test\Util; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; +use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; /** @@ -171,38 +173,50 @@ private function validateMissingAnnotations($annotationObjects, $filename) /** * Validates that all Story/Title combinations are unique, builds list of violators if found. - * @throws XmlException + * * @return void + * @throws TestFrameworkException */ public function validateStoryTitleUniqueness() { - $dupes = []; + if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::EXECUTION_PHASE) { + return; + } + $dupes = []; foreach ($this->storyToTitleMappings as $storyTitle => $files) { if (count($files) > 1) { $dupes[$storyTitle] = "'" . implode("', '", $files) . "'"; } } if (!empty($dupes)) { - $message = "Story and Title annotation pairs must be unique:\n\n"; foreach ($dupes as $storyTitle => $tests) { - $storyTitleArray = explode("/", $storyTitle); - $story = $storyTitleArray[0]; - $title = $storyTitleArray[1]; - $message .= "Story: '{$story}' Title: '{$title}' in Tests {$tests}\n\n"; + $message = "Story and Title annotation pairs is not unique in Tests {$tests}\n"; + LoggingUtil::getInstance()->getLogger(self::class)->error($message); + if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { + print('ERROR: ' . $message); + } + $testArray = explode(',', $tests); + foreach ($testArray as $test) { + GenerationErrorHandler::getInstance()->addError( + 'test', trim($test, "' \t"), $message, true + ); + } } - throw new XmlException($message); } } /** * Validates uniqueness between Test Case ID and Titles globally - * @returns void - * @throws XmlException * @return void + * @throws TestFrameworkException */ public function validateTestCaseIdTitleUniqueness() { + if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::EXECUTION_PHASE) { + return; + } + $dupes = []; foreach ($this->testCaseToTitleMappings as $newTitle => $files) { if (count($files) > 1) { @@ -210,14 +224,19 @@ public function validateTestCaseIdTitleUniqueness() } } if (!empty($dupes)) { - $message = "TestCaseId and Title pairs must be unique:\n\n"; foreach ($dupes as $newTitle => $tests) { - $testCaseTitleArray = explode(": ", $newTitle); - $testCaseId = $testCaseTitleArray[0]; - $title = $testCaseTitleArray[1]; - $message .= "TestCaseId: '{$testCaseId}' Title: '{$title}' in Tests {$tests}\n\n"; + $message = "TestCaseId and Title pairs is not unique in Tests {$tests}\n"; + LoggingUtil::getInstance()->getLogger(self::class)->error($message); + if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { + print('ERROR: ' . $message); + } + $testArray = explode(',', $tests); + foreach ($testArray as $test) { + GenerationErrorHandler::getInstance()->addError( + 'test', trim($test, "' \t"), $message, true + ); + } } - throw new XmlException($message); } } diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/ObjectExtensionUtil.php b/src/Magento/FunctionalTestingFramework/Test/Util/ObjectExtensionUtil.php index 91617b1e2..b59cdb53c 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/ObjectExtensionUtil.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/ObjectExtensionUtil.php @@ -7,6 +7,7 @@ namespace Magento\FunctionalTestingFramework\Test\Util; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Test\Handlers\ActionGroupObjectHandler; @@ -32,7 +33,8 @@ public function __construct() * * @param TestObject $testObject * @return TestObject - * @throws TestReferenceException|XmlException + * @throws TestFrameworkException + * @throws XmlException */ public function extendTest($testObject) { diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/TestHookObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/TestHookObjectExtractor.php index e9c163d31..523f1278b 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/TestHookObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/TestHookObjectExtractor.php @@ -6,6 +6,8 @@ namespace Magento\FunctionalTestingFramework\Test\Util; +use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; +use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Magento\FunctionalTestingFramework\Test\Objects\TestHookObject; @@ -37,7 +39,8 @@ public function __construct() * @param string $hookType * @param array $testHook * @return TestHookObject - * @throws \Exception + * @throws XmlException + * @throws TestReferenceException */ public function extractHook($parentName, $hookType, $testHook) { diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php index ff3a1e5f8..daee2ada2 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php @@ -7,6 +7,7 @@ namespace Magento\FunctionalTestingFramework\Test\Util; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Page\Objects\ElementObject; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; @@ -86,7 +87,9 @@ public function getAnnotationExtractor() * @param array $testData * @param boolean $validateAnnotations * @return TestObject - * @throws \Exception + * @throws TestReferenceException + * @throws XmlException + * @throws TestFrameworkException */ public function extractTestData($testData, $validateAnnotations = true) { diff --git a/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php b/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php new file mode 100644 index 000000000..2517145cf --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php @@ -0,0 +1,125 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\FunctionalTestingFramework\Util; + +use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use PHP_CodeSniffer\Exceptions\RuntimeException; + +class GenerationErrorHandler +{ + /** + * Generation Error Handler Instance + * + * @var GenerationErrorHandler + */ + private static $instance; + + /** + * Collected errors + * + * @var array + */ + private $errors = []; + + /** + * Singleton method to return GenerationErrorHandler + * + * @return GenerationErrorHandler + */ + public static function getInstance() + { + if (!self::$instance) { + self::$instance = new GenerationErrorHandler(); + } + + return self::$instance; + } + + /** + * GenerationErrorHandler constructor + */ + private function __construct() + { + } + + /** + * Add a generation error into error handler + * + * @param string $type + * @param string $entityName + * @param string $message + * @param boolean $generated + * @return void + * @throws \Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException + */ + public function addError($type, $entityName, $message, $generated = false) + { + if (MftfApplicationConfig::getConfig()->getPhase() != MftfApplicationConfig::EXECUTION_PHASE) { + $error[$entityName] = [ + 'message' => $message, + 'generated' => $generated, + ]; + if (isset($this->errors[$type])) { + $this->errors[$type] = array_merge_recursive($this->errors[$type], $error); + } else { + $this->errors[$type] = $error; + } + } + } + + /** + * Return all errors + * + * @return array + */ + public function getAllErrors() + { + return $this->errors; + } + + /** + * Return errors for given type + * + * @param string $type + * @return array + */ + public function getErrorsByType($type) + { + return $this->errors[$type] ?? []; + } + + /** + * Reset error to empty array + * + * @return void + */ + public function reset() + { + $this->errors = []; + } + + /** + * Print error summary in console + * + * @return void + */ + public function printErrorSummary() + { + if (is_array(array_keys($this->errors))) { + foreach (array_keys($this->errors) as $type) { + print( + PHP_EOL + . 'ERROR: ' + . strval(count($this->getErrorsByType($type))) + . ' ' + . ucfirst($type) + . " failed to generate or generated but with annotation errors" + ); + } + print(PHP_EOL); + } + } +} diff --git a/src/Magento/FunctionalTestingFramework/Util/Logger/LoggingUtil.php b/src/Magento/FunctionalTestingFramework/Util/Logger/LoggingUtil.php index 97fdada21..268bc5193 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Logger/LoggingUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/Logger/LoggingUtil.php @@ -9,7 +9,6 @@ use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Monolog\Handler\StreamHandler; -use Monolog\Logger; class LoggingUtil { @@ -63,12 +62,12 @@ private function __clone() * * @param string $className * @return MftfLogger - * @throws \Exception + * @throws TestFrameworkException */ public function getLogger($className): MftfLogger { if ($className == null) { - throw new \Exception("You must pass a class name to receive a logger"); + throw new TestFrameworkException("You must pass a class name to receive a logger"); } if (!array_key_exists($className, $this->loggers)) { diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index a2a7709a1..a44e04d1c 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -128,20 +128,6 @@ class TestGenerator */ private $deprecationMessages = []; - /** - * Test deprecation messages. - * - * @var array - */ - private $cestPhpArray = []; - - /** - * Test deprecation messages. - * - * @var array - */ - private $notGeneratedTestsArray = []; - /** * Private constructor for Factory * @@ -191,6 +177,9 @@ public function getExportDir() * * @param array $testsToIgnore * @return array + * @throws TestReferenceException + * @throws TestFrameworkException + * @throws FastFailException */ private function loadAllTestObjects($testsToIgnore) { @@ -219,7 +208,7 @@ private function loadAllTestObjects($testsToIgnore) * @param string $testPhp * @param string $filename * @return void - * @throws \Exception + * @throws TestFrameworkException */ private function createCestFile(string $testPhp, string $filename) { @@ -228,7 +217,7 @@ private function createCestFile(string $testPhp, string $filename) $file = fopen($exportFilePath, 'w'); if (!$file) { - throw new \Exception(sprintf('Could not open test file: "%s"', $exportFilePath)); + throw new TestFrameworkException(sprintf('Could not open test file: "%s"', $exportFilePath)); } fwrite($file, $testPhp); @@ -242,8 +231,10 @@ private function createCestFile(string $testPhp, string $filename) * @param BaseTestManifest $testManifest * @param array $testsToIgnore * @return void + * @throws TestFrameworkException + * @throws XmlException + * @throws FastFailException * @throws TestReferenceException - * @throws \Exception */ public function createAllTestFiles($testManifest = null, $testsToIgnore = null) { @@ -257,18 +248,10 @@ public function createAllTestFiles($testManifest = null, $testsToIgnore = null) $testsToIgnore = SuiteObjectHandler::getInstance()->getAllTestReferences(); } - $noError = $this->assembleAllTestPhp($testManifest, $testsToIgnore); - foreach ($this->cestPhpArray as $testPhpFile) { + $testPhpArray = $this->assembleAllTestPhp($testManifest, $testsToIgnore); + foreach ($testPhpArray as $testPhpFile) { $this->createCestFile($testPhpFile[1], $testPhpFile[0]); } - - if (!$noError) { - throw new TestFrameworkException( - "ERROR: " - . strval(count($this->notGeneratedTestsArray)) - . " Test failed to generate." - ); - } } /** @@ -345,20 +328,16 @@ private function generateInjectMethod() * * @param BaseTestManifest $testManifest * @param array $testsToIgnore - * @return boolean + * @return array * @throws TestFrameworkException * @throws TestReferenceException - * @throws XmlException * @throws FastFailException */ private function assembleAllTestPhp($testManifest, array $testsToIgnore) { - $this->cestPhpArray = []; - $this->notGeneratedTestsArray = []; - /** @var TestObject[] $testObjects */ $testObjects = $this->loadAllTestObjects($testsToIgnore); - + $cestPhpArray = []; $filters = MftfApplicationConfig::getConfig()->getFilterList()->getFilters(); /** @var FilterInterface $filter */ foreach ($filters as $filter) { @@ -377,8 +356,8 @@ private function assembleAllTestPhp($testManifest, array $testsToIgnore) } catch (TestReferenceException $e) { TestObjectHandler::getInstance()->sanitizeTests([$test->getName()]); if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { - print("{$test->getName()} will not be generated. Parent {$e->getMessage()} \n"); - LoggingUtil::getInstance()->getLogger(self::class)->info( + print("ERROR: {$test->getName()} will not be generated. Parent {$e->getMessage()} \n"); + LoggingUtil::getInstance()->getLogger(self::class)->error( "{$test->getName()} will not be generated. Parent does not exist." ); } @@ -388,7 +367,7 @@ private function assembleAllTestPhp($testManifest, array $testsToIgnore) $this->debug("<comment>Start creating test: " . $test->getCodeceptionName() . "</comment>"); $php = $this->assembleTestPhp($test); - $this->cestPhpArray[] = [$test->getCodeceptionName(), $php]; + $cestPhpArray[] = [$test->getCodeceptionName(), $php]; // Set flag in case something goes wrong $removeLastTest = true; @@ -403,22 +382,24 @@ private function assembleAllTestPhp($testManifest, array $testsToIgnore) } catch (FastFailException $e) { throw $e; } catch (\Exception $e) { - $this->notGeneratedTestsArray[] = [$test->getName() => $e->getMessage()]; + if (MftfApplicationConfig::getConfig()->getPhase() != MftfApplicationConfig::EXECUTION_PHASE) { + GenerationErrorHandler::getInstance()->addError( + 'test', + $test->getName(), + self::class . ': ' . $e->getMessage() + ); + } LoggingUtil::getInstance()->getLogger(self::class)->error( "Failed to generate {$test->getName()}" ); if ($removeLastTest) { - array_pop($this->cestPhpArray); + array_pop($cestPhpArray); } TestObjectHandler::getInstance()->sanitizeTests([$test->getName()]); } } - if (empty($this->notGeneratedTestsArray)) { - return true; - } else { - return false; - } + return $cestPhpArray; } /** diff --git a/src/Magento/FunctionalTestingFramework/Util/Validation/NameValidationUtil.php b/src/Magento/FunctionalTestingFramework/Util/Validation/NameValidationUtil.php index cf9f34164..68642c53a 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Validation/NameValidationUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/Validation/NameValidationUtil.php @@ -6,7 +6,7 @@ namespace Magento\FunctionalTestingFramework\Util\Validation; -use Exception; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; @@ -84,7 +84,7 @@ public static function validateName($name, $type) * @param string $str * @param string $type * @param string $filename - * @throws Exception + * @throws TestFrameworkException * @return void */ public function validatePascalCase($str, $type, $filename = null) @@ -112,7 +112,7 @@ public function validatePascalCase($str, $type, $filename = null) * @param string $str * @param string $type * @param string $filename - * @throws Exception + * @throws TestFrameworkException * @return void */ public function validateCamelCase($str, $type, $filename = null) @@ -140,7 +140,7 @@ public function validateCamelCase($str, $type, $filename = null) * @param string $str * @param string $type * @param string $filename - * @throws Exception + * @throws TestFrameworkException * @return void */ public function validateAffixes($str, $type, $filename = null) @@ -170,7 +170,7 @@ public function validateAffixes($str, $type, $filename = null) * Outputs the number of validations detected by this instance. * * @param string $type - * @throws Exception + * @throws TestFrameworkException * @return void */ public function summarize($type) From 4234cdac94e86c773b47d1250f91f3b96be0e648 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 14 Sep 2020 13:07:48 -0500 Subject: [PATCH 534/888] MQE-1800: Allow generate:tests to continue running even if one test fails generation --- .../Console/BaseGenerateCommandTest.php | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php index ce7586eab..d2a58c0ff 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php @@ -188,13 +188,7 @@ public function mockHandlers($testArray, $suiteArray) $property->setAccessible(true); $property->setValue($handler, $testArray); - AspectMock::double( - SuiteObjectHandler::class, - [ - 'initSuiteData' => '', - 'parseSuccessful' => true, - ] - )->make(); + AspectMock::double(SuiteObjectHandler::class, ['initSuiteData' => ''])->make(); $handler = SuiteObjectHandler::getInstance(); $property = new \ReflectionProperty(SuiteObjectHandler::class, 'suiteObjects'); $property->setAccessible(true); From a3e33d916d3c0bb1e5071f537ec1a0f73549d16f Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 14 Sep 2020 13:18:18 -0500 Subject: [PATCH 535/888] MQE-1800: Allow generate:tests to continue running even if one test fails generation --- .../Test/Util/AnnotationExtractor.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php index 39016ab64..1d1719037 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php @@ -199,7 +199,10 @@ public function validateStoryTitleUniqueness() $testArray = explode(',', $tests); foreach ($testArray as $test) { GenerationErrorHandler::getInstance()->addError( - 'test', trim($test, "' \t"), $message, true + 'test', + trim($test, "' \t"), + $message, + true ); } } @@ -233,7 +236,10 @@ public function validateTestCaseIdTitleUniqueness() $testArray = explode(',', $tests); foreach ($testArray as $test) { GenerationErrorHandler::getInstance()->addError( - 'test', trim($test, "' \t"), $message, true + 'test', + trim($test, "' \t"), + $message, + true ); } } From 0006101b5a7f2ae6ae53fe31728cb22ab1ba85c1 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 14 Sep 2020 13:22:35 -0500 Subject: [PATCH 536/888] MQE-1800: Allow generate:tests to continue running even if one test fails generation --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 92289622a..813ab382b 100755 --- a/composer.json +++ b/composer.json @@ -63,7 +63,7 @@ }, "autoload-dev": { "psr-4": { - "tests\\": "dev/tests" + "tests\\unit\\": "dev/tests/unit" } }, "scripts": { From 9540a81b7d1b65cd7a6c69c540dac28e5002b063 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 14 Sep 2020 13:24:13 -0500 Subject: [PATCH 537/888] MQE-1800: Allow generate:tests to continue running even if one test fails generation --- .github/workflows/main.yml | 2 +- composer.json | 2 +- composer.lock | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4554d09e6..3a25c9bc5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -27,7 +27,7 @@ jobs: uses: actions/cache@v2 with: path: vendor - key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} + key: {{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} restore-keys: | ${{ runner.os }}-php- diff --git a/composer.json b/composer.json index 813ab382b..92289622a 100755 --- a/composer.json +++ b/composer.json @@ -63,7 +63,7 @@ }, "autoload-dev": { "psr-4": { - "tests\\unit\\": "dev/tests/unit" + "tests\\": "dev/tests" } }, "scripts": { diff --git a/composer.lock b/composer.lock index 7f7648096..8b89b023a 100644 --- a/composer.lock +++ b/composer.lock @@ -7126,6 +7126,7 @@ ], "description": "FinderFacade is a convenience wrapper for Symfony's Finder component.", "homepage": "https://github.com/sebastianbergmann/finder-facade", + "abandoned": true, "time": "2020-02-08T06:07:58+00:00" }, { @@ -7470,6 +7471,5 @@ "ext-json": "*", "ext-openssl": "*" }, - "platform-dev": [], - "plugin-api-version": "1.1.0" + "platform-dev": [] } From 6abc4c8a05fefa9b828cb7f1697d8f721f6252b4 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 14 Sep 2020 13:26:03 -0500 Subject: [PATCH 538/888] MQE-1800: Allow generate:tests to continue running even if one test fails generation --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3a25c9bc5..e98ab3bc5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -27,7 +27,7 @@ jobs: uses: actions/cache@v2 with: path: vendor - key: {{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} + key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} restore-keys: | ${{ runner.os }}-php- @@ -73,7 +73,7 @@ jobs: ${{ runner.os }}-php- - name: Install dependencies - #if: steps.composer-cache.outputs.cache-hit != 'true' + if: steps.composer-cache.outputs.cache-hit != 'true' run: composer install --prefer-dist --no-progress --no-suggest - name: Run tests From 09a579cbf76a128eac202515d0927af0057ab0fb Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 14 Sep 2020 13:31:38 -0500 Subject: [PATCH 539/888] MQE-1800: Allow generate:tests to continue running even if one test fails generation --- .../Test/Util/AnnotationExtractorTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/AnnotationExtractorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/AnnotationExtractorTest.php index 3e3c44429..82a1f32b8 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/AnnotationExtractorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/AnnotationExtractorTest.php @@ -200,7 +200,9 @@ public function testTestCaseIdUniqueness() // assert that no exception for validateTestCaseIdTitleUniqueness // and validation error is stored in GenerationErrorHandler - $errorMessage = '/' . preg_quote("TestCaseId and Title pairs is not unique in Tests 'firstTest', 'secondTest'") . '/'; + $errorMessage = '/' + . preg_quote("TestCaseId and Title pairs is not unique in Tests 'firstTest', 'secondTest'") + . '/'; TestLoggingUtil::getInstance()->validateMockLogStatmentRegex('error', $errorMessage, []); $testErrors = GenerationErrorHandler::getInstance()->getErrorsByType('test'); $this->assertArrayHasKey('firstTest', $testErrors); From 55e0beda60ee39f3afb5cc66511fa5b876143cdd Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 16 Sep 2020 14:59:08 -0500 Subject: [PATCH 540/888] MQE-1800: Allow generate:tests to continue running even if one test fails generation --- .../Util/GenerationErrorHandler.php | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php b/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php index 2517145cf..15941adb5 100644 --- a/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php +++ b/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php @@ -108,16 +108,37 @@ public function reset() */ public function printErrorSummary() { + if (is_array(array_keys($this->errors))) { foreach (array_keys($this->errors) as $type) { - print( - PHP_EOL - . 'ERROR: ' - . strval(count($this->getErrorsByType($type))) - . ' ' - . ucfirst($type) - . " failed to generate or generated but with annotation errors" - ); + $totalErrors = count($this->getErrorsByType($type)); + $totalAnnotationErrors = 0; + foreach ($this->getErrorsByType($type) as $entity => $error) { + if ($error['generated'] == true) { + $totalAnnotationErrors++; + } + } + $totalNotGenErrors = $totalErrors - $totalAnnotationErrors; + if ($totalNotGenErrors > 0) { + print( + PHP_EOL + . 'ERROR: ' + . strval($totalNotGenErrors) + . ' ' + . ucfirst($type) + . " failed to generate" + ); + } + if ($totalAnnotationErrors > 0) { + print( + PHP_EOL + . 'ERROR: ' + . strval($totalAnnotationErrors) + . ' ' + . ucfirst($type) + . " generated with annotation errors" + ); + } } print(PHP_EOL); } From 7ff4c3db9ce2f46cea98d1f4fab8740d48c154c7 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 16 Sep 2020 15:09:37 -0500 Subject: [PATCH 541/888] MQE-1800: Allow generate:tests to continue running even if one test fails generation --- .../Util/GenerationErrorHandler.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php b/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php index 15941adb5..c17c987eb 100644 --- a/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php +++ b/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php @@ -108,7 +108,6 @@ public function reset() */ public function printErrorSummary() { - if (is_array(array_keys($this->errors))) { foreach (array_keys($this->errors) as $type) { $totalErrors = count($this->getErrorsByType($type)); @@ -126,7 +125,7 @@ public function printErrorSummary() . strval($totalNotGenErrors) . ' ' . ucfirst($type) - . " failed to generate" + . " failed to generate. See mftf.log for details." ); } if ($totalAnnotationErrors > 0) { @@ -136,7 +135,7 @@ public function printErrorSummary() . strval($totalAnnotationErrors) . ' ' . ucfirst($type) - . " generated with annotation errors" + . " generated with annotation errors. See mftf.log for details." ); } } From eb7ffdd63db48973fabad2435d3b518685f7cdeb Mon Sep 17 00:00:00 2001 From: Tom Reece <treece@adobe.com> Date: Thu, 17 Sep 2020 13:37:09 -0500 Subject: [PATCH 542/888] MQE-2289: Cant generate urn catalog --- docs/commands/mftf.md | 6 +++--- docs/getting-started.md | 4 ++-- docs/update.md | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index aabc8dadb..8e2146ad4 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -245,10 +245,10 @@ It also enables auto-completion in PhpStorm. #### Usage ```bash -vendor/bin/mftf generate:urn-catalog [--force] [<path to the directory with misc.xml>] +vendor/bin/mftf generate:urn-catalog [--force] [<path to misc.xml>] ``` -`misc.xml` is typically located in `<project root>/.idea/`. +`misc.xml` is typically located at `<project root>/.idea/misc.xml`. #### Options @@ -259,7 +259,7 @@ vendor/bin/mftf generate:urn-catalog [--force] [<path to the directory with misc #### Example ```bash -vendor/bin/mftf generate:urn-catalog .idea/ +vendor/bin/mftf generate:urn-catalog .idea/misc.xml ``` ### `reset` diff --git a/docs/getting-started.md b/docs/getting-started.md index 1c8200e3b..f0707f632 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -170,13 +170,13 @@ vendor/bin/mftf build:project If you use PhpStorm, generate a URN catalog: ```bash -vendor/bin/mftf generate:urn-catalog .idea/ +vendor/bin/mftf generate:urn-catalog .idea/misc.xml ``` If the file does not exist, add the `--force` option to create it: ```bash -vendor/bin/mftf generate:urn-catalog --force .idea/ +vendor/bin/mftf generate:urn-catalog --force .idea/misc.xml ``` See [`generate:urn-catalog`][] for more details. diff --git a/docs/update.md b/docs/update.md index dc5e7fbc8..284730430 100644 --- a/docs/update.md +++ b/docs/update.md @@ -39,7 +39,7 @@ Takes place when **first** digit of version number changes. ## After updating -1. It is a good idea to regenerate your IDE Schema Definition catalog with `vendor/bin/mftf generate:urn-catalog .idea/` +1. It is a good idea to regenerate your IDE Schema Definition catalog with `vendor/bin/mftf generate:urn-catalog .idea/misc.xml` 1. Update your tests, including data, metadata and other resources. Check if they contain tags that are unsupported in the newer version. 1. Remove the references to resources (ActionGroups, Sections, Tests) marked as deprecated. From 1812a0fe75bc42228af2546012295a52554f22af Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 23 Sep 2020 17:13:25 -0500 Subject: [PATCH 543/888] MQE-1800: Allow generate:tests to continue running even if one test fails generation --- .../Console/GenerateSuiteCommand.php | 17 ++++-- .../Console/GenerateTestsCommand.php | 2 +- .../DataTransport/Auth/WebApiAuth.php | 52 ++++++++++-------- .../DataTransport/WebApiExecutor.php | 5 +- .../Suite/Handlers/SuiteObjectHandler.php | 7 ++- .../Test/Handlers/TestObjectHandler.php | 53 ++++++++++++++----- .../Util/GenerationErrorHandler.php | 7 +-- 7 files changed, 97 insertions(+), 46 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php index 10e245a79..920516168 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php @@ -67,12 +67,14 @@ protected function execute(InputInterface $input, OutputInterface $output) $suites = $input->getArgument('suites'); + $generated = 0; foreach ($suites as $suite) { try { SuiteGenerator::getInstance()->generateSuite($suite); if ($output->isVerbose()) { $output->writeLn("suite $suite generated"); } + $generated++; } catch (FastFailException $e) { throw $e; } catch (\Exception $e) { @@ -80,13 +82,20 @@ protected function execute(InputInterface $input, OutputInterface $output) } if (empty(GenerationErrorHandler::getInstance()->getAllErrors())) { - $output->writeln("Suites Generated"); - return 0; + if ($generated > 0) { + $output->writeln("Suites Generated"); + return 0; + } } else { GenerationErrorHandler::getInstance()->printErrorSummary(); GenerationErrorHandler::getInstance()->reset(); - $output->writeln("Suites Generated (with failures)"); - return 1; + if ($generated > 0) { + $output->writeln("Suites Generated (with errors)"); + return 1; + } } + + $output->writeln("No Suite Generated"); + return 1; } } diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php index 8a6bc60de..8db65ab4a 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php @@ -169,7 +169,7 @@ protected function execute(InputInterface $input, OutputInterface $output) } else { GenerationErrorHandler::getInstance()->printErrorSummary(); GenerationErrorHandler::getInstance()->reset(); - $output->writeln("Generate Tests Command Run (with failures)"); + $output->writeln("Generate Tests Command Run (with errors)"); return 1; } } diff --git a/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php b/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php index 566d2b348..8a8529939 100644 --- a/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php +++ b/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php @@ -6,6 +6,7 @@ namespace Magento\FunctionalTestingFramework\DataTransport\Auth; +use Magento\FunctionalTestingFramework\Exceptions\FastFailException; use Magento\FunctionalTestingFramework\Util\MftfGlobals; use Magento\FunctionalTestingFramework\DataTransport\Protocol\CurlInterface; use Magento\FunctionalTestingFramework\DataTransport\Protocol\CurlTransport; @@ -42,7 +43,7 @@ class WebApiAuth * @param string $username * @param string $password * @return string - * @throws TestFrameworkException + * @throws FastFailException */ public static function getAdminToken($username = null, $password = null) { @@ -56,32 +57,37 @@ public static function getAdminToken($username = null, $password = null) 'MAGENTO_ADMIN_USERNAME' => getenv('MAGENTO_ADMIN_USERNAME'), 'MAGENTO_ADMIN_PASSWORD' => getenv('MAGENTO_ADMIN_PASSWORD'), ]; - throw new TestFrameworkException($message, $context); + throw new FastFailException($message, $context); } if (isset(self::$adminAuthTokens[$login])) { return self::$adminAuthTokens[$login]; } - $authUrl = MftfGlobals::getWebApiBaseUrl() . self::PATH_ADMIN_AUTH; + try { + $authUrl = MftfGlobals::getWebApiBaseUrl() . self::PATH_ADMIN_AUTH; - $data = [ - 'username' => $login, - 'password' => $password - ]; + $data = [ + 'username' => $login, + 'password' => $password + ]; - if (Tfa::isEnabled()) { - $authUrl = MftfGlobals::getWebApiBaseUrl() . Tfa::getProviderWebApiAuthEndpoint('google'); - $data['otp'] = OTP::getOTP(); - } + if (Tfa::isEnabled()) { + $authUrl = MftfGlobals::getWebApiBaseUrl() . Tfa::getProviderWebApiAuthEndpoint('google'); + $data['otp'] = OTP::getOTP(); + } - $transport = new CurlTransport(); - $transport->write( - $authUrl, - json_encode($data, JSON_PRETTY_PRINT), - CurlInterface::POST, - self::$headers - ); + $transport = new CurlTransport(); + $transport->write( + $authUrl, + json_encode($data, JSON_PRETTY_PRINT), + CurlInterface::POST, + self::$headers + ); + } catch (TestFrameworkException $e) { + $message = "Cannot retrieve API token with credentials. Please check configurations in .env.\n"; + throw new FastFailException($message . $e->getMessage(), $e->getContext()); + } try { $response = $transport->read(); @@ -97,12 +103,16 @@ public static function getAdminToken($username = null, $password = null) $errMessage = $e->getMessage(); } - $message = 'Cannot retrieve API token with credentials. Please check the following credentials'; - $message .= Tfa::isEnabled() ? ' and 2FA settings:' : ':' . PHP_EOL; + $message = 'Cannot retrieve API token with credentials. Please check the following configurations'; + try { + // No exception will ever throw from here + $message .= Tfa::isEnabled() ? ' and 2FA settings:' : ':' . PHP_EOL; + } catch (TestFrameworkException $e) { + } $message .= "username: {$login}" . PHP_EOL; $message .= "password: {$password}" . PHP_EOL; $message .= $errMessage; $context = ['url' => $authUrl]; - throw new TestFrameworkException($message, $context); + throw new FastFailException($message, $context); } } diff --git a/src/Magento/FunctionalTestingFramework/DataTransport/WebApiExecutor.php b/src/Magento/FunctionalTestingFramework/DataTransport/WebApiExecutor.php index 4c6682438..1bf792003 100644 --- a/src/Magento/FunctionalTestingFramework/DataTransport/WebApiExecutor.php +++ b/src/Magento/FunctionalTestingFramework/DataTransport/WebApiExecutor.php @@ -6,6 +6,7 @@ namespace Magento\FunctionalTestingFramework\DataTransport; +use Magento\FunctionalTestingFramework\Exceptions\FastFailException; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Util\MftfGlobals; use Magento\FunctionalTestingFramework\DataTransport\Protocol\CurlInterface; @@ -45,7 +46,7 @@ class WebApiExecutor implements CurlInterface * WebApiExecutor Constructor * * @param string $storeCode - * @throws TestFrameworkException + * @throws FastFailException */ public function __construct($storeCode = null) { @@ -58,7 +59,7 @@ public function __construct($storeCode = null) * Acquire and store the authorization token needed for REST requests * * @return void - * @throws TestFrameworkException + * @throws FastFailException */ protected function authorize() { diff --git a/src/Magento/FunctionalTestingFramework/Suite/Handlers/SuiteObjectHandler.php b/src/Magento/FunctionalTestingFramework/Suite/Handlers/SuiteObjectHandler.php index 5f21e08e1..f5d9e45dd 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Handlers/SuiteObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Handlers/SuiteObjectHandler.php @@ -126,7 +126,12 @@ public function getAllTestReferences(): array */ private function initSuiteData() { - $suiteDataParser = ObjectManagerFactory::getObjectManager()->create(SuiteDataParser::class); + try { + $suiteDataParser = ObjectManagerFactory::getObjectManager()->create(SuiteDataParser::class); + } catch (\Exception $e) { + throw new FastFailException("Suite Data Parser Error: " . $e->getMessage()); + } + $suiteObjectExtractor = new SuiteObjectExtractor(); $this->suiteObjects = $suiteObjectExtractor->parseSuiteDataIntoObjects($suiteDataParser->readSuiteData()); } diff --git a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php index 334696b06..535d9b935 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php @@ -102,6 +102,7 @@ public function getObject($testName) */ public function getAllObjects() { + $errCount = 0; $testObjects = []; foreach ($this->tests as $testName => $test) { try { @@ -109,21 +110,29 @@ public function getAllObjects() } catch (FastFailException $exception) { throw $exception; } catch (\Exception $exception) { + $errCount++; LoggingUtil::getInstance()->getLogger(self::class)->error( - "Unable to create test " . $testName . "\n" . $exception->getMessage() + "Unable to extend test " . $testName . "\n" . $exception->getMessage() ); - if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { - print("ERROR: Unable to create test " . $testName . "\n" . $exception->getMessage()); - } if (MftfApplicationConfig::getConfig()->getPhase() != MftfApplicationConfig::EXECUTION_PHASE) { GenerationErrorHandler::getInstance()->addError( 'test', $testName, - self::class . ': Unable to create test ' . $exception->getMessage() + self::class . ': Unable to extend test ' . $exception->getMessage() ); } } } + + if ($errCount > 0 + && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { + print( + "ERROR in TestObjectHandler::getAllObjects(): " + . strval($errCount) + . " Test(s) cannot to be extended. See mftf.log for details." + ); + } + return $testObjects; } @@ -137,6 +146,7 @@ public function getAllObjects() */ public function getTestsByGroup($groupName) { + $errCount = 0; $relevantTests = []; foreach ($this->tests as $test) { try { @@ -147,14 +157,12 @@ public function getTestsByGroup($groupName) } catch (FastFailException $exception) { throw $exception; } catch (\Exception $exception) { + $errCount++; $message = "Unable to reference test " . $test->getName() . " for group {$groupName}\n" . $exception->getMessage(); LoggingUtil::getInstance()->getLogger(self::class)->error($message); - if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { - print('ERROR: ' . $message); - } if (MftfApplicationConfig::getConfig()->getPhase() != MftfApplicationConfig::EXECUTION_PHASE) { GenerationErrorHandler::getInstance()->addError( 'test', @@ -165,6 +173,15 @@ public function getTestsByGroup($groupName) } } + if ($errCount > 0 + && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { + print( + "ERROR in TestObjectHandler::getTestsByGroup(): " + . strval($errCount) + . " Test(s) cannot be referenced for group {$groupName}. See mftf.log for details." + ); + } + return $relevantTests; } @@ -194,16 +211,24 @@ public function sanitizeTests($testsToRemove) */ private function initTestData($validateAnnotations = true) { - $testDataParser = ObjectManagerFactory::getObjectManager()->create(TestDataParser::class); - $parsedTestArray = $testDataParser->readTestData(); + $parserErrorMessage = null; + try { + $testDataParser = ObjectManagerFactory::getObjectManager()->create(TestDataParser::class); + $parsedTestArray = $testDataParser->readTestData(); - $testObjectExtractor = new TestObjectExtractor(); + if (!$parsedTestArray) { + $parserErrorMessage = "Could not parse any test in xml."; + } + } catch (\Exception $e) { + $parserErrorMessage = $e->getMessage(); + } - if (!$parsedTestArray) { - trigger_error("Could not parse any test in xml.", E_USER_NOTICE); - return; + if ($parserErrorMessage) { + throw new FastFailException("Test Data Parser Error: " . $parserErrorMessage); } + $testObjectExtractor = new TestObjectExtractor(); + $testNameValidator = new NameValidationUtil(); foreach ($parsedTestArray as $testName => $testData) { try { diff --git a/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php b/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php index c17c987eb..e3ff3f37c 100644 --- a/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php +++ b/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php @@ -113,7 +113,8 @@ public function printErrorSummary() $totalErrors = count($this->getErrorsByType($type)); $totalAnnotationErrors = 0; foreach ($this->getErrorsByType($type) as $entity => $error) { - if ($error['generated'] == true) { + if ( (is_array($error['generated']) && $error['generated'][0] === true) + || ($error['generated'] === true) ) { $totalAnnotationErrors++; } } @@ -125,7 +126,7 @@ public function printErrorSummary() . strval($totalNotGenErrors) . ' ' . ucfirst($type) - . " failed to generate. See mftf.log for details." + . "(s) failed to generate. See mftf.log for details." ); } if ($totalAnnotationErrors > 0) { @@ -135,7 +136,7 @@ public function printErrorSummary() . strval($totalAnnotationErrors) . ' ' . ucfirst($type) - . " generated with annotation errors. See mftf.log for details." + . "(s) generated with annotation errors. See mftf.log for details." ); } } From 5134007f120f3da5d9445382baf6ce41d6c97413 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 24 Sep 2020 09:36:19 -0500 Subject: [PATCH 544/888] MQE-1800: Allow generate:tests to continue running even if one test fails generation --- .../Suite/SuiteGeneratorTest.php | 18 +++++++--- .../Test/Handlers/TestObjectHandlerTest.php | 3 +- .../Util/ModuleResolverTest.php | 7 ++-- .../Suite/NotGenerateEmptySuite.xml | 12 +++++++ ...enerateActionGroupHasBeforeOrAfterTest.xml | 13 ++++++++ .../NotGenerateNonExistingActionGroupTest.xml | 13 ++++++++ ...NotGenerateExtendNonExistingParentTest.xml | 13 ++++++++ .../ExtendTest/NotGenerateExtendSelfTest.xml | 13 ++++++++ ...enerateActionHasBothBeforeAndAfterTest.xml | 13 ++++++++ ...erateActionHasInvalidBeforeOrAfterTest.xml | 14 ++++++++ .../Tests/ResilientGenerationTest.php | 33 ++++++++++++++++++- .../Tests/SuiteTestReferences.php | 2 ++ docs/commands/mftf.md | 8 +++++ .../DataTransport/Auth/WebApiAuth.php | 2 ++ .../Test/Handlers/TestObjectHandler.php | 14 +++++--- .../Util/GenerationErrorHandler.php | 4 +-- .../Util/TestGenerator.php | 11 +++++-- 17 files changed, 173 insertions(+), 20 deletions(-) create mode 100644 dev/tests/verification/ResilientGenerationModule/Suite/NotGenerateEmptySuite.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateActionGroupHasBeforeOrAfterTest.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateNonExistingActionGroupTest.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/ExtendTest/NotGenerateExtendNonExistingParentTest.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/ExtendTest/NotGenerateExtendSelfTest.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/NotGenerateActionHasBothBeforeAndAfterTest.xml create mode 100644 dev/tests/verification/ResilientGenerationModule/Test/NotGenerateActionHasInvalidBeforeOrAfterTest.xml diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php index f296013ab..035807fb0 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php @@ -51,7 +51,6 @@ public function setUp(): void /** * Tests generating a single suite given a set of parsed test data - * @throws \Exception */ public function testGenerateSuite() { @@ -87,7 +86,6 @@ public function testGenerateSuite() /** * Tests generating all suites given a set of parsed test data - * @throws \Exception */ public function testGenerateAllSuites() { @@ -124,10 +122,16 @@ public function testGenerateAllSuites() /** * Tests attempting to generate a suite with no included/excluded tests and no hooks - * @throws \Exception */ public function testGenerateEmptySuite() { + $testDataArrayBuilder = new TestDataArrayBuilder(); + $mockTestData = $testDataArrayBuilder + ->withName('test') + ->withAnnotations() + ->withTestActions() + ->build(); + $suiteDataArrayBuilder = new SuiteDataArrayBuilder(); $mockData = $suiteDataArrayBuilder ->withName('basicTestSuite') @@ -135,7 +139,6 @@ public function testGenerateEmptySuite() unset($mockData['suites']['basicTestSuite'][TestObjectExtractor::TEST_BEFORE_HOOK]); unset($mockData['suites']['basicTestSuite'][TestObjectExtractor::TEST_AFTER_HOOK]); - $mockTestData = null; $this->setMockTestAndSuiteParserOutput($mockTestData, $mockData); // set expected error message @@ -146,6 +149,9 @@ public function testGenerateEmptySuite() $mockSuiteGenerator->generateSuite("basicTestSuite"); } + /** + * Tests generating all suites with a suite containing invalid test reference + */ public function testInvalidSuiteTestPair() { // Mock Suite1 => Test1 and Suite2 => Test2 @@ -191,6 +197,9 @@ public function testInvalidSuiteTestPair() $this->assertArrayHasKey('Suite2', $suiteErrors); } + /** + * Tests generating all suites with a non-existing suite + */ public function testNonExistentSuiteTestPair() { $testDataArrayBuilder = new TestDataArrayBuilder(); @@ -221,6 +230,7 @@ public function testNonExistentSuiteTestPair() * Function used to set mock for parser return and force init method to run between tests. * * @param array $testData + * @param array $suiteData * @throws \Exception */ private function setMockTestAndSuiteParserOutput($testData, $suiteData) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php index f05277b82..6d259cca2 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php @@ -118,8 +118,7 @@ public function testGetTestObject() */ public function testGetTestWithFileName() { - $this->markTestIncomplete(); - //TODO + $this->markTestIncomplete('TODO'); } /** diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php index c554062fd..f43f82fe2 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php @@ -10,6 +10,7 @@ use AspectMock\Test as AspectMock; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Exceptions\FastFailException; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\ObjectManager; use Magento\FunctionalTestingFramework\ObjectManagerFactory; @@ -777,7 +778,7 @@ public function testGetModulePathsNoAdminToken() $this->setMockResolverProperties($resolver, null, null); // Cannot Generate if no --force was passed in and no Admin Token is returned succesfully - $this->expectException(TestFrameworkException::class); + $this->expectException(FastFailException::class); $resolver->getModulesPath(); } @@ -816,7 +817,7 @@ public function testGetAdminTokenWithMissingEnv() $resolver = ModuleResolver::getInstance(); // Expect exception - $this->expectException(TestFrameworkException::class); + $this->expectException(FastFailException::class); $resolver->getModulesPath(); } @@ -833,7 +834,7 @@ public function testGetAdminTokenWithBadResponse() $resolver = ModuleResolver::getInstance(); // Expect exception - $this->expectException(TestFrameworkException::class); + $this->expectException(FastFailException::class); $resolver->getModulesPath(); } diff --git a/dev/tests/verification/ResilientGenerationModule/Suite/NotGenerateEmptySuite.xml b/dev/tests/verification/ResilientGenerationModule/Suite/NotGenerateEmptySuite.xml new file mode 100644 index 000000000..869b4acf6 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Suite/NotGenerateEmptySuite.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<suites xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Suite/etc/suiteSchema.xsd"> + <suite name="NotGenerateEmptySuite"> + </suite> +</suites> diff --git a/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateActionGroupHasBeforeOrAfterTest.xml b/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateActionGroupHasBeforeOrAfterTest.xml new file mode 100644 index 000000000..1cb3dd4a2 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateActionGroupHasBeforeOrAfterTest.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateActionGroupHasBeforeOrAfterTest"> + <actionGroup ref="FunctionalActionGroup" stepKey="ag" before="N"/> + </test> +</tests> diff --git a/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateNonExistingActionGroupTest.xml b/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateNonExistingActionGroupTest.xml new file mode 100644 index 000000000..61b7544e8 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/ActionGroupTest/NotGenerateNonExistingActionGroupTest.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateNonExistingActionGroupTest"> + <actionGroup ref="NNNFunctionalActionGroup" stepKey="ag"/> + </test> +</tests> diff --git a/dev/tests/verification/ResilientGenerationModule/Test/ExtendTest/NotGenerateExtendNonExistingParentTest.xml b/dev/tests/verification/ResilientGenerationModule/Test/ExtendTest/NotGenerateExtendNonExistingParentTest.xml new file mode 100644 index 000000000..9f42cb55c --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/ExtendTest/NotGenerateExtendNonExistingParentTest.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateExtendNonExistingParentTest" extends="N"> + <comment stepKey="comment" userInput="comment"/> + </test> +</tests> diff --git a/dev/tests/verification/ResilientGenerationModule/Test/ExtendTest/NotGenerateExtendSelfTest.xml b/dev/tests/verification/ResilientGenerationModule/Test/ExtendTest/NotGenerateExtendSelfTest.xml new file mode 100644 index 000000000..46ae93933 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/ExtendTest/NotGenerateExtendSelfTest.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateExtendSelfTest" extends="NotGenerateExtendSelfTest"> + <comment stepKey="comment" userInput="comment"/> + </test> +</tests> diff --git a/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateActionHasBothBeforeAndAfterTest.xml b/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateActionHasBothBeforeAndAfterTest.xml new file mode 100644 index 000000000..2ba798498 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateActionHasBothBeforeAndAfterTest.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateActionHasBothBeforeAndAfterTest"> + <amOnPage url="{{AdminLoginPage.url}}" stepKey="navigateToAdmin" before="B" after="A"/> + </test> +</tests> diff --git a/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateActionHasInvalidBeforeOrAfterTest.xml b/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateActionHasInvalidBeforeOrAfterTest.xml new file mode 100644 index 000000000..eddb2da94 --- /dev/null +++ b/dev/tests/verification/ResilientGenerationModule/Test/NotGenerateActionHasInvalidBeforeOrAfterTest.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="NotGenerateActionHasInvalidBeforeOrAfterTest"> + <amOnPage url="{{AdminLoginPage.url}}" stepKey="navigateToAdmin" after="N"/> + <click stepKey="a" selector="{{$a.b$}}" userInput="a"/> + </test> +</tests> diff --git a/dev/tests/verification/Tests/ResilientGenerationTest.php b/dev/tests/verification/Tests/ResilientGenerationTest.php index e7df5260d..bf65094e3 100644 --- a/dev/tests/verification/Tests/ResilientGenerationTest.php +++ b/dev/tests/verification/Tests/ResilientGenerationTest.php @@ -38,7 +38,10 @@ class ResilientGenerationTest extends MftfTestCase ], 'NotGenerateHookAfterSuite' => [ '/Suite NotGenerateHookAfterSuite is not defined in xml or is invalid./' - ] + ], + 'NotGenerateEmptySuite' => [ + '/Suite NotGenerateEmptySuite is not defined in xml or is invalid./' + ], ]; /** @@ -213,6 +216,34 @@ function () use ($groupName) { } } + /** + * Test generate an empty suite + */ + public function testGenerateEmptySuites() + { + $groupName = 'NotGenerateEmptySuite'; + + // Validate exception is thrown + $this->assertExceptionRegex( + \Exception::class, + self::$exceptionGrpLogs[$groupName], + function () use ($groupName) { + SuiteGenerator::getInstance()->generateSuite($groupName); + } + ); + + // Validate suite is not generated + $dirContents = array_diff(scandir(self::GENERATE_RESULT_DIR), ['..', '.']); + $this->assertFalse(in_array($groupName, $dirContents)); + + // Validate log message + $type = 'error'; + $message = self::$exceptionGrpLogs[$groupName][0]; + $context = []; + + TestLoggingUtil::getInstance()->validateMockLogStatmentRegex($type, $message, $context); + } + /** * * revert any changes made to config.yml diff --git a/dev/tests/verification/Tests/SuiteTestReferences.php b/dev/tests/verification/Tests/SuiteTestReferences.php index 800285528..83481cabf 100644 --- a/dev/tests/verification/Tests/SuiteTestReferences.php +++ b/dev/tests/verification/Tests/SuiteTestReferences.php @@ -61,5 +61,7 @@ class SuiteTestReferences 'DeprecationCheckDeprecatedTestCest.php', 'DeprecationCheckTestCest.php' ], + 'NotGenerateEmptySuite' => [ + ], ]; } diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index aabc8dadb..42e289caa 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -89,6 +89,14 @@ vendor/bin/mftf run:failed This command cleans up the previously generated tests; generates and runs the tests listed in `dev/tests/acceptance/tests/_output/failed`. For more details about `failed`, refer to [Reporting][]. +## Error tolerance during generation + +Starting from version 3.2.0, when generation errors are encountered, MFTF will not fail right away. +Instead MFTF will try to generate as many tests and suites as it can, log errors in `mftf.log` file and exit with non-zero generation status. + +Note that not all errors are tolerable at generation. +For example, schema validation error, parser error, WebApi authentication error will still cause `hard` failure with no test or suite generated. + ## Reference ### `build:project` diff --git a/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php b/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php index 8a8529939..377913cfb 100644 --- a/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php +++ b/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php @@ -44,6 +44,8 @@ class WebApiAuth * @param string $password * @return string * @throws FastFailException + * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public static function getAdminToken($username = null, $password = null) { diff --git a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php index 535d9b935..fc461d9b9 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php @@ -127,9 +127,9 @@ public function getAllObjects() if ($errCount > 0 && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { print( - "ERROR in TestObjectHandler::getAllObjects(): " + "ERROR: " . strval($errCount) - . " Test(s) cannot to be extended. See mftf.log for details." + . " Test(s) cannot to be extended in TestObjectHandler::getAllObjects(). See mftf.log for details." ); } @@ -176,9 +176,10 @@ public function getTestsByGroup($groupName) if ($errCount > 0 && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { print( - "ERROR in TestObjectHandler::getTestsByGroup(): " + "ERROR: " . strval($errCount) - . " Test(s) cannot be referenced for group {$groupName}. See mftf.log for details." + . " Test(s) cannot be referenced for group {$groupName} in TestObjectHandler::getTestsByGroup()." + . " See mftf.log for details." ); } @@ -204,10 +205,13 @@ public function sanitizeTests($testsToRemove) /** * This method reads all Test.xml files into objects and stores them in an array for future access. * + * @param boolean $validateAnnotations * @return void - * @SuppressWarnings(PHPMD.UnusedPrivateMethod) * @throws FastFailException * @throws TestFrameworkException + * + * @SuppressWarnings(PHPMD.UnusedPrivateMethod) + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ private function initTestData($validateAnnotations = true) { diff --git a/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php b/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php index e3ff3f37c..7034e13b6 100644 --- a/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php +++ b/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php @@ -113,8 +113,8 @@ public function printErrorSummary() $totalErrors = count($this->getErrorsByType($type)); $totalAnnotationErrors = 0; foreach ($this->getErrorsByType($type) as $entity => $error) { - if ( (is_array($error['generated']) && $error['generated'][0] === true) - || ($error['generated'] === true) ) { + if ((is_array($error['generated']) && $error['generated'][0] === true) + || ($error['generated'] === true)) { $totalAnnotationErrors++; } } diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index a44e04d1c..dd44ee4ea 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -356,9 +356,14 @@ private function assembleAllTestPhp($testManifest, array $testsToIgnore) } catch (TestReferenceException $e) { TestObjectHandler::getInstance()->sanitizeTests([$test->getName()]); if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { - print("ERROR: {$test->getName()} will not be generated. Parent {$e->getMessage()} \n"); - LoggingUtil::getInstance()->getLogger(self::class)->error( - "{$test->getName()} will not be generated. Parent does not exist." + $errMessage = "{$test->getName()} will not be generated. " + . "Parent test {$test->getParentName()} not defined in xml."; + print("ERROR: {$errMessage}"); + LoggingUtil::getInstance()->getLogger(self::class)->error($errMessage); + GenerationErrorHandler::getInstance()->addError( + 'test', + $test->getName(), + self::class . ': ' . $errMessage ); } continue; From c7eb83b171593cab8ac8e8b7b7c596482ca589b2 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 24 Sep 2020 10:55:47 -0500 Subject: [PATCH 545/888] MQE-1800: Allow generate:tests to continue running even if one test fails generation --- .../Test/Handlers/TestObjectHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php index fc461d9b9..c1acf9be0 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php @@ -129,7 +129,7 @@ public function getAllObjects() print( "ERROR: " . strval($errCount) - . " Test(s) cannot to be extended in TestObjectHandler::getAllObjects(). See mftf.log for details." + . " Test(s) cannot be extended in TestObjectHandler::getAllObjects(). See mftf.log for details." ); } From a9041d59f49158e2e89ff55e3a22fa65daefaaa5 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Fri, 25 Sep 2020 17:45:33 -0500 Subject: [PATCH 546/888] MQE-1800: Allow generate:tests to continue running even if one test fails generation --- .../Console/GenerateTestsCommand.php | 3 ++- .../DataGenerator/Handlers/PersistedObjectHandler.php | 3 ++- .../DataGenerator/Util/DataExtensionUtil.php | 4 ++-- .../Suite/Util/SuiteObjectExtractor.php | 6 ++++-- .../Test/Handlers/TestObjectHandler.php | 5 ++++- .../Test/Util/AnnotationExtractor.php | 6 ++++-- .../Util/GenerationErrorHandler.php | 8 ++++---- .../FunctionalTestingFramework/Util/TestGenerator.php | 4 +++- 8 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php index 8db65ab4a..ddd447420 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php @@ -205,7 +205,8 @@ private function createTestConfiguration( LoggingUtil::getInstance()->getLogger(self::class)->error( $message. PHP_EOL . $e->getMessage() ); - if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { + if (MftfApplicationConfig::getConfig()->verboseEnabled() + && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { print($message . PHP_EOL); } if (MftfApplicationConfig::getConfig()->getPhase() != MftfApplicationConfig::EXECUTION_PHASE) { diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php index 49da76697..60fdf0212 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php @@ -194,7 +194,8 @@ public function retrieveEntityField($stepKey, $field, $scope) $warnMsg .= "Please fix the invalid reference. This will result in fatal error in next major release."; //TODO: change this to throw an exception in next major release LoggingUtil::getInstance()->getLogger(PersistedObjectHandler::class)->warn($warnMsg); - if (MftfApplicationConfig::getConfig()->getPhase() !== MftfApplicationConfig::UNIT_TEST_PHASE) { + if (MftfApplicationConfig::getConfig()->verboseEnabled() + && MftfApplicationConfig::getConfig()->getPhase() !== MftfApplicationConfig::UNIT_TEST_PHASE) { print("\n$warnMsg\n"); } } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Util/DataExtensionUtil.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Util/DataExtensionUtil.php index 53fe71fc0..986f087e3 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Util/DataExtensionUtil.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Util/DataExtensionUtil.php @@ -52,8 +52,8 @@ public function extendEntity($entityObject) PHP_EOL ); } - if (MftfApplicationConfig::getConfig()->verboseEnabled() && - MftfApplicationConfig::getConfig()->getPhase() !== MftfApplicationConfig::UNIT_TEST_PHASE) { + if (MftfApplicationConfig::getConfig()->verboseEnabled() + && MftfApplicationConfig::getConfig()->getPhase() !== MftfApplicationConfig::UNIT_TEST_PHASE) { print("Extending Data: " . $parentEntity->getName() . " => " . $entityObject->getName() . PHP_EOL); } diff --git a/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php index b3696b30c..d0f945b6e 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php @@ -126,7 +126,8 @@ public function parseSuiteDataIntoObjects($parsedSuiteData) if (!empty($includeMessage)) { LoggingUtil::getInstance()->getLogger(self::class)->error($includeMessage); - if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { + if (MftfApplicationConfig::getConfig()->verboseEnabled() + && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { print($includeMessage); } if (MftfApplicationConfig::getConfig()->getPhase() != MftfApplicationConfig::EXECUTION_PHASE) { @@ -144,7 +145,8 @@ public function parseSuiteDataIntoObjects($parsedSuiteData) LoggingUtil::getInstance()->getLogger(self::class)->error( "Unable to parse suite " . $parsedSuite[self::NAME] . "\n" . $e->getMessage() ); - if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { + if (MftfApplicationConfig::getConfig()->verboseEnabled() + && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { print("ERROR: Unable to parse suite " . $parsedSuite[self::NAME] . "\n"); } if (MftfApplicationConfig::getConfig()->getPhase() != MftfApplicationConfig::EXECUTION_PHASE) { diff --git a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php index c1acf9be0..3142e2cb0 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php @@ -125,6 +125,7 @@ public function getAllObjects() } if ($errCount > 0 + && MftfApplicationConfig::getConfig()->verboseEnabled() && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { print( "ERROR: " @@ -174,6 +175,7 @@ public function getTestsByGroup($groupName) } if ($errCount > 0 + && MftfApplicationConfig::getConfig()->verboseEnabled() && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { print( "ERROR: " @@ -248,7 +250,8 @@ private function initTestData($validateAnnotations = true) LoggingUtil::getInstance()->getLogger(self::class)->error( "Unable to parse test " . $testName . "\n" . $exception->getMessage() ); - if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { + if (MftfApplicationConfig::getConfig()->verboseEnabled() + && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { print("ERROR: Unable to parse test " . $testName . "\n"); } if (MftfApplicationConfig::getConfig()->getPhase() != MftfApplicationConfig::EXECUTION_PHASE) { diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php index 1d1719037..b169f267d 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php @@ -193,7 +193,8 @@ public function validateStoryTitleUniqueness() foreach ($dupes as $storyTitle => $tests) { $message = "Story and Title annotation pairs is not unique in Tests {$tests}\n"; LoggingUtil::getInstance()->getLogger(self::class)->error($message); - if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { + if (MftfApplicationConfig::getConfig()->verboseEnabled() + && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { print('ERROR: ' . $message); } $testArray = explode(',', $tests); @@ -230,7 +231,8 @@ public function validateTestCaseIdTitleUniqueness() foreach ($dupes as $newTitle => $tests) { $message = "TestCaseId and Title pairs is not unique in Tests {$tests}\n"; LoggingUtil::getInstance()->getLogger(self::class)->error($message); - if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { + if (MftfApplicationConfig::getConfig()->verboseEnabled() + && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { print('ERROR: ' . $message); } $testArray = explode(',', $tests); diff --git a/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php b/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php index 7034e13b6..866757ec5 100644 --- a/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php +++ b/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php @@ -121,22 +121,22 @@ public function printErrorSummary() $totalNotGenErrors = $totalErrors - $totalAnnotationErrors; if ($totalNotGenErrors > 0) { print( - PHP_EOL - . 'ERROR: ' + 'ERROR: ' . strval($totalNotGenErrors) . ' ' . ucfirst($type) . "(s) failed to generate. See mftf.log for details." + . PHP_EOL ); } if ($totalAnnotationErrors > 0) { print( - PHP_EOL - . 'ERROR: ' + 'ERROR: ' . strval($totalAnnotationErrors) . ' ' . ucfirst($type) . "(s) generated with annotation errors. See mftf.log for details." + . PHP_EOL ); } } diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index dd44ee4ea..fecd847db 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -358,7 +358,9 @@ private function assembleAllTestPhp($testManifest, array $testsToIgnore) if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { $errMessage = "{$test->getName()} will not be generated. " . "Parent test {$test->getParentName()} not defined in xml."; - print("ERROR: {$errMessage}"); + if (MftfApplicationConfig::getConfig()->verboseEnabled()) { + print("ERROR: {$errMessage}"); + } LoggingUtil::getInstance()->getLogger(self::class)->error($errMessage); GenerationErrorHandler::getInstance()->addError( 'test', From 1f01cdd61386fae2fdab45735e2467a24aefe73d Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Mon, 28 Sep 2020 09:58:39 -0500 Subject: [PATCH 547/888] MQE-2279: PWA - waitForPwaElementVisible method does not work in all scenario's. (#798) --- .../Module/MagentoPwaWebDriver.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoPwaWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoPwaWebDriver.php index 272f4206d..f2f818bd4 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoPwaWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoPwaWebDriver.php @@ -63,12 +63,13 @@ public function waitForPwaElementNotVisible($selector, $timeout = null) // Determine what type of Selector is used. // Then use the correct JavaScript to locate the Element. - if (\Codeception\Util\Locator::isXPath($selector)) { + if (\Codeception\Util\Locator::isCss($selector)) { $this->waitForLoadingMaskToDisappear($timeout); - $this->waitForJS("return !document.evaluate(`$selector`, document);", $timeout); + $this->waitForJS("return !document.querySelector(`$selector`);", $timeout); } else { $this->waitForLoadingMaskToDisappear($timeout); - $this->waitForJS("return !document.querySelector(`$selector`);", $timeout); + $this->waitForJS("return !document.evaluate(`$selector`, document, null, + XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;", $timeout); } } @@ -84,15 +85,16 @@ public function waitForPwaElementNotVisible($selector, $timeout = null) public function waitForPwaElementVisible($selector, $timeout = null) { $timeout = $timeout ?? $this->_getConfig()['pageload_timeout']; - + // Determine what type of Selector is used. // Then use the correct JavaScript to locate the Element. - if (\Codeception\Util\Locator::isXPath($selector)) { + if (\Codeception\Util\Locator::isCss($selector)) { $this->waitForLoadingMaskToDisappear($timeout); - $this->waitForJS("return !!document && !!document.evaluate(`$selector`, document);", $timeout); + $this->waitForJS("return !!document && !!document.querySelector(`$selector`);", $timeout); } else { $this->waitForLoadingMaskToDisappear($timeout); - $this->waitForJS("return !!document && !!document.querySelector(`$selector`);", $timeout); + $this->waitForJS("return !!document && !!document.evaluate(`$selector`, document, null, + XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;", $timeout); } } } From 9e14ab45bd63a5ca0863a7db3251c460b2bfee8a Mon Sep 17 00:00:00 2001 From: soumyau <sunnikri@adobe.com> Date: Tue, 29 Sep 2020 13:32:37 -0500 Subject: [PATCH 548/888] MQE-2292: CHANGELOG.MD and version bump (#804) 3.1.1 --- CHANGELOG.md | 11 +- composer.json | 2 +- composer.lock | 353 +++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 363 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd555ee88..a48b18c9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,16 @@ Magento Functional Testing Framework Changelog ================================================ +3.1.1 +--------- + +* Traceability + * Removed `travis.yml` and replaced with `.github/workflows/main.yml` + +### Fixes +Fixed issue with XPath locators for waits in MagentoPwaWebDriver. + 3.1.0 -________ +--------- ### Enhancements diff --git a/composer.json b/composer.json index 813ab382b..eeaa5d4c6 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "3.1.0", + "version": "3.1.1", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index 7f7648096..c4db9daff 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "278e33e2c7d183d0b7689b5a76127d29", + "content-hash": "3a49492cfc55a8d534163c854fc887a5", "packages": [ { "name": "allure-framework/allure-codeception", @@ -491,6 +491,12 @@ "functional testing", "unit testing" ], + "funding": [ + { + "url": "https://opencollective.com/codeception", + "type": "open_collective" + } + ], "time": "2020-03-23T17:07:20+00:00" }, { @@ -816,6 +822,16 @@ "ssl", "tls" ], + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], "time": "2020-04-08T08:27:21+00:00" }, { @@ -896,6 +912,16 @@ "dependency", "package" ], + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], "time": "2020-04-10T09:44:22+00:00" }, { @@ -1061,6 +1087,12 @@ "Xdebug", "performance" ], + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + } + ], "time": "2020-03-01T12:26:26+00:00" }, { @@ -2533,6 +2565,12 @@ "sftp", "storage" ], + "funding": [ + { + "url": "https://offset.earth/frankdejonge", + "type": "other" + } + ], "time": "2020-04-16T13:21:26+00:00" }, { @@ -3467,6 +3505,12 @@ "filesystem", "iterator" ], + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-04-18T05:02:12+00:00" }, { @@ -3615,6 +3659,12 @@ "keywords": [ "timer" ], + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-04-20T06:00:37+00:00" }, { @@ -3753,6 +3803,16 @@ "testing", "xunit" ], + "funding": [ + { + "url": "https://phpunit.de/donate.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-04-23T04:42:05+00:00" }, { @@ -4166,6 +4226,12 @@ ], "description": "Collection of value objects that represent the PHP code units", "homepage": "https://github.com/sebastianbergmann/code-unit", + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-03-30T11:59:20+00:00" }, { @@ -4384,6 +4450,12 @@ "environment", "hhvm" ], + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-04-14T13:36:52+00:00" }, { @@ -5024,6 +5096,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-03-30T11:41:10+00:00" }, { @@ -5077,6 +5163,20 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-03-27T16:56:45+00:00" }, { @@ -5127,6 +5227,20 @@ ], "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-06-06T08:49:21+00:00" }, { @@ -5197,6 +5311,20 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-03-27T16:54:36+00:00" }, { @@ -5305,6 +5433,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-03-27T16:56:45+00:00" }, { @@ -5354,6 +5496,20 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-03-27T16:56:45+00:00" }, { @@ -5415,6 +5571,20 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-06-15T06:52:54+00:00" }, { @@ -5477,6 +5647,20 @@ "mime", "mime-type" ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-03-27T16:56:45+00:00" }, { @@ -5535,6 +5719,20 @@ "polyfill", "portable" ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-02-27T09:26:54+00:00" }, { @@ -5597,6 +5795,20 @@ "portable", "shim" ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-03-09T19:04:49+00:00" }, { @@ -5656,6 +5868,20 @@ "portable", "shim" ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-03-09T19:04:49+00:00" }, { @@ -5711,6 +5937,20 @@ "portable", "shim" ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-02-27T09:26:54+00:00" }, { @@ -5769,6 +6009,20 @@ "portable", "shim" ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-02-27T09:26:54+00:00" }, { @@ -5835,6 +6089,20 @@ "portable", "shim" ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-06-06T08:46:27+00:00" }, { @@ -5884,6 +6152,20 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-03-27T16:54:36+00:00" }, { @@ -6001,6 +6283,20 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-03-30T11:41:10+00:00" }, { @@ -6230,6 +6526,12 @@ "env", "environment" ], + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } + ], "time": "2020-04-12T15:11:38+00:00" }, { @@ -6541,6 +6843,12 @@ } ], "description": "Library for accessing git", + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/gitonomy/gitlib", + "type": "tidelift" + } + ], "time": "2020-03-23T12:43:44+00:00" }, { @@ -7126,6 +7434,7 @@ ], "description": "FinderFacade is a convenience wrapper for Symfony's Finder component.", "homepage": "https://github.com/sebastianbergmann/finder-facade", + "abandoned": true, "time": "2020-02-08T06:07:58+00:00" }, { @@ -7292,6 +7601,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-03-27T16:54:36+00:00" }, { @@ -7365,6 +7688,20 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-03-30T10:09:30+00:00" }, { @@ -7414,6 +7751,20 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-03-15T09:38:08+00:00" }, { From ace52b85e5b2dbab3c1e04a01e689d7c6b2e84bc Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 30 Sep 2020 15:18:27 -0500 Subject: [PATCH 549/888] MQE-1800: Allow generate:tests to continue running even if one test fails generation --- docs/commands/mftf.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 8340ea93d..37daf4b83 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -91,11 +91,12 @@ For more details about `failed`, refer to [Reporting][]. ## Error tolerance during generation -Starting from version 3.2.0, when generation errors are encountered, MFTF will not fail right away. +Starting from version 3.2.0, MFTF will not fail right away when encounter generation errors. Instead MFTF will try to generate as many tests and suites as it can, log errors in `mftf.log` file and exit with non-zero generation status. -Note that not all errors are tolerable at generation. -For example, schema validation error, parser error, WebApi authentication error will still cause `hard` failure with no test or suite generated. +Note: +- Not all errors are tolerable at generation. For example, schema validation error, parser error, WebApi authentication error will still cause `hard` failure with no test or suite generated. +- Error tolerance in generation is mean to help local test development and testing. You should only expect to run generated tests locally. You must fix all generation errors to use other framework functionalities, pass static checks and to deliver MFTF tests. ## Reference From d9bee7bde4e5e51c2012cec624fad31636ce3151 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 1 Oct 2020 10:17:02 -0500 Subject: [PATCH 550/888] MQE-1800: Allow generate:tests to continue running even if one test fails generation --- docs/commands/mftf.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 37daf4b83..6105c0d19 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -91,12 +91,12 @@ For more details about `failed`, refer to [Reporting][]. ## Error tolerance during generation -Starting from version 3.2.0, MFTF will not fail right away when encounter generation errors. -Instead MFTF will try to generate as many tests and suites as it can, log errors in `mftf.log` file and exit with non-zero generation status. +Starting from version 3.2.0, MFTF will not fail right away when encountering generation errors. +Instead, MFTF will generate as many tests and suites as it can, log errors to `mftf.log`, and exit with a non-zero generation status. Note: -- Not all errors are tolerable at generation. For example, schema validation error, parser error, WebApi authentication error will still cause `hard` failure with no test or suite generated. -- Error tolerance in generation is mean to help local test development and testing. You should only expect to run generated tests locally. You must fix all generation errors to use other framework functionalities, pass static checks and to deliver MFTF tests. +- Not all errors are tolerable at generation. For example, schema validation errors, parser errors, and WebApi authentication errors will cause `hard` failures, with no tests or suites being generated. +- Error tolerance in generation is meant to help local test development and testing and is expected to be run locally. All generation errors must be fixed in order to use other framework functionality, pass static checks, and to deliver MFTF tests. ## Reference From 25e6635ea8a95f6c88af6a07067b413b984d5f3d Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 5 Oct 2020 09:08:38 -0500 Subject: [PATCH 551/888] MQE-2173: CUSTOM_MODULE_PATHS env variable doesn't use all paths --- src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index ecdf19613..7865e49a8 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -747,7 +747,8 @@ private function getCustomModulePaths() } foreach (explode(',', $paths) as $path) { - $customModulePaths = [$this->findVendorAndModuleNameFromPath(trim($path)) => $path]; + //$customModulePaths = [$this->findVendorAndModuleNameFromPath(trim($path)) => $path]; + $customModulePaths[$this->findVendorAndModuleNameFromPath(trim($path))] = $path; } return $customModulePaths; From 11bb8e08a40fd9d8c919730c3b998d03e9fbb2ca Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 6 Oct 2020 17:54:44 -0500 Subject: [PATCH 552/888] MQE-1800: Allow generate:tests to continue running even if one test fails generation --- .../Console/GenerateSuiteCommand.php | 7 +-- .../Console/GenerateTestsCommand.php | 28 +++++---- .../Console/RunTestCommand.php | 10 ++- .../Console/RunTestGroupCommand.php | 9 ++- .../Suite/Util/SuiteObjectExtractor.php | 43 +++++++------ .../Test/Handlers/TestObjectHandler.php | 37 +++++------ .../Util/GenerationErrorHandler.php | 63 ++++++++++--------- .../Util/TestGenerator.php | 34 +++++----- 8 files changed, 122 insertions(+), 109 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php index 920516168..102930472 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateSuiteCommand.php @@ -83,19 +83,18 @@ protected function execute(InputInterface $input, OutputInterface $output) if (empty(GenerationErrorHandler::getInstance()->getAllErrors())) { if ($generated > 0) { - $output->writeln("Suites Generated"); + $output->writeln("Suites Generated" . PHP_EOL); return 0; } } else { GenerationErrorHandler::getInstance()->printErrorSummary(); - GenerationErrorHandler::getInstance()->reset(); if ($generated > 0) { - $output->writeln("Suites Generated (with errors)"); + $output->writeln("Suites Generated (with errors)" . PHP_EOL); return 1; } } - $output->writeln("No Suite Generated"); + $output->writeln("No Suite Generated" . PHP_EOL); return 1; } } diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php index ddd447420..d7bb5f7b4 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php @@ -136,7 +136,12 @@ protected function execute(InputInterface $input, OutputInterface $output) $testManifest = TestManifestFactory::makeManifest($config, $testConfiguration['suites']); try { - TestGenerator::getInstance(null, $testConfiguration['tests'])->createAllTestFiles($testManifest); + if (empty($tests) || !empty($testConfiguration['tests'])) { + // $testConfiguration['tests'] cannot be empty if $tests is not empty + TestGenerator::getInstance(null, $testConfiguration['tests'])->createAllTestFiles($testManifest); + } elseif (empty($testConfiguration['suites'])) { + throw new FastFailException('Invalid input'); + } } catch (FastFailException $e) { throw $e; } catch (\Exception $e) { @@ -164,12 +169,11 @@ protected function execute(InputInterface $input, OutputInterface $output) } if (empty(GenerationErrorHandler::getInstance()->getAllErrors())) { - $output->writeln("Generate Tests Command Run"); + $output->writeln("Generate Tests Command Run" . PHP_EOL); return 0; } else { GenerationErrorHandler::getInstance()->printErrorSummary(); - GenerationErrorHandler::getInstance()->reset(); - $output->writeln("Generate Tests Command Run (with errors)"); + $output->writeln("Generate Tests Command Run (with errors)" . PHP_EOL); return 1; } } @@ -200,18 +204,16 @@ private function createTestConfiguration( foreach ($testConfiguration['tests'] as $test) { try { $testObjects[$test] = TestObjectHandler::getInstance()->getObject($test); - } catch (TestReferenceException $e) { - $message = "Unable to find test {$test} from test configuration"; - LoggingUtil::getInstance()->getLogger(self::class)->error( - $message. PHP_EOL . $e->getMessage() - ); + } catch (FastFailException $e) { + throw $e; + } catch (\Exception $e) { + $message = "Unable to create test object {$test} from test configuration. " . $e->getMessage(); + LoggingUtil::getInstance()->getLogger(self::class)->error($message); if (MftfApplicationConfig::getConfig()->verboseEnabled() && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { - print($message . PHP_EOL); - } - if (MftfApplicationConfig::getConfig()->getPhase() != MftfApplicationConfig::EXECUTION_PHASE) { - GenerationErrorHandler::getInstance()->addError('test', $test, $message); + print($message); } + GenerationErrorHandler::getInstance()->addError('test', $test, $message); } } diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php index 6931e8303..3f4f43e81 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php @@ -8,6 +8,8 @@ namespace Magento\FunctionalTestingFramework\Console; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; +use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Magento\FunctionalTestingFramework\Util\TestGenerator; use Symfony\Component\Console\Input\ArrayInput; @@ -86,6 +88,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int $testConfiguration = $this->getTestAndSuiteConfiguration($tests); + $generationErrorCode = 0; + if (!$skipGeneration) { $command = $this->getApplication()->find('generate:tests'); $args = [ @@ -97,6 +101,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int '-v' => $verbose ]; $command->run(new ArrayInput($args), $output); + + if (!empty(GenerationErrorHandler::getInstance()->getAllErrors())) { + $generationErrorCode = 1; + } } $testConfigArray = json_decode($testConfiguration, true); @@ -109,7 +117,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->runTestsInSuite($testConfigArray['suites'], $output); } - return $this->returnCode; + return max($this->returnCode, $generationErrorCode); } /** diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php index f18b9dc30..530c8a510 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php @@ -10,6 +10,7 @@ use Magento\FunctionalTestingFramework\Suite\Handlers\SuiteObjectHandler; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; +use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -80,6 +81,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int $allowSkipped ); + $generationErrorCode = 0; + if (!$skipGeneration) { $testConfiguration = $this->getGroupAndSuiteConfiguration($groups); $command = $this->getApplication()->find('generate:tests'); @@ -93,6 +96,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int ]; $command->run(new ArrayInput($args), $output); + + if (!empty(GenerationErrorHandler::getInstance()->getAllErrors())) { + $generationErrorCode = 1; + } } if ($this->pauseEnabled()) { @@ -130,6 +137,6 @@ function ($type, $buffer) use ($output) { } $exitCode = 0; } - return $exitCode; + return max($exitCode, $generationErrorCode); } } diff --git a/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php index d0f945b6e..247286f6d 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php @@ -109,13 +109,13 @@ public function parseSuiteDataIntoObjects($parsedSuiteData) LoggingUtil::getInstance()->getLogger(self::class)->error( "Unable to parse suite " . $parsedSuite[self::NAME] . ". Suite must not be empty." ); - if (MftfApplicationConfig::getConfig()->getPhase() != MftfApplicationConfig::EXECUTION_PHASE) { - GenerationErrorHandler::getInstance()->addError( - 'suite', - $parsedSuite[self::NAME], - self::class . ': ' . 'Suite must not be empty.' - ); - } + + GenerationErrorHandler::getInstance()->addError( + 'suite', + $parsedSuite[self::NAME], + self::class . ': ' . 'Suite must not be empty.' + ); + continue; }; @@ -130,14 +130,13 @@ public function parseSuiteDataIntoObjects($parsedSuiteData) && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { print($includeMessage); } - if (MftfApplicationConfig::getConfig()->getPhase() != MftfApplicationConfig::EXECUTION_PHASE) { - GenerationErrorHandler::getInstance()->addError( - 'suite', - $parsedSuite[self::NAME], - self::class . ': ' . $includeMessage, - true - ); - } + + GenerationErrorHandler::getInstance()->addError( + 'suite', + $parsedSuite[self::NAME], + self::class . ': ' . $includeMessage, + true + ); } } catch (FastFailException $e) { throw $e; @@ -149,13 +148,13 @@ public function parseSuiteDataIntoObjects($parsedSuiteData) && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { print("ERROR: Unable to parse suite " . $parsedSuite[self::NAME] . "\n"); } - if (MftfApplicationConfig::getConfig()->getPhase() != MftfApplicationConfig::EXECUTION_PHASE) { - GenerationErrorHandler::getInstance()->addError( - 'suite', - $parsedSuite[self::NAME], - self::class . ': Unable to parse suite ' . $e->getMessage() - ); - } + + GenerationErrorHandler::getInstance()->addError( + 'suite', + $parsedSuite[self::NAME], + self::class . ': Unable to parse suite ' . $e->getMessage() + ); + continue; } diff --git a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php index 3142e2cb0..4abc26c36 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php @@ -114,13 +114,11 @@ public function getAllObjects() LoggingUtil::getInstance()->getLogger(self::class)->error( "Unable to extend test " . $testName . "\n" . $exception->getMessage() ); - if (MftfApplicationConfig::getConfig()->getPhase() != MftfApplicationConfig::EXECUTION_PHASE) { - GenerationErrorHandler::getInstance()->addError( - 'test', - $testName, - self::class . ': Unable to extend test ' . $exception->getMessage() - ); - } + GenerationErrorHandler::getInstance()->addError( + 'test', + $testName, + self::class . ': Unable to extend test ' . $exception->getMessage() + ); } } @@ -164,13 +162,12 @@ public function getTestsByGroup($groupName) . " for group {$groupName}\n" . $exception->getMessage(); LoggingUtil::getInstance()->getLogger(self::class)->error($message); - if (MftfApplicationConfig::getConfig()->getPhase() != MftfApplicationConfig::EXECUTION_PHASE) { - GenerationErrorHandler::getInstance()->addError( - 'test', - $test->getName(), - self::class . ': ' . $message - ); - } + + GenerationErrorHandler::getInstance()->addError( + 'test', + $test->getName(), + self::class . ': ' . $message + ); } } @@ -254,13 +251,11 @@ private function initTestData($validateAnnotations = true) && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { print("ERROR: Unable to parse test " . $testName . "\n"); } - if (MftfApplicationConfig::getConfig()->getPhase() != MftfApplicationConfig::EXECUTION_PHASE) { - GenerationErrorHandler::getInstance()->addError( - 'test', - $testName, - self::class . ': Unable to parse test ' . $exception->getMessage() - ); - } + GenerationErrorHandler::getInstance()->addError( + 'test', + $testName, + self::class . ': Unable to parse test ' . $exception->getMessage() + ); } } $testNameValidator->summarize(NameValidationUtil::TEST_NAME); diff --git a/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php b/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php index 866757ec5..e6b31d0db 100644 --- a/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php +++ b/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php @@ -57,16 +57,14 @@ private function __construct() */ public function addError($type, $entityName, $message, $generated = false) { - if (MftfApplicationConfig::getConfig()->getPhase() != MftfApplicationConfig::EXECUTION_PHASE) { - $error[$entityName] = [ - 'message' => $message, - 'generated' => $generated, - ]; - if (isset($this->errors[$type])) { - $this->errors[$type] = array_merge_recursive($this->errors[$type], $error); - } else { - $this->errors[$type] = $error; - } + $error[$entityName] = [ + 'message' => $message, + 'generated' => $generated, + ]; + if (isset($this->errors[$type])) { + $this->errors[$type] = array_merge_recursive($this->errors[$type], $error); + } else { + $this->errors[$type] = $error; } } @@ -108,39 +106,48 @@ public function reset() */ public function printErrorSummary() { - if (is_array(array_keys($this->errors))) { - foreach (array_keys($this->errors) as $type) { - $totalErrors = count($this->getErrorsByType($type)); - $totalAnnotationErrors = 0; - foreach ($this->getErrorsByType($type) as $entity => $error) { - if ((is_array($error['generated']) && $error['generated'][0] === true) - || ($error['generated'] === true)) { - $totalAnnotationErrors++; - } + foreach (array_keys($this->errors) as $type) { + $totalErrors = count($this->getErrorsByType($type)); + $totalAnnotationErrors = 0; + foreach ($this->getErrorsByType($type) as $entity => $error) { + if ((is_array($error['generated']) && $error['generated'][0] === true) + || ($error['generated'] === true)) { + $totalAnnotationErrors++; } - $totalNotGenErrors = $totalErrors - $totalAnnotationErrors; - if ($totalNotGenErrors > 0) { + } + $totalNotGenErrors = $totalErrors - $totalAnnotationErrors; + if ($totalNotGenErrors > 0) { + print( + 'ERROR: ' + . strval($totalNotGenErrors) + . ' ' + . ucfirst($type) + . "(s) failed to generate. See mftf.log for details." + . PHP_EOL + ); + } + if ($totalAnnotationErrors > 0) { + if ($type !== 'suite') { print( 'ERROR: ' - . strval($totalNotGenErrors) + . strval($totalAnnotationErrors) . ' ' . ucfirst($type) - . "(s) failed to generate. See mftf.log for details." + . "(s) generated with annotation errors. See mftf.log for details." . PHP_EOL ); - } - if ($totalAnnotationErrors > 0) { + } else { print( - 'ERROR: ' + 'ERROR: ' . strval($totalAnnotationErrors) . ' ' . ucfirst($type) - . "(s) generated with annotation errors. See mftf.log for details." + . "(s) has(have) tests with annotation errors. See mftf.log for details." . PHP_EOL ); } } - print(PHP_EOL); } + print(PHP_EOL); } } diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index fecd847db..8549f83e6 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -355,19 +355,17 @@ private function assembleAllTestPhp($testManifest, array $testsToIgnore) TestObjectHandler::getInstance()->getObject($test->getParentName()); } catch (TestReferenceException $e) { TestObjectHandler::getInstance()->sanitizeTests([$test->getName()]); - if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { - $errMessage = "{$test->getName()} will not be generated. " - . "Parent test {$test->getParentName()} not defined in xml."; - if (MftfApplicationConfig::getConfig()->verboseEnabled()) { - print("ERROR: {$errMessage}"); - } - LoggingUtil::getInstance()->getLogger(self::class)->error($errMessage); - GenerationErrorHandler::getInstance()->addError( - 'test', - $test->getName(), - self::class . ': ' . $errMessage - ); + $errMessage = "{$test->getName()} will not be generated. " + . "Parent test {$test->getParentName()} not defined in xml."; + if (MftfApplicationConfig::getConfig()->verboseEnabled()) { + print("ERROR: {$errMessage}"); } + LoggingUtil::getInstance()->getLogger(self::class)->error($errMessage); + GenerationErrorHandler::getInstance()->addError( + 'test', + $test->getName(), + self::class . ': ' . $errMessage + ); continue; } } @@ -389,13 +387,11 @@ private function assembleAllTestPhp($testManifest, array $testsToIgnore) } catch (FastFailException $e) { throw $e; } catch (\Exception $e) { - if (MftfApplicationConfig::getConfig()->getPhase() != MftfApplicationConfig::EXECUTION_PHASE) { - GenerationErrorHandler::getInstance()->addError( - 'test', - $test->getName(), - self::class . ': ' . $e->getMessage() - ); - } + GenerationErrorHandler::getInstance()->addError( + 'test', + $test->getName(), + self::class . ': ' . $e->getMessage() + ); LoggingUtil::getInstance()->getLogger(self::class)->error( "Failed to generate {$test->getName()}" ); From a89e2b0909b34ab3d611c168aa3fc39c16776905 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 6 Oct 2020 18:02:57 -0500 Subject: [PATCH 553/888] MQE-1800: Allow generate:tests to continue running even if one test fails generation --- .../FunctionalTestingFramework/Console/RunTestGroupCommand.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php index 530c8a510..7cbdf1f1b 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php @@ -54,6 +54,7 @@ protected function configure() * * @SuppressWarnings(PHPMD.UnusedLocalVariable) * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) */ protected function execute(InputInterface $input, OutputInterface $output): int { From 8ac5662c34ee7496baf013fde3aeb6241a24bb4d Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 7 Oct 2020 16:50:34 -0500 Subject: [PATCH 554/888] MQE-1800: Allow generate:tests to continue running even if one test fails generation --- .../Suite/SuiteGenerator.php | 10 ++++++++-- .../FunctionalTestingFramework/Util/TestGenerator.php | 11 ++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php index 4b05c2c9d..13ac13371 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php @@ -102,7 +102,7 @@ public function generateAllSuites($testManifest) try { if (empty($suiteContent)) { LoggingUtil::getInstance()->getLogger(self::class)->notification( - "NOTICE: Suite '" . $suiteName . "' contains no tests and won't be generated." . PHP_EOL, + "Suite '" . $suiteName . "' contains no tests and won't be generated.", [], true ); @@ -182,7 +182,13 @@ private function generateSuiteFromTest($suiteName, $tests = [], $originalSuiteNa if (empty($relevantTests)) { $exceptionCollector->reset(); - throw new TestFrameworkException("No relevant test found for suite \"{$suiteName}\""); + // There are suites that include no test on purpose for certain Magento edition. + // To keep backward compatibility, we will return with no error. + // This might inevitably hide some suite errors that are resulted by real broken tests. + if (file_exists($fullPath)) { + DirSetupUtil::rmdirRecursive($fullPath); + } + return; } try { diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 8549f83e6..31035c8f6 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -357,15 +357,12 @@ private function assembleAllTestPhp($testManifest, array $testsToIgnore) TestObjectHandler::getInstance()->sanitizeTests([$test->getName()]); $errMessage = "{$test->getName()} will not be generated. " . "Parent test {$test->getParentName()} not defined in xml."; + // There are tests extend from non-existing parent on purpose on certain Magento editions. + // To keep backward compatibility, we will skip the test and continue if (MftfApplicationConfig::getConfig()->verboseEnabled()) { - print("ERROR: {$errMessage}"); + print("NOTICE: {$errMessage}"); } - LoggingUtil::getInstance()->getLogger(self::class)->error($errMessage); - GenerationErrorHandler::getInstance()->addError( - 'test', - $test->getName(), - self::class . ': ' . $errMessage - ); + LoggingUtil::getInstance()->getLogger(self::class)->warn($errMessage); continue; } } From 76c7df7178790a3de20b34679ce37e48491d59e4 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 12 Oct 2020 10:01:34 -0500 Subject: [PATCH 555/888] MQE-2173: CUSTOM_MODULE_PATHS env variable doesn't use all paths --- src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index 7865e49a8..1a10e3029 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -747,7 +747,6 @@ private function getCustomModulePaths() } foreach (explode(',', $paths) as $path) { - //$customModulePaths = [$this->findVendorAndModuleNameFromPath(trim($path)) => $path]; $customModulePaths[$this->findVendorAndModuleNameFromPath(trim($path))] = $path; } From 8b56bfe70cba8ab68ea0c86f69e4760548653dd8 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 12 Oct 2020 21:18:53 -0500 Subject: [PATCH 556/888] MQE-1800: Allow generate:tests to continue running even if one test fails generation --- .../Util/GenerationErrorHandlerTest.php | 87 +++++++++++++++++++ .../Console/GenerateTestsCommand.php | 8 +- .../Util/GenerationErrorHandler.php | 22 +++++ 3 files changed, 116 insertions(+), 1 deletion(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/GenerationErrorHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/GenerationErrorHandlerTest.php index 630583567..70b354687 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/GenerationErrorHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/GenerationErrorHandlerTest.php @@ -242,6 +242,93 @@ public function testGetAllErrorsDuplicate() $this->assertEquals($expectedSuiteErrors, GenerationErrorHandler::getInstance()->getErrorsByType('suite')); } + /** + * Test get all error messages + * + * @param string $expectedErrMessages + * @param array $errors + * @dataProvider getAllErrorMessagesDataProvider + */ + public function testGetAllErrorMessages($expectedErrMessages, $errors) + { + $handler = GenerationErrorHandler::getInstance(); + $handler->reset(); + + $property = new \ReflectionProperty(GenerationErrorHandler::class, 'errors'); + $property->setAccessible(true); + $property->setValue($handler, $errors); + + // Assert getAllErrorMessages + $this->assertEquals($expectedErrMessages, GenerationErrorHandler::getInstance()->getAllErrorMessages()); + } + + /** + * Data provider for testGetAllErrorMessages() + * + * @return array + */ + public function getAllErrorMessagesDataProvider() + { + return [ + ['', []], + ['', [ + 'test' => [], + 'suite' => [], + ] + ], + ['TestError1' + . PHP_EOL + . 'TestError2' + . PHP_EOL + . 'TestError3' + . PHP_EOL + . 'SuiteError1' + . PHP_EOL + . 'SuiteError2' + . PHP_EOL + . 'SuiteError3' + . PHP_EOL + . 'SuiteError4', + [ + 'test' => [ + 'Sameple1Test' => [ + 'message' => [ + 0 => 'TestError1', + 1 => 'TestError2' + ], + 'generated' => [ + 0 => false, + 1 => false + ], + ], + 'Sameple2Test' => [ + 'message' => 'TestError3', + 'generated' => true, + ], + ], + 'suite' => [ + 'Sameple1Suite' => [ + 'message' => 'SuiteError1', + 'generated' => true, + ], + 'Sameple2Suite' => [ + 'message' => [ + 0 => 'SuiteError2', + 1 => 'SuiteError3', + 2 => 'SuiteError4', + ], + 'generated' => [ + 0 => false, + 1 => true, + 2 => false, + ], + ], + ], + ] + ], + ]; + } + /** * Test reset */ diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php index d7bb5f7b4..03aa39462 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php @@ -140,7 +140,13 @@ protected function execute(InputInterface $input, OutputInterface $output) // $testConfiguration['tests'] cannot be empty if $tests is not empty TestGenerator::getInstance(null, $testConfiguration['tests'])->createAllTestFiles($testManifest); } elseif (empty($testConfiguration['suites'])) { - throw new FastFailException('Invalid input'); + throw new FastFailException( + !empty(GenerationErrorHandler::getInstance()->getAllErrors()) + ? + GenerationErrorHandler::getInstance()->getAllErrorMessages() + : + 'Invalid input' + ); } } catch (FastFailException $e) { throw $e; diff --git a/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php b/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php index e6b31d0db..486158eac 100644 --- a/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php +++ b/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php @@ -78,6 +78,28 @@ public function getAllErrors() return $this->errors; } + /** + * Return all error message in a string + * + * @return string + */ + public function getAllErrorMessages() + { + $errMessages = ''; + + foreach ($this->errors as $type => $errors) { + foreach ($errors as $error) { + if (is_array($error['message'])) { + $errMessages .= (!empty($errMessages) ? PHP_EOL : '') . implode(PHP_EOL, $error['message']); + } else { + $errMessages .= (!empty($errMessages) ? PHP_EOL : '') . $error['message']; + } + } + } + + return $errMessages; + } + /** * Return errors for given type * From 69772628e15ad8ceb9624259b04c862b85c9b4ed Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 14 Oct 2020 18:01:59 -0500 Subject: [PATCH 557/888] MQE-2114: Add additional checks to the annotations static check --- .../StaticCheck/AnnotationsCheckTest.php | 190 ++++++++++++++++++ .../Test/Util/AnnotationExtractorTest.php | 62 ++++++ .../StaticCheck/AnnotationsCheck.php | 16 +- .../Test/Util/AnnotationExtractor.php | 13 +- 4 files changed, 272 insertions(+), 9 deletions(-) create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/StaticCheck/AnnotationsCheckTest.php diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/StaticCheck/AnnotationsCheckTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/StaticCheck/AnnotationsCheckTest.php new file mode 100644 index 000000000..d497f68a4 --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/StaticCheck/AnnotationsCheckTest.php @@ -0,0 +1,190 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace tests\unit\Magento\FunctionalTestFramework\StaticCheck; + +use AspectMock\Test as AspectMock; +use Magento\FunctionalTestingFramework\StaticCheck\AnnotationsCheck; +use Magento\FunctionalTestingFramework\Test\Objects\TestObject; +use tests\unit\Util\MagentoTestCase; +use ReflectionClass; + +class AnnotationsCheckTest extends MagentoTestCase +{ + /** @var AnnotationsCheck */ + private $staticCheck; + + /** @var ReflectionClass*/ + private $staticCheckClass; + + public function setUp(): void + { + $this->staticCheck = new AnnotationsCheck(); + $this->staticCheckClass = new \ReflectionClass($this->staticCheck); + } + + public function tearDown(): void + { + AspectMock::clean(); + } + + public function testValidateRequiredAnnotationsNoError() + { + $annotations = [ + 'features' => [ + 0 => 'feature1' + ], + 'stories' => [ + 0 => 'story1' + ], + 'description' => [ + 'main' => 'description1', + 'test_files' => 'file1', + 'deprecated' => [ + 0 => 'deprecated1' + ] + ], + 'severity' => [ + 0 => 'severity1' + ], + 'title' => [ + 0 => '[NO TESTCASEID]: title1' + ], + ]; + $expected = []; + + // mock test object + $test = AspectMock::double( + TestObject::class, ['getAnnotations' => $annotations, 'getName' => 'AnnotationsCheckTest'] + )->make(); + + $validateRequiredAnnotations = $this->staticCheckClass->getMethod('validateRequiredAnnotations'); + $validateRequiredAnnotations->setAccessible(true); + + $validateRequiredAnnotations->invoke($this->staticCheck, $test); + $this->assertEquals($expected, $this->staticCheck->getErrors()); + } + + public function testValidateRequiredAnnotationsMissing() + { + $testCaseId = 'MC-12345'; + + $annotations = [ + 'features' => [ + 0 => 'feature1' + ], + 'stories' => [ + 0 => 'story1' + ], + 'description' => [ + 'test_files' => 'file1', + 'deprecated' => [ + 0 => 'deprecated1' + ] + ], + 'title' => [ + 0 => $testCaseId . ': title1' + ], + 'testCaseId' => [ + 0 => $testCaseId + ] + ]; + $expected = [ + 0 => [ + 0 => 'Test AnnotationsCheckTest is missing the required annotations: description, severity' + ] + ]; + + // mock test object + $test = AspectMock::double( + TestObject::class, ['getAnnotations' => $annotations, 'getName' => 'AnnotationsCheckTest'] + )->make(); + + $validateRequiredAnnotations = $this->staticCheckClass->getMethod('validateRequiredAnnotations'); + $validateRequiredAnnotations->setAccessible(true); + + $validateRequiredAnnotations->invoke($this->staticCheck, $test); + $this->assertEquals($expected, $this->staticCheck->getErrors()); + } + + public function testValidateRequiredAnnotationsMissingNoTestCaseId() + { + $annotations = [ + 'features' => [ + 0 => 'feature1' + ], + 'stories' => [ + 0 => 'story1' + ], + 'description' => [ + 'test_files' => 'file1', + 'deprecated' => [ + 0 => 'deprecated1' + ] + ], + 'title' => [ + 0 => "[NO TESTCASEID]: \t" + ], + ]; + $expected = [ + 0 => [ + 0 => 'Test AnnotationsCheckTest is missing the required annotations: title, description, severity' + ] + ]; + + // mock test object + $test = AspectMock::double( + TestObject::class, ['getAnnotations' => $annotations, 'getName' => 'AnnotationsCheckTest'] + )->make(); + + $validateRequiredAnnotations = $this->staticCheckClass->getMethod('validateRequiredAnnotations'); + $validateRequiredAnnotations->setAccessible(true); + + $validateRequiredAnnotations->invoke($this->staticCheck, $test); + $this->assertEquals($expected, $this->staticCheck->getErrors()); + } + + public function testValidateRequiredAnnotationsEmpty() + { + $annotations = [ + 'features' => [ + 0 => 'feature1' + ], + 'stories' => [ + 0 => 'story1' + ], + 'description' => [ + 'main' => 'description1', + 'test_files' => 'file1', + 'deprecated' => [ + 0 => 'deprecated1' + ] + ], + 'severity' => [ + 0 => 'severity1' + ], + 'title' => [ + 0 => '' + ], + ]; + $expected = [ + 0 => [ + 0 => 'Test AnnotationsCheckTest is missing the required annotations: title' + ] + ]; + + // mock test object + $test = AspectMock::double( + TestObject::class, ['getAnnotations' => $annotations, 'getName' => 'AnnotationsCheckTest'] + )->make(); + + $validateRequiredAnnotations = $this->staticCheckClass->getMethod('validateRequiredAnnotations'); + $validateRequiredAnnotations->setAccessible(true); + + $validateRequiredAnnotations->invoke($this->staticCheck, $test); + $this->assertEquals($expected, $this->staticCheck->getErrors()); + } +} diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/AnnotationExtractorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/AnnotationExtractorTest.php index bfb108ce8..8b140c063 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/AnnotationExtractorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/AnnotationExtractorTest.php @@ -122,6 +122,68 @@ public function testMissingAnnotations() ); } + /** + * Annotation extractor should throw warning when required annotations are empty + * + * @throws \Exception + */ + public function testEmptyRequiredAnnotations() + { + // Test Data, missing title, description, and severity + $testAnnotations = [ + "nodeName" => "annotations", + "features" => [ + [ + "nodeName" => "features", + "value" => "" + ] + ], + "stories" => [ + [ + "nodeName" => "stories", + "value" => "TestStories" + ] + ], + "title" => [ + [ + "nodeName" => "title", + "value" => " " + ] + ], + "description" => [ + [ + "nodeName" => "description", + "value" => "\t" + ] + ], + "severity" => [ + [ + "nodeName" => "severity", + "value" => "" + ] + ], + "group" => [ + [ + "nodeName" => "group", + "value" => "TestGroup" + ] + ], + ]; + // Perform Test + $extractor = new AnnotationExtractor(); + $returnedAnnotations = $extractor->extractAnnotations($testAnnotations, "testFileName"); + + // Asserts + TestLoggingUtil::getInstance()->validateMockLogStatement( + 'warning', + 'DEPRECATION: Test testFileName is missing required annotations.', + [ + 'testName' => 'testFileName', + 'missingAnnotations' => "title, description, severity" + ] + ); + } + public function testTestCaseIdUniqueness() { // Test Data diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php index b27c23d84..819b98f18 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php @@ -124,22 +124,30 @@ private function validateRequiredAnnotations($test) $missing = []; $stories = $annotations['stories'] ?? null; - if ($stories === null) { + if ($stories === null || !isset($stories[0]) || empty(trim($stories[0]))) { $missing[] = "stories"; } + $testCaseId = "[NO TESTCASEID]"; + if (isset($annotations['testCaseId'][0])) { + $testCaseId = trim($annotations['testCaseId'][0]); + } + $title = $annotations['title'] ?? null; - if ($title === null) { + if ($title === null + || !isset($title[0]) + || empty(trim($title[0])) + || empty(trim(substr(trim($title[0]), strlen($testCaseId . ': '))))) { $missing[] = "title"; } $description = $annotations['description']['main'] ?? null; - if ($description === null) { + if ($description === null || empty(trim($description))) { $missing[] = "description"; } $severity = $annotations['severity'] ?? null; - if ($severity === null) { + if ($severity === null || !isset($severity[0]) || empty(trim($severity[0]))) { $missing[] = "severity"; } diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php index 46adb7ce2..2061842b9 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php @@ -77,7 +77,7 @@ public function extractAnnotations($testAnnotations, $filename, $validateAnnotat // Only transform severity annotation if ($annotationKey == "severity") { $annotationObjects[$annotationKey] = $this->transformAllureSeverityToMagento( - $annotationData[0]['value'] + trim($annotationData[0][self::ANNOTATION_VALUE]) ); continue; } @@ -90,16 +90,17 @@ public function extractAnnotations($testAnnotations, $filename, $validateAnnotat } foreach ($annotationData as $annotationValue) { - $annotationValues[] = $annotationValue[self::ANNOTATION_VALUE]; + $annotationValues[] = trim($annotationValue[self::ANNOTATION_VALUE]); } $annotationObjects[$annotationKey] = $annotationValues; } - $this->addTestCaseIdToTitle($annotationObjects, $filename); if ($validateAnnotations) { $this->validateMissingAnnotations($annotationObjects, $filename); } + + $this->addTestCaseIdToTitle($annotationObjects, $filename); $this->addStoryTitleToMap($annotationObjects, $filename); return $annotationObjects; @@ -154,7 +155,9 @@ private function validateMissingAnnotations($annotationObjects, $filename) $missingAnnotations = []; foreach (self::REQUIRED_ANNOTATIONS as $REQUIRED_ANNOTATION) { - if (!array_key_exists($REQUIRED_ANNOTATION, $annotationObjects)) { + if (!array_key_exists($REQUIRED_ANNOTATION, $annotationObjects) + || !isset($annotationObjects[$REQUIRED_ANNOTATION][0]) + || empty($annotationObjects[$REQUIRED_ANNOTATION][0])) { $missingAnnotations[] = $REQUIRED_ANNOTATION; } } @@ -231,7 +234,7 @@ public function validateTestCaseIdTitleUniqueness() public function validateSkippedIssues($issues, $filename) { foreach ($issues as $issueId) { - if (empty($issueId['value'])) { + if (empty(trim($issueId['value']))) { $message = "issueId for skipped tests cannot be empty. Test: $filename"; throw new XmlException($message); } From 4c216f3411dfbf783ae1ea67464dffc09f377db4 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 14 Oct 2020 18:14:30 -0500 Subject: [PATCH 558/888] MQE-2114: Add additional checks to the annotations static check --- .../StaticCheck/AnnotationsCheckTest.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/StaticCheck/AnnotationsCheckTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/StaticCheck/AnnotationsCheckTest.php index d497f68a4..010a9e357 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/StaticCheck/AnnotationsCheckTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/StaticCheck/AnnotationsCheckTest.php @@ -58,7 +58,8 @@ public function testValidateRequiredAnnotationsNoError() // mock test object $test = AspectMock::double( - TestObject::class, ['getAnnotations' => $annotations, 'getName' => 'AnnotationsCheckTest'] + TestObject::class, + ['getAnnotations' => $annotations, 'getName' => 'AnnotationsCheckTest'] )->make(); $validateRequiredAnnotations = $this->staticCheckClass->getMethod('validateRequiredAnnotations'); @@ -100,7 +101,8 @@ public function testValidateRequiredAnnotationsMissing() // mock test object $test = AspectMock::double( - TestObject::class, ['getAnnotations' => $annotations, 'getName' => 'AnnotationsCheckTest'] + TestObject::class, + ['getAnnotations' => $annotations, 'getName' => 'AnnotationsCheckTest'] )->make(); $validateRequiredAnnotations = $this->staticCheckClass->getMethod('validateRequiredAnnotations'); @@ -137,7 +139,8 @@ public function testValidateRequiredAnnotationsMissingNoTestCaseId() // mock test object $test = AspectMock::double( - TestObject::class, ['getAnnotations' => $annotations, 'getName' => 'AnnotationsCheckTest'] + TestObject::class, + ['getAnnotations' => $annotations, 'getName' => 'AnnotationsCheckTest'] )->make(); $validateRequiredAnnotations = $this->staticCheckClass->getMethod('validateRequiredAnnotations'); @@ -178,7 +181,8 @@ public function testValidateRequiredAnnotationsEmpty() // mock test object $test = AspectMock::double( - TestObject::class, ['getAnnotations' => $annotations, 'getName' => 'AnnotationsCheckTest'] + TestObject::class, + ['getAnnotations' => $annotations, 'getName' => 'AnnotationsCheckTest'] )->make(); $validateRequiredAnnotations = $this->staticCheckClass->getMethod('validateRequiredAnnotations'); From e0dc6a18c2c7192dfa0591d081932dea111dd036 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 14 Oct 2020 18:19:39 -0500 Subject: [PATCH 559/888] MQE-2114: Add additional checks to the annotations static check --- .../FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php index 819b98f18..e7a0b7e54 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php @@ -117,6 +117,8 @@ public function getOutput() * * @param TestObject $test * @return void + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) */ private function validateRequiredAnnotations($test) { From e2ac7e40a4ea242fbfa10c94fdf3f3b0e56bfb6a Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 26 Oct 2020 14:39:06 -0500 Subject: [PATCH 560/888] MQE-2272: run:failed only runs last failed test when multiple tests are run with run:test --- .../Console/BaseGenerateCommand.php | 112 ++++++++++++++++++ .../Console/RunTestCommand.php | 12 ++ .../Console/RunTestFailedCommand.php | 15 +-- .../Console/RunTestGroupCommand.php | 9 ++ 4 files changed, 135 insertions(+), 13 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index f6a4ff4a5..ef6fc2cec 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -36,6 +36,8 @@ class BaseGenerateCommand extends Command const CODECEPT_RUN = 'codecept:run'; const CODECEPT_RUN_FUNCTIONAL = self::CODECEPT_RUN . ' functional '; const CODECEPT_RUN_OPTION_NO_EXIT = ' --no-exit '; + const FAILED_FILE = 'failed'; + const FAILED_ALL_FILE = 'failed_all'; /** * Enable pause() @@ -44,6 +46,20 @@ class BaseGenerateCommand extends Command */ private $enablePause = null; + /** + * Full path to '_output' dir + * + * @var string + */ + private $testsOutputDir = null; + + /** + * File handle for 'failed_all' file + * + * @var resource + */ + private $fhFailedAll; + /** * Console output style * @@ -51,6 +67,13 @@ class BaseGenerateCommand extends Command */ protected $ioStyle = null; + /** + * Full path to 'failed' file + * + * @var string + */ + protected $testsFailedFile = null; + /** * Configures the base command. * @@ -270,4 +293,93 @@ protected function codeceptRunTest(string $commandStr, OutputInterface $output) $command = $this->getApplication()->find(self::CODECEPT_RUN); return $command->run($input, $output); } + + /** + * Return tests _output directory + * + * @return string + * @throws TestFrameworkException + */ + protected function getTestsOutputDir() + { + if (!$this->testsOutputDir) { + $this->testsOutputDir = FilePathFormatter::format(TESTS_BP) . + "tests" . + DIRECTORY_SEPARATOR . + "_output" . + DIRECTORY_SEPARATOR; + } + + return $this->testsOutputDir; + } + + /** + * Initialize 'failed_all' file + * + * @return void + * @throws TestFrameworkException + */ + protected function initializeFailedAllFile() + { + // Initialize 'failed_all' file + $allFailedFile = $this->getTestsOutputDir() . self::FAILED_ALL_FILE; + $this->fhFailedAll = fopen($allFailedFile, 'w+'); + } + + /** + * Appends content of file 'failed' to file 'failed_all' + * + * @return void + */ + protected function appendRunFailed() + { + try { + if (!$this->testsFailedFile) { + $this->testsFailedFile = $this->getTestsOutputDir() . self::FAILED_FILE; + } + + if (file_exists($this->testsFailedFile)) { + // Append 'failed' into 'failed_all' + $contents = file_get_contents($this->testsFailedFile); + if ($contents !== false && !empty($contents)) { + fwrite($this->fhFailedAll, trim($contents) . PHP_EOL); + } + } + } catch (TestFrameworkException $e) { + } + } + + /** + * Replace content of file 'failed' with content in file 'failed_all' + * + * @return void + */ + protected function updateRunFailedWithFailedAll() + { + try { + if (!$this->testsFailedFile) { + $this->testsFailedFile = $this->getTestsOutputDir() . self::FAILED_FILE; + } + + if (file_exists($this->getTestsOutputDir() . self::FAILED_ALL_FILE)) { + // Update 'failed' with content from 'failed_all' + $contents = file_get_contents($this->getTestsOutputDir() . self::FAILED_ALL_FILE); + if ($contents !== false && !empty($contents)) { + if (file_exists($this->testsFailedFile)) { + rename($this->testsFailedFile, $this->testsFailedFile . '.copy'); + } + if (file_put_contents($this->testsFailedFile, $contents) === false + && file_exists($this->testsFailedFile . '.copy')) { + rename($this->testsFailedFile . '.copy', $this->testsFailedFile); + } + if (file_exists($this->testsFailedFile . '.copy')) { + unlink($this->testsFailedFile . '.copy'); + } + } + fclose($this->fhFailedAll); + unlink($this->getTestsOutputDir() . self::FAILED_ALL_FILE); + } + } catch (TestFrameworkException $e) { + } + } } diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php index 3f4f43e81..d6e485bdb 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php @@ -109,6 +109,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int $testConfigArray = json_decode($testConfiguration, true); + // Initialize `failed_all` file + $this->initializeFailedAllFile(); + if (isset($testConfigArray['tests'])) { $this->runTests($testConfigArray['tests'], $output); } @@ -117,6 +120,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->runTestsInSuite($testConfigArray['suites'], $output); } + // Update `failed` with contents from `failed_all` + $this->updateRunFailedWithFailedAll(); + return max($this->returnCode, $generationErrorCode); } @@ -161,6 +167,9 @@ private function runTests(array $tests, OutputInterface $output) $fullCommand = $codeceptionCommand . $testsDirectory . $testName . ' --verbose --steps'; $this->returnCode = max($this->returnCode, $this->executeTestCommand($fullCommand, $output)); } + + // Append `failed` to `failed_all` + $this->appendRunFailed(); } } @@ -196,6 +205,9 @@ private function runTestsInSuite(array $suitesConfig, OutputInterface $output) } else { $this->returnCode = max($this->returnCode, $this->executeTestCommand($fullCommand, $output)); } + + // Append `failed` to `failed_all` + $this->appendRunFailed(); } } diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php index 6e6954c70..1652a896d 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php @@ -23,11 +23,6 @@ class RunTestFailedCommand extends BaseGenerateCommand */ const DEFAULT_TEST_GROUP = 'default'; - /** - * @var string - */ - private $testsFailedFile; - /** * @var string */ @@ -69,14 +64,8 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output): int { - $testsOutputDir = FilePathFormatter::format(TESTS_BP) . - "tests" . - DIRECTORY_SEPARATOR . - "_output" . - DIRECTORY_SEPARATOR; - - $this->testsFailedFile = $testsOutputDir . "failed"; - $this->testsReRunFile = $testsOutputDir . "rerun_tests"; + $this->testsFailedFile = $this->getTestsOutputDir() . self::FAILED_FILE; + $this->testsReRunFile = $this->getTestsOutputDir() . "rerun_tests"; $this->testsManifestFile= FilePathFormatter::format(TESTS_MODULE_PATH) . "_generated" . DIRECTORY_SEPARATOR . diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php index 7cbdf1f1b..6df902635 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php @@ -103,6 +103,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int } } + // Initialize `failed_all` file + $this->initializeFailedAllFile(); + if ($this->pauseEnabled()) { $commandString = self::CODECEPT_RUN_FUNCTIONAL . '--verbose --steps --debug'; } else { @@ -130,8 +133,14 @@ function ($type, $buffer) use ($output) { } ); } + + // Append `failed` to `failed_all` + $this->appendRunFailed(); } + // Update `failed` with contents from `failed_all` + $this->updateRunFailedWithFailedAll(); + foreach ($returnCodes as $returnCode) { if ($returnCode != 0) { return $returnCode; From f6ccbb51a954c3062cc4387166c86a5ccaa93ec0 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 26 Oct 2020 14:46:52 -0500 Subject: [PATCH 561/888] MQE-2272: run:failed only runs last failed test when multiple tests are run with run:test --- .../FunctionalTestingFramework/Console/BaseGenerateCommand.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index ef6fc2cec..481e27203 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -353,6 +353,7 @@ protected function appendRunFailed() * Replace content of file 'failed' with content in file 'failed_all' * * @return void + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ protected function updateRunFailedWithFailedAll() { From e56232d61ee16868f96a23c1cb24931de3e72fbc Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 28 Oct 2020 15:55:57 -0500 Subject: [PATCH 562/888] MQE-2272: run:failed only runs last failed test when multiple tests are run with run:test --- .../Console/BaseGenerateCommand.php | 54 +++++++------------ .../Console/RunTestCommand.php | 11 ++-- .../Console/RunTestGroupCommand.php | 9 ++-- 3 files changed, 25 insertions(+), 49 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index 481e27203..b88203cca 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -54,11 +54,11 @@ class BaseGenerateCommand extends Command private $testsOutputDir = null; /** - * File handle for 'failed_all' file + * String contains all 'failed' tests * - * @var resource + * @var string */ - private $fhFailedAll; + private $allFailed; /** * Console output style @@ -314,20 +314,7 @@ protected function getTestsOutputDir() } /** - * Initialize 'failed_all' file - * - * @return void - * @throws TestFrameworkException - */ - protected function initializeFailedAllFile() - { - // Initialize 'failed_all' file - $allFailedFile = $this->getTestsOutputDir() . self::FAILED_ALL_FILE; - $this->fhFailedAll = fopen($allFailedFile, 'w+'); - } - - /** - * Appends content of file 'failed' to file 'failed_all' + * Save 'failed' tests * * @return void */ @@ -339,10 +326,10 @@ protected function appendRunFailed() } if (file_exists($this->testsFailedFile)) { - // Append 'failed' into 'failed_all' + // Save 'failed' tests $contents = file_get_contents($this->testsFailedFile); if ($contents !== false && !empty($contents)) { - fwrite($this->fhFailedAll, trim($contents) . PHP_EOL); + $this->allFailed .= trim($contents) . PHP_EOL; } } } catch (TestFrameworkException $e) { @@ -350,35 +337,30 @@ protected function appendRunFailed() } /** - * Replace content of file 'failed' with content in file 'failed_all' + * Apply 'allFailed' in 'failed' file * * @return void * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ - protected function updateRunFailedWithFailedAll() + protected function applyAllFailed() { try { if (!$this->testsFailedFile) { $this->testsFailedFile = $this->getTestsOutputDir() . self::FAILED_FILE; } - if (file_exists($this->getTestsOutputDir() . self::FAILED_ALL_FILE)) { + if (!empty($this->allFailed)) { // Update 'failed' with content from 'failed_all' - $contents = file_get_contents($this->getTestsOutputDir() . self::FAILED_ALL_FILE); - if ($contents !== false && !empty($contents)) { - if (file_exists($this->testsFailedFile)) { - rename($this->testsFailedFile, $this->testsFailedFile . '.copy'); - } - if (file_put_contents($this->testsFailedFile, $contents) === false - && file_exists($this->testsFailedFile . '.copy')) { - rename($this->testsFailedFile . '.copy', $this->testsFailedFile); - } - if (file_exists($this->testsFailedFile . '.copy')) { - unlink($this->testsFailedFile . '.copy'); - } + if (file_exists($this->testsFailedFile)) { + rename($this->testsFailedFile, $this->testsFailedFile . '.copy'); + } + if (file_put_contents($this->testsFailedFile, $this->allFailed) === false + && file_exists($this->testsFailedFile . '.copy')) { + rename($this->testsFailedFile . '.copy', $this->testsFailedFile); + } + if (file_exists($this->testsFailedFile . '.copy')) { + unlink($this->testsFailedFile . '.copy'); } - fclose($this->fhFailedAll); - unlink($this->getTestsOutputDir() . self::FAILED_ALL_FILE); } } catch (TestFrameworkException $e) { } diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php index d6e485bdb..1b3f939ba 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php @@ -109,9 +109,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int $testConfigArray = json_decode($testConfiguration, true); - // Initialize `failed_all` file - $this->initializeFailedAllFile(); - if (isset($testConfigArray['tests'])) { $this->runTests($testConfigArray['tests'], $output); } @@ -120,8 +117,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->runTestsInSuite($testConfigArray['suites'], $output); } - // Update `failed` with contents from `failed_all` - $this->updateRunFailedWithFailedAll(); + // Add all failed tests in 'failed' file + $this->applyAllFailed(); return max($this->returnCode, $generationErrorCode); } @@ -168,7 +165,7 @@ private function runTests(array $tests, OutputInterface $output) $this->returnCode = max($this->returnCode, $this->executeTestCommand($fullCommand, $output)); } - // Append `failed` to `failed_all` + // Save failed tests $this->appendRunFailed(); } } @@ -206,7 +203,7 @@ private function runTestsInSuite(array $suitesConfig, OutputInterface $output) $this->returnCode = max($this->returnCode, $this->executeTestCommand($fullCommand, $output)); } - // Append `failed` to `failed_all` + // Save failed tests $this->appendRunFailed(); } } diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php index 6df902635..601438f96 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php @@ -103,9 +103,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int } } - // Initialize `failed_all` file - $this->initializeFailedAllFile(); - if ($this->pauseEnabled()) { $commandString = self::CODECEPT_RUN_FUNCTIONAL . '--verbose --steps --debug'; } else { @@ -134,12 +131,12 @@ function ($type, $buffer) use ($output) { ); } - // Append `failed` to `failed_all` + // Save failed tests $this->appendRunFailed(); } - // Update `failed` with contents from `failed_all` - $this->updateRunFailedWithFailedAll(); + // Add all failed tests in 'failed' file + $this->applyAllFailed(); foreach ($returnCodes as $returnCode) { if ($returnCode != 0) { From b4b0be1a43475b339c592ca7544c3edfbdbc85ae Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Thu, 29 Oct 2020 11:20:12 -0400 Subject: [PATCH 563/888] Fixing link --- docs/getting-started.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 1c8200e3b..10de901b4 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -358,11 +358,11 @@ allure serve dev/tests/_output/allure-results/ [install Allure]: https://github.com/allure-framework/allure2#download [java]: http://www.oracle.com/technetwork/java/javase/downloads/index.html [mftf tests]: introduction.html#mftf-tests -[php]: https://devdocs.magento.com/guides/v2.3/install-gde/system-requirements-tech.html#php +[php]: https://devdocs.magento.com/guides/v2.3/install-gde/system-requirements.html [PhpStorm]: https://www.jetbrains.com/phpstorm/ [selenium server]: https://www.seleniumhq.org/download/ [Set up a standalone MFTF]: #set-up-a-standalone-mftf [test suite]: suite.html [Find your version]: introduction.html#find-your-mftf-version -[Installation Guide docroot]: https://devdocs.magento.com/guides/v2.3/install-gde/tutorials/change-docroot-to-pub.html -[Magento Two-Factor Authentication (2FA) extension]: https://devdocs.magento.com/guides/v2.3/security/two-factor-authentication.html +[Installation Guide docroot]: https://devdocs.magento.com/guides/v2.4/install-gde/tutorials/change-docroot-to-pub.html +[Magento Two-Factor Authentication (2FA) extension]: https://devdocs.magento.com/guides/v2.4/security/two-factor-authentication.html From 0c4114d98c248aa4d6d3836313ece544c3620119 Mon Sep 17 00:00:00 2001 From: Donald Booth <dobooth@adobe.com> Date: Thu, 29 Oct 2020 11:21:49 -0400 Subject: [PATCH 564/888] Fix --- docs/getting-started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 10de901b4..7dc761e76 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -358,7 +358,7 @@ allure serve dev/tests/_output/allure-results/ [install Allure]: https://github.com/allure-framework/allure2#download [java]: http://www.oracle.com/technetwork/java/javase/downloads/index.html [mftf tests]: introduction.html#mftf-tests -[php]: https://devdocs.magento.com/guides/v2.3/install-gde/system-requirements.html +[php]: https://devdocs.magento.com/guides/v2.4/install-gde/system-requirements.html [PhpStorm]: https://www.jetbrains.com/phpstorm/ [selenium server]: https://www.seleniumhq.org/download/ [Set up a standalone MFTF]: #set-up-a-standalone-mftf From 4c48ad196cda76a0b65500711b24b0aa2be55012 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 29 Oct 2020 10:30:07 -0500 Subject: [PATCH 565/888] MQE-2272: run:failed only runs last failed test when multiple tests are run with run:test --- .../FunctionalTestingFramework/Console/BaseGenerateCommand.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index b88203cca..407006e59 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -37,7 +37,6 @@ class BaseGenerateCommand extends Command const CODECEPT_RUN_FUNCTIONAL = self::CODECEPT_RUN . ' functional '; const CODECEPT_RUN_OPTION_NO_EXIT = ' --no-exit '; const FAILED_FILE = 'failed'; - const FAILED_ALL_FILE = 'failed_all'; /** * Enable pause() From fe8bd5952a425c62c1b4e955eddd99f7b8c3567e Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 29 Oct 2020 10:34:11 -0500 Subject: [PATCH 566/888] MQE-2272: run:failed only runs last failed test when multiple tests are run with run:test --- .../FunctionalTestingFramework/Console/BaseGenerateCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index 407006e59..2d00e0abd 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -349,7 +349,7 @@ protected function applyAllFailed() } if (!empty($this->allFailed)) { - // Update 'failed' with content from 'failed_all' + // Update 'failed' with content from 'allFailed' if (file_exists($this->testsFailedFile)) { rename($this->testsFailedFile, $this->testsFailedFile . '.copy'); } From 22c17e17fcdee704dea76d3185d70420db914b74 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 4 Nov 2020 13:57:13 -0600 Subject: [PATCH 567/888] MQE-2339: CHANGELOG.MD and version bump for 3.2.0 --- CHANGELOG.md | 18 +++ composer.json | 2 +- composer.lock | 352 +------------------------------------------------- 3 files changed, 20 insertions(+), 352 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a48b18c9b..f4e3f28ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ Magento Functional Testing Framework Changelog ================================================ + +3.2.0 +--------- + +### Enhancements + +* Usability + * Introduced error tolerance during test and suite generation. See the [command page](./docs/commands/mftf.md#Error tolerance during generation) for details. + Addressed github issue [#276](https://github.com/magento/magento2-functional-testing-framework/issues/276). + +* Maintainability + * Enhanced annotation static-check to include all required annotations. + +### Fixes + +* Fixed issue where CUSTOM_MODULE_PATHS env variable doesn't use all paths. +* Fixed issue where run:test only records the last failed test in `failed` file. + 3.1.1 --------- diff --git a/composer.json b/composer.json index b916ad285..7ed0e31ff 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "3.1.1", + "version": "3.2.0", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index 7772ce788..b4b04a3a5 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3a49492cfc55a8d534163c854fc887a5", + "content-hash": "3aaf16914c319f584eb5f6ce39bef11b", "packages": [ { "name": "allure-framework/allure-codeception", @@ -491,12 +491,6 @@ "functional testing", "unit testing" ], - "funding": [ - { - "url": "https://opencollective.com/codeception", - "type": "open_collective" - } - ], "time": "2020-03-23T17:07:20+00:00" }, { @@ -822,16 +816,6 @@ "ssl", "tls" ], - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], "time": "2020-04-08T08:27:21+00:00" }, { @@ -912,16 +896,6 @@ "dependency", "package" ], - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], "time": "2020-04-10T09:44:22+00:00" }, { @@ -1087,12 +1061,6 @@ "Xdebug", "performance" ], - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - } - ], "time": "2020-03-01T12:26:26+00:00" }, { @@ -2565,12 +2533,6 @@ "sftp", "storage" ], - "funding": [ - { - "url": "https://offset.earth/frankdejonge", - "type": "other" - } - ], "time": "2020-04-16T13:21:26+00:00" }, { @@ -3505,12 +3467,6 @@ "filesystem", "iterator" ], - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], "time": "2020-04-18T05:02:12+00:00" }, { @@ -3659,12 +3615,6 @@ "keywords": [ "timer" ], - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], "time": "2020-04-20T06:00:37+00:00" }, { @@ -3803,16 +3753,6 @@ "testing", "xunit" ], - "funding": [ - { - "url": "https://phpunit.de/donate.html", - "type": "custom" - }, - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], "time": "2020-04-23T04:42:05+00:00" }, { @@ -4226,12 +4166,6 @@ ], "description": "Collection of value objects that represent the PHP code units", "homepage": "https://github.com/sebastianbergmann/code-unit", - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], "time": "2020-03-30T11:59:20+00:00" }, { @@ -4450,12 +4384,6 @@ "environment", "hhvm" ], - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], "time": "2020-04-14T13:36:52+00:00" }, { @@ -5096,20 +5024,6 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-03-30T11:41:10+00:00" }, { @@ -5163,20 +5077,6 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-03-27T16:56:45+00:00" }, { @@ -5227,20 +5127,6 @@ ], "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-06-06T08:49:21+00:00" }, { @@ -5311,20 +5197,6 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-03-27T16:54:36+00:00" }, { @@ -5433,20 +5305,6 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-03-27T16:56:45+00:00" }, { @@ -5496,20 +5354,6 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-03-27T16:56:45+00:00" }, { @@ -5571,20 +5415,6 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-06-15T06:52:54+00:00" }, { @@ -5647,20 +5477,6 @@ "mime", "mime-type" ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-03-27T16:56:45+00:00" }, { @@ -5719,20 +5535,6 @@ "polyfill", "portable" ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-02-27T09:26:54+00:00" }, { @@ -5795,20 +5597,6 @@ "portable", "shim" ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-03-09T19:04:49+00:00" }, { @@ -5868,20 +5656,6 @@ "portable", "shim" ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-03-09T19:04:49+00:00" }, { @@ -5937,20 +5711,6 @@ "portable", "shim" ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-02-27T09:26:54+00:00" }, { @@ -6009,20 +5769,6 @@ "portable", "shim" ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-02-27T09:26:54+00:00" }, { @@ -6089,20 +5835,6 @@ "portable", "shim" ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-06-06T08:46:27+00:00" }, { @@ -6152,20 +5884,6 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-03-27T16:54:36+00:00" }, { @@ -6283,20 +6001,6 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-03-30T11:41:10+00:00" }, { @@ -6526,12 +6230,6 @@ "env", "environment" ], - "funding": [ - { - "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", - "type": "tidelift" - } - ], "time": "2020-04-12T15:11:38+00:00" }, { @@ -6843,12 +6541,6 @@ } ], "description": "Library for accessing git", - "funding": [ - { - "url": "https://tidelift.com/funding/github/packagist/gitonomy/gitlib", - "type": "tidelift" - } - ], "time": "2020-03-23T12:43:44+00:00" }, { @@ -7601,20 +7293,6 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-03-27T16:54:36+00:00" }, { @@ -7688,20 +7366,6 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-03-30T10:09:30+00:00" }, { @@ -7751,20 +7415,6 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2020-03-15T09:38:08+00:00" }, { From 89eb5072f3bbbd327d5a6157836d6c8f52299112 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 4 Nov 2020 14:05:15 -0600 Subject: [PATCH 568/888] MQE-2339: CHANGELOG.MD and version bump for 3.2.0 --- CHANGELOG.md | 2 +- .../FunctionalTestingFramework/Util/GenerationErrorHandler.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4e3f28ad..f9452e3ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ Magento Functional Testing Framework Changelog Addressed github issue [#276](https://github.com/magento/magento2-functional-testing-framework/issues/276). * Maintainability - * Enhanced annotation static-check to include all required annotations. + * Updated annotation static-check to check all required annotations. ### Fixes diff --git a/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php b/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php index 486158eac..d4d9b43ad 100644 --- a/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php +++ b/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php @@ -164,7 +164,7 @@ public function printErrorSummary() . strval($totalAnnotationErrors) . ' ' . ucfirst($type) - . "(s) has(have) tests with annotation errors. See mftf.log for details." + . "(s) has(have) tests with errors. See mftf.log for details." . PHP_EOL ); } From 0a7324ccc2f884660c6606e867b81856287cf974 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 4 Nov 2020 14:21:04 -0600 Subject: [PATCH 569/888] MQE-2339: CHANGELOG.MD and version bump for 3.2.0 --- .../FunctionalTestingFramework/Util/GenerationErrorHandler.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php b/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php index d4d9b43ad..a86cd459d 100644 --- a/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php +++ b/src/Magento/FunctionalTestingFramework/Util/GenerationErrorHandler.php @@ -164,7 +164,8 @@ public function printErrorSummary() . strval($totalAnnotationErrors) . ' ' . ucfirst($type) - . "(s) has(have) tests with errors. See mftf.log for details." + . '(s) has(have) tests with annotation errors or some included tests missing.' + . ' See mftf.log for details.' . PHP_EOL ); } From ec4b1deed9d42bf8ccc712a8c2e64c854b011eab Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 4 Nov 2020 14:34:16 -0600 Subject: [PATCH 570/888] MQE-2339: CHANGELOG.MD and version bump for 3.2.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f9452e3ab..0c7793272 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ Magento Functional Testing Framework Changelog ### Enhancements * Usability - * Introduced error tolerance during test and suite generation. See the [command page](./docs/commands/mftf.md#Error tolerance during generation) for details. + * Introduced error tolerance during test and suite generation. See the [command page](./docs/commands/mftf.md#error-tolerance-during-generation) for details. Addressed github issue [#276](https://github.com/magento/magento2-functional-testing-framework/issues/276). * Maintainability From e0b23bb9ecd4b19b759c72b84b5223504dbe23a0 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 4 Nov 2020 14:39:16 -0600 Subject: [PATCH 571/888] MQE-2339: CHANGELOG.MD and version bump for 3.2.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c7793272..4d68da7cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ Magento Functional Testing Framework Changelog ### Fixes -* Fixed issue where CUSTOM_MODULE_PATHS env variable doesn't use all paths. +* Fixed issue where CUSTOM_MODULE_PATHS env variable does not use all paths. * Fixed issue where run:test only records the last failed test in `failed` file. 3.1.1 From 592346a1bcc94aa8d0fe477365ed992e0ad7aa71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20K=C3=B6cke?= <jens@koecke.net> Date: Fri, 13 Nov 2020 12:47:03 +0100 Subject: [PATCH 572/888] Use last entity when multiple candidates for requiredEntity are found. This enables to overwrite a requiredEntity in an extended entity. --- .../DataGenerator/Persist/OperationDataArrayResolver.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/OperationDataArrayResolver.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/OperationDataArrayResolver.php index 60b6e73c2..e4dc5f267 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/OperationDataArrayResolver.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/OperationDataArrayResolver.php @@ -245,10 +245,11 @@ private function getDependentEntitiesOfType($type) private function resolveOperationObjectAndEntityData($entityObject, $operationElementValue) { if ($operationElementValue != $entityObject->getType()) { - // if we have a mismatch attempt to retrieve linked data and return just the first linkage + // if we have a mismatch attempt to retrieve linked data and return just the last linkage + // this enables overwriting of required entity fields $linkName = $entityObject->getLinkedEntitiesOfType($operationElementValue); if (!empty($linkName)) { - $linkName = $linkName[0]; + $linkName = array_pop($linkName); return DataObjectHandler::getInstance()->getObject($linkName); } return null; From e95fb10d3a55d72af5d60e07703d09201812599e Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 18 Nov 2020 12:18:26 -0600 Subject: [PATCH 573/888] MQE-2391: [GitHub Issue] Magento fails with xdebug 3 due to mftf --- dev/tests/functional/standalone_bootstrap.php | 3 --- src/Magento/FunctionalTestingFramework/_bootstrap.php | 3 --- 2 files changed, 6 deletions(-) diff --git a/dev/tests/functional/standalone_bootstrap.php b/dev/tests/functional/standalone_bootstrap.php index 58030231d..49e6be69b 100755 --- a/dev/tests/functional/standalone_bootstrap.php +++ b/dev/tests/functional/standalone_bootstrap.php @@ -74,6 +74,3 @@ // add the debug flag here $debug_mode = $_ENV['MFTF_DEBUG'] ?? false; -if (!(bool)$debug_mode && extension_loaded('xdebug')) { - xdebug_disable(); -} diff --git a/src/Magento/FunctionalTestingFramework/_bootstrap.php b/src/Magento/FunctionalTestingFramework/_bootstrap.php index b655fb28e..d12e5ab8d 100644 --- a/src/Magento/FunctionalTestingFramework/_bootstrap.php +++ b/src/Magento/FunctionalTestingFramework/_bootstrap.php @@ -77,6 +77,3 @@ // add the debug flag here $debugMode = $_ENV['MFTF_DEBUG'] ?? false; -if (!(bool)$debugMode && extension_loaded('xdebug')) { - xdebug_disable(); -} From 6d6a7c59fc789625345c0b7b071fe08ea68b487b Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 24 Nov 2020 14:19:01 -0600 Subject: [PATCH 574/888] MQE-2391: [GitHub Issue] Magento fails with xdebug 3 due to mftf --- dev/tests/functional/standalone_bootstrap.php | 4 ---- .../Config/MftfApplicationConfig.php | 10 ++++------ src/Magento/FunctionalTestingFramework/_bootstrap.php | 3 --- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/dev/tests/functional/standalone_bootstrap.php b/dev/tests/functional/standalone_bootstrap.php index 49e6be69b..5ce6f029a 100755 --- a/dev/tests/functional/standalone_bootstrap.php +++ b/dev/tests/functional/standalone_bootstrap.php @@ -70,7 +70,3 @@ $RELATIVE_TESTS_MODULE_PATH = '/tests/functional/tests/MFTF'; defined('TESTS_MODULE_PATH') || define('TESTS_MODULE_PATH', realpath(TESTS_BP . $RELATIVE_TESTS_MODULE_PATH)); - - -// add the debug flag here -$debug_mode = $_ENV['MFTF_DEBUG'] ?? false; diff --git a/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php b/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php index ab06b5612..3aad73a06 100644 --- a/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php +++ b/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php @@ -100,17 +100,15 @@ private function __construct( $this->phase = $phase; $this->verboseEnabled = $verboseEnabled; - if (isset($debugLevel) && !in_array(strtolower($debugLevel), self::MFTF_DEBUG_LEVEL)) { + if (!in_array(strtolower($debugLevel), self::MFTF_DEBUG_LEVEL)) { throw new TestFrameworkException("{$debugLevel} is not a debug level. Use 'DEFAULT' or 'DEVELOPER'"); } switch (strtolower($debugLevel)) { - case self::LEVEL_DEVELOPER: case self::LEVEL_DEFAULT: - $this->debugLevel = $debugLevel; + $this->debugLevel = self::LEVEL_DEFAULT; break; - case null: + default: $this->debugLevel = self::LEVEL_DEVELOPER; - break; } $this->allowSkipped = $allowSkipped; $this->filterList = new FilterList($filters); @@ -196,7 +194,7 @@ public function verboseEnabled() */ public function getDebugLevel() { - return $this->debugLevel ?? getenv('MFTF_DEBUG'); + return $this->debugLevel; } /** diff --git a/src/Magento/FunctionalTestingFramework/_bootstrap.php b/src/Magento/FunctionalTestingFramework/_bootstrap.php index d12e5ab8d..9c13eaa54 100644 --- a/src/Magento/FunctionalTestingFramework/_bootstrap.php +++ b/src/Magento/FunctionalTestingFramework/_bootstrap.php @@ -74,6 +74,3 @@ 'TESTS_MODULE_PATH', realpath(TESTS_BP . $RELATIVE_TESTS_MODULE_PATH) ); - -// add the debug flag here -$debugMode = $_ENV['MFTF_DEBUG'] ?? false; From ee3811af8b9ea9b2ea4a3da86fef2b7cdf9a730c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20K=C3=B6cke?= <jens@koecke.net> Date: Wed, 25 Nov 2020 13:50:01 +0100 Subject: [PATCH 575/888] Add unit test --- .../OperationDataArrayResolverTest.php | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php index 3596edd98..e13447c51 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php @@ -477,6 +477,57 @@ public function testNestedMetadataArrayOfDiverseObjects() $this->assertEquals($expectedResult, $result); } + + public function testExtendedWithRequiredEntity() + { + $entityDataObjectBuilder = new EntityDataObjectBuilder(); + $extEntityDataObject = $entityDataObjectBuilder + ->withName("extEntity") + ->withType("entity") + ->withLinkedEntities(["baseSubentity" => "subentity","extSubentity" => "subentity"]) + ->build(); + + $mockDOHInstance = AspectMock::double(DataObjectHandler::class, ["getObject" => function ($name) { + $entityDataObjectBuilder = new EntityDataObjectBuilder(); + + if ($name == "baseSubentity") { + return $entityDataObjectBuilder + ->withName("baseSubentity") + ->withType("subentity") + ->withDataFields(["subtest" => "BaseSubtest"]) + ->build(); + } + + if ($name == "extSubentity") { + return $entityDataObjectBuilder + ->withName("extSubentity") + ->withType("subentity") + ->withDataFields(["subtest" => "ExtSubtest"]) + ->build(); + } + }])->make(); + AspectMock::double(DataObjectHandler::class, ['getInstance' => $mockDOHInstance]); + + $subentityOpElementBuilder = new OperationElementBuilder(); + $subentityOpElement = $subentityOpElementBuilder + ->withKey("sub") + ->withType("subentity") + ->withElementType("object") + ->withFields(["subtest" => "string"]) + ->build(); + + $operationResolver = new OperationDataArrayResolver(); + $result = $operationResolver->resolveOperationDataArray($extEntityDataObject,[$subentityOpElement], "create", false); + + $expected = [ + "sub" => [ + "subtest" => "ExtSubtest" + ] + ]; + + $this->assertEquals($expected, $result); + + } /** * After class functionality * @return void From ae7ae3cc8dc8eef49b2051720f831257c5bb2d7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20K=C3=B6cke?= <jens@koecke.net> Date: Wed, 25 Nov 2020 13:58:46 +0100 Subject: [PATCH 576/888] Fix code sniffer errors --- .../Persist/OperationDataArrayResolverTest.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php index e13447c51..2721bd266 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php @@ -477,7 +477,6 @@ public function testNestedMetadataArrayOfDiverseObjects() $this->assertEquals($expectedResult, $result); } - public function testExtendedWithRequiredEntity() { $entityDataObjectBuilder = new EntityDataObjectBuilder(); @@ -517,7 +516,12 @@ public function testExtendedWithRequiredEntity() ->build(); $operationResolver = new OperationDataArrayResolver(); - $result = $operationResolver->resolveOperationDataArray($extEntityDataObject,[$subentityOpElement], "create", false); + $result = $operationResolver->resolveOperationDataArray( + $extEntityDataObject, + [$subentityOpElement], + "create", + false + ); $expected = [ "sub" => [ @@ -526,7 +530,6 @@ public function testExtendedWithRequiredEntity() ]; $this->assertEquals($expected, $result); - } /** * After class functionality From 3e7d3ac97dee64efb1b6f8e063b68bd6675f969e Mon Sep 17 00:00:00 2001 From: Oleh Posyniak <oposyniak@magento.com> Date: Mon, 7 Dec 2020 12:58:24 -0600 Subject: [PATCH 577/888] MCLOUD-7387: Add MFTF documentation for AWS S3 --- docs/configuration.md | 60 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/docs/configuration.md b/docs/configuration.md index ce3adadd7..599ac7539 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -359,6 +359,66 @@ Global MFTF configuration for the default amount of time (in seconds) that a tes WAIT_TIMEOUT=30 ``` +### REMOTE_STORAGE_AWSS3_DRIVER + +The remote storage driver, to enable AWS S3 use `aws-s3` + +Example: + +```conf +REMOTE_STORAGE_AWSS3_DRIVER=aws-s3 +``` + +### REMOTE_STORAGE_AWSS3_REGION + +The region of S3 bucket. + +Example: + +```conf +REMOTE_STORAGE_AWSS3_REGION=us-west-2 +``` + +### REMOTE_STORAGE_AWSS3_BUCKET + +The name of S3 bucket. + +Example: + +```conf +REMOTE_STORAGE_AWSS3_BUCKET=my-test-bucket +``` + +### REMOTE_STORAGE_AWSS3_PREFIX + +The optional prefix inside S3 bucket. + +Example: + +```conf +REMOTE_STORAGE_AWSS3_PREFIX=local +``` + +### REMOTE_STORAGE_AWSS3_ACCESS_KEY + +The optional access key to access S3 bucket. + +Example: + +```conf +REMOTE_STORAGE_AWSS3_ACCESS_KEY=MY_ACCESS_KEY +``` + +### REMOTE_STORAGE_AWSS3_SECRET_KEY + +The optional secret ket to access S3 bucket. + +Example: + +```conf +REMOTE_STORAGE_AWSS3_SECRET_KEY=MY_SECRET_KEY +``` + <!-- Link definitions --> [`MAGENTO_CLI_COMMAND_PATH`]: #magento_cli_command_path From e13a93e86c27f36a0fbd58cd15158580b94f3cd6 Mon Sep 17 00:00:00 2001 From: Oleg Posyniak <posyniak@adobe.com> Date: Mon, 7 Dec 2020 13:58:27 -0600 Subject: [PATCH 578/888] Update docs/configuration.md Co-authored-by: Dmitry Shevtsov <12731225+dshevtsov@users.noreply.github.com> --- docs/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index 668e7f6ca..859ff63c2 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -370,7 +370,7 @@ ENABLE_PAUSE=true ### REMOTE_STORAGE_AWSS3_DRIVER -The remote storage driver, to enable AWS S3 use `aws-s3` +The remote storage driver. To enable AWS S3, use `aws-s3`. Example: From 02a1ea3d0ff100d454f4a1540def28dae9c505a7 Mon Sep 17 00:00:00 2001 From: Oleg Posyniak <posyniak@adobe.com> Date: Mon, 7 Dec 2020 13:58:34 -0600 Subject: [PATCH 579/888] Update docs/configuration.md Co-authored-by: Dmitry Shevtsov <12731225+dshevtsov@users.noreply.github.com> --- docs/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index 859ff63c2..6a63b0b5d 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -420,7 +420,7 @@ REMOTE_STORAGE_AWSS3_ACCESS_KEY=MY_ACCESS_KEY ### REMOTE_STORAGE_AWSS3_SECRET_KEY -The optional secret ket to access S3 bucket. +The optional secret key to access S3 bucket. Example: From 5997c3115e4b9e403d39cec4ee2083366d771ced Mon Sep 17 00:00:00 2001 From: Oleh Posyniak <oposyniak@magento.com> Date: Fri, 11 Dec 2020 20:10:43 -0600 Subject: [PATCH 580/888] MCLOUD-7387: Add MFTF documentation for AWS S3 --- docs/configuration.md | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 668e7f6ca..962e658e6 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -408,26 +408,6 @@ Example: REMOTE_STORAGE_AWSS3_PREFIX=local ``` -### REMOTE_STORAGE_AWSS3_ACCESS_KEY - -The optional access key to access S3 bucket. - -Example: - -```conf -REMOTE_STORAGE_AWSS3_ACCESS_KEY=MY_ACCESS_KEY -``` - -### REMOTE_STORAGE_AWSS3_SECRET_KEY - -The optional secret ket to access S3 bucket. - -Example: - -```conf -REMOTE_STORAGE_AWSS3_SECRET_KEY=MY_SECRET_KEY -``` - <!-- Link definitions --> [`MAGENTO_CLI_COMMAND_PATH`]: #magento_cli_command_path From 2fcca423eed9665fa9ecc573fb41a4c9ec45b000 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 14 Dec 2020 11:17:24 -0600 Subject: [PATCH 581/888] MQE-2416: CHANGELOG.MD and version bump for 3.2.1 --- CHANGELOG.md | 12 ++++++++++++ composer.json | 2 +- composer.lock | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d68da7cd..50830b410 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,18 @@ Magento Functional Testing Framework Changelog ================================================ +3.2.1 +--------- + +### Fixes + +* Fixed issue that causes Magento bin/magento to fail when xdebug 3 is used. [GitHub Issue #808](https://github.com/magento/magento2-functional-testing-framework/issues/808) + +### GitHub Pull requests: + + * [#806](https://github.com/magento/magento2-functional-testing-framework/pull/806) -- Enable an extending entity to overwrite a requiredEntity binding + * [#809](https://github.com/magento/magento2-functional-testing-framework/pull/809) -- Add MFTF documentation for AWS S3 + 3.2.0 --------- diff --git a/composer.json b/composer.json index 7ed0e31ff..528110db9 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "3.2.0", + "version": "3.2.1", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index b4b04a3a5..1cdca924c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3aaf16914c319f584eb5f6ce39bef11b", + "content-hash": "c10e8e92b057c17fa3d1818a240b7361", "packages": [ { "name": "allure-framework/allure-codeception", From 2df65d0fc45843c8dda9be58b2b199cbccd87b0e Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 14 Dec 2020 11:27:45 -0600 Subject: [PATCH 582/888] MQE-2416: CHANGELOG.MD and version bump for 3.2.1 --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50830b410..1e676e89b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ Magento Functional Testing Framework Changelog * Fixed issue that causes Magento bin/magento to fail when xdebug 3 is used. [GitHub Issue #808](https://github.com/magento/magento2-functional-testing-framework/issues/808) -### GitHub Pull requests: +### GitHub Pull Requests: * [#806](https://github.com/magento/magento2-functional-testing-framework/pull/806) -- Enable an extending entity to overwrite a requiredEntity binding * [#809](https://github.com/magento/magento2-functional-testing-framework/pull/809) -- Add MFTF documentation for AWS S3 @@ -65,7 +65,7 @@ Fixed issue with XPath locators for waits in MagentoPwaWebDriver. * Fixed issue with suite precondition failure for `createData` with required entity. -### GitHub Issues/Pull requests: +### GitHub Issues/Pull Requests: * [#547](https://github.com/magento/magento2-functional-testing-framework/pull/547) -- Fix invalid behavior of MAGENTO_BACKEND_BASE_URL * [#742](https://github.com/magento/magento2-functional-testing-framework/pull/742) -- Fix Waits In MagentoPwaWebDriver From bede92f472a462c3d982160b87175d95db523089 Mon Sep 17 00:00:00 2001 From: Ajith <ajithkumar.maragathavel@ziffity.com> Date: Mon, 11 Jan 2021 01:36:16 +0530 Subject: [PATCH 583/888] Added examples and modified url links --- docs/test.md | 2 +- docs/test/assertions.md | 160 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 158 insertions(+), 4 deletions(-) diff --git a/docs/test.md b/docs/test.md index 78021fb26..4a77016f1 100644 --- a/docs/test.md +++ b/docs/test.md @@ -87,7 +87,7 @@ Allure annotations provide metadata for reporting. `<before>` may contain these child elements: * Any [Action][actions] -* [`<actionGroup>`]s +* [`<actionGroup>`] ### after {#after-tag} diff --git a/docs/test/assertions.md b/docs/test/assertions.md index 554852fcc..4588dc8ec 100644 --- a/docs/test/assertions.md +++ b/docs/test/assertions.md @@ -51,6 +51,8 @@ The following example shows a common test that gets text from a page and asserts ### assertElementContainsAttribute +The `<assertElementContainsAttribute>` asserts that the selected html element contains and matches the expected value for the given attribute. + Example: ```xml @@ -92,7 +94,8 @@ It must be in typical array format like `[1,2,3,4,5]` or `[alpha, brontosaurus, See [assertArrayHasKey docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertArrayHasKey) Attribute|Type|Use|Description ----|---|---|---`message`|string|optional|Text of informational message about a cause of failure. +---|---|---|--- +`message`|string|optional|Text of informational message about a cause of failure. `stepKey`|string|required| A unique identifier of the text step. `before`|string|optional| `stepKey` of action that must be executed next. `after`|string|optional| `stepKey` of the preceding action. @@ -123,6 +126,15 @@ Attribute|Type|Use|Description See [assertStringContainsString docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertStringContainsString). +Example: + +```xml +<assertStringContainsString stepKey="assertDropDownTierPriceTextProduct1"> + <expectedResult type="string">Buy 5 for $5.00 each and save 50%</expectedResult> + <actualResult type="variable">DropDownTierPriceTextProduct1</actualResult> +</assertStringContainsString> +``` + Attribute|Type|Use|Description ---|---|---|--- `message`|string|optional|Text describing the cause of the failure. @@ -134,6 +146,15 @@ Attribute|Type|Use|Description See [assertStringContainsStringIgnoringCase docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertStringContainsStringIgnoringCase). +Example: + +```xml +<assertStringContainsStringIgnoringCase stepKey="verifyContentType"> + <actualResult type="variable">grabContentType</actualResult> + <expectedResult type="string">{{image.extension}}</expectedResult> +</assertStringContainsStringIgnoringCase> +``` + Attribute|Type|Use|Description ---|---|---|--- `message`|string|optional|Message describing the cause of failure. @@ -156,6 +177,14 @@ Attribute|Type|Use|Description See [assertEmpty docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertEmpty). +Example: + +```xml +<assertEmpty stepKey="assertSearchButtonEnabled"> + <actualResult type="string">$grabSearchButtonAttribute</actualResult> +</assertEmpty> +``` + Attribute|Type|Use|Description ---|---|---|--- `message`|string|optional|Text of informational message about a cause of failure. @@ -167,6 +196,15 @@ Attribute|Type|Use|Description See [assertEquals docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertEquals). +Example: + +```xml +<assertEquals message="ExpectedPrice" stepKey="assertBundleProductPrice"> + <actualResult type="variable">grabProductPrice</actualResult> + <expectedResult type="string">$75.00</expectedResult> +</assertEquals> +``` + Attribute|Type|Use|Description ---|---|---|--- `message`|string|optional|Text of informational message about a cause of failure. @@ -245,6 +283,15 @@ Attribute|Type|Use|Description See [assertGreaterOrEquals docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertGreaterOrEquals). +Example: + +```xml +<assertGreaterOrEquals stepKey="checkStatusSortOrderAsc" after="getOrderStatusSecondRow"> + <actualResult type="const">$getOrderStatusSecondRow</actualResult> + <expectedResult type="const">$getOrderStatusFirstRow</expectedResult> +</assertGreaterOrEquals> +``` + Attribute|Type|Use|Description ---|---|---|--- `message`|string|optional|Text of informational message about a cause of failure. @@ -256,6 +303,15 @@ Attribute|Type|Use|Description See [assertGreaterThan docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertGreaterThan). +Example: + +```xml +<assertGreaterThan stepKey="checkQuantityWasChanged"> + <actualResult type="const">$grabEndQuantity</actualResult> + <expectedResult type="const">$grabStartQuantity</expectedResult> +</assertGreaterThan> +``` + Attribute|Type|Use|Description ---|---|---|--- `message`|string|optional|Text of informational message about a cause of failure. @@ -267,6 +323,15 @@ Attribute|Type|Use|Description See [assertGreaterThanOrEqual docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertGreaterThanOrEqual). +Example: + +```xml +<assertGreaterThanOrEqual stepKey="checkStatusSortOrderAsc" after="getOrderStatusSecondRow"> + <actualResult type="const">$getOrderStatusSecondRow</actualResult> + <expectedResult type="const">$getOrderStatusFirstRow</expectedResult> +</assertGreaterThanOrEqual> +``` + Attribute|Type|Use|Description ---|---|---|--- `message`|string|optional|Text of informational message about a cause of failure. @@ -300,6 +365,15 @@ Attribute|Type|Use|Description See [assertLessOrEquals docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertLessOrEquals). +Example: + +```xml +<assertLessOrEquals stepKey="checkHeightIsCorrect"> + <actualResult type="variable">getImageHeight</actualResult> + <expectedResult type="variable">getSectionHeight</expectedResult> +</assertLessOrEquals> +``` + Attribute|Type|Use|Description ---|---|---|--- `message`|string|optional|Text of informational message about a cause of failure. @@ -311,6 +385,15 @@ Attribute|Type|Use|Description See [assertLessThan docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertLessThan). +Example: + +```xml +<assertLessThan stepKey="assertLessImages"> + <expectedResult type="variable">initialImages</expectedResult> + <actualResult type="variable">newImages</actualResult> +</assertLessThan> +``` + Attribute|Type|Use|Description ---|---|---|--- `message`|string|optional|Text of informational message about a cause of failure. @@ -322,6 +405,15 @@ Attribute|Type|Use|Description See [assertLessThanOrEqual docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertLessThanOrEqual). +Example: + +```xml +<assertLessThanOrEqual stepKey="checkHeightIsCorrect"> + <actualResult type="variable">getImageHeight</actualResult> + <expectedResult type="variable">getSectionHeight</expectedResult> +</assertLessThanOrEqual> +``` + Attribute|Type|Use|Description ---|---|---|--- `message`|string|optional|Text of informational message about a cause of failure. @@ -333,6 +425,15 @@ Attribute|Type|Use|Description See [assertNotContains docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertNotContains). +Example: + +```xml +<assertNotContains stepKey="assertCustomerGroupNotInOptions"> + <actualResult type="variable">customerGroups</actualResult> + <expectedResult type="string">{{customerGroup.code}}</expectedResult> +</assertNotContains> +``` + Attribute|Type|Use|Description ---|---|---|--- `message`|string|optional|Text of informational message about a cause of failure. @@ -344,6 +445,15 @@ Attribute|Type|Use|Description See [assertStringNotContainsString docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertStringNotContainsString). +Example: + +```xml +<assertStringNotContainsString stepKey="checkoutAsGuest"> + <expectedResult type="string">{{CaptchaData.checkoutAsGuest}}</expectedResult> + <actualResult type="variable">$formItems</actualResult> +</assertStringNotContainsString> +``` + Attribute|Type|Use|Description ---|---|---|--- `message`|string|optional|Text of informational message about a cause of failure. @@ -355,6 +465,15 @@ Attribute|Type|Use|Description See [assertStringNotContainsStringIgnoringCase docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertStringNotContainsStringIgnoringCase). +Example: + +```xml +<assertStringContainsStringIgnoringCase stepKey="verifyContentType"> + <actualResult type="variable">grabContentType</actualResult> + <expectedResult type="string">{{image.extension}}</expectedResult> +</assertStringContainsStringIgnoringCase> +``` + Attribute|Type|Use|Description ---|---|---|--- `message`|string|optional|Text of informational message about a cause of failure. @@ -366,6 +485,14 @@ Attribute|Type|Use|Description See [assertNotEmpty docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertNotEmpty). +Example: + +```xml +<assertNotEmpty stepKey="checkSwatchFieldForAdmin"> + <actualResult type="const">$grabSwatchForAdmin</actualResult> +</assertNotEmpty> +``` + Attribute|Type|Use|Description ---|---|---|--- `message`|string|optional|Text of informational message about a cause of failure. @@ -377,6 +504,15 @@ Attribute|Type|Use|Description See [assertNotEquals docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertNotEquals). +Example: + +```xml +<assertNotEquals stepKey="assertNotEquals"> + <actualResult type="string">{$grabTotalAfter}</actualResult> + <expectedResult type="string">{$grabTotalBefore}</expectedResult> +</assertNotEquals> +``` + Attribute|Type|Use|Description ---|---|---|--- `message`|string|optional|Text of informational message about a cause of failure. @@ -444,6 +580,15 @@ Attribute|Type|Use|Description See [assertNotRegExp docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertNotRegExp). +Example: + +```xml +<assertNotRegExp stepKey="simpleThumbnailIsNotDefault"> + <actualResult type="const">$getSimpleProductThumbnail</actualResult> + <expectedResult type="const">'/placeholder\/thumbnail\.jpg/'</expectedResult> +</assertNotRegExp> +``` + Attribute|Type|Use|Description ---|---|---|--- `message`|string|optional|Text of informational message about a cause of failure. @@ -477,6 +622,15 @@ Attribute|Type|Use|Description See [assertRegExp docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertRegExp). +Example: + +```xml +<assertRegExp message="adminAnalyticsMetadata object is invalid" stepKey="validateadminAnalyticsMetadata"> + <expectedResult type="string">#var\s+adminAnalyticsMetadata\s+=\s+{\s+("[\w_]+":\s+"[^"]*?",\s+)*?("[\w_]+":\s+"[^"]*?"\s+)};#s</expectedResult> + <actualResult type="variable">$pageSource</actualResult> +</assertRegExp> +``` + Attribute|Type|Use|Description ---|---|---|--- `message`|string|optional|Text of informational message about a cause of failure. @@ -530,7 +684,7 @@ Attribute|Type|Use|Description ### expectException -See [expectException docs on codeception.com](http://codeception.com/docs/modules/WebDriver#expectException). +See [expectException docs on codeception.com](https://codeception.com/docs/modules/Asserts#expectException). Attribute|Type|Use|Description ---|---|---|--- @@ -540,7 +694,7 @@ Attribute|Type|Use|Description ### fail -See [fail docs on codeception.com](http://codeception.com/docs/modules/WebDriver#fail). +See [fail docs on codeception.com](https://codeception.com/docs/modules/Asserts#fail). Attribute|Type|Use|Description ---|---|---|--- From d090f551673b36720110c0f28741e6d4fcfa16db Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 21 Jan 2021 14:51:31 -0600 Subject: [PATCH 584/888] MQE-2463: Mftf test extends from a skipped parent should be skipped --- .../Test/Util/ObjectExtensionUtil.php | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/ObjectExtensionUtil.php b/src/Magento/FunctionalTestingFramework/Test/Util/ObjectExtensionUtil.php index b59cdb53c..f0a36955b 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/ObjectExtensionUtil.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/ObjectExtensionUtil.php @@ -48,7 +48,7 @@ public function extendTest($testObject) ["parent" => $testObject->getParentName(), "test" => $testObject->getName()] ); } - $skippedTest = $this->skipTest($testObject); + $skippedTest = $this->skipTest($testObject, 'ParentTestDoesNotExist'); return $skippedTest; } @@ -64,6 +64,11 @@ public function extendTest($testObject) ->debug("extending test", ["parent" => $parentTest->getName(), "test" => $testObject->getName()]); } + // Skip test if parent is skipped + if ($parentTest->isSkipped()) { + return $this->skipTest($testObject); + } + // Get steps for both the parent and the child tests $referencedTestSteps = $parentTest->getUnresolvedSteps(); $newSteps = $this->processRemoveActions(array_merge($referencedTestSteps, $testObject->getUnresolvedSteps())); @@ -207,17 +212,19 @@ private function processRemoveActions($actions) * This method returns a skipped form of the Test Object * * @param TestObject $testObject + * @param string $skipReason * @return TestObject */ - public function skipTest($testObject) + public function skipTest($testObject, $skipReason = null) { $annotations = $testObject->getAnnotations(); + $skipReason = $skipReason ?? 'ParentTestIsSkipped'; // Add skip to the group array if it doesn't already exist if (array_key_exists('skip', $annotations)) { return $testObject; } elseif (!array_key_exists('skip', $annotations)) { - $annotations['skip'] = ['issueId' => "ParentTestDoesNotExist"]; + $annotations['skip'] = ['issueId' => $skipReason]; } $skippedTest = new TestObject( @@ -229,6 +236,10 @@ public function skipTest($testObject) $testObject->getParentName() ); + LoggingUtil::getInstance()->getLogger(ObjectExtensionUtil::class)->info( + "\nMQE-2463 LOGGING: {$testObject->getName()} is skipped due to {$skipReason}\n" + ); + return $skippedTest; } } From 07bf4278298d0e6778ee439adefb074210d2c8f3 Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Sat, 23 Jan 2021 13:41:21 -0600 Subject: [PATCH 585/888] MQE-2466: Test generation error in a split suite group (--config=parallel) fails generation of subsequent groups --- .../Suite/SuiteGeneratorTest.php | 51 +++++++++++++++++++ .../Suite/SuiteGenerator.php | 10 +++- 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php index 035807fb0..136b32e2a 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php @@ -226,6 +226,57 @@ public function testNonExistentSuiteTestPair() $this->assertArrayHasKey('Suite3', $suiteErrors); } + /** + * Tests generating split suites for parallel test generation + */ + public function testGenerateSplitSuiteFromTest() + { + $suiteDataArrayBuilder = new SuiteDataArrayBuilder(); + $mockSuiteData = $suiteDataArrayBuilder + ->withName('mockSuite') + ->includeGroups(['group1']) + ->build(); + $testDataArrayBuilder = new TestDataArrayBuilder(); + $mockSimpleTest1 = $testDataArrayBuilder + ->withName('simpleTest1') + ->withAnnotations(['group' => [['value' => 'group1']]]) + ->withTestReference("NonExistantTest") + ->withTestActions() + ->build(); + $mockSimpleTest2 = $testDataArrayBuilder + ->withName('simpleTest2') + ->withAnnotations(['group' => [['value' => 'group1']]]) + ->withTestActions() + ->build(); + $mockSimpleTest3 = $testDataArrayBuilder + ->withName('simpleTest3') + ->withAnnotations(['group' => [['value' => 'group1']]]) + ->withTestActions() + ->build(); + $mockTestData = array_merge($mockSimpleTest1, $mockSimpleTest2, $mockSimpleTest3); + $this->setMockTestAndSuiteParserOutput($mockTestData, $mockSuiteData); + + // Make manifest for split suites + $suiteConfig = [ + 'mockSuite' => [ + 'mockSuite_0_G' => ['simpleTest1', 'simpleTest2'], + 'mockSuite_1_G' => ['simpleTest3'], + ], + ]; + $manifest = TestManifestFactory::makeManifest('default', $suiteConfig); + + // parse and generate suite object with mocked data and manifest + $mockSuiteGenerator = SuiteGenerator::getInstance(); + $mockSuiteGenerator->generateAllSuites($manifest); + + // assert last split suite group generated + TestLoggingUtil::getInstance()->validateMockLogStatement( + 'info', + "suite generated", + ['suite' => 'mockSuite_1_G', 'relative_path' => "_generated" . DIRECTORY_SEPARATOR . "mockSuite_1_G"] + ); + } + /** * Function used to set mock for parser return and force init method to run between tests. * diff --git a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php index 13ac13371..e8af3f20c 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php @@ -265,7 +265,15 @@ private function validateTestsReferencedInSuite($suiteName, $testsReferenced, $o private function generateSplitSuiteFromTest($suiteName, $suiteContent) { foreach ($suiteContent as $suiteSplitName => $tests) { - $this->generateSuiteFromTest($suiteSplitName, $tests, $suiteName); + try { + $this->generateSuiteFromTest($suiteSplitName, $tests, $suiteName); + } catch (FastFailException $e) { + throw $e; + } catch (\Exception $e) { + // There are suites that include tests that reference tests from other Magento editions + // To keep backward compatibility, we will catch such exceptions with no error. + // This might inevitably hide some suite errors that are resulted by tests with broken references + } } } From 1373f1644ccf8c5fb7ba6ad2c31cd7be71fbbc2e Mon Sep 17 00:00:00 2001 From: Sergey Nezbritskiy <sergey.nezbritskiy@gmail.com> Date: Sun, 24 Jan 2021 22:24:27 +0200 Subject: [PATCH 586/888] update dependencies in order to make mftf php8 compatible, fix running phpcpd --- composer.json | 2 +- composer.lock | 2488 +++++++++++------ .../Console/BuildProjectCommand.php | 2 +- .../Console/RunManifestCommand.php | 2 +- .../Console/RunTestCommand.php | 2 +- .../Console/RunTestGroupCommand.php | 2 +- 6 files changed, 1627 insertions(+), 871 deletions(-) diff --git a/composer.json b/composer.json index 528110db9..b2d215b51 100755 --- a/composer.json +++ b/composer.json @@ -47,7 +47,7 @@ "phpmd/phpmd": "^2.8.0", "phpunit/phpunit": "^9.0", "rregeer/phpunit-coverage-check": "^0.1.4", - "sebastian/phpcpd": "~5.0.0", + "sebastian/phpcpd": "~6.0.0", "squizlabs/php_codesniffer": "~3.5.4", "symfony/stopwatch": "~3.4.6" }, diff --git a/composer.lock b/composer.lock index 1cdca924c..41a85a97c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,24 +4,24 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c10e8e92b057c17fa3d1818a240b7361", + "content-hash": "a3a50528ff432489bdd4acc275050ef5", "packages": [ { "name": "allure-framework/allure-codeception", - "version": "1.4.3", + "version": "1.4.5", "source": { "type": "git", "url": "https://github.com/allure-framework/allure-codeception.git", - "reference": "9e0e25f8960fa5ac17c65c932ea8153ce6700713" + "reference": "ac3d471902d2903856bbd0a95e7546788319ed22" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/allure-framework/allure-codeception/zipball/9e0e25f8960fa5ac17c65c932ea8153ce6700713", - "reference": "9e0e25f8960fa5ac17c65c932ea8153ce6700713", + "url": "https://api.github.com/repos/allure-framework/allure-codeception/zipball/ac3d471902d2903856bbd0a95e7546788319ed22", + "reference": "ac3d471902d2903856bbd0a95e7546788319ed22", "shasum": "" }, "require": { - "allure-framework/allure-php-api": "~1.1.8", + "allure-framework/allure-php-api": "~1.2.1", "codeception/codeception": "^2.3|^3.0|^4.0", "php": ">=5.6", "symfony/filesystem": ">=2.6", @@ -55,26 +55,26 @@ "steps", "testing" ], - "time": "2020-03-13T11:07:13+00:00" + "time": "2020-11-26T11:41:53+00:00" }, { "name": "allure-framework/allure-php-api", - "version": "1.1.8", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/allure-framework/allure-php-commons.git", - "reference": "5ae2deac1c7e1b992cfa572167370de45bdd346d" + "reference": "13ef45d83ce4f5ef70499ff87ed0c3d1c192ab80" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/allure-framework/allure-php-commons/zipball/5ae2deac1c7e1b992cfa572167370de45bdd346d", - "reference": "5ae2deac1c7e1b992cfa572167370de45bdd346d", + "url": "https://api.github.com/repos/allure-framework/allure-php-commons/zipball/13ef45d83ce4f5ef70499ff87ed0c3d1c192ab80", + "reference": "13ef45d83ce4f5ef70499ff87ed0c3d1c192ab80", "shasum": "" }, "require": { "jms/serializer": "^0.16 || ^1.0", "php": ">=5.4.0", - "ramsey/uuid": "^3.0", + "ramsey/uuid": "^3.0 || ^4.0", "symfony/http-foundation": "^2.0 || ^3.0 || ^4.0 || ^5.0" }, "require-dev": { @@ -108,20 +108,20 @@ "php", "report" ], - "time": "2020-03-13T10:47:35+00:00" + "time": "2020-11-26T09:20:44+00:00" }, { "name": "aws/aws-sdk-php", - "version": "3.135.3", + "version": "3.172.0", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "0f6f6e8f4a44193908e18b8c7b8530b02f5bc428" + "reference": "5a5e66c4d54c392042820703eeb8a6bd3d222924" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/0f6f6e8f4a44193908e18b8c7b8530b02f5bc428", - "reference": "0f6f6e8f4a44193908e18b8c7b8530b02f5bc428", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/5a5e66c4d54c392042820703eeb8a6bd3d222924", + "reference": "5a5e66c4d54c392042820703eeb8a6bd3d222924", "shasum": "" }, "require": { @@ -144,6 +144,7 @@ "ext-pcntl": "*", "ext-sockets": "*", "nette/neon": "^2.3", + "paragonie/random_compat": ">= 2", "phpunit/phpunit": "^4.8.35|^5.4.3", "psr/cache": "^1.0", "psr/simple-cache": "^1.0", @@ -192,36 +193,35 @@ "s3", "sdk" ], - "time": "2020-04-23T18:18:24+00:00" + "time": "2021-01-22T19:21:38+00:00" }, { "name": "beberlei/assert", - "version": "v3.2.7", + "version": "v3.3.0", "source": { "type": "git", "url": "https://github.com/beberlei/assert.git", - "reference": "d63a6943fc4fd1a2aedb65994e3548715105abcf" + "reference": "5367e3895976b49704ae671f75bc5f0ba1b986ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/beberlei/assert/zipball/d63a6943fc4fd1a2aedb65994e3548715105abcf", - "reference": "d63a6943fc4fd1a2aedb65994e3548715105abcf", + "url": "https://api.github.com/repos/beberlei/assert/zipball/5367e3895976b49704ae671f75bc5f0ba1b986ab", + "reference": "5367e3895976b49704ae671f75bc5f0ba1b986ab", "shasum": "" }, "require": { "ext-ctype": "*", + "ext-intl": "*", "ext-json": "*", "ext-mbstring": "*", "ext-simplexml": "*", - "php": "^7" + "php": "^7.0 || ^8.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "*", - "phpstan/phpstan-shim": "*", - "phpunit/phpunit": ">=6.0.0 <8" - }, - "suggest": { - "ext-intl": "Needed to allow Assertion::count(), Assertion::isCountable(), Assertion::minCount(), and Assertion::maxCount() to operate on ResourceBundles" + "phpstan/phpstan": "*", + "phpunit/phpunit": ">=6.0.0", + "yoast/phpunit-polyfills": "^0.1.0" }, "type": "library", "autoload": { @@ -254,27 +254,27 @@ "assertion", "validation" ], - "time": "2019-12-19T17:51:41+00:00" + "time": "2020-11-13T20:02:54+00:00" }, { "name": "behat/gherkin", - "version": "v4.6.2", + "version": "v4.7.0", "source": { "type": "git", "url": "https://github.com/Behat/Gherkin.git", - "reference": "51ac4500c4dc30cbaaabcd2f25694299df666a31" + "reference": "0ffe6a7f67f8d038166143d71b30a9088f932576" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Behat/Gherkin/zipball/51ac4500c4dc30cbaaabcd2f25694299df666a31", - "reference": "51ac4500c4dc30cbaaabcd2f25694299df666a31", + "url": "https://api.github.com/repos/Behat/Gherkin/zipball/0ffe6a7f67f8d038166143d71b30a9088f932576", + "reference": "0ffe6a7f67f8d038166143d71b30a9088f932576", "shasum": "" }, "require": { - "php": ">=5.3.1" + "php": ">=5.6" }, "require-dev": { - "phpunit/phpunit": "~4.5|~5", + "phpunit/phpunit": "~5.7|~6|~7", "symfony/phpunit-bridge": "~2.7|~3|~4", "symfony/yaml": "~2.3|~3|~4" }, @@ -303,7 +303,7 @@ "homepage": "http://everzet.com" } ], - "description": "Gherkin DSL parser for PHP 5.3", + "description": "Gherkin DSL parser for PHP", "homepage": "http://behat.org/", "keywords": [ "BDD", @@ -313,7 +313,59 @@ "gherkin", "parser" ], - "time": "2020-03-17T14:03:26+00:00" + "time": "2021-01-24T14:06:27+00:00" + }, + { + "name": "brick/math", + "version": "0.9.2", + "source": { + "type": "git", + "url": "https://github.com/brick/math.git", + "reference": "dff976c2f3487d42c1db75a3b180e2b9f0e72ce0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/brick/math/zipball/dff976c2f3487d42c1db75a3b180e2b9f0e72ce0", + "reference": "dff976c2f3487d42c1db75a3b180e2b9f0e72ce0", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.2", + "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0", + "vimeo/psalm": "4.3.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Brick\\Math\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Arbitrary-precision arithmetic library", + "keywords": [ + "Arbitrary-precision", + "BigInteger", + "BigRational", + "arithmetic", + "bigdecimal", + "bignum", + "brick", + "math" + ], + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/brick/math", + "type": "tidelift" + } + ], + "time": "2021-01-20T22:51:39+00:00" }, { "name": "cache/cache", @@ -410,16 +462,16 @@ }, { "name": "codeception/codeception", - "version": "4.1.4", + "version": "4.1.15", "source": { "type": "git", "url": "https://github.com/Codeception/Codeception.git", - "reference": "55d8d1d882fa0777e47de17b04c29b3c50fe29e7" + "reference": "9b174d18ba58bb2e8cc4cecce619d6124df1d83a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/Codeception/zipball/55d8d1d882fa0777e47de17b04c29b3c50fe29e7", - "reference": "55d8d1d882fa0777e47de17b04c29b3c50fe29e7", + "url": "https://api.github.com/repos/Codeception/Codeception/zipball/9b174d18ba58bb2e8cc4cecce619d6124df1d83a", + "reference": "9b174d18ba58bb2e8cc4cecce619d6124df1d83a", "shasum": "" }, "require": { @@ -431,7 +483,7 @@ "ext-json": "*", "ext-mbstring": "*", "guzzlehttp/psr7": "~1.4", - "php": ">=5.6.0 <8.0", + "php": ">=5.6.0 <9.0", "symfony/console": ">=2.7 <6.0", "symfony/css-selector": ">=2.7 <6.0", "symfony/event-dispatcher": ">=2.7 <6.0", @@ -449,7 +501,7 @@ "monolog/monolog": "~1.8", "squizlabs/php_codesniffer": "~2.0", "symfony/process": ">=2.7 <6.0", - "vlucas/phpdotenv": "^2.0 | ^3.0 | ^4.0" + "vlucas/phpdotenv": "^2.0 | ^3.0 | ^4.0 | ^5.0" }, "suggest": { "codeception/specify": "BDD-style code blocks", @@ -491,25 +543,32 @@ "functional testing", "unit testing" ], - "time": "2020-03-23T17:07:20+00:00" + "funding": [ + { + "url": "https://opencollective.com/codeception", + "type": "open_collective" + } + ], + "time": "2021-01-17T19:19:40+00:00" }, { "name": "codeception/lib-asserts", - "version": "1.12.0", + "version": "1.13.2", "source": { "type": "git", "url": "https://github.com/Codeception/lib-asserts.git", - "reference": "acd0dc8b394595a74b58dcc889f72569ff7d8e71" + "reference": "184231d5eab66bc69afd6b9429344d80c67a33b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/lib-asserts/zipball/acd0dc8b394595a74b58dcc889f72569ff7d8e71", - "reference": "acd0dc8b394595a74b58dcc889f72569ff7d8e71", + "url": "https://api.github.com/repos/Codeception/lib-asserts/zipball/184231d5eab66bc69afd6b9429344d80c67a33b6", + "reference": "184231d5eab66bc69afd6b9429344d80c67a33b6", "shasum": "" }, "require": { "codeception/phpunit-wrapper": ">6.0.15 <6.1.0 | ^6.6.1 | ^7.7.1 | ^8.0.3 | ^9.0", - "php": ">=5.6.0 <8.0" + "ext-dom": "*", + "php": ">=5.6.0 <9.0" }, "type": "library", "autoload": { @@ -529,40 +588,41 @@ }, { "name": "Gintautas Miselis" + }, + { + "name": "Gustavo Nieves", + "homepage": "https://medium.com/@ganieves" } ], "description": "Assertion methods used by Codeception core and Asserts module", - "homepage": "http://codeception.com/", + "homepage": "https://codeception.com/", "keywords": [ "codeception" ], - "time": "2020-04-17T18:20:46+00:00" + "time": "2020-10-21T16:26:20+00:00" }, { "name": "codeception/module-asserts", - "version": "1.2.1", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/Codeception/module-asserts.git", - "reference": "79f13d05b63f2fceba4d0e78044bab668c9b2a6b" + "reference": "59374f2fef0cabb9e8ddb53277e85cdca74328de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/module-asserts/zipball/79f13d05b63f2fceba4d0e78044bab668c9b2a6b", - "reference": "79f13d05b63f2fceba4d0e78044bab668c9b2a6b", + "url": "https://api.github.com/repos/Codeception/module-asserts/zipball/59374f2fef0cabb9e8ddb53277e85cdca74328de", + "reference": "59374f2fef0cabb9e8ddb53277e85cdca74328de", "shasum": "" }, "require": { "codeception/codeception": "*@dev", - "codeception/lib-asserts": "^1.12.0", - "php": ">=5.6.0 <8.0" + "codeception/lib-asserts": "^1.13.1", + "php": ">=5.6.0 <9.0" }, "conflict": { "codeception/codeception": "<4.0" }, - "require-dev": { - "codeception/util-robohelpers": "dev-master" - }, "type": "library", "autoload": { "classmap": [ @@ -579,37 +639,38 @@ }, { "name": "Gintautas Miselis" + }, + { + "name": "Gustavo Nieves", + "homepage": "https://medium.com/@ganieves" } ], "description": "Codeception module containing various assertions", - "homepage": "http://codeception.com/", + "homepage": "https://codeception.com/", "keywords": [ "assertions", "asserts", "codeception" ], - "time": "2020-04-20T07:26:11+00:00" + "time": "2020-10-21T16:48:15+00:00" }, { "name": "codeception/module-sequence", - "version": "1.0.0", + "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/Codeception/module-sequence.git", - "reference": "70563527b768194d6ab22e1ff943a5e69741c5dd" + "reference": "b75be26681ae90824cde8f8df785981f293667e1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/module-sequence/zipball/70563527b768194d6ab22e1ff943a5e69741c5dd", - "reference": "70563527b768194d6ab22e1ff943a5e69741c5dd", + "url": "https://api.github.com/repos/Codeception/module-sequence/zipball/b75be26681ae90824cde8f8df785981f293667e1", + "reference": "b75be26681ae90824cde8f8df785981f293667e1", "shasum": "" }, "require": { - "codeception/codeception": "4.0.x-dev | ^4.0", - "php": ">=5.6.0 <8.0" - }, - "require-dev": { - "codeception/util-robohelpers": "dev-master" + "codeception/codeception": "^4.0", + "php": ">=5.6.0 <9.0" }, "type": "library", "autoload": { @@ -631,29 +692,26 @@ "keywords": [ "codeception" ], - "time": "2019-10-10T12:08:50+00:00" + "time": "2020-10-31T18:36:26+00:00" }, { "name": "codeception/module-webdriver", - "version": "1.0.7", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/Codeception/module-webdriver.git", - "reference": "f05c5c25e39d10fbfb2d508779e1537df019ff9b" + "reference": "63ea08880a44df809bdfbca08597e1b68cee9f87" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/module-webdriver/zipball/f05c5c25e39d10fbfb2d508779e1537df019ff9b", - "reference": "f05c5c25e39d10fbfb2d508779e1537df019ff9b", + "url": "https://api.github.com/repos/Codeception/module-webdriver/zipball/63ea08880a44df809bdfbca08597e1b68cee9f87", + "reference": "63ea08880a44df809bdfbca08597e1b68cee9f87", "shasum": "" }, "require": { "codeception/codeception": "^4.0", - "php": ">=5.6.0 <8.0", - "php-webdriver/webdriver": "^1.6.0" - }, - "require-dev": { - "codeception/util-robohelpers": "dev-master" + "php": ">=5.6.0 <9.0", + "php-webdriver/webdriver": "^1.8.0" }, "suggest": { "codeception/phpbuiltinserver": "Start and stop PHP built-in web server for your tests" @@ -686,20 +744,20 @@ "browser-testing", "codeception" ], - "time": "2020-04-01T10:18:18+00:00" + "time": "2021-01-17T19:23:20+00:00" }, { "name": "codeception/phpunit-wrapper", - "version": "9.0.2", + "version": "9.0.6", "source": { "type": "git", "url": "https://github.com/Codeception/phpunit-wrapper.git", - "reference": "eb27243d8edde68593bf8d9ef5e9074734777931" + "reference": "b0c06abb3181eedca690170f7ed0fd26a70bfacc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/phpunit-wrapper/zipball/eb27243d8edde68593bf8d9ef5e9074734777931", - "reference": "eb27243d8edde68593bf8d9ef5e9074734777931", + "url": "https://api.github.com/repos/Codeception/phpunit-wrapper/zipball/b0c06abb3181eedca690170f7ed0fd26a70bfacc", + "reference": "b0c06abb3181eedca690170f7ed0fd26a70bfacc", "shasum": "" }, "require": { @@ -708,6 +766,7 @@ }, "require-dev": { "codeception/specify": "*", + "consolidation/robo": "^3.0.0-alpha3", "vlucas/phpdotenv": "^3.0" }, "type": "library", @@ -730,20 +789,20 @@ } ], "description": "PHPUnit classes used by Codeception", - "time": "2020-04-17T18:16:31+00:00" + "time": "2020-12-28T13:59:47+00:00" }, { "name": "codeception/stub", - "version": "3.6.1", + "version": "3.7.0", "source": { "type": "git", "url": "https://github.com/Codeception/Stub.git", - "reference": "a3ba01414cbee76a1bced9f9b6b169cc8d203880" + "reference": "468dd5fe659f131fc997f5196aad87512f9b1304" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/Stub/zipball/a3ba01414cbee76a1bced9f9b6b169cc8d203880", - "reference": "a3ba01414cbee76a1bced9f9b6b169cc8d203880", + "url": "https://api.github.com/repos/Codeception/Stub/zipball/468dd5fe659f131fc997f5196aad87512f9b1304", + "reference": "468dd5fe659f131fc997f5196aad87512f9b1304", "shasum": "" }, "require": { @@ -760,20 +819,20 @@ "MIT" ], "description": "Flexible Stub wrapper for PHPUnit's Mock Builder", - "time": "2020-02-07T18:42:28+00:00" + "time": "2020-07-03T15:54:43+00:00" }, { "name": "composer/ca-bundle", - "version": "1.2.7", + "version": "1.2.9", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "95c63ab2117a72f48f5a55da9740a3273d45b7fd" + "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/95c63ab2117a72f48f5a55da9740a3273d45b7fd", - "reference": "95c63ab2117a72f48f5a55da9740a3273d45b7fd", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/78a0e288fdcebf92aa2318a8d3656168da6ac1a5", + "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5", "shasum": "" }, "require": { @@ -782,14 +841,15 @@ "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8", + "phpstan/phpstan": "^0.12.55", "psr/log": "^1.0", + "symfony/phpunit-bridge": "^4.2 || ^5", "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-main": "1.x-dev" } }, "autoload": { @@ -816,20 +876,34 @@ "ssl", "tls" ], - "time": "2020-04-08T08:27:21+00:00" + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2021-01-12T12:10:35+00:00" }, { "name": "composer/composer", - "version": "1.10.5", + "version": "1.10.19", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "7a4d5b6aa30d2118af27c04f5e897b57156ccfa9" + "reference": "196601d50c08c3fae389a417a7689367fcf37cef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/7a4d5b6aa30d2118af27c04f5e897b57156ccfa9", - "reference": "7a4d5b6aa30d2118af27c04f5e897b57156ccfa9", + "url": "https://api.github.com/repos/composer/composer/zipball/196601d50c08c3fae389a417a7689367fcf37cef", + "reference": "196601d50c08c3fae389a417a7689367fcf37cef", "shasum": "" }, "require": { @@ -837,8 +911,8 @@ "composer/semver": "^1.0", "composer/spdx-licenses": "^1.2", "composer/xdebug-handler": "^1.1", - "justinrainbow/json-schema": "^3.0 || ^4.0 || ^5.0", - "php": "^5.3.2 || ^7.0", + "justinrainbow/json-schema": "^5.2.10", + "php": "^5.3.2 || ^7.0 || ^8.0", "psr/log": "^1.0", "seld/jsonlint": "^1.4", "seld/phar-utils": "^1.0", @@ -852,7 +926,7 @@ }, "require-dev": { "phpspec/prophecy": "^1.10", - "symfony/phpunit-bridge": "^3.4" + "symfony/phpunit-bridge": "^4.2" }, "suggest": { "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages", @@ -896,24 +970,38 @@ "dependency", "package" ], - "time": "2020-04-10T09:44:22+00:00" + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2020-12-04T08:14:16+00:00" }, { "name": "composer/semver", - "version": "1.5.1", + "version": "1.7.2", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de" + "reference": "647490bbcaf7fc4891c58f47b825eb99d19c377a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/c6bea70230ef4dd483e6bbcab6005f682ed3a8de", - "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de", + "url": "https://api.github.com/repos/composer/semver/zipball/647490bbcaf7fc4891c58f47b825eb99d19c377a", + "reference": "647490bbcaf7fc4891c58f47b825eb99d19c377a", "shasum": "" }, "require": { - "php": "^5.3.2 || ^7.0" + "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { "phpunit/phpunit": "^4.5 || ^5.0.5" @@ -957,20 +1045,34 @@ "validation", "versioning" ], - "time": "2020-01-13T12:06:48+00:00" + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2020-12-03T15:47:16+00:00" }, { "name": "composer/spdx-licenses", - "version": "1.5.3", + "version": "1.5.5", "source": { "type": "git", "url": "https://github.com/composer/spdx-licenses.git", - "reference": "0c3e51e1880ca149682332770e25977c70cf9dae" + "reference": "de30328a7af8680efdc03e396aad24befd513200" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/0c3e51e1880ca149682332770e25977c70cf9dae", - "reference": "0c3e51e1880ca149682332770e25977c70cf9dae", + "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/de30328a7af8680efdc03e396aad24befd513200", + "reference": "de30328a7af8680efdc03e396aad24befd513200", "shasum": "" }, "require": { @@ -982,7 +1084,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-main": "1.x-dev" } }, "autoload": { @@ -1017,20 +1119,34 @@ "spdx", "validator" ], - "time": "2020-02-14T07:44:31+00:00" + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2020-12-03T16:04:16+00:00" }, { "name": "composer/xdebug-handler", - "version": "1.4.1", + "version": "1.4.5", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "1ab9842d69e64fb3a01be6b656501032d1b78cb7" + "reference": "f28d44c286812c714741478d968104c5e604a1d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/1ab9842d69e64fb3a01be6b656501032d1b78cb7", - "reference": "1ab9842d69e64fb3a01be6b656501032d1b78cb7", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/f28d44c286812c714741478d968104c5e604a1d4", + "reference": "f28d44c286812c714741478d968104c5e604a1d4", "shasum": "" }, "require": { @@ -1061,7 +1177,21 @@ "Xdebug", "performance" ], - "time": "2020-03-01T12:26:26+00:00" + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2020-11-13T08:04:11+00:00" }, { "name": "csharpru/vault-php", @@ -1151,31 +1281,33 @@ }, { "name": "doctrine/annotations", - "version": "1.10.2", + "version": "1.11.1", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "b9d758e831c70751155c698c2f7df4665314a1cb" + "reference": "ce77a7ba1770462cd705a91a151b6c3746f9c6ad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/b9d758e831c70751155c698c2f7df4665314a1cb", - "reference": "b9d758e831c70751155c698c2f7df4665314a1cb", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/ce77a7ba1770462cd705a91a151b6c3746f9c6ad", + "reference": "ce77a7ba1770462cd705a91a151b6c3746f9c6ad", "shasum": "" }, "require": { "doctrine/lexer": "1.*", "ext-tokenizer": "*", - "php": "^7.1" + "php": "^7.1 || ^8.0" }, "require-dev": { "doctrine/cache": "1.*", - "phpunit/phpunit": "^7.5" + "doctrine/coding-standard": "^6.0 || ^8.1", + "phpstan/phpstan": "^0.12.20", + "phpunit/phpunit": "^7.5 || ^9.1.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.9.x-dev" + "dev-master": "1.11.x-dev" } }, "autoload": { @@ -1210,13 +1342,13 @@ } ], "description": "Docblock Annotations Parser", - "homepage": "http://www.doctrine-project.org", + "homepage": "https://www.doctrine-project.org/projects/annotations.html", "keywords": [ "annotations", "docblock", "parser" ], - "time": "2020-04-20T09:18:32+00:00" + "time": "2020-10-26T10:28:16+00:00" }, { "name": "doctrine/cache", @@ -1357,36 +1489,31 @@ }, { "name": "doctrine/instantiator", - "version": "1.3.0", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "ae466f726242e637cebdd526a7d991b9433bacf1" + "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/ae466f726242e637cebdd526a7d991b9433bacf1", - "reference": "ae466f726242e637cebdd526a7d991b9433bacf1", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/d56bf6102915de5702778fe20f2de3b2fe570b5b", + "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b", "shasum": "" }, "require": { - "php": "^7.1" + "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^6.0", + "doctrine/coding-standard": "^8.0", "ext-pdo": "*", "ext-phar": "*", - "phpbench/phpbench": "^0.13", - "phpstan/phpstan-phpunit": "^0.11", - "phpstan/phpstan-shim": "^0.11", - "phpunit/phpunit": "^7.0" + "phpbench/phpbench": "^0.13 || 1.0.0-alpha2", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, "autoload": { "psr-4": { "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" @@ -1400,7 +1527,7 @@ { "name": "Marco Pivetta", "email": "ocramius@gmail.com", - "homepage": "http://ocramius.github.com/" + "homepage": "https://ocramius.github.io/" } ], "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", @@ -1409,24 +1536,38 @@ "constructor", "instantiate" ], - "time": "2019-10-21T16:45:58+00:00" + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } + ], + "time": "2020-11-10T18:47:58+00:00" }, { "name": "doctrine/lexer", - "version": "1.2.0", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/doctrine/lexer.git", - "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6" + "reference": "e864bbf5904cb8f5bb334f99209b48018522f042" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6", - "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/e864bbf5904cb8f5bb334f99209b48018522f042", + "reference": "e864bbf5904cb8f5bb334f99209b48018522f042", "shasum": "" }, "require": { - "php": "^7.2" + "php": "^7.2 || ^8.0" }, "require-dev": { "doctrine/coding-standard": "^6.0", @@ -1471,20 +1612,34 @@ "parser", "php" ], - "time": "2019-10-30T14:39:59+00:00" + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", + "type": "tidelift" + } + ], + "time": "2020-05-25T17:44:05+00:00" }, { "name": "guzzlehttp/guzzle", - "version": "6.5.3", + "version": "6.5.5", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "aab4ebd862aa7d04f01a4b51849d657db56d882e" + "reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/aab4ebd862aa7d04f01a4b51849d657db56d882e", - "reference": "aab4ebd862aa7d04f01a4b51849d657db56d882e", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/9d4290de1cfd701f38099ef7e183b64b4b7b0c5e", + "reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e", "shasum": "" }, "require": { @@ -1492,7 +1647,7 @@ "guzzlehttp/promises": "^1.0", "guzzlehttp/psr7": "^1.6.1", "php": ">=5.5", - "symfony/polyfill-intl-idn": "^1.11" + "symfony/polyfill-intl-idn": "^1.17.0" }, "require-dev": { "ext-curl": "*", @@ -1538,27 +1693,27 @@ "rest", "web service" ], - "time": "2020-04-18T10:38:46+00:00" + "time": "2020-06-16T21:01:06+00:00" }, { "name": "guzzlehttp/promises", - "version": "v1.3.1", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" + "reference": "60d379c243457e073cff02bc323a2a86cb355631" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", - "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "url": "https://api.github.com/repos/guzzle/promises/zipball/60d379c243457e073cff02bc323a2a86cb355631", + "reference": "60d379c243457e073cff02bc323a2a86cb355631", "shasum": "" }, "require": { - "php": ">=5.5.0" + "php": ">=5.5" }, "require-dev": { - "phpunit/phpunit": "^4.0" + "symfony/phpunit-bridge": "^4.4 || ^5.1" }, "type": "library", "extra": { @@ -1589,20 +1744,20 @@ "keywords": [ "promise" ], - "time": "2016-12-20T10:07:11+00:00" + "time": "2020-09-30T07:37:28+00:00" }, { "name": "guzzlehttp/psr7", - "version": "1.6.1", + "version": "1.7.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "239400de7a173fe9901b9ac7c06497751f00727a" + "reference": "53330f47520498c0ae1f61f7e2c90f55690c06a3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/239400de7a173fe9901b9ac7c06497751f00727a", - "reference": "239400de7a173fe9901b9ac7c06497751f00727a", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/53330f47520498c0ae1f61f7e2c90f55690c06a3", + "reference": "53330f47520498c0ae1f61f7e2c90f55690c06a3", "shasum": "" }, "require": { @@ -1615,15 +1770,15 @@ }, "require-dev": { "ext-zlib": "*", - "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8" + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" }, "suggest": { - "zendframework/zend-httphandlerrunner": "Emit PSR-7 responses" + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.6-dev" + "dev-master": "1.7-dev" } }, "autoload": { @@ -1660,7 +1815,7 @@ "uri", "url" ], - "time": "2019-07-01T23:21:34+00:00" + "time": "2020-09-30T07:37:11+00:00" }, { "name": "hoa/consistency", @@ -2387,16 +2542,16 @@ }, { "name": "justinrainbow/json-schema", - "version": "5.2.9", + "version": "5.2.10", "source": { "type": "git", "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "44c6787311242a979fa15c704327c20e7221a0e4" + "reference": "2ba9c8c862ecd5510ed16c6340aa9f6eadb4f31b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/44c6787311242a979fa15c704327c20e7221a0e4", - "reference": "44c6787311242a979fa15c704327c20e7221a0e4", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/2ba9c8c862ecd5510ed16c6340aa9f6eadb4f31b", + "reference": "2ba9c8c862ecd5510ed16c6340aa9f6eadb4f31b", "shasum": "" }, "require": { @@ -2449,32 +2604,33 @@ "json", "schema" ], - "time": "2019-09-25T14:49:45+00:00" + "time": "2020-05-27T16:41:55+00:00" }, { "name": "league/flysystem", - "version": "1.0.67", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "5b1f36c75c4bdde981294c2a0ebdb437ee6f275e" + "reference": "9be3b16c877d477357c015cec057548cf9b2a14a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/5b1f36c75c4bdde981294c2a0ebdb437ee6f275e", - "reference": "5b1f36c75c4bdde981294c2a0ebdb437ee6f275e", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/9be3b16c877d477357c015cec057548cf9b2a14a", + "reference": "9be3b16c877d477357c015cec057548cf9b2a14a", "shasum": "" }, "require": { "ext-fileinfo": "*", - "php": ">=5.5.9" + "league/mime-type-detection": "^1.3", + "php": "^7.2.5 || ^8.0" }, "conflict": { "league/flysystem-sftp": "<1.0.6" }, "require-dev": { - "phpspec/phpspec": "^3.4", - "phpunit/phpunit": "^5.7.26" + "phpspec/prophecy": "^1.11.1", + "phpunit/phpunit": "^8.5.8" }, "suggest": { "ext-fileinfo": "Required for MimeType", @@ -2533,20 +2689,78 @@ "sftp", "storage" ], - "time": "2020-04-16T13:21:26+00:00" + "funding": [ + { + "url": "https://offset.earth/frankdejonge", + "type": "other" + } + ], + "time": "2020-08-23T07:39:11+00:00" + }, + { + "name": "league/mime-type-detection", + "version": "1.7.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/mime-type-detection.git", + "reference": "3b9dff8aaf7323590c1d2e443db701eb1f9aa0d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/3b9dff8aaf7323590c1d2e443db701eb1f9aa0d3", + "reference": "3b9dff8aaf7323590c1d2e443db701eb1f9aa0d3", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.18", + "phpstan/phpstan": "^0.12.68", + "phpunit/phpunit": "^8.5.8 || ^9.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\MimeTypeDetection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Mime-type detection for Flysystem", + "funding": [ + { + "url": "https://github.com/frankdejonge", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/flysystem", + "type": "tidelift" + } + ], + "time": "2021-01-18T20:58:21+00:00" }, { "name": "monolog/monolog", - "version": "1.25.3", + "version": "1.26.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "fa82921994db851a8becaf3787a9e73c5976b6f1" + "reference": "2209ddd84e7ef1256b7af205d0717fb62cfc9c33" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fa82921994db851a8becaf3787a9e73c5976b6f1", - "reference": "fa82921994db851a8becaf3787a9e73c5976b6f1", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/2209ddd84e7ef1256b7af205d0717fb62cfc9c33", + "reference": "2209ddd84e7ef1256b7af205d0717fb62cfc9c33", "shasum": "" }, "require": { @@ -2560,11 +2774,10 @@ "aws/aws-sdk-php": "^2.4.9 || ^3.0", "doctrine/couchdb": "~1.0@dev", "graylog2/gelf-php": "~1.0", - "jakub-onderka/php-parallel-lint": "0.9", "php-amqplib/php-amqplib": "~2.4", "php-console/php-console": "^3.1.3", + "phpstan/phpstan": "^0.12.59", "phpunit/phpunit": "~4.5", - "phpunit/phpunit-mock-objects": "2.3.0", "ruflin/elastica": ">=0.90 <3.0", "sentry/sentry": "^0.13", "swiftmailer/swiftmailer": "^5.3|^6.0" @@ -2583,11 +2796,6 @@ "sentry/sentry": "Allow sending log messages to a Sentry server" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, "autoload": { "psr-4": { "Monolog\\": "src/Monolog" @@ -2611,29 +2819,39 @@ "logging", "psr-3" ], - "time": "2019-12-20T14:15:16+00:00" + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2020-12-14T12:56:38+00:00" }, { "name": "mtdowling/jmespath.php", - "version": "2.5.0", + "version": "2.6.0", "source": { "type": "git", "url": "https://github.com/jmespath/jmespath.php.git", - "reference": "52168cb9472de06979613d365c7f1ab8798be895" + "reference": "42dae2cbd13154083ca6d70099692fef8ca84bfb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/52168cb9472de06979613d365c7f1ab8798be895", - "reference": "52168cb9472de06979613d365c7f1ab8798be895", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/42dae2cbd13154083ca6d70099692fef8ca84bfb", + "reference": "42dae2cbd13154083ca6d70099692fef8ca84bfb", "shasum": "" }, "require": { - "php": ">=5.4.0", - "symfony/polyfill-mbstring": "^1.4" + "php": "^5.4 || ^7.0 || ^8.0", + "symfony/polyfill-mbstring": "^1.17" }, "require-dev": { - "composer/xdebug-handler": "^1.2", - "phpunit/phpunit": "^4.8.36|^7.5.15" + "composer/xdebug-handler": "^1.4", + "phpunit/phpunit": "^4.8.36 || ^7.5.15" }, "bin": [ "bin/jp.php" @@ -2641,7 +2859,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.5-dev" + "dev-master": "2.6-dev" } }, "autoload": { @@ -2668,7 +2886,7 @@ "json", "jsonpath" ], - "time": "2019-12-30T18:03:34+00:00" + "time": "2020-07-31T21:01:56+00:00" }, { "name": "mustache/mustache", @@ -2718,20 +2936,20 @@ }, { "name": "myclabs/deep-copy", - "version": "1.9.5", + "version": "1.10.2", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef" + "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/b2c28789e80a97badd14145fda39b545d83ca3ef", - "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/776f831124e9c62e1a2c601ecc52e776d8bb7220", + "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220", "shasum": "" }, "require": { - "php": "^7.1" + "php": "^7.1 || ^8.0" }, "replace": { "myclabs/deep-copy": "self.version" @@ -2762,28 +2980,34 @@ "object", "object graph" ], - "time": "2020-01-17T21:11:47+00:00" + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2020-11-13T09:40:50+00:00" }, { "name": "paragonie/constant_time_encoding", - "version": "v2.3.0", + "version": "v2.4.0", "source": { "type": "git", "url": "https://github.com/paragonie/constant_time_encoding.git", - "reference": "47a1cedd2e4d52688eb8c96469c05ebc8fd28fa2" + "reference": "f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/47a1cedd2e4d52688eb8c96469c05ebc8fd28fa2", - "reference": "47a1cedd2e4d52688eb8c96469c05ebc8fd28fa2", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c", + "reference": "f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c", "shasum": "" }, "require": { "php": "^7|^8" }, "require-dev": { - "phpunit/phpunit": "^6|^7", - "vimeo/psalm": "^1|^2|^3" + "phpunit/phpunit": "^6|^7|^8|^9", + "vimeo/psalm": "^1|^2|^3|^4" }, "type": "library", "autoload": { @@ -2824,52 +3048,7 @@ "hex2bin", "rfc4648" ], - "time": "2019-11-06T19:20:29+00:00" - }, - { - "name": "paragonie/random_compat", - "version": "v9.99.99", - "source": { - "type": "git", - "url": "https://github.com/paragonie/random_compat.git", - "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", - "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", - "shasum": "" - }, - "require": { - "php": "^7" - }, - "require-dev": { - "phpunit/phpunit": "4.*|5.*", - "vimeo/psalm": "^1" - }, - "suggest": { - "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." - }, - "type": "library", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Paragon Initiative Enterprises", - "email": "security@paragonie.com", - "homepage": "https://paragonie.com" - } - ], - "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", - "keywords": [ - "csprng", - "polyfill", - "pseudorandom", - "random" - ], - "time": "2018-07-02T15:55:56+00:00" + "time": "2020-12-06T15:14:20+00:00" }, { "name": "phar-io/manifest", @@ -3088,28 +3267,25 @@ }, { "name": "phpdocumentor/reflection-common", - "version": "2.0.0", + "version": "2.2.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a" + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a", - "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", "shasum": "" }, "require": { - "php": ">=7.1" - }, - "require-dev": { - "phpunit/phpunit": "~6" + "php": "^7.2 || ^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.x-dev" + "dev-2.x": "2.x-dev" } }, "autoload": { @@ -3136,32 +3312,31 @@ "reflection", "static analysis" ], - "time": "2018-08-07T13:53:10+00:00" + "time": "2020-06-27T09:03:43+00:00" }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.1.0", + "version": "5.2.2", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e" + "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e", - "reference": "cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/069a785b2141f5bcf49f3e353548dc1cce6df556", + "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556", "shasum": "" }, "require": { - "ext-filter": "^7.1", - "php": "^7.2", - "phpdocumentor/reflection-common": "^2.0", - "phpdocumentor/type-resolver": "^1.0", - "webmozart/assert": "^1" + "ext-filter": "*", + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.2", + "phpdocumentor/type-resolver": "^1.3", + "webmozart/assert": "^1.9.1" }, "require-dev": { - "doctrine/instantiator": "^1", - "mockery/mockery": "^1" + "mockery/mockery": "~1.3.2" }, "type": "library", "extra": { @@ -3189,34 +3364,33 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2020-02-22T12:28:44+00:00" + "time": "2020-09-03T19:13:55+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "1.1.0", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "7462d5f123dfc080dfdf26897032a6513644fc95" + "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/7462d5f123dfc080dfdf26897032a6513644fc95", - "reference": "7462d5f123dfc080dfdf26897032a6513644fc95", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", + "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", "shasum": "" }, "require": { - "php": "^7.2", + "php": "^7.2 || ^8.0", "phpdocumentor/reflection-common": "^2.0" }, "require-dev": { - "ext-tokenizer": "^7.2", - "mockery/mockery": "~1" + "ext-tokenizer": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-1.x": "1.x-dev" } }, "autoload": { @@ -3235,28 +3409,28 @@ } ], "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "time": "2020-02-18T18:59:58+00:00" + "time": "2020-09-17T18:55:26+00:00" }, { "name": "phpoption/phpoption", - "version": "1.7.3", + "version": "1.7.5", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "4acfd6a4b33a509d8c88f50e5222f734b6aeebae" + "reference": "994ecccd8f3283ecf5ac33254543eb0ac946d525" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/4acfd6a4b33a509d8c88f50e5222f734b6aeebae", - "reference": "4acfd6a4b33a509d8c88f50e5222f734b6aeebae", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/994ecccd8f3283ecf5ac33254543eb0ac946d525", + "reference": "994ecccd8f3283ecf5ac33254543eb0ac946d525", "shasum": "" }, "require": { "php": "^5.5.9 || ^7.0 || ^8.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.3", - "phpunit/phpunit": "^4.8.35 || ^5.0 || ^6.0 || ^7.0" + "bamarni/composer-bin-plugin": "^1.4.1", + "phpunit/phpunit": "^4.8.35 || ^5.7.27 || ^6.5.6 || ^7.0 || ^8.0 || ^9.0" }, "type": "library", "extra": { @@ -3290,37 +3464,47 @@ "php", "type" ], - "time": "2020-03-21T18:07:53+00:00" + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", + "type": "tidelift" + } + ], + "time": "2020-07-20T17:29:33+00:00" }, { "name": "phpspec/prophecy", - "version": "v1.10.3", + "version": "1.12.2", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "451c3cd1418cf640de218914901e51b064abb093" + "reference": "245710e971a030f42e08f4912863805570f23d39" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/451c3cd1418cf640de218914901e51b064abb093", - "reference": "451c3cd1418cf640de218914901e51b064abb093", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/245710e971a030f42e08f4912863805570f23d39", + "reference": "245710e971a030f42e08f4912863805570f23d39", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.0.2", - "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", - "sebastian/comparator": "^1.2.3|^2.0|^3.0|^4.0", - "sebastian/recursion-context": "^1.0|^2.0|^3.0|^4.0" + "doctrine/instantiator": "^1.2", + "php": "^7.2 || ~8.0, <8.1", + "phpdocumentor/reflection-docblock": "^5.2", + "sebastian/comparator": "^3.0 || ^4.0", + "sebastian/recursion-context": "^3.0 || ^4.0" }, "require-dev": { - "phpspec/phpspec": "^2.5 || ^3.2", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" + "phpspec/phpspec": "^6.0", + "phpunit/phpunit": "^8.0 || ^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.10.x-dev" + "dev-master": "1.11.x-dev" } }, "autoload": { @@ -3353,20 +3537,20 @@ "spy", "stub" ], - "time": "2020-03-05T15:02:03+00:00" + "time": "2020-12-19T10:15:11+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "8.0.1", + "version": "8.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "31e94ccc084025d6abee0585df533eb3a792b96a" + "reference": "ca6647ffddd2add025ab3f21644a441d7c146cdc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/31e94ccc084025d6abee0585df533eb3a792b96a", - "reference": "31e94ccc084025d6abee0585df533eb3a792b96a", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca6647ffddd2add025ab3f21644a441d7c146cdc", + "reference": "ca6647ffddd2add025ab3f21644a441d7c146cdc", "shasum": "" }, "require": { @@ -3417,27 +3601,33 @@ "testing", "xunit" ], - "time": "2020-02-19T13:41:19+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-05-23T08:02:54+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "3.0.1", + "version": "3.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "4ac5b3e13df14829daa60a2eb4fdd2f2b7d33cf4" + "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/4ac5b3e13df14829daa60a2eb4fdd2f2b7d33cf4", - "reference": "4ac5b3e13df14829daa60a2eb4fdd2f2b7d33cf4", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/aa4be8575f26070b100fccb67faabb28f21f66f8", + "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8", "shasum": "" }, "require": { - "php": "^7.3" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { @@ -3467,28 +3657,34 @@ "filesystem", "iterator" ], - "time": "2020-04-18T05:02:12+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:57:25+00:00" }, { "name": "phpunit/php-invoker", - "version": "3.0.0", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "7579d5a1ba7f3ac11c80004d205877911315ae7a" + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/7579d5a1ba7f3ac11c80004d205877911315ae7a", - "reference": "7579d5a1ba7f3ac11c80004d205877911315ae7a", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", "shasum": "" }, "require": { - "php": "^7.3" + "php": ">=7.3" }, "require-dev": { "ext-pcntl": "*", - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" }, "suggest": { "ext-pcntl": "*" @@ -3496,7 +3692,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.1-dev" } }, "autoload": { @@ -3520,24 +3716,33 @@ "keywords": [ "process" ], - "time": "2020-02-07T06:06:11+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:58:55+00:00" }, { "name": "phpunit/php-text-template", - "version": "2.0.0", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "526dc996cc0ebdfa428cd2dfccd79b7b53fee346" + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/526dc996cc0ebdfa428cd2dfccd79b7b53fee346", - "reference": "526dc996cc0ebdfa428cd2dfccd79b7b53fee346", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", "shasum": "" }, "require": { - "php": "^7.3" + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { @@ -3566,32 +3771,38 @@ "keywords": [ "template" ], - "time": "2020-02-01T07:43:44+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T05:33:50+00:00" }, { "name": "phpunit/php-timer", - "version": "3.1.4", + "version": "5.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "dc9368fae6ef2ffa57eba80a7410bcef81df6258" + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/dc9368fae6ef2ffa57eba80a7410bcef81df6258", - "reference": "dc9368fae6ef2ffa57eba80a7410bcef81df6258", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", "shasum": "" }, "require": { - "php": "^7.3" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -3615,25 +3826,31 @@ "keywords": [ "timer" ], - "time": "2020-04-20T06:00:37+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:16:10+00:00" }, { "name": "phpunit/php-token-stream", - "version": "4.0.0", + "version": "4.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "b2560a0c33f7710e4d7f8780964193e8e8f8effe" + "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/b2560a0c33f7710e4d7f8780964193e8e8f8effe", - "reference": "b2560a0c33f7710e4d7f8780964193e8e8f8effe", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/a853a0e183b9db7eed023d7933a858fa1c8d25a3", + "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3", "shasum": "" }, "require": { "ext-tokenizer": "*", - "php": "^7.3" + "php": "^7.3 || ^8.0" }, "require-dev": { "phpunit/phpunit": "^9.0" @@ -3664,51 +3881,57 @@ "keywords": [ "tokenizer" ], + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "abandoned": true, - "time": "2020-02-07T06:19:00+00:00" + "time": "2020-08-04T08:28:15+00:00" }, { "name": "phpunit/phpunit", - "version": "9.1.3", + "version": "9.2.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "a74780472172957a65cb5999a597e8c0878cf39c" + "reference": "1c6a9e4312e209e659f1fce3ce88dd197c2448f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a74780472172957a65cb5999a597e8c0878cf39c", - "reference": "a74780472172957a65cb5999a597e8c0878cf39c", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1c6a9e4312e209e659f1fce3ce88dd197c2448f6", + "reference": "1c6a9e4312e209e659f1fce3ce88dd197c2448f6", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.2.0", + "doctrine/instantiator": "^1.3.1", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.9.1", + "myclabs/deep-copy": "^1.9.5", "phar-io/manifest": "^1.0.3", "phar-io/version": "^2.0.1", "php": "^7.3", - "phpspec/prophecy": "^1.8.1", - "phpunit/php-code-coverage": "^8.0.1", - "phpunit/php-file-iterator": "^3.0", - "phpunit/php-invoker": "^3.0", - "phpunit/php-text-template": "^2.0", - "phpunit/php-timer": "^3.1.4", - "sebastian/code-unit": "^1.0", - "sebastian/comparator": "^4.0", - "sebastian/diff": "^4.0", - "sebastian/environment": "^5.0.1", - "sebastian/exporter": "^4.0", + "phpspec/prophecy": "^1.10.3", + "phpunit/php-code-coverage": "^8.0.2", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-invoker": "^3.0.2", + "phpunit/php-text-template": "^2.0.2", + "phpunit/php-timer": "^5.0.1", + "sebastian/code-unit": "^1.0.5", + "sebastian/comparator": "^4.0.3", + "sebastian/diff": "^4.0.1", + "sebastian/environment": "^5.1.2", + "sebastian/exporter": "^4.0.2", "sebastian/global-state": "^4.0", - "sebastian/object-enumerator": "^4.0", - "sebastian/resource-operations": "^3.0", - "sebastian/type": "^2.0", - "sebastian/version": "^3.0" + "sebastian/object-enumerator": "^4.0.2", + "sebastian/resource-operations": "^3.0.2", + "sebastian/type": "^2.1.1", + "sebastian/version": "^3.0.1" }, "require-dev": { "ext-pdo": "*", @@ -3724,7 +3947,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.1-dev" + "dev-master": "9.2-dev" } }, "autoload": { @@ -3753,7 +3976,17 @@ "testing", "xunit" ], - "time": "2020-04-23T04:42:05+00:00" + "funding": [ + { + "url": "https://phpunit.de/donate.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-07-13T17:55:55+00:00" }, { "name": "psr/cache", @@ -4035,55 +4268,137 @@ "description": "A polyfill for getallheaders.", "time": "2019-03-08T08:55:37+00:00" }, + { + "name": "ramsey/collection", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/ramsey/collection.git", + "reference": "28a5c4ab2f5111db6a60b2b4ec84057e0f43b9c1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/collection/zipball/28a5c4ab2f5111db6a60b2b4ec84057e0f43b9c1", + "reference": "28a5c4ab2f5111db6a60b2b4ec84057e0f43b9c1", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8" + }, + "require-dev": { + "captainhook/captainhook": "^5.3", + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", + "ergebnis/composer-normalize": "^2.6", + "fakerphp/faker": "^1.5", + "hamcrest/hamcrest-php": "^2", + "jangregor/phpstan-prophecy": "^0.8", + "mockery/mockery": "^1.3", + "phpstan/extension-installer": "^1", + "phpstan/phpstan": "^0.12.32", + "phpstan/phpstan-mockery": "^0.12.5", + "phpstan/phpstan-phpunit": "^0.12.11", + "phpunit/phpunit": "^8.5 || ^9", + "psy/psysh": "^0.10.4", + "slevomat/coding-standard": "^6.3", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^4.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Ramsey\\Collection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + } + ], + "description": "A PHP 7.2+ library for representing and manipulating collections.", + "keywords": [ + "array", + "collection", + "hash", + "map", + "queue", + "set" + ], + "funding": [ + { + "url": "https://github.com/ramsey", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/ramsey/collection", + "type": "tidelift" + } + ], + "time": "2021-01-21T17:40:04+00:00" + }, { "name": "ramsey/uuid", - "version": "3.9.3", + "version": "4.1.1", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "7e1633a6964b48589b142d60542f9ed31bd37a92" + "reference": "cd4032040a750077205918c86049aa0f43d22947" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/7e1633a6964b48589b142d60542f9ed31bd37a92", - "reference": "7e1633a6964b48589b142d60542f9ed31bd37a92", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/cd4032040a750077205918c86049aa0f43d22947", + "reference": "cd4032040a750077205918c86049aa0f43d22947", "shasum": "" }, "require": { + "brick/math": "^0.8 || ^0.9", "ext-json": "*", - "paragonie/random_compat": "^1 | ^2 | 9.99.99", - "php": "^5.4 | ^7 | ^8", + "php": "^7.2 || ^8", + "ramsey/collection": "^1.0", "symfony/polyfill-ctype": "^1.8" }, "replace": { "rhumsaa/uuid": "self.version" }, "require-dev": { - "codeception/aspect-mock": "^1 | ^2", - "doctrine/annotations": "^1.2", - "goaop/framework": "1.0.0-alpha.2 | ^1 | ^2.1", - "jakub-onderka/php-parallel-lint": "^1", - "mockery/mockery": "^0.9.11 | ^1", + "codeception/aspect-mock": "^3", + "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7.0", + "doctrine/annotations": "^1.8", + "goaop/framework": "^2", + "mockery/mockery": "^1.3", "moontoast/math": "^1.1", "paragonie/random-lib": "^2", - "php-mock/php-mock-phpunit": "^0.3 | ^1.1", - "phpunit/phpunit": "^4.8 | ^5.4 | ^6.5", - "squizlabs/php_codesniffer": "^3.5" + "php-mock/php-mock-mockery": "^1.3", + "php-mock/php-mock-phpunit": "^2.5", + "php-parallel-lint/php-parallel-lint": "^1.1", + "phpbench/phpbench": "^0.17.1", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-mockery": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpunit/phpunit": "^8.5", + "psy/psysh": "^0.10.0", + "slevomat/coding-standard": "^6.0", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "3.9.4" }, "suggest": { - "ext-ctype": "Provides support for PHP Ctype functions", - "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator", - "ext-openssl": "Provides the OpenSSL extension for use with the OpenSslGenerator", - "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator", - "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).", + "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", + "ext-ctype": "Enables faster processing of character classification using ctype functions.", + "ext-gmp": "Enables faster math with arbitrary-precision integers using GMP.", + "ext-uuid": "Enables the use of PeclUuidTimeGenerator and PeclUuidRandomGenerator.", "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter", - "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid", "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.x-dev" + "dev-master": "4.x-dev" } }, "autoload": { @@ -4098,49 +4413,40 @@ "license": [ "MIT" ], - "authors": [ - { - "name": "Ben Ramsey", - "email": "ben@benramsey.com", - "homepage": "https://benramsey.com" - }, - { - "name": "Marijn Huizendveld", - "email": "marijn.huizendveld@gmail.com" - }, - { - "name": "Thibaud Fabre", - "email": "thibaud@aztech.io" - } - ], - "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).", + "description": "A PHP library for generating and working with universally unique identifiers (UUIDs).", "homepage": "https://github.com/ramsey/uuid", "keywords": [ "guid", "identifier", "uuid" ], - "time": "2020-02-21T04:36:14+00:00" + "funding": [ + { + "url": "https://github.com/ramsey", + "type": "github" + } + ], + "time": "2020-08-18T17:17:46+00:00" }, { "name": "sebastian/code-unit", - "version": "1.0.0", + "version": "1.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "8d8f09bd47c75159921e6e84fdef146343962866" + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/8d8f09bd47c75159921e6e84fdef146343962866", - "reference": "8d8f09bd47c75159921e6e84fdef146343962866", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", "shasum": "" }, "require": { - "php": "^7.3" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { @@ -4166,27 +4472,33 @@ ], "description": "Collection of value objects that represent the PHP code units", "homepage": "https://github.com/sebastianbergmann/code-unit", - "time": "2020-03-30T11:59:20+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:08:54+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", - "version": "2.0.0", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "5b5dbe0044085ac41df47e79d34911a15b96d82e" + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5b5dbe0044085ac41df47e79d34911a15b96d82e", - "reference": "5b5dbe0044085ac41df47e79d34911a15b96d82e", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", "shasum": "" }, "require": { - "php": "^7.3" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { @@ -4211,29 +4523,35 @@ ], "description": "Looks up which function or method a line of code belongs to", "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "time": "2020-02-07T06:20:13+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:30:19+00:00" }, { "name": "sebastian/comparator", - "version": "4.0.0", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "85b3435da967696ed618ff745f32be3ff4a2b8e8" + "reference": "55f4261989e546dc112258c7a75935a81a7ce382" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/85b3435da967696ed618ff745f32be3ff4a2b8e8", - "reference": "85b3435da967696ed618ff745f32be3ff4a2b8e8", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55f4261989e546dc112258c7a75935a81a7ce382", + "reference": "55f4261989e546dc112258c7a75935a81a7ce382", "shasum": "" }, "require": { - "php": "^7.3", + "php": ">=7.3", "sebastian/diff": "^4.0", "sebastian/exporter": "^4.0" }, "require-dev": { - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { @@ -4275,28 +4593,34 @@ "compare", "equality" ], - "time": "2020-02-07T06:08:51+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T15:49:45+00:00" }, { "name": "sebastian/diff", - "version": "4.0.0", + "version": "4.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "c0c26c9188b538bfa985ae10c9f05d278f12060d" + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c0c26c9188b538bfa985ae10c9f05d278f12060d", - "reference": "c0c26c9188b538bfa985ae10c9f05d278f12060d", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", "shasum": "" }, "require": { - "php": "^7.3" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^9.0", - "symfony/process": "^4 || ^5" + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" }, "type": "library", "extra": { @@ -4331,27 +4655,33 @@ "unidiff", "unified diff" ], - "time": "2020-02-07T06:09:38+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:10:38+00:00" }, { "name": "sebastian/environment", - "version": "5.1.0", + "version": "5.1.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "c753f04d68cd489b6973cf9b4e505e191af3b05c" + "reference": "388b6ced16caa751030f6a69e588299fa09200ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/c753f04d68cd489b6973cf9b4e505e191af3b05c", - "reference": "c753f04d68cd489b6973cf9b4e505e191af3b05c", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/388b6ced16caa751030f6a69e588299fa09200ac", + "reference": "388b6ced16caa751030f6a69e588299fa09200ac", "shasum": "" }, "require": { - "php": "^7.3" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" }, "suggest": { "ext-posix": "*" @@ -4359,7 +4689,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "5.1-dev" } }, "autoload": { @@ -4384,29 +4714,35 @@ "environment", "hhvm" ], - "time": "2020-04-14T13:36:52+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:52:38+00:00" }, { "name": "sebastian/exporter", - "version": "4.0.0", + "version": "4.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "80c26562e964016538f832f305b2286e1ec29566" + "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/80c26562e964016538f832f305b2286e1ec29566", - "reference": "80c26562e964016538f832f305b2286e1ec29566", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/d89cc98761b8cb5a1a235a6b703ae50d34080e65", + "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65", "shasum": "" }, "require": { - "php": "^7.3", + "php": ">=7.3", "sebastian/recursion-context": "^4.0" }, "require-dev": { "ext-mbstring": "*", - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { @@ -4451,7 +4787,13 @@ "export", "exporter" ], - "time": "2020-02-07T06:10:52+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:24:23+00:00" }, { "name": "sebastian/global-state", @@ -4509,25 +4851,25 @@ }, { "name": "sebastian/object-enumerator", - "version": "4.0.0", + "version": "4.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "e67516b175550abad905dc952f43285957ef4363" + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/e67516b175550abad905dc952f43285957ef4363", - "reference": "e67516b175550abad905dc952f43285957ef4363", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", "shasum": "" }, "require": { - "php": "^7.3", + "php": ">=7.3", "sebastian/object-reflector": "^2.0", "sebastian/recursion-context": "^4.0" }, "require-dev": { - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { @@ -4552,27 +4894,33 @@ ], "description": "Traverses array structures and object graphs to enumerate all referenced objects", "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2020-02-07T06:12:23+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:12:34+00:00" }, { "name": "sebastian/object-reflector", - "version": "2.0.0", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "f4fd0835cabb0d4a6546d9fe291e5740037aa1e7" + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/f4fd0835cabb0d4a6546d9fe291e5740037aa1e7", - "reference": "f4fd0835cabb0d4a6546d9fe291e5740037aa1e7", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", "shasum": "" }, "require": { - "php": "^7.3" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { @@ -4597,27 +4945,33 @@ ], "description": "Allows reflection of object attributes, including inherited and non-public ones", "homepage": "https://github.com/sebastianbergmann/object-reflector/", - "time": "2020-02-07T06:19:40+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:14:26+00:00" }, { "name": "sebastian/recursion-context", - "version": "4.0.0", + "version": "4.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "cdd86616411fc3062368b720b0425de10bd3d579" + "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/cdd86616411fc3062368b720b0425de10bd3d579", - "reference": "cdd86616411fc3062368b720b0425de10bd3d579", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/cd9d8cf3c5804de4341c283ed787f099f5506172", + "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172", "shasum": "" }, "require": { - "php": "^7.3" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { @@ -4650,24 +5004,30 @@ ], "description": "Provides functionality to recursively process PHP variables", "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2020-02-07T06:18:20+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:17:30+00:00" }, { "name": "sebastian/resource-operations", - "version": "3.0.0", + "version": "3.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "8c98bf0dfa1f9256d0468b9803a1e1df31b6fa98" + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/8c98bf0dfa1f9256d0468b9803a1e1df31b6fa98", - "reference": "8c98bf0dfa1f9256d0468b9803a1e1df31b6fa98", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", "shasum": "" }, "require": { - "php": "^7.3" + "php": ">=7.3" }, "require-dev": { "phpunit/phpunit": "^9.0" @@ -4695,32 +5055,38 @@ ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2020-02-07T06:13:02+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:45:17+00:00" }, { "name": "sebastian/type", - "version": "2.0.0", + "version": "2.3.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "9e8f42f740afdea51f5f4e8cec2035580e797ee1" + "reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/9e8f42f740afdea51f5f4e8cec2035580e797ee1", - "reference": "9e8f42f740afdea51f5f4e8cec2035580e797ee1", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/81cd61ab7bbf2de744aba0ea61fae32f721df3d2", + "reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2", "shasum": "" }, "require": { - "php": "^7.3" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "2.3-dev" } }, "autoload": { @@ -4741,24 +5107,30 @@ ], "description": "Collection of value objects that represent the types of the PHP type system", "homepage": "https://github.com/sebastianbergmann/type", - "time": "2020-02-07T06:13:43+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:18:59+00:00" }, { "name": "sebastian/version", - "version": "3.0.0", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", - "reference": "0411bde656dce64202b39c2f4473993a9081d39e" + "reference": "c6c1022351a901512170118436c764e473f6de8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/0411bde656dce64202b39c2f4473993a9081d39e", - "reference": "0411bde656dce64202b39c2f4473993a9081d39e", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", "shasum": "" }, "require": { - "php": "^7.3" + "php": ">=7.3" }, "type": "library", "extra": { @@ -4784,24 +5156,30 @@ ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", - "time": "2020-01-21T06:36:37+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:39:44+00:00" }, { "name": "seld/jsonlint", - "version": "1.7.2", + "version": "1.8.3", "source": { "type": "git", "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "e2e5d290e4d2a4f0eb449f510071392e00e10d19" + "reference": "9ad6ce79c342fbd44df10ea95511a1b24dee5b57" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/e2e5d290e4d2a4f0eb449f510071392e00e10d19", - "reference": "e2e5d290e4d2a4f0eb449f510071392e00e10d19", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/9ad6ce79c342fbd44df10ea95511a1b24dee5b57", + "reference": "9ad6ce79c342fbd44df10ea95511a1b24dee5b57", "shasum": "" }, "require": { - "php": "^5.3 || ^7.0" + "php": "^5.3 || ^7.0 || ^8.0" }, "require-dev": { "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" @@ -4833,20 +5211,30 @@ "parser", "validator" ], - "time": "2019-10-24T14:27:39+00:00" + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/seld/jsonlint", + "type": "tidelift" + } + ], + "time": "2020-11-11T09:19:24+00:00" }, { "name": "seld/phar-utils", - "version": "1.1.0", + "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/Seldaek/phar-utils.git", - "reference": "8800503d56b9867d43d9c303b9cbcc26016e82f0" + "reference": "8674b1d84ffb47cc59a101f5d5a3b61e87d23796" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/8800503d56b9867d43d9c303b9cbcc26016e82f0", - "reference": "8800503d56b9867d43d9c303b9cbcc26016e82f0", + "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/8674b1d84ffb47cc59a101f5d5a3b61e87d23796", + "reference": "8674b1d84ffb47cc59a101f5d5a3b61e87d23796", "shasum": "" }, "require": { @@ -4877,7 +5265,7 @@ "keywords": [ "phar" ], - "time": "2020-02-14T15:25:33+00:00" + "time": "2020-07-07T18:42:57+00:00" }, { "name": "spomky-labs/otphp", @@ -4952,22 +5340,23 @@ }, { "name": "symfony/console", - "version": "v4.4.7", + "version": "v4.4.18", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "10bb3ee3c97308869d53b3e3d03f6ac23ff985f7" + "reference": "12e071278e396cc3e1c149857337e9e192deca0b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/10bb3ee3c97308869d53b3e3d03f6ac23ff985f7", - "reference": "10bb3ee3c97308869d53b3e3d03f6ac23ff985f7", + "url": "https://api.github.com/repos/symfony/console/zipball/12e071278e396cc3e1c149857337e9e192deca0b", + "reference": "12e071278e396cc3e1c149857337e9e192deca0b", "shasum": "" }, "require": { - "php": "^7.1.3", + "php": ">=7.1.3", "symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-php73": "^1.8", + "symfony/polyfill-php80": "^1.15", "symfony/service-contracts": "^1.1|^2" }, "conflict": { @@ -4995,11 +5384,6 @@ "symfony/process": "" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Console\\": "" @@ -5024,31 +5408,40 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2020-03-30T11:41:10+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-12-18T07:41:31+00:00" }, { "name": "symfony/css-selector", - "version": "v5.0.7", + "version": "v5.2.1", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "5f8d5271303dad260692ba73dfa21777d38e124e" + "reference": "f789e7ead4c79e04ca9a6d6162fc629c89bd8054" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/5f8d5271303dad260692ba73dfa21777d38e124e", - "reference": "5f8d5271303dad260692ba73dfa21777d38e124e", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/f789e7ead4c79e04ca9a6d6162fc629c89bd8054", + "reference": "f789e7ead4c79e04ca9a6d6162fc629c89bd8054", "shasum": "" }, "require": { - "php": "^7.2.5" + "php": ">=7.2.5" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\CssSelector\\": "" @@ -5077,20 +5470,34 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "time": "2020-03-27T16:56:45+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-12-08T17:02:38+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v2.1.3", + "version": "v2.2.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "5e20b83385a77593259c9f8beb2c43cd03b2ac14" + "reference": "5fa56b4074d1ae755beb55617ddafe6f5d78f665" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5e20b83385a77593259c9f8beb2c43cd03b2ac14", - "reference": "5e20b83385a77593259c9f8beb2c43cd03b2ac14", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5fa56b4074d1ae755beb55617ddafe6f5d78f665", + "reference": "5fa56b4074d1ae755beb55617ddafe6f5d78f665", "shasum": "" }, "require": { @@ -5099,7 +5506,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1-dev" + "dev-master": "2.2-dev" }, "thanks": { "name": "symfony/contracts", @@ -5127,24 +5534,38 @@ ], "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", - "time": "2020-06-06T08:49:21+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-09-07T11:33:47+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v4.4.7", + "version": "v4.4.18", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "abc8e3618bfdb55e44c8c6a00abd333f831bbfed" + "reference": "5d4c874b0eb1c32d40328a09dbc37307a5a910b0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/abc8e3618bfdb55e44c8c6a00abd333f831bbfed", - "reference": "abc8e3618bfdb55e44c8c6a00abd333f831bbfed", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/5d4c874b0eb1c32d40328a09dbc37307a5a910b0", + "reference": "5d4c874b0eb1c32d40328a09dbc37307a5a910b0", "shasum": "" }, "require": { - "php": "^7.1.3", + "php": ">=7.1.3", "symfony/event-dispatcher-contracts": "^1.1" }, "conflict": { @@ -5158,6 +5579,7 @@ "psr/log": "~1.0", "symfony/config": "^3.4|^4.0|^5.0", "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/error-handler": "~3.4|~4.4", "symfony/expression-language": "^3.4|^4.0|^5.0", "symfony/http-foundation": "^3.4|^4.0|^5.0", "symfony/service-contracts": "^1.1|^2", @@ -5168,11 +5590,6 @@ "symfony/http-kernel": "" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\EventDispatcher\\": "" @@ -5197,24 +5614,38 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2020-03-27T16:54:36+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-12-18T07:41:31+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v1.1.7", + "version": "v1.1.9", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "c43ab685673fb6c8d84220c77897b1d6cdbe1d18" + "reference": "84e23fdcd2517bf37aecbd16967e83f0caee25a7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/c43ab685673fb6c8d84220c77897b1d6cdbe1d18", - "reference": "c43ab685673fb6c8d84220c77897b1d6cdbe1d18", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/84e23fdcd2517bf37aecbd16967e83f0caee25a7", + "reference": "84e23fdcd2517bf37aecbd16967e83f0caee25a7", "shasum": "" }, "require": { - "php": "^7.1.3" + "php": ">=7.1.3" }, "suggest": { "psr/event-dispatcher": "", @@ -5224,6 +5655,10 @@ "extra": { "branch-alias": { "dev-master": "1.1-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -5255,32 +5690,41 @@ "interoperability", "standards" ], - "time": "2019-09-17T09:54:03+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-07-06T13:19:58+00:00" }, { "name": "symfony/filesystem", - "version": "v5.0.7", + "version": "v5.2.1", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "ca3b87dd09fff9b771731637f5379965fbfab420" + "reference": "fa8f8cab6b65e2d99a118e082935344c5ba8c60d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/ca3b87dd09fff9b771731637f5379965fbfab420", - "reference": "ca3b87dd09fff9b771731637f5379965fbfab420", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/fa8f8cab6b65e2d99a118e082935344c5ba8c60d", + "reference": "fa8f8cab6b65e2d99a118e082935344c5ba8c60d", "shasum": "" }, "require": { - "php": "^7.2.5", + "php": ">=7.2.5", "symfony/polyfill-ctype": "~1.8" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Filesystem\\": "" @@ -5305,31 +5749,40 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2020-03-27T16:56:45+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-11-30T17:05:38+00:00" }, { "name": "symfony/finder", - "version": "v5.0.7", + "version": "v5.2.1", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "600a52c29afc0d1caa74acbec8d3095ca7e9910d" + "reference": "0b9231a5922fd7287ba5b411893c0ecd2733e5ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/600a52c29afc0d1caa74acbec8d3095ca7e9910d", - "reference": "600a52c29afc0d1caa74acbec8d3095ca7e9910d", + "url": "https://api.github.com/repos/symfony/finder/zipball/0b9231a5922fd7287ba5b411893c0ecd2733e5ba", + "reference": "0b9231a5922fd7287ba5b411893c0ecd2733e5ba", "shasum": "" }, "require": { - "php": "^7.2.5" + "php": ">=7.2.5" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Finder\\": "" @@ -5354,20 +5807,34 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2020-03-27T16:56:45+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-12-08T17:02:38+00:00" }, { "name": "symfony/http-foundation", - "version": "v5.1.2", + "version": "v5.2.1", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "f93055171b847915225bd5b0a5792888419d8d75" + "reference": "a1f6218b29897ab52acba58cfa905b83625bef8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/f93055171b847915225bd5b0a5792888419d8d75", - "reference": "f93055171b847915225bd5b0a5792888419d8d75", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/a1f6218b29897ab52acba58cfa905b83625bef8d", + "reference": "a1f6218b29897ab52acba58cfa905b83625bef8d", "shasum": "" }, "require": { @@ -5386,11 +5853,6 @@ "symfony/mime": "To use the file extension guesser" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.1-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\HttpFoundation\\": "" @@ -5415,40 +5877,55 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2020-06-15T06:52:54+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-12-18T10:00:10+00:00" }, { "name": "symfony/mime", - "version": "v5.0.7", + "version": "v5.2.1", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "481b7d6da88922fb1e0d86a943987722b08f3955" + "reference": "de97005aef7426ba008c46ba840fc301df577ada" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/481b7d6da88922fb1e0d86a943987722b08f3955", - "reference": "481b7d6da88922fb1e0d86a943987722b08f3955", + "url": "https://api.github.com/repos/symfony/mime/zipball/de97005aef7426ba008c46ba840fc301df577ada", + "reference": "de97005aef7426ba008c46ba840fc301df577ada", "shasum": "" }, "require": { - "php": "^7.2.5", + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", "symfony/polyfill-intl-idn": "^1.10", - "symfony/polyfill-mbstring": "^1.0" + "symfony/polyfill-mbstring": "^1.0", + "symfony/polyfill-php80": "^1.15" }, "conflict": { "symfony/mailer": "<4.4" }, "require-dev": { "egulias/email-validator": "^2.1.10", - "symfony/dependency-injection": "^4.4|^5.0" + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/property-access": "^4.4|^5.1", + "symfony/property-info": "^4.4|^5.1", + "symfony/serializer": "^5.2" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Mime\\": "" @@ -5477,37 +5954,133 @@ "mime", "mime-type" ], - "time": "2020-03-27T16:56:45+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-12-09T18:54:12+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.22.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "c6c942b1ac76c82448322025e084cadc56048b4e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/c6c942b1ac76c82448322025e084cadc56048b4e", + "reference": "c6c942b1ac76c82448322025e084cadc56048b4e", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-01-07T16:49:33+00:00" }, { - "name": "symfony/polyfill-ctype", - "version": "v1.15.0", + "name": "symfony/polyfill-intl-idn", + "version": "v1.22.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "4719fa9c18b0464d399f1a63bf624b42b6fa8d14" + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "0eb8293dbbcd6ef6bf81404c9ce7d95bcdf34f44" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/4719fa9c18b0464d399f1a63bf624b42b6fa8d14", - "reference": "4719fa9c18b0464d399f1a63bf624b42b6fa8d14", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/0eb8293dbbcd6ef6bf81404c9ce7d95bcdf34f44", + "reference": "0eb8293dbbcd6ef6bf81404c9ce7d95bcdf34f44", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.1", + "symfony/polyfill-intl-normalizer": "^1.10", + "symfony/polyfill-php72": "^1.10" }, "suggest": { - "ext-ctype": "For best performance" + "ext-intl": "For best performance" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.15-dev" + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" + "Symfony\\Polyfill\\Intl\\Idn\\": "" }, "files": [ "bootstrap.php" @@ -5519,42 +6092,60 @@ ], "authors": [ { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for ctype functions", + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", "homepage": "https://symfony.com", "keywords": [ "compatibility", - "ctype", + "idn", + "intl", "polyfill", - "portable" + "portable", + "shim" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } ], - "time": "2020-02-27T09:26:54+00:00" + "time": "2021-01-07T16:49:33+00:00" }, { - "name": "symfony/polyfill-intl-idn", - "version": "v1.15.0", + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.22.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf" + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "6e971c891537eb617a00bb07a43d182a6915faba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf", - "reference": "47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/6e971c891537eb617a00bb07a43d182a6915faba", + "reference": "6e971c891537eb617a00bb07a43d182a6915faba", "shasum": "" }, "require": { - "php": ">=5.3.3", - "symfony/polyfill-mbstring": "^1.3", - "symfony/polyfill-php72": "^1.10" + "php": ">=7.1" }, "suggest": { "ext-intl": "For best performance" @@ -5562,15 +6153,22 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.15-dev" + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { "psr-4": { - "Symfony\\Polyfill\\Intl\\Idn\\": "" + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" }, "files": [ "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" ] }, "notification-url": "https://packagist.org/downloads/", @@ -5579,42 +6177,56 @@ ], "authors": [ { - "name": "Laurent Bassin", - "email": "laurent@bassin.info" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "description": "Symfony polyfill for intl's Normalizer class and related functions", "homepage": "https://symfony.com", "keywords": [ "compatibility", - "idn", "intl", + "normalizer", "polyfill", "portable", "shim" ], - "time": "2020-03-09T19:04:49+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-01-07T17:09:11+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.15.0", + "version": "v1.22.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac" + "reference": "f377a3dd1fde44d37b9831d68dc8dea3ffd28e13" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/81ffd3a9c6d707be22e3012b827de1c9775fc5ac", - "reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/f377a3dd1fde44d37b9831d68dc8dea3ffd28e13", + "reference": "f377a3dd1fde44d37b9831d68dc8dea3ffd28e13", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.1" }, "suggest": { "ext-mbstring": "For best performance" @@ -5622,7 +6234,11 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.15-dev" + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { @@ -5656,29 +6272,47 @@ "portable", "shim" ], - "time": "2020-03-09T19:04:49+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.15.0", + "version": "v1.22.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "37b0976c78b94856543260ce09b460a7bc852747" + "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/37b0976c78b94856543260ce09b460a7bc852747", - "reference": "37b0976c78b94856543260ce09b460a7bc852747", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", + "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.15-dev" + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { @@ -5711,29 +6345,47 @@ "portable", "shim" ], - "time": "2020-02-27T09:26:54+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.15.0", + "version": "v1.22.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7" + "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7", - "reference": "0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", + "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.15-dev" + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { @@ -5769,29 +6421,43 @@ "portable", "shim" ], - "time": "2020-02-27T09:26:54+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.17.1", + "version": "v1.22.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "4a5b6bba3259902e386eb80dd1956181ee90b5b2" + "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4a5b6bba3259902e386eb80dd1956181ee90b5b2", - "reference": "4a5b6bba3259902e386eb80dd1956181ee90b5b2", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dc3063ba22c2a1fd2f45ed856374d79114998f91", + "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91", "shasum": "" }, "require": { - "php": ">=7.0.8" + "php": ">=7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.17-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -5835,31 +6501,40 @@ "portable", "shim" ], - "time": "2020-06-06T08:46:27+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/process", - "version": "v4.4.7", + "version": "v4.4.18", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "3e40e87a20eaf83a1db825e1fa5097ae89042db3" + "reference": "075316ff72233ce3d04a9743414292e834f2cb4a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/3e40e87a20eaf83a1db825e1fa5097ae89042db3", - "reference": "3e40e87a20eaf83a1db825e1fa5097ae89042db3", + "url": "https://api.github.com/repos/symfony/process/zipball/075316ff72233ce3d04a9743414292e834f2cb4a", + "reference": "075316ff72233ce3d04a9743414292e834f2cb4a", "shasum": "" }, "require": { - "php": "^7.1.3" + "php": ">=7.1.3" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Process\\": "" @@ -5884,24 +6559,38 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2020-03-27T16:54:36+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-12-08T16:59:59+00:00" }, { "name": "symfony/service-contracts", - "version": "v2.0.1", + "version": "v2.2.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "144c5e51266b281231e947b51223ba14acf1a749" + "reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/144c5e51266b281231e947b51223ba14acf1a749", - "reference": "144c5e51266b281231e947b51223ba14acf1a749", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d15da7ba4957ffb8f1747218be9e1a121fd298a1", + "reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1", "shasum": "" }, "require": { - "php": "^7.2.5", + "php": ">=7.2.5", "psr/container": "^1.0" }, "suggest": { @@ -5910,7 +6599,11 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "2.2-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -5942,24 +6635,38 @@ "interoperability", "standards" ], - "time": "2019-11-18T17:27:11+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-09-07T11:33:47+00:00" }, { "name": "symfony/yaml", - "version": "v4.4.7", + "version": "v4.4.18", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "ef166890d821518106da3560086bfcbeb4fadfec" + "reference": "bbce94f14d73732340740366fcbe63363663a403" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/ef166890d821518106da3560086bfcbeb4fadfec", - "reference": "ef166890d821518106da3560086bfcbeb4fadfec", + "url": "https://api.github.com/repos/symfony/yaml/zipball/bbce94f14d73732340740366fcbe63363663a403", + "reference": "bbce94f14d73732340740366fcbe63363663a403", "shasum": "" }, "require": { - "php": "^7.1.3", + "php": ">=7.1.3", "symfony/polyfill-ctype": "~1.8" }, "conflict": { @@ -5972,11 +6679,6 @@ "symfony/console": "For validating YAML files using the lint command" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Yaml\\": "" @@ -6001,20 +6703,34 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2020-03-30T11:41:10+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-12-08T16:59:59+00:00" }, { "name": "thecodingmachine/safe", - "version": "v1.1", + "version": "v1.3.3", "source": { "type": "git", "url": "https://github.com/thecodingmachine/safe.git", - "reference": "f440677bad66c0ef42fa3f875bf05718028af5d3" + "reference": "a8ab0876305a4cdaef31b2350fcb9811b5608dbc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/f440677bad66c0ef42fa3f875bf05718028af5d3", - "reference": "f440677bad66c0ef42fa3f875bf05718028af5d3", + "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/a8ab0876305a4cdaef31b2350fcb9811b5608dbc", + "reference": "a8ab0876305a4cdaef31b2350fcb9811b5608dbc", "shasum": "" }, "require": { @@ -6035,15 +6751,21 @@ "psr-4": { "Safe\\": [ "lib/", + "deprecated/", "generated/" ] }, "files": [ + "deprecated/apc.php", + "deprecated/libevent.php", + "deprecated/mssql.php", + "deprecated/stats.php", + "lib/special_cases.php", "generated/apache.php", - "generated/apc.php", "generated/apcu.php", "generated/array.php", "generated/bzip2.php", + "generated/calendar.php", "generated/classobj.php", "generated/com.php", "generated/cubrid.php", @@ -6072,14 +6794,12 @@ "generated/inotify.php", "generated/json.php", "generated/ldap.php", - "generated/libevent.php", "generated/libxml.php", "generated/lzf.php", "generated/mailparse.php", "generated/mbstring.php", "generated/misc.php", "generated/msql.php", - "generated/mssql.php", "generated/mysql.php", "generated/mysqli.php", "generated/mysqlndMs.php", @@ -6098,6 +6818,7 @@ "generated/ps.php", "generated/pspell.php", "generated/readline.php", + "generated/rpminfo.php", "generated/rrd.php", "generated/sem.php", "generated/session.php", @@ -6110,7 +6831,6 @@ "generated/sqlsrv.php", "generated/ssdeep.php", "generated/ssh2.php", - "generated/stats.php", "generated/stream.php", "generated/strings.php", "generated/swoole.php", @@ -6124,8 +6844,7 @@ "generated/yaml.php", "generated/yaz.php", "generated/zip.php", - "generated/zlib.php", - "lib/special_cases.php" + "generated/zlib.php" ] }, "notification-url": "https://packagist.org/downloads/", @@ -6133,27 +6852,27 @@ "MIT" ], "description": "PHP core functions that throw exceptions instead of returning FALSE on error", - "time": "2020-03-24T13:59:42+00:00" + "time": "2020-10-28T17:51:34+00:00" }, { "name": "theseer/tokenizer", - "version": "1.1.3", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9" + "reference": "75a63c33a8577608444246075ea0af0d052e452a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9", - "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/75a63c33a8577608444246075ea0af0d052e452a", + "reference": "75a63c33a8577608444246075ea0af0d052e452a", "shasum": "" }, "require": { "ext-dom": "*", "ext-tokenizer": "*", "ext-xmlwriter": "*", - "php": "^7.0" + "php": "^7.2 || ^8.0" }, "type": "library", "autoload": { @@ -6173,30 +6892,36 @@ } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "time": "2019-06-13T22:48:21+00:00" + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2020-07-12T23:59:07+00:00" }, { "name": "vlucas/phpdotenv", - "version": "v2.6.3", + "version": "v2.6.7", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "df4c4d08a639be4ef5d6d1322868f9e477553679" + "reference": "b786088918a884258c9e3e27405c6a4cf2ee246e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/df4c4d08a639be4ef5d6d1322868f9e477553679", - "reference": "df4c4d08a639be4ef5d6d1322868f9e477553679", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/b786088918a884258c9e3e27405c6a4cf2ee246e", + "reference": "b786088918a884258c9e3e27405c6a4cf2ee246e", "shasum": "" }, "require": { - "php": ">=5.3.9", - "symfony/polyfill-ctype": "^1.9" + "php": "^5.3.9 || ^7.0 || ^8.0", + "symfony/polyfill-ctype": "^1.17" }, "require-dev": { "ext-filter": "*", "ext-pcre": "*", - "phpunit/phpunit": "^4.8.35 || ^5.0" + "phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20" }, "suggest": { "ext-filter": "Required to use the boolean validator.", @@ -6218,10 +6943,15 @@ "BSD-3-Clause" ], "authors": [ + { + "name": "Graham Campbell", + "email": "graham@alt-three.com", + "homepage": "https://gjcampbell.co.uk/" + }, { "name": "Vance Lucas", "email": "vance@vancelucas.com", - "homepage": "http://www.vancelucas.com" + "homepage": "https://vancelucas.com/" } ], "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", @@ -6230,27 +6960,38 @@ "env", "environment" ], - "time": "2020-04-12T15:11:38+00:00" + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } + ], + "time": "2021-01-20T14:39:13+00:00" }, { "name": "webmozart/assert", - "version": "1.8.0", + "version": "1.9.1", "source": { "type": "git", - "url": "https://github.com/webmozart/assert.git", - "reference": "ab2cb0b3b559010b75981b1bdce728da3ee90ad6" + "url": "https://github.com/webmozarts/assert.git", + "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/ab2cb0b3b559010b75981b1bdce728da3ee90ad6", - "reference": "ab2cb0b3b559010b75981b1bdce728da3ee90ad6", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389", + "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0", + "php": "^5.3.3 || ^7.0 || ^8.0", "symfony/polyfill-ctype": "^1.8" }, "conflict": { + "phpstan/phpstan": "<0.12.20", "vimeo/psalm": "<3.9.1" }, "require-dev": { @@ -6278,7 +7019,7 @@ "check", "validate" ], - "time": "2020-04-18T12:12:48+00:00" + "time": "2020-07-08T17:02:28+00:00" }, { "name": "weew/helpers-array", @@ -6481,26 +7222,27 @@ }, { "name": "gitonomy/gitlib", - "version": "v1.2.1", + "version": "v1.2.3", "source": { "type": "git", "url": "https://github.com/gitonomy/gitlib.git", - "reference": "718ca021c67f3ea8f6a5fa5d231ec49675068868" + "reference": "d22f212b97fdb631ac73dfae65c194dc4cb0d227" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/gitonomy/gitlib/zipball/718ca021c67f3ea8f6a5fa5d231ec49675068868", - "reference": "718ca021c67f3ea8f6a5fa5d231ec49675068868", + "url": "https://api.github.com/repos/gitonomy/gitlib/zipball/d22f212b97fdb631ac73dfae65c194dc4cb0d227", + "reference": "d22f212b97fdb631ac73dfae65c194dc4cb0d227", "shasum": "" }, "require": { "ext-pcre": "*", - "php": "^5.6 || ^7.0", + "php": "^5.6 || ^7.0 || ^8.0", "symfony/polyfill-mbstring": "^1.7", - "symfony/process": "^3.4|^4.0|^5.0" + "symfony/process": "^3.4 || ^4.0 || ^5.0" }, "require-dev": { - "phpunit/phpunit": "^5.7|^6.5|^7.0", + "ext-fileinfo": "*", + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.0 || ^8.0 || ^9.0", "psr/log": "^1.0" }, "suggest": { @@ -6508,11 +7250,6 @@ "psr/log": "Required to use loggers for reporting of execution" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2-dev" - } - }, "autoload": { "psr-4": { "Gitonomy\\Git\\": "src/Gitonomy/Git/" @@ -6541,7 +7278,13 @@ } ], "description": "Library for accessing git", - "time": "2020-03-23T12:43:44+00:00" + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/gitonomy/gitlib", + "type": "tidelift" + } + ], + "time": "2020-12-29T16:48:45+00:00" }, { "name": "goaop/framework", @@ -6613,20 +7356,20 @@ }, { "name": "goaop/parser-reflection", - "version": "2.1.1", + "version": "2.1.3", "source": { "type": "git", "url": "https://github.com/goaop/parser-reflection.git", - "reference": "e9628006b321c8a62a8ad22085bc61eec0c21558" + "reference": "2e837e150e15d38f7004b0dbcd0af4abe034c9e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/goaop/parser-reflection/zipball/e9628006b321c8a62a8ad22085bc61eec0c21558", - "reference": "e9628006b321c8a62a8ad22085bc61eec0c21558", + "url": "https://api.github.com/repos/goaop/parser-reflection/zipball/2e837e150e15d38f7004b0dbcd0af4abe034c9e2", + "reference": "2e837e150e15d38f7004b0dbcd0af4abe034c9e2", "shasum": "" }, "require": { - "nikic/php-parser": "^4.0", + "nikic/php-parser": "^4.0 <4.7.0", "php": ">=7.1" }, "require-dev": { @@ -6635,7 +7378,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.x-dev" + "dev-master": "3.x-dev" } }, "autoload": { @@ -6660,7 +7403,7 @@ } ], "description": "Provides reflection information, based on raw source", - "time": "2020-02-21T19:52:39+00:00" + "time": "2020-08-13T21:02:42+00:00" }, { "name": "guzzle/guzzle", @@ -6812,16 +7555,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.4.0", + "version": "v4.6.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "bd43ec7152eaaab3bd8c6d0aa95ceeb1df8ee120" + "reference": "c346bbfafe2ff60680258b631afb730d186ed864" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/bd43ec7152eaaab3bd8c6d0aa95ceeb1df8ee120", - "reference": "bd43ec7152eaaab3bd8c6d0aa95ceeb1df8ee120", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/c346bbfafe2ff60680258b631afb730d186ed864", + "reference": "c346bbfafe2ff60680258b631afb730d186ed864", "shasum": "" }, "require": { @@ -6860,20 +7603,20 @@ "parser", "php" ], - "time": "2020-04-10T16:34:50+00:00" + "time": "2020-07-02T17:12:47+00:00" }, { "name": "pdepend/pdepend", - "version": "2.7.1", + "version": "2.8.0", "source": { "type": "git", "url": "https://github.com/pdepend/pdepend.git", - "reference": "daba1cf0a6edaf172fa02a17807ae29f4c1c7471" + "reference": "c64472f8e76ca858c79ad9a4cf1e2734b3f8cc38" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pdepend/pdepend/zipball/daba1cf0a6edaf172fa02a17807ae29f4c1c7471", - "reference": "daba1cf0a6edaf172fa02a17807ae29f4c1c7471", + "url": "https://api.github.com/repos/pdepend/pdepend/zipball/c64472f8e76ca858c79ad9a4cf1e2734b3f8cc38", + "reference": "c64472f8e76ca858c79ad9a4cf1e2734b3f8cc38", "shasum": "" }, "require": { @@ -6907,7 +7650,13 @@ "BSD-3-Clause" ], "description": "Official version of pdepend to be handled with Composer", - "time": "2020-02-08T12:06:13+00:00" + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/pdepend/pdepend", + "type": "tidelift" + } + ], + "time": "2020-06-20T10:53:13+00:00" }, { "name": "php-coveralls/php-coveralls", @@ -6972,16 +7721,16 @@ }, { "name": "phpmd/phpmd", - "version": "2.8.2", + "version": "2.9.1", "source": { "type": "git", "url": "https://github.com/phpmd/phpmd.git", - "reference": "714629ed782537f638fe23c4346637659b779a77" + "reference": "ce10831d4ddc2686c1348a98069771dd314534a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpmd/phpmd/zipball/714629ed782537f638fe23c4346637659b779a77", - "reference": "714629ed782537f638fe23c4346637659b779a77", + "url": "https://api.github.com/repos/phpmd/phpmd/zipball/ce10831d4ddc2686c1348a98069771dd314534a8", + "reference": "ce10831d4ddc2686c1348a98069771dd314534a8", "shasum": "" }, "require": { @@ -6992,6 +7741,8 @@ }, "require-dev": { "easy-doc/easy-doc": "0.0.0 || ^1.3.2", + "ext-json": "*", + "ext-simplexml": "*", "gregwar/rst": "^1.0", "mikey179/vfsstream": "^1.6.4", "phpunit/phpunit": "^4.8.36 || ^5.7.27", @@ -7038,7 +7789,13 @@ "phpmd", "pmd" ], - "time": "2020-02-16T20:15:50+00:00" + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/phpmd/phpmd", + "type": "tidelift" + } + ], + "time": "2020-09-23T22:06:32+00:00" }, { "name": "rregeer/phpunit-coverage-check", @@ -7083,29 +7840,29 @@ "time": "2018-07-29T13:27:58+00:00" }, { - "name": "sebastian/finder-facade", - "version": "2.0.0", + "name": "sebastian/cli-parser", + "version": "1.0.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/finder-facade.git", - "reference": "9d3e74b845a2ce50e19b25b5f0c2718e153bee6c" + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/finder-facade/zipball/9d3e74b845a2ce50e19b25b5f0c2718e153bee6c", - "reference": "9d3e74b845a2ce50e19b25b5f0c2718e153bee6c", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", "shasum": "" }, "require": { - "ext-ctype": "*", - "php": "^7.3", - "symfony/finder": "^4.1|^5.0", - "theseer/fdomdocument": "^1.6" + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "1.0-dev" } }, "autoload": { @@ -7124,32 +7881,37 @@ "role": "lead" } ], - "description": "FinderFacade is a convenience wrapper for Symfony's Finder component.", - "homepage": "https://github.com/sebastianbergmann/finder-facade", - "abandoned": true, - "time": "2020-02-08T06:07:58+00:00" + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:08:49+00:00" }, { "name": "sebastian/phpcpd", - "version": "5.0.2", + "version": "6.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpcpd.git", - "reference": "8724382966b1861df4e12db915eaed2165e10bf3" + "reference": "f3683aa0db2e8e09287c2bb33a595b2873ea9176" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpcpd/zipball/8724382966b1861df4e12db915eaed2165e10bf3", - "reference": "8724382966b1861df4e12db915eaed2165e10bf3", + "url": "https://api.github.com/repos/sebastianbergmann/phpcpd/zipball/f3683aa0db2e8e09287c2bb33a595b2873ea9176", + "reference": "f3683aa0db2e8e09287c2bb33a595b2873ea9176", "shasum": "" }, "require": { "ext-dom": "*", - "php": "^7.3", - "phpunit/php-timer": "^3.0", - "sebastian/finder-facade": "^2.0", - "sebastian/version": "^3.0", - "symfony/console": "^4.0|^5.0" + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0", + "phpunit/php-timer": "^5.0", + "sebastian/cli-parser": "^1.0", + "sebastian/version": "^3.0" }, "bin": [ "phpcpd" @@ -7157,7 +7919,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "6.0-dev" } }, "autoload": { @@ -7178,20 +7940,26 @@ ], "description": "Copy/Paste Detector (CPD) for PHP code.", "homepage": "https://github.com/sebastianbergmann/phpcpd", - "time": "2020-02-22T06:03:17+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-12-07T05:39:23+00:00" }, { "name": "squizlabs/php_codesniffer", - "version": "3.5.5", + "version": "3.5.8", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "73e2e7f57d958e7228fce50dc0c61f58f017f9f6" + "reference": "9d583721a7157ee997f235f327de038e7ea6dac4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/73e2e7f57d958e7228fce50dc0c61f58f017f9f6", - "reference": "73e2e7f57d958e7228fce50dc0c61f58f017f9f6", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/9d583721a7157ee997f235f327de038e7ea6dac4", + "reference": "9d583721a7157ee997f235f327de038e7ea6dac4", "shasum": "" }, "require": { @@ -7229,24 +7997,24 @@ "phpcs", "standards" ], - "time": "2020-04-17T01:09:41+00:00" + "time": "2020-10-23T02:01:07+00:00" }, { "name": "symfony/config", - "version": "v4.4.7", + "version": "v4.4.18", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "3f4a3de1af498ed0ea653d4dc2317794144e6ca4" + "reference": "e501c56d2fa70798075b9811d0eb4c27de491459" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/3f4a3de1af498ed0ea653d4dc2317794144e6ca4", - "reference": "3f4a3de1af498ed0ea653d4dc2317794144e6ca4", + "url": "https://api.github.com/repos/symfony/config/zipball/e501c56d2fa70798075b9811d0eb4c27de491459", + "reference": "e501c56d2fa70798075b9811d0eb4c27de491459", "shasum": "" }, "require": { - "php": "^7.1.3", + "php": ">=7.1.3", "symfony/filesystem": "^3.4|^4.0|^5.0", "symfony/polyfill-ctype": "~1.8" }, @@ -7264,11 +8032,6 @@ "symfony/yaml": "To use the yaml reference dumper" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Config\\": "" @@ -7293,24 +8056,38 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2020-03-27T16:54:36+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-12-09T08:58:17+00:00" }, { "name": "symfony/dependency-injection", - "version": "v4.4.7", + "version": "v4.4.18", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "755b18859be26b90f4bf63753432d3387458bf31" + "reference": "3860f64c6deb2cb48b1ada27460c58ae479bdc0f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/755b18859be26b90f4bf63753432d3387458bf31", - "reference": "755b18859be26b90f4bf63753432d3387458bf31", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/3860f64c6deb2cb48b1ada27460c58ae479bdc0f", + "reference": "3860f64c6deb2cb48b1ada27460c58ae479bdc0f", "shasum": "" }, "require": { - "php": "^7.1.3", + "php": ">=7.1.3", "psr/container": "^1.0", "symfony/service-contracts": "^1.1.6|^2" }, @@ -7337,11 +8114,6 @@ "symfony/yaml": "" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\DependencyInjection\\": "" @@ -7366,31 +8138,40 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2020-03-30T10:09:30+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-12-18T07:41:31+00:00" }, { "name": "symfony/stopwatch", - "version": "v3.4.39", + "version": "v3.4.47", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "a7a98f40dcc382a332c3729a6d04b298ffbb8f1f" + "reference": "298b81faad4ce60e94466226b2abbb8c9bca7462" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/a7a98f40dcc382a332c3729a6d04b298ffbb8f1f", - "reference": "a7a98f40dcc382a332c3729a6d04b298ffbb8f1f", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/298b81faad4ce60e94466226b2abbb8c9bca7462", + "reference": "298b81faad4ce60e94466226b2abbb8c9bca7462", "shasum": "" }, "require": { "php": "^5.5.9|>=7.0.8" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Stopwatch\\": "" @@ -7415,47 +8196,21 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", - "time": "2020-03-15T09:38:08+00:00" - }, - { - "name": "theseer/fdomdocument", - "version": "1.6.6", - "source": { - "type": "git", - "url": "https://github.com/theseer/fDOMDocument.git", - "reference": "6e8203e40a32a9c770bcb62fe37e68b948da6dca" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/theseer/fDOMDocument/zipball/6e8203e40a32a9c770bcb62fe37e68b948da6dca", - "reference": "6e8203e40a32a9c770bcb62fe37e68b948da6dca", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "lib-libxml": "*", - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ + "funding": [ { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "lead" + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" } ], - "description": "The classes contained within this repository extend the standard DOM to use exceptions at all occasions of errors instead of PHP warnings or notices. They also add various custom methods and shortcuts for convenience and to simplify the usage of DOM.", - "homepage": "https://github.com/theseer/fDOMDocument", - "time": "2017-06-30T11:53:12+00:00" + "time": "2020-10-24T10:57:07+00:00" } ], "aliases": [], @@ -7471,5 +8226,6 @@ "ext-json": "*", "ext-openssl": "*" }, - "platform-dev": [] + "platform-dev": [], + "plugin-api-version": "1.1.0" } diff --git a/src/Magento/FunctionalTestingFramework/Console/BuildProjectCommand.php b/src/Magento/FunctionalTestingFramework/Console/BuildProjectCommand.php index 23736925f..afeacaad3 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BuildProjectCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BuildProjectCommand.php @@ -67,7 +67,7 @@ protected function configure() * @param OutputInterface $output * @return void * @throws \Exception - * @SuppressWarnings(PHPMD.UnusedLocalVariable) + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ protected function execute(InputInterface $input, OutputInterface $output) { diff --git a/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php index 683be1b53..89b184676 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php @@ -112,7 +112,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int * @return void * @throws \Exception * - * @SuppressWarnings(PHPMD.UnusedLocalVariable) Need this because of the unused $type variable in the closure + * @SuppressWarnings(PHPMD.UnusedFormalParameter) Need this because of the unused $type variable in the closure */ private function runManifestLine($manifestLine, $output, $exit = false) { diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php index 1b3f939ba..fcf04cb3d 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php @@ -215,7 +215,7 @@ private function runTestsInSuite(array $suitesConfig, OutputInterface $output) * @param OutputInterface $output * @return integer * - * @SuppressWarnings(PHPMD.UnusedLocalVariable) + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ private function executeTestCommand(string $command, OutputInterface $output) { diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php index 601438f96..a6302dacd 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php @@ -52,7 +52,7 @@ protected function configure() * @return integer * @throws \Exception * - * @SuppressWarnings(PHPMD.UnusedLocalVariable) + * @SuppressWarnings(PHPMD.UnusedFormalParameter) * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) */ From 8b56226bc7ff08a1feddaba1132b83e8d56167f2 Mon Sep 17 00:00:00 2001 From: Roman Hanin <rganin@adobe.com> Date: Mon, 25 Jan 2021 09:22:22 -0600 Subject: [PATCH 587/888] MTS-1836: Upgrade csharpru/vault-php to 4.1+ --- composer.json | 2 +- composer.lock | 2100 ++++++++++++++++++++++++------------------------- 2 files changed, 1009 insertions(+), 1093 deletions(-) diff --git a/composer.json b/composer.json index 528110db9..f9aecf89b 100755 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "codeception/module-sequence": "^1.0", "codeception/module-webdriver": "^1.0", "composer/composer": "^1.9", - "csharpru/vault-php": "~3.5.3", + "csharpru/vault-php": "^4.1.0", "csharpru/vault-php-guzzle6-transport": "^2.0", "hoa/console": "~3.0", "monolog/monolog": "^1.17", diff --git a/composer.lock b/composer.lock index 1cdca924c..b8dcdaee1 100644 --- a/composer.lock +++ b/composer.lock @@ -4,24 +4,24 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c10e8e92b057c17fa3d1818a240b7361", + "content-hash": "a2a73a21666676a513eb3efab5992946", "packages": [ { "name": "allure-framework/allure-codeception", - "version": "1.4.3", + "version": "1.4.5", "source": { "type": "git", "url": "https://github.com/allure-framework/allure-codeception.git", - "reference": "9e0e25f8960fa5ac17c65c932ea8153ce6700713" + "reference": "ac3d471902d2903856bbd0a95e7546788319ed22" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/allure-framework/allure-codeception/zipball/9e0e25f8960fa5ac17c65c932ea8153ce6700713", - "reference": "9e0e25f8960fa5ac17c65c932ea8153ce6700713", + "url": "https://api.github.com/repos/allure-framework/allure-codeception/zipball/ac3d471902d2903856bbd0a95e7546788319ed22", + "reference": "ac3d471902d2903856bbd0a95e7546788319ed22", "shasum": "" }, "require": { - "allure-framework/allure-php-api": "~1.1.8", + "allure-framework/allure-php-api": "~1.2.1", "codeception/codeception": "^2.3|^3.0|^4.0", "php": ">=5.6", "symfony/filesystem": ">=2.6", @@ -55,26 +55,26 @@ "steps", "testing" ], - "time": "2020-03-13T11:07:13+00:00" + "time": "2020-11-26T11:41:53+00:00" }, { "name": "allure-framework/allure-php-api", - "version": "1.1.8", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/allure-framework/allure-php-commons.git", - "reference": "5ae2deac1c7e1b992cfa572167370de45bdd346d" + "reference": "13ef45d83ce4f5ef70499ff87ed0c3d1c192ab80" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/allure-framework/allure-php-commons/zipball/5ae2deac1c7e1b992cfa572167370de45bdd346d", - "reference": "5ae2deac1c7e1b992cfa572167370de45bdd346d", + "url": "https://api.github.com/repos/allure-framework/allure-php-commons/zipball/13ef45d83ce4f5ef70499ff87ed0c3d1c192ab80", + "reference": "13ef45d83ce4f5ef70499ff87ed0c3d1c192ab80", "shasum": "" }, "require": { "jms/serializer": "^0.16 || ^1.0", "php": ">=5.4.0", - "ramsey/uuid": "^3.0", + "ramsey/uuid": "^3.0 || ^4.0", "symfony/http-foundation": "^2.0 || ^3.0 || ^4.0 || ^5.0" }, "require-dev": { @@ -108,20 +108,20 @@ "php", "report" ], - "time": "2020-03-13T10:47:35+00:00" + "time": "2020-11-26T09:20:44+00:00" }, { "name": "aws/aws-sdk-php", - "version": "3.135.3", + "version": "3.172.0", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "0f6f6e8f4a44193908e18b8c7b8530b02f5bc428" + "reference": "5a5e66c4d54c392042820703eeb8a6bd3d222924" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/0f6f6e8f4a44193908e18b8c7b8530b02f5bc428", - "reference": "0f6f6e8f4a44193908e18b8c7b8530b02f5bc428", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/5a5e66c4d54c392042820703eeb8a6bd3d222924", + "reference": "5a5e66c4d54c392042820703eeb8a6bd3d222924", "shasum": "" }, "require": { @@ -144,6 +144,7 @@ "ext-pcntl": "*", "ext-sockets": "*", "nette/neon": "^2.3", + "paragonie/random_compat": ">= 2", "phpunit/phpunit": "^4.8.35|^5.4.3", "psr/cache": "^1.0", "psr/simple-cache": "^1.0", @@ -192,36 +193,35 @@ "s3", "sdk" ], - "time": "2020-04-23T18:18:24+00:00" + "time": "2021-01-22T19:21:38+00:00" }, { "name": "beberlei/assert", - "version": "v3.2.7", + "version": "v3.3.0", "source": { "type": "git", "url": "https://github.com/beberlei/assert.git", - "reference": "d63a6943fc4fd1a2aedb65994e3548715105abcf" + "reference": "5367e3895976b49704ae671f75bc5f0ba1b986ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/beberlei/assert/zipball/d63a6943fc4fd1a2aedb65994e3548715105abcf", - "reference": "d63a6943fc4fd1a2aedb65994e3548715105abcf", + "url": "https://api.github.com/repos/beberlei/assert/zipball/5367e3895976b49704ae671f75bc5f0ba1b986ab", + "reference": "5367e3895976b49704ae671f75bc5f0ba1b986ab", "shasum": "" }, "require": { "ext-ctype": "*", + "ext-intl": "*", "ext-json": "*", "ext-mbstring": "*", "ext-simplexml": "*", - "php": "^7" + "php": "^7.0 || ^8.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "*", - "phpstan/phpstan-shim": "*", - "phpunit/phpunit": ">=6.0.0 <8" - }, - "suggest": { - "ext-intl": "Needed to allow Assertion::count(), Assertion::isCountable(), Assertion::minCount(), and Assertion::maxCount() to operate on ResourceBundles" + "phpstan/phpstan": "*", + "phpunit/phpunit": ">=6.0.0", + "yoast/phpunit-polyfills": "^0.1.0" }, "type": "library", "autoload": { @@ -254,27 +254,27 @@ "assertion", "validation" ], - "time": "2019-12-19T17:51:41+00:00" + "time": "2020-11-13T20:02:54+00:00" }, { "name": "behat/gherkin", - "version": "v4.6.2", + "version": "v4.7.0", "source": { "type": "git", "url": "https://github.com/Behat/Gherkin.git", - "reference": "51ac4500c4dc30cbaaabcd2f25694299df666a31" + "reference": "0ffe6a7f67f8d038166143d71b30a9088f932576" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Behat/Gherkin/zipball/51ac4500c4dc30cbaaabcd2f25694299df666a31", - "reference": "51ac4500c4dc30cbaaabcd2f25694299df666a31", + "url": "https://api.github.com/repos/Behat/Gherkin/zipball/0ffe6a7f67f8d038166143d71b30a9088f932576", + "reference": "0ffe6a7f67f8d038166143d71b30a9088f932576", "shasum": "" }, "require": { - "php": ">=5.3.1" + "php": ">=5.6" }, "require-dev": { - "phpunit/phpunit": "~4.5|~5", + "phpunit/phpunit": "~5.7|~6|~7", "symfony/phpunit-bridge": "~2.7|~3|~4", "symfony/yaml": "~2.3|~3|~4" }, @@ -303,7 +303,7 @@ "homepage": "http://everzet.com" } ], - "description": "Gherkin DSL parser for PHP 5.3", + "description": "Gherkin DSL parser for PHP", "homepage": "http://behat.org/", "keywords": [ "BDD", @@ -313,113 +313,66 @@ "gherkin", "parser" ], - "time": "2020-03-17T14:03:26+00:00" + "time": "2021-01-24T14:06:27+00:00" }, { - "name": "cache/cache", - "version": "0.4.0", + "name": "brick/math", + "version": "0.9.2", "source": { "type": "git", - "url": "https://github.com/php-cache/cache.git", - "reference": "902b2e5b54ea57e3a801437748652228c4c58604" + "url": "https://github.com/brick/math.git", + "reference": "dff976c2f3487d42c1db75a3b180e2b9f0e72ce0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-cache/cache/zipball/902b2e5b54ea57e3a801437748652228c4c58604", - "reference": "902b2e5b54ea57e3a801437748652228c4c58604", + "url": "https://api.github.com/repos/brick/math/zipball/dff976c2f3487d42c1db75a3b180e2b9f0e72ce0", + "reference": "dff976c2f3487d42c1db75a3b180e2b9f0e72ce0", "shasum": "" }, "require": { - "doctrine/cache": "^1.3", - "league/flysystem": "^1.0", - "php": "^5.6 || ^7.0", - "psr/cache": "^1.0", - "psr/log": "^1.0", - "psr/simple-cache": "^1.0" - }, - "conflict": { - "cache/adapter-common": "*", - "cache/apc-adapter": "*", - "cache/apcu-adapter": "*", - "cache/array-adapter": "*", - "cache/chain-adapter": "*", - "cache/doctrine-adapter": "*", - "cache/filesystem-adapter": "*", - "cache/hierarchical-cache": "*", - "cache/illuminate-adapter": "*", - "cache/memcache-adapter": "*", - "cache/memcached-adapter": "*", - "cache/mongodb-adapter": "*", - "cache/predis-adapter": "*", - "cache/psr-6-doctrine-bridge": "*", - "cache/redis-adapter": "*", - "cache/session-handler": "*", - "cache/taggable-cache": "*", - "cache/void-adapter": "*" + "ext-json": "*", + "php": "^7.1 || ^8.0" }, "require-dev": { - "cache/integration-tests": "^0.16", - "defuse/php-encryption": "^2.0", - "illuminate/cache": "^5.4", - "mockery/mockery": "^0.9", - "phpunit/phpunit": "^4.0 || ^5.1", - "predis/predis": "^1.0", - "symfony/cache": "dev-master" - }, - "suggest": { - "ext-apc": "APC extension is required to use the APC Adapter", - "ext-apcu": "APCu extension is required to use the APCu Adapter", - "ext-memcache": "Memcache extension is required to use the Memcache Adapter", - "ext-memcached": "Memcached extension is required to use the Memcached Adapter", - "ext-mongodb": "Mongodb extension required to use the Mongodb adapter", - "ext-redis": "Redis extension is required to use the Redis adapter", - "mongodb/mongodb": "Mongodb lib required to use the Mongodb adapter" + "php-coveralls/php-coveralls": "^2.2", + "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0", + "vimeo/psalm": "4.3.2" }, "type": "library", "autoload": { "psr-4": { - "Cache\\": "src/" - }, - "exclude-from-classmap": [ - "**/Tests/" - ] + "Brick\\Math\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ - { - "name": "Aaron Scherer", - "email": "aequasi@gmail.com", - "homepage": "https://github.com/aequasi" - }, - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com", - "homepage": "https://github.com/Nyholm" - } - ], - "description": "Library of all the php-cache adapters", - "homepage": "http://www.php-cache.com/en/latest/", + "description": "Arbitrary-precision arithmetic library", "keywords": [ - "cache", - "psr6" + "Arbitrary-precision", + "BigInteger", + "BigRational", + "arithmetic", + "bigdecimal", + "bignum", + "brick", + "math" ], - "time": "2017-03-28T16:08:48+00:00" + "time": "2021-01-20T22:51:39+00:00" }, { "name": "codeception/codeception", - "version": "4.1.4", + "version": "4.1.15", "source": { "type": "git", "url": "https://github.com/Codeception/Codeception.git", - "reference": "55d8d1d882fa0777e47de17b04c29b3c50fe29e7" + "reference": "9b174d18ba58bb2e8cc4cecce619d6124df1d83a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/Codeception/zipball/55d8d1d882fa0777e47de17b04c29b3c50fe29e7", - "reference": "55d8d1d882fa0777e47de17b04c29b3c50fe29e7", + "url": "https://api.github.com/repos/Codeception/Codeception/zipball/9b174d18ba58bb2e8cc4cecce619d6124df1d83a", + "reference": "9b174d18ba58bb2e8cc4cecce619d6124df1d83a", "shasum": "" }, "require": { @@ -431,7 +384,7 @@ "ext-json": "*", "ext-mbstring": "*", "guzzlehttp/psr7": "~1.4", - "php": ">=5.6.0 <8.0", + "php": ">=5.6.0 <9.0", "symfony/console": ">=2.7 <6.0", "symfony/css-selector": ">=2.7 <6.0", "symfony/event-dispatcher": ">=2.7 <6.0", @@ -449,7 +402,7 @@ "monolog/monolog": "~1.8", "squizlabs/php_codesniffer": "~2.0", "symfony/process": ">=2.7 <6.0", - "vlucas/phpdotenv": "^2.0 | ^3.0 | ^4.0" + "vlucas/phpdotenv": "^2.0 | ^3.0 | ^4.0 | ^5.0" }, "suggest": { "codeception/specify": "BDD-style code blocks", @@ -491,25 +444,26 @@ "functional testing", "unit testing" ], - "time": "2020-03-23T17:07:20+00:00" + "time": "2021-01-17T19:19:40+00:00" }, { "name": "codeception/lib-asserts", - "version": "1.12.0", + "version": "1.13.2", "source": { "type": "git", "url": "https://github.com/Codeception/lib-asserts.git", - "reference": "acd0dc8b394595a74b58dcc889f72569ff7d8e71" + "reference": "184231d5eab66bc69afd6b9429344d80c67a33b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/lib-asserts/zipball/acd0dc8b394595a74b58dcc889f72569ff7d8e71", - "reference": "acd0dc8b394595a74b58dcc889f72569ff7d8e71", + "url": "https://api.github.com/repos/Codeception/lib-asserts/zipball/184231d5eab66bc69afd6b9429344d80c67a33b6", + "reference": "184231d5eab66bc69afd6b9429344d80c67a33b6", "shasum": "" }, "require": { "codeception/phpunit-wrapper": ">6.0.15 <6.1.0 | ^6.6.1 | ^7.7.1 | ^8.0.3 | ^9.0", - "php": ">=5.6.0 <8.0" + "ext-dom": "*", + "php": ">=5.6.0 <9.0" }, "type": "library", "autoload": { @@ -529,40 +483,41 @@ }, { "name": "Gintautas Miselis" + }, + { + "name": "Gustavo Nieves", + "homepage": "https://medium.com/@ganieves" } ], "description": "Assertion methods used by Codeception core and Asserts module", - "homepage": "http://codeception.com/", + "homepage": "https://codeception.com/", "keywords": [ "codeception" ], - "time": "2020-04-17T18:20:46+00:00" + "time": "2020-10-21T16:26:20+00:00" }, { "name": "codeception/module-asserts", - "version": "1.2.1", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/Codeception/module-asserts.git", - "reference": "79f13d05b63f2fceba4d0e78044bab668c9b2a6b" + "reference": "59374f2fef0cabb9e8ddb53277e85cdca74328de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/module-asserts/zipball/79f13d05b63f2fceba4d0e78044bab668c9b2a6b", - "reference": "79f13d05b63f2fceba4d0e78044bab668c9b2a6b", + "url": "https://api.github.com/repos/Codeception/module-asserts/zipball/59374f2fef0cabb9e8ddb53277e85cdca74328de", + "reference": "59374f2fef0cabb9e8ddb53277e85cdca74328de", "shasum": "" }, "require": { "codeception/codeception": "*@dev", - "codeception/lib-asserts": "^1.12.0", - "php": ">=5.6.0 <8.0" + "codeception/lib-asserts": "^1.13.1", + "php": ">=5.6.0 <9.0" }, "conflict": { "codeception/codeception": "<4.0" }, - "require-dev": { - "codeception/util-robohelpers": "dev-master" - }, "type": "library", "autoload": { "classmap": [ @@ -579,37 +534,38 @@ }, { "name": "Gintautas Miselis" + }, + { + "name": "Gustavo Nieves", + "homepage": "https://medium.com/@ganieves" } ], "description": "Codeception module containing various assertions", - "homepage": "http://codeception.com/", + "homepage": "https://codeception.com/", "keywords": [ "assertions", "asserts", "codeception" ], - "time": "2020-04-20T07:26:11+00:00" + "time": "2020-10-21T16:48:15+00:00" }, { "name": "codeception/module-sequence", - "version": "1.0.0", + "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/Codeception/module-sequence.git", - "reference": "70563527b768194d6ab22e1ff943a5e69741c5dd" + "reference": "b75be26681ae90824cde8f8df785981f293667e1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/module-sequence/zipball/70563527b768194d6ab22e1ff943a5e69741c5dd", - "reference": "70563527b768194d6ab22e1ff943a5e69741c5dd", + "url": "https://api.github.com/repos/Codeception/module-sequence/zipball/b75be26681ae90824cde8f8df785981f293667e1", + "reference": "b75be26681ae90824cde8f8df785981f293667e1", "shasum": "" }, "require": { - "codeception/codeception": "4.0.x-dev | ^4.0", - "php": ">=5.6.0 <8.0" - }, - "require-dev": { - "codeception/util-robohelpers": "dev-master" + "codeception/codeception": "^4.0", + "php": ">=5.6.0 <9.0" }, "type": "library", "autoload": { @@ -631,29 +587,26 @@ "keywords": [ "codeception" ], - "time": "2019-10-10T12:08:50+00:00" + "time": "2020-10-31T18:36:26+00:00" }, { "name": "codeception/module-webdriver", - "version": "1.0.7", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/Codeception/module-webdriver.git", - "reference": "f05c5c25e39d10fbfb2d508779e1537df019ff9b" + "reference": "63ea08880a44df809bdfbca08597e1b68cee9f87" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/module-webdriver/zipball/f05c5c25e39d10fbfb2d508779e1537df019ff9b", - "reference": "f05c5c25e39d10fbfb2d508779e1537df019ff9b", + "url": "https://api.github.com/repos/Codeception/module-webdriver/zipball/63ea08880a44df809bdfbca08597e1b68cee9f87", + "reference": "63ea08880a44df809bdfbca08597e1b68cee9f87", "shasum": "" }, "require": { "codeception/codeception": "^4.0", - "php": ">=5.6.0 <8.0", - "php-webdriver/webdriver": "^1.6.0" - }, - "require-dev": { - "codeception/util-robohelpers": "dev-master" + "php": ">=5.6.0 <9.0", + "php-webdriver/webdriver": "^1.8.0" }, "suggest": { "codeception/phpbuiltinserver": "Start and stop PHP built-in web server for your tests" @@ -686,20 +639,20 @@ "browser-testing", "codeception" ], - "time": "2020-04-01T10:18:18+00:00" + "time": "2021-01-17T19:23:20+00:00" }, { "name": "codeception/phpunit-wrapper", - "version": "9.0.2", + "version": "9.0.6", "source": { "type": "git", "url": "https://github.com/Codeception/phpunit-wrapper.git", - "reference": "eb27243d8edde68593bf8d9ef5e9074734777931" + "reference": "b0c06abb3181eedca690170f7ed0fd26a70bfacc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/phpunit-wrapper/zipball/eb27243d8edde68593bf8d9ef5e9074734777931", - "reference": "eb27243d8edde68593bf8d9ef5e9074734777931", + "url": "https://api.github.com/repos/Codeception/phpunit-wrapper/zipball/b0c06abb3181eedca690170f7ed0fd26a70bfacc", + "reference": "b0c06abb3181eedca690170f7ed0fd26a70bfacc", "shasum": "" }, "require": { @@ -708,6 +661,7 @@ }, "require-dev": { "codeception/specify": "*", + "consolidation/robo": "^3.0.0-alpha3", "vlucas/phpdotenv": "^3.0" }, "type": "library", @@ -730,20 +684,20 @@ } ], "description": "PHPUnit classes used by Codeception", - "time": "2020-04-17T18:16:31+00:00" + "time": "2020-12-28T13:59:47+00:00" }, { "name": "codeception/stub", - "version": "3.6.1", + "version": "3.7.0", "source": { "type": "git", "url": "https://github.com/Codeception/Stub.git", - "reference": "a3ba01414cbee76a1bced9f9b6b169cc8d203880" + "reference": "468dd5fe659f131fc997f5196aad87512f9b1304" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/Stub/zipball/a3ba01414cbee76a1bced9f9b6b169cc8d203880", - "reference": "a3ba01414cbee76a1bced9f9b6b169cc8d203880", + "url": "https://api.github.com/repos/Codeception/Stub/zipball/468dd5fe659f131fc997f5196aad87512f9b1304", + "reference": "468dd5fe659f131fc997f5196aad87512f9b1304", "shasum": "" }, "require": { @@ -760,20 +714,20 @@ "MIT" ], "description": "Flexible Stub wrapper for PHPUnit's Mock Builder", - "time": "2020-02-07T18:42:28+00:00" + "time": "2020-07-03T15:54:43+00:00" }, { "name": "composer/ca-bundle", - "version": "1.2.7", + "version": "1.2.9", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "95c63ab2117a72f48f5a55da9740a3273d45b7fd" + "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/95c63ab2117a72f48f5a55da9740a3273d45b7fd", - "reference": "95c63ab2117a72f48f5a55da9740a3273d45b7fd", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/78a0e288fdcebf92aa2318a8d3656168da6ac1a5", + "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5", "shasum": "" }, "require": { @@ -782,14 +736,15 @@ "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8", + "phpstan/phpstan": "^0.12.55", "psr/log": "^1.0", + "symfony/phpunit-bridge": "^4.2 || ^5", "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-main": "1.x-dev" } }, "autoload": { @@ -816,20 +771,20 @@ "ssl", "tls" ], - "time": "2020-04-08T08:27:21+00:00" + "time": "2021-01-12T12:10:35+00:00" }, { "name": "composer/composer", - "version": "1.10.5", + "version": "1.10.19", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "7a4d5b6aa30d2118af27c04f5e897b57156ccfa9" + "reference": "196601d50c08c3fae389a417a7689367fcf37cef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/7a4d5b6aa30d2118af27c04f5e897b57156ccfa9", - "reference": "7a4d5b6aa30d2118af27c04f5e897b57156ccfa9", + "url": "https://api.github.com/repos/composer/composer/zipball/196601d50c08c3fae389a417a7689367fcf37cef", + "reference": "196601d50c08c3fae389a417a7689367fcf37cef", "shasum": "" }, "require": { @@ -837,8 +792,8 @@ "composer/semver": "^1.0", "composer/spdx-licenses": "^1.2", "composer/xdebug-handler": "^1.1", - "justinrainbow/json-schema": "^3.0 || ^4.0 || ^5.0", - "php": "^5.3.2 || ^7.0", + "justinrainbow/json-schema": "^5.2.10", + "php": "^5.3.2 || ^7.0 || ^8.0", "psr/log": "^1.0", "seld/jsonlint": "^1.4", "seld/phar-utils": "^1.0", @@ -852,7 +807,7 @@ }, "require-dev": { "phpspec/prophecy": "^1.10", - "symfony/phpunit-bridge": "^3.4" + "symfony/phpunit-bridge": "^4.2" }, "suggest": { "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages", @@ -896,24 +851,24 @@ "dependency", "package" ], - "time": "2020-04-10T09:44:22+00:00" + "time": "2020-12-04T08:14:16+00:00" }, { "name": "composer/semver", - "version": "1.5.1", + "version": "1.7.2", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de" + "reference": "647490bbcaf7fc4891c58f47b825eb99d19c377a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/c6bea70230ef4dd483e6bbcab6005f682ed3a8de", - "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de", + "url": "https://api.github.com/repos/composer/semver/zipball/647490bbcaf7fc4891c58f47b825eb99d19c377a", + "reference": "647490bbcaf7fc4891c58f47b825eb99d19c377a", "shasum": "" }, "require": { - "php": "^5.3.2 || ^7.0" + "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { "phpunit/phpunit": "^4.5 || ^5.0.5" @@ -957,20 +912,20 @@ "validation", "versioning" ], - "time": "2020-01-13T12:06:48+00:00" + "time": "2020-12-03T15:47:16+00:00" }, { "name": "composer/spdx-licenses", - "version": "1.5.3", + "version": "1.5.5", "source": { "type": "git", "url": "https://github.com/composer/spdx-licenses.git", - "reference": "0c3e51e1880ca149682332770e25977c70cf9dae" + "reference": "de30328a7af8680efdc03e396aad24befd513200" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/0c3e51e1880ca149682332770e25977c70cf9dae", - "reference": "0c3e51e1880ca149682332770e25977c70cf9dae", + "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/de30328a7af8680efdc03e396aad24befd513200", + "reference": "de30328a7af8680efdc03e396aad24befd513200", "shasum": "" }, "require": { @@ -982,7 +937,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-main": "1.x-dev" } }, "autoload": { @@ -1017,20 +972,20 @@ "spdx", "validator" ], - "time": "2020-02-14T07:44:31+00:00" + "time": "2020-12-03T16:04:16+00:00" }, { "name": "composer/xdebug-handler", - "version": "1.4.1", + "version": "1.4.5", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "1ab9842d69e64fb3a01be6b656501032d1b78cb7" + "reference": "f28d44c286812c714741478d968104c5e604a1d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/1ab9842d69e64fb3a01be6b656501032d1b78cb7", - "reference": "1ab9842d69e64fb3a01be6b656501032d1b78cb7", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/f28d44c286812c714741478d968104c5e604a1d4", + "reference": "f28d44c286812c714741478d968104c5e604a1d4", "shasum": "" }, "require": { @@ -1061,36 +1016,40 @@ "Xdebug", "performance" ], - "time": "2020-03-01T12:26:26+00:00" + "time": "2020-11-13T08:04:11+00:00" }, { "name": "csharpru/vault-php", - "version": "3.5.3", + "version": "4.2.0", "source": { "type": "git", "url": "https://github.com/CSharpRU/vault-php.git", - "reference": "04be9776310fe7d1afb97795645f95c21e6b4fcf" + "reference": "de812a9667a1111c4f4d4080b2c9166692ee9efe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CSharpRU/vault-php/zipball/04be9776310fe7d1afb97795645f95c21e6b4fcf", - "reference": "04be9776310fe7d1afb97795645f95c21e6b4fcf", + "url": "https://api.github.com/repos/CSharpRU/vault-php/zipball/de812a9667a1111c4f4d4080b2c9166692ee9efe", + "reference": "de812a9667a1111c4f4d4080b2c9166692ee9efe", "shasum": "" }, "require": { - "cache/cache": "^0.4.0", - "doctrine/inflector": "~1.1.0", - "guzzlehttp/promises": "^1.3", - "guzzlehttp/psr7": "^1.4", + "ext-json": "*", + "php": "^7.2", "psr/cache": "^1.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", "psr/log": "^1.0", "weew/helpers-array": "^1.3" }, "require-dev": { - "codacy/coverage": "^1.1", + "alextartan/guzzle-psr18-adapter": "^1.2", + "cache/array-adapter": "^1.0", "codeception/codeception": "^2.2", - "csharpru/vault-php-guzzle6-transport": "~2.0", - "php-vcr/php-vcr": "^1.3" + "laminas/laminas-diactoros": "^2.3", + "php-vcr/php-vcr": "dev-issues/289 as 1.4.5" + }, + "suggest": { + "cache/array-adapter": "For usage with CachedClient class" }, "type": "library", "autoload": { @@ -1109,7 +1068,7 @@ } ], "description": "Best Vault client for PHP that you can find", - "time": "2018-04-28T04:52:17+00:00" + "time": "2020-11-27T09:07:28+00:00" }, { "name": "csharpru/vault-php-guzzle6-transport", @@ -1151,31 +1110,33 @@ }, { "name": "doctrine/annotations", - "version": "1.10.2", + "version": "1.11.1", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "b9d758e831c70751155c698c2f7df4665314a1cb" + "reference": "ce77a7ba1770462cd705a91a151b6c3746f9c6ad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/b9d758e831c70751155c698c2f7df4665314a1cb", - "reference": "b9d758e831c70751155c698c2f7df4665314a1cb", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/ce77a7ba1770462cd705a91a151b6c3746f9c6ad", + "reference": "ce77a7ba1770462cd705a91a151b6c3746f9c6ad", "shasum": "" }, "require": { "doctrine/lexer": "1.*", "ext-tokenizer": "*", - "php": "^7.1" + "php": "^7.1 || ^8.0" }, "require-dev": { "doctrine/cache": "1.*", - "phpunit/phpunit": "^7.5" + "doctrine/coding-standard": "^6.0 || ^8.1", + "phpstan/phpstan": "^0.12.20", + "phpunit/phpunit": "^7.5 || ^9.1.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.9.x-dev" + "dev-master": "1.11.x-dev" } }, "autoload": { @@ -1210,183 +1171,41 @@ } ], "description": "Docblock Annotations Parser", - "homepage": "http://www.doctrine-project.org", + "homepage": "https://www.doctrine-project.org/projects/annotations.html", "keywords": [ "annotations", "docblock", "parser" ], - "time": "2020-04-20T09:18:32+00:00" - }, - { - "name": "doctrine/cache", - "version": "v1.6.2", - "source": { - "type": "git", - "url": "https://github.com/doctrine/cache.git", - "reference": "eb152c5100571c7a45470ff2a35095ab3f3b900b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/eb152c5100571c7a45470ff2a35095ab3f3b900b", - "reference": "eb152c5100571c7a45470ff2a35095ab3f3b900b", - "shasum": "" - }, - "require": { - "php": "~5.5|~7.0" - }, - "conflict": { - "doctrine/common": ">2.2,<2.4" - }, - "require-dev": { - "phpunit/phpunit": "~4.8|~5.0", - "predis/predis": "~1.0", - "satooshi/php-coveralls": "~0.6" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.6.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "Caching library offering an object-oriented API for many cache backends", - "homepage": "http://www.doctrine-project.org", - "keywords": [ - "cache", - "caching" - ], - "time": "2017-07-22T12:49:21+00:00" - }, - { - "name": "doctrine/inflector", - "version": "v1.1.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/inflector.git", - "reference": "90b2128806bfde671b6952ab8bea493942c1fdae" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/90b2128806bfde671b6952ab8bea493942c1fdae", - "reference": "90b2128806bfde671b6952ab8bea493942c1fdae", - "shasum": "" - }, - "require": { - "php": ">=5.3.2" - }, - "require-dev": { - "phpunit/phpunit": "4.*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1.x-dev" - } - }, - "autoload": { - "psr-0": { - "Doctrine\\Common\\Inflector\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "Common String Manipulations with regard to casing and singular/plural rules.", - "homepage": "http://www.doctrine-project.org", - "keywords": [ - "inflection", - "pluralize", - "singularize", - "string" - ], - "time": "2015-11-06T14:35:42+00:00" + "time": "2020-10-26T10:28:16+00:00" }, { "name": "doctrine/instantiator", - "version": "1.3.0", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "ae466f726242e637cebdd526a7d991b9433bacf1" + "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/ae466f726242e637cebdd526a7d991b9433bacf1", - "reference": "ae466f726242e637cebdd526a7d991b9433bacf1", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/d56bf6102915de5702778fe20f2de3b2fe570b5b", + "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b", "shasum": "" }, "require": { - "php": "^7.1" + "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^6.0", + "doctrine/coding-standard": "^8.0", "ext-pdo": "*", "ext-phar": "*", - "phpbench/phpbench": "^0.13", - "phpstan/phpstan-phpunit": "^0.11", - "phpstan/phpstan-shim": "^0.11", - "phpunit/phpunit": "^7.0" + "phpbench/phpbench": "^0.13 || 1.0.0-alpha2", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, "autoload": { "psr-4": { "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" @@ -1400,7 +1219,7 @@ { "name": "Marco Pivetta", "email": "ocramius@gmail.com", - "homepage": "http://ocramius.github.com/" + "homepage": "https://ocramius.github.io/" } ], "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", @@ -1409,24 +1228,24 @@ "constructor", "instantiate" ], - "time": "2019-10-21T16:45:58+00:00" + "time": "2020-11-10T18:47:58+00:00" }, { "name": "doctrine/lexer", - "version": "1.2.0", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/doctrine/lexer.git", - "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6" + "reference": "e864bbf5904cb8f5bb334f99209b48018522f042" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6", - "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/e864bbf5904cb8f5bb334f99209b48018522f042", + "reference": "e864bbf5904cb8f5bb334f99209b48018522f042", "shasum": "" }, "require": { - "php": "^7.2" + "php": "^7.2 || ^8.0" }, "require-dev": { "doctrine/coding-standard": "^6.0", @@ -1471,20 +1290,20 @@ "parser", "php" ], - "time": "2019-10-30T14:39:59+00:00" + "time": "2020-05-25T17:44:05+00:00" }, { "name": "guzzlehttp/guzzle", - "version": "6.5.3", + "version": "6.5.5", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "aab4ebd862aa7d04f01a4b51849d657db56d882e" + "reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/aab4ebd862aa7d04f01a4b51849d657db56d882e", - "reference": "aab4ebd862aa7d04f01a4b51849d657db56d882e", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/9d4290de1cfd701f38099ef7e183b64b4b7b0c5e", + "reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e", "shasum": "" }, "require": { @@ -1492,7 +1311,7 @@ "guzzlehttp/promises": "^1.0", "guzzlehttp/psr7": "^1.6.1", "php": ">=5.5", - "symfony/polyfill-intl-idn": "^1.11" + "symfony/polyfill-intl-idn": "^1.17.0" }, "require-dev": { "ext-curl": "*", @@ -1538,27 +1357,27 @@ "rest", "web service" ], - "time": "2020-04-18T10:38:46+00:00" + "time": "2020-06-16T21:01:06+00:00" }, { "name": "guzzlehttp/promises", - "version": "v1.3.1", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" + "reference": "60d379c243457e073cff02bc323a2a86cb355631" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", - "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "url": "https://api.github.com/repos/guzzle/promises/zipball/60d379c243457e073cff02bc323a2a86cb355631", + "reference": "60d379c243457e073cff02bc323a2a86cb355631", "shasum": "" }, "require": { - "php": ">=5.5.0" + "php": ">=5.5" }, "require-dev": { - "phpunit/phpunit": "^4.0" + "symfony/phpunit-bridge": "^4.4 || ^5.1" }, "type": "library", "extra": { @@ -1589,20 +1408,20 @@ "keywords": [ "promise" ], - "time": "2016-12-20T10:07:11+00:00" + "time": "2020-09-30T07:37:28+00:00" }, { "name": "guzzlehttp/psr7", - "version": "1.6.1", + "version": "1.7.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "239400de7a173fe9901b9ac7c06497751f00727a" + "reference": "53330f47520498c0ae1f61f7e2c90f55690c06a3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/239400de7a173fe9901b9ac7c06497751f00727a", - "reference": "239400de7a173fe9901b9ac7c06497751f00727a", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/53330f47520498c0ae1f61f7e2c90f55690c06a3", + "reference": "53330f47520498c0ae1f61f7e2c90f55690c06a3", "shasum": "" }, "require": { @@ -1615,15 +1434,15 @@ }, "require-dev": { "ext-zlib": "*", - "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8" + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" }, "suggest": { - "zendframework/zend-httphandlerrunner": "Emit PSR-7 responses" + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.6-dev" + "dev-master": "1.7-dev" } }, "autoload": { @@ -1660,7 +1479,7 @@ "uri", "url" ], - "time": "2019-07-01T23:21:34+00:00" + "time": "2020-09-30T07:37:11+00:00" }, { "name": "hoa/consistency", @@ -2387,16 +2206,16 @@ }, { "name": "justinrainbow/json-schema", - "version": "5.2.9", + "version": "5.2.10", "source": { "type": "git", "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "44c6787311242a979fa15c704327c20e7221a0e4" + "reference": "2ba9c8c862ecd5510ed16c6340aa9f6eadb4f31b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/44c6787311242a979fa15c704327c20e7221a0e4", - "reference": "44c6787311242a979fa15c704327c20e7221a0e4", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/2ba9c8c862ecd5510ed16c6340aa9f6eadb4f31b", + "reference": "2ba9c8c862ecd5510ed16c6340aa9f6eadb4f31b", "shasum": "" }, "require": { @@ -2449,104 +2268,20 @@ "json", "schema" ], - "time": "2019-09-25T14:49:45+00:00" - }, - { - "name": "league/flysystem", - "version": "1.0.67", - "source": { - "type": "git", - "url": "https://github.com/thephpleague/flysystem.git", - "reference": "5b1f36c75c4bdde981294c2a0ebdb437ee6f275e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/5b1f36c75c4bdde981294c2a0ebdb437ee6f275e", - "reference": "5b1f36c75c4bdde981294c2a0ebdb437ee6f275e", - "shasum": "" - }, - "require": { - "ext-fileinfo": "*", - "php": ">=5.5.9" - }, - "conflict": { - "league/flysystem-sftp": "<1.0.6" - }, - "require-dev": { - "phpspec/phpspec": "^3.4", - "phpunit/phpunit": "^5.7.26" - }, - "suggest": { - "ext-fileinfo": "Required for MimeType", - "ext-ftp": "Allows you to use FTP server storage", - "ext-openssl": "Allows you to use FTPS server storage", - "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2", - "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3", - "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", - "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", - "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", - "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", - "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib", - "league/flysystem-webdav": "Allows you to use WebDAV storage", - "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter", - "spatie/flysystem-dropbox": "Allows you to use Dropbox storage", - "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - } - }, - "autoload": { - "psr-4": { - "League\\Flysystem\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Frank de Jonge", - "email": "info@frenky.net" - } - ], - "description": "Filesystem abstraction: Many filesystems, one API.", - "keywords": [ - "Cloud Files", - "WebDAV", - "abstraction", - "aws", - "cloud", - "copy.com", - "dropbox", - "file systems", - "files", - "filesystem", - "filesystems", - "ftp", - "rackspace", - "remote", - "s3", - "sftp", - "storage" - ], - "time": "2020-04-16T13:21:26+00:00" + "time": "2020-05-27T16:41:55+00:00" }, { "name": "monolog/monolog", - "version": "1.25.3", + "version": "1.26.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "fa82921994db851a8becaf3787a9e73c5976b6f1" + "reference": "2209ddd84e7ef1256b7af205d0717fb62cfc9c33" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fa82921994db851a8becaf3787a9e73c5976b6f1", - "reference": "fa82921994db851a8becaf3787a9e73c5976b6f1", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/2209ddd84e7ef1256b7af205d0717fb62cfc9c33", + "reference": "2209ddd84e7ef1256b7af205d0717fb62cfc9c33", "shasum": "" }, "require": { @@ -2560,11 +2295,10 @@ "aws/aws-sdk-php": "^2.4.9 || ^3.0", "doctrine/couchdb": "~1.0@dev", "graylog2/gelf-php": "~1.0", - "jakub-onderka/php-parallel-lint": "0.9", "php-amqplib/php-amqplib": "~2.4", "php-console/php-console": "^3.1.3", + "phpstan/phpstan": "^0.12.59", "phpunit/phpunit": "~4.5", - "phpunit/phpunit-mock-objects": "2.3.0", "ruflin/elastica": ">=0.90 <3.0", "sentry/sentry": "^0.13", "swiftmailer/swiftmailer": "^5.3|^6.0" @@ -2583,11 +2317,6 @@ "sentry/sentry": "Allow sending log messages to a Sentry server" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, "autoload": { "psr-4": { "Monolog\\": "src/Monolog" @@ -2611,29 +2340,29 @@ "logging", "psr-3" ], - "time": "2019-12-20T14:15:16+00:00" + "time": "2020-12-14T12:56:38+00:00" }, { "name": "mtdowling/jmespath.php", - "version": "2.5.0", + "version": "2.6.0", "source": { "type": "git", "url": "https://github.com/jmespath/jmespath.php.git", - "reference": "52168cb9472de06979613d365c7f1ab8798be895" + "reference": "42dae2cbd13154083ca6d70099692fef8ca84bfb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/52168cb9472de06979613d365c7f1ab8798be895", - "reference": "52168cb9472de06979613d365c7f1ab8798be895", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/42dae2cbd13154083ca6d70099692fef8ca84bfb", + "reference": "42dae2cbd13154083ca6d70099692fef8ca84bfb", "shasum": "" }, "require": { - "php": ">=5.4.0", - "symfony/polyfill-mbstring": "^1.4" + "php": "^5.4 || ^7.0 || ^8.0", + "symfony/polyfill-mbstring": "^1.17" }, "require-dev": { - "composer/xdebug-handler": "^1.2", - "phpunit/phpunit": "^4.8.36|^7.5.15" + "composer/xdebug-handler": "^1.4", + "phpunit/phpunit": "^4.8.36 || ^7.5.15" }, "bin": [ "bin/jp.php" @@ -2641,7 +2370,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.5-dev" + "dev-master": "2.6-dev" } }, "autoload": { @@ -2668,7 +2397,7 @@ "json", "jsonpath" ], - "time": "2019-12-30T18:03:34+00:00" + "time": "2020-07-31T21:01:56+00:00" }, { "name": "mustache/mustache", @@ -2718,20 +2447,20 @@ }, { "name": "myclabs/deep-copy", - "version": "1.9.5", + "version": "1.10.2", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef" + "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/b2c28789e80a97badd14145fda39b545d83ca3ef", - "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/776f831124e9c62e1a2c601ecc52e776d8bb7220", + "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220", "shasum": "" }, "require": { - "php": "^7.1" + "php": "^7.1 || ^8.0" }, "replace": { "myclabs/deep-copy": "self.version" @@ -2762,28 +2491,28 @@ "object", "object graph" ], - "time": "2020-01-17T21:11:47+00:00" + "time": "2020-11-13T09:40:50+00:00" }, { "name": "paragonie/constant_time_encoding", - "version": "v2.3.0", + "version": "v2.4.0", "source": { "type": "git", "url": "https://github.com/paragonie/constant_time_encoding.git", - "reference": "47a1cedd2e4d52688eb8c96469c05ebc8fd28fa2" + "reference": "f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/47a1cedd2e4d52688eb8c96469c05ebc8fd28fa2", - "reference": "47a1cedd2e4d52688eb8c96469c05ebc8fd28fa2", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c", + "reference": "f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c", "shasum": "" }, "require": { "php": "^7|^8" }, "require-dev": { - "phpunit/phpunit": "^6|^7", - "vimeo/psalm": "^1|^2|^3" + "phpunit/phpunit": "^6|^7|^8|^9", + "vimeo/psalm": "^1|^2|^3|^4" }, "type": "library", "autoload": { @@ -2824,52 +2553,7 @@ "hex2bin", "rfc4648" ], - "time": "2019-11-06T19:20:29+00:00" - }, - { - "name": "paragonie/random_compat", - "version": "v9.99.99", - "source": { - "type": "git", - "url": "https://github.com/paragonie/random_compat.git", - "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", - "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", - "shasum": "" - }, - "require": { - "php": "^7" - }, - "require-dev": { - "phpunit/phpunit": "4.*|5.*", - "vimeo/psalm": "^1" - }, - "suggest": { - "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." - }, - "type": "library", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Paragon Initiative Enterprises", - "email": "security@paragonie.com", - "homepage": "https://paragonie.com" - } - ], - "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", - "keywords": [ - "csprng", - "polyfill", - "pseudorandom", - "random" - ], - "time": "2018-07-02T15:55:56+00:00" + "time": "2020-12-06T15:14:20+00:00" }, { "name": "phar-io/manifest", @@ -3088,28 +2772,25 @@ }, { "name": "phpdocumentor/reflection-common", - "version": "2.0.0", + "version": "2.2.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a" + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a", - "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", "shasum": "" }, "require": { - "php": ">=7.1" - }, - "require-dev": { - "phpunit/phpunit": "~6" + "php": "^7.2 || ^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.x-dev" + "dev-2.x": "2.x-dev" } }, "autoload": { @@ -3136,32 +2817,31 @@ "reflection", "static analysis" ], - "time": "2018-08-07T13:53:10+00:00" + "time": "2020-06-27T09:03:43+00:00" }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.1.0", + "version": "5.2.2", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e" + "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e", - "reference": "cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/069a785b2141f5bcf49f3e353548dc1cce6df556", + "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556", "shasum": "" }, "require": { - "ext-filter": "^7.1", - "php": "^7.2", - "phpdocumentor/reflection-common": "^2.0", - "phpdocumentor/type-resolver": "^1.0", - "webmozart/assert": "^1" + "ext-filter": "*", + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.2", + "phpdocumentor/type-resolver": "^1.3", + "webmozart/assert": "^1.9.1" }, "require-dev": { - "doctrine/instantiator": "^1", - "mockery/mockery": "^1" + "mockery/mockery": "~1.3.2" }, "type": "library", "extra": { @@ -3189,34 +2869,33 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2020-02-22T12:28:44+00:00" + "time": "2020-09-03T19:13:55+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "1.1.0", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "7462d5f123dfc080dfdf26897032a6513644fc95" + "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/7462d5f123dfc080dfdf26897032a6513644fc95", - "reference": "7462d5f123dfc080dfdf26897032a6513644fc95", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", + "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", "shasum": "" }, "require": { - "php": "^7.2", + "php": "^7.2 || ^8.0", "phpdocumentor/reflection-common": "^2.0" }, "require-dev": { - "ext-tokenizer": "^7.2", - "mockery/mockery": "~1" + "ext-tokenizer": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-1.x": "1.x-dev" } }, "autoload": { @@ -3235,28 +2914,28 @@ } ], "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "time": "2020-02-18T18:59:58+00:00" + "time": "2020-09-17T18:55:26+00:00" }, { "name": "phpoption/phpoption", - "version": "1.7.3", + "version": "1.7.5", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "4acfd6a4b33a509d8c88f50e5222f734b6aeebae" + "reference": "994ecccd8f3283ecf5ac33254543eb0ac946d525" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/4acfd6a4b33a509d8c88f50e5222f734b6aeebae", - "reference": "4acfd6a4b33a509d8c88f50e5222f734b6aeebae", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/994ecccd8f3283ecf5ac33254543eb0ac946d525", + "reference": "994ecccd8f3283ecf5ac33254543eb0ac946d525", "shasum": "" }, "require": { "php": "^5.5.9 || ^7.0 || ^8.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.3", - "phpunit/phpunit": "^4.8.35 || ^5.0 || ^6.0 || ^7.0" + "bamarni/composer-bin-plugin": "^1.4.1", + "phpunit/phpunit": "^4.8.35 || ^5.7.27 || ^6.5.6 || ^7.0 || ^8.0 || ^9.0" }, "type": "library", "extra": { @@ -3290,37 +2969,37 @@ "php", "type" ], - "time": "2020-03-21T18:07:53+00:00" + "time": "2020-07-20T17:29:33+00:00" }, { "name": "phpspec/prophecy", - "version": "v1.10.3", + "version": "1.12.2", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "451c3cd1418cf640de218914901e51b064abb093" + "reference": "245710e971a030f42e08f4912863805570f23d39" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/451c3cd1418cf640de218914901e51b064abb093", - "reference": "451c3cd1418cf640de218914901e51b064abb093", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/245710e971a030f42e08f4912863805570f23d39", + "reference": "245710e971a030f42e08f4912863805570f23d39", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.0.2", - "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", - "sebastian/comparator": "^1.2.3|^2.0|^3.0|^4.0", - "sebastian/recursion-context": "^1.0|^2.0|^3.0|^4.0" + "doctrine/instantiator": "^1.2", + "php": "^7.2 || ~8.0, <8.1", + "phpdocumentor/reflection-docblock": "^5.2", + "sebastian/comparator": "^3.0 || ^4.0", + "sebastian/recursion-context": "^3.0 || ^4.0" }, "require-dev": { - "phpspec/phpspec": "^2.5 || ^3.2", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" + "phpspec/phpspec": "^6.0", + "phpunit/phpunit": "^8.0 || ^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.10.x-dev" + "dev-master": "1.11.x-dev" } }, "autoload": { @@ -3353,20 +3032,20 @@ "spy", "stub" ], - "time": "2020-03-05T15:02:03+00:00" + "time": "2020-12-19T10:15:11+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "8.0.1", + "version": "8.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "31e94ccc084025d6abee0585df533eb3a792b96a" + "reference": "ca6647ffddd2add025ab3f21644a441d7c146cdc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/31e94ccc084025d6abee0585df533eb3a792b96a", - "reference": "31e94ccc084025d6abee0585df533eb3a792b96a", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca6647ffddd2add025ab3f21644a441d7c146cdc", + "reference": "ca6647ffddd2add025ab3f21644a441d7c146cdc", "shasum": "" }, "require": { @@ -3417,27 +3096,27 @@ "testing", "xunit" ], - "time": "2020-02-19T13:41:19+00:00" + "time": "2020-05-23T08:02:54+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "3.0.1", + "version": "3.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "4ac5b3e13df14829daa60a2eb4fdd2f2b7d33cf4" + "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/4ac5b3e13df14829daa60a2eb4fdd2f2b7d33cf4", - "reference": "4ac5b3e13df14829daa60a2eb4fdd2f2b7d33cf4", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/aa4be8575f26070b100fccb67faabb28f21f66f8", + "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8", "shasum": "" }, "require": { - "php": "^7.3" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { @@ -3467,28 +3146,28 @@ "filesystem", "iterator" ], - "time": "2020-04-18T05:02:12+00:00" + "time": "2020-09-28T05:57:25+00:00" }, { "name": "phpunit/php-invoker", - "version": "3.0.0", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "7579d5a1ba7f3ac11c80004d205877911315ae7a" + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/7579d5a1ba7f3ac11c80004d205877911315ae7a", - "reference": "7579d5a1ba7f3ac11c80004d205877911315ae7a", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", "shasum": "" }, "require": { - "php": "^7.3" + "php": ">=7.3" }, "require-dev": { "ext-pcntl": "*", - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" }, "suggest": { "ext-pcntl": "*" @@ -3496,7 +3175,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.1-dev" } }, "autoload": { @@ -3520,24 +3199,27 @@ "keywords": [ "process" ], - "time": "2020-02-07T06:06:11+00:00" + "time": "2020-09-28T05:58:55+00:00" }, { "name": "phpunit/php-text-template", - "version": "2.0.0", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "526dc996cc0ebdfa428cd2dfccd79b7b53fee346" + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/526dc996cc0ebdfa428cd2dfccd79b7b53fee346", - "reference": "526dc996cc0ebdfa428cd2dfccd79b7b53fee346", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", "shasum": "" }, "require": { - "php": "^7.3" + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { @@ -3566,7 +3248,7 @@ "keywords": [ "template" ], - "time": "2020-02-01T07:43:44+00:00" + "time": "2020-10-26T05:33:50+00:00" }, { "name": "phpunit/php-timer", @@ -3619,21 +3301,21 @@ }, { "name": "phpunit/php-token-stream", - "version": "4.0.0", + "version": "4.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "b2560a0c33f7710e4d7f8780964193e8e8f8effe" + "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/b2560a0c33f7710e4d7f8780964193e8e8f8effe", - "reference": "b2560a0c33f7710e4d7f8780964193e8e8f8effe", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/a853a0e183b9db7eed023d7933a858fa1c8d25a3", + "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3", "shasum": "" }, "require": { "ext-tokenizer": "*", - "php": "^7.3" + "php": "^7.3 || ^8.0" }, "require-dev": { "phpunit/phpunit": "^9.0" @@ -3665,20 +3347,20 @@ "tokenizer" ], "abandoned": true, - "time": "2020-02-07T06:19:00+00:00" + "time": "2020-08-04T08:28:15+00:00" }, { "name": "phpunit/phpunit", - "version": "9.1.3", + "version": "9.1.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "a74780472172957a65cb5999a597e8c0878cf39c" + "reference": "1b570cd7edbe136055bf5f651857dc8af6b829d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a74780472172957a65cb5999a597e8c0878cf39c", - "reference": "a74780472172957a65cb5999a597e8c0878cf39c", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1b570cd7edbe136055bf5f651857dc8af6b829d2", + "reference": "1b570cd7edbe136055bf5f651857dc8af6b829d2", "shasum": "" }, "require": { @@ -3699,7 +3381,7 @@ "phpunit/php-invoker": "^3.0", "phpunit/php-text-template": "^2.0", "phpunit/php-timer": "^3.1.4", - "sebastian/code-unit": "^1.0", + "sebastian/code-unit": "^1.0.2", "sebastian/comparator": "^4.0", "sebastian/diff": "^4.0", "sebastian/environment": "^5.0.1", @@ -3753,7 +3435,7 @@ "testing", "xunit" ], - "time": "2020-04-23T04:42:05+00:00" + "time": "2020-05-22T13:54:05+00:00" }, { "name": "psr/cache", @@ -3851,21 +3533,71 @@ "time": "2017-02-14T16:28:37+00:00" }, { - "name": "psr/http-message", + "name": "psr/http-client", "version": "1.0.1", "source": { "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + "url": "https://github.com/php-fig/http-client.git", + "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "time": "2020-06-29T06:28:15+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" }, "type": "library", "extra": { @@ -3888,30 +3620,31 @@ "homepage": "http://www.php-fig.org/" } ], - "description": "Common interface for HTTP messages", - "homepage": "https://github.com/php-fig/http-message", + "description": "Common interfaces for PSR-7 HTTP message factories", "keywords": [ + "factory", "http", - "http-message", + "message", "psr", + "psr-17", "psr-7", "request", "response" ], - "time": "2016-08-06T14:39:51+00:00" + "time": "2019-04-30T12:38:16+00:00" }, { - "name": "psr/log", - "version": "1.1.3", + "name": "psr/http-message", + "version": "1.0.1", "source": { "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc" + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc", - "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", "shasum": "" }, "require": { @@ -3920,12 +3653,12 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1.x-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { "psr-4": { - "Psr\\Log\\": "Psr/Log/" + "Psr\\Http\\Message\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -3938,27 +3671,30 @@ "homepage": "http://www.php-fig.org/" } ], - "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", "keywords": [ - "log", + "http", + "http-message", "psr", - "psr-3" + "psr-7", + "request", + "response" ], - "time": "2020-03-23T09:12:05+00:00" + "time": "2016-08-06T14:39:51+00:00" }, { - "name": "psr/simple-cache", - "version": "1.0.1", + "name": "psr/log", + "version": "1.1.3", "source": { "type": "git", - "url": "https://github.com/php-fig/simple-cache.git", - "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + "url": "https://github.com/php-fig/log.git", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", - "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc", "shasum": "" }, "require": { @@ -3967,12 +3703,12 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.1.x-dev" } }, "autoload": { "psr-4": { - "Psr\\SimpleCache\\": "src/" + "Psr\\Log\\": "Psr/Log/" } }, "notification-url": "https://packagist.org/downloads/", @@ -3985,15 +3721,14 @@ "homepage": "http://www.php-fig.org/" } ], - "description": "Common interfaces for simple caching", + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", "keywords": [ - "cache", - "caching", + "log", "psr", - "psr-16", - "simple-cache" + "psr-3" ], - "time": "2017-10-23T01:57:42+00:00" + "time": "2020-03-23T09:12:05+00:00" }, { "name": "ralouphie/getallheaders", @@ -4035,55 +3770,127 @@ "description": "A polyfill for getallheaders.", "time": "2019-03-08T08:55:37+00:00" }, + { + "name": "ramsey/collection", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/ramsey/collection.git", + "reference": "28a5c4ab2f5111db6a60b2b4ec84057e0f43b9c1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/collection/zipball/28a5c4ab2f5111db6a60b2b4ec84057e0f43b9c1", + "reference": "28a5c4ab2f5111db6a60b2b4ec84057e0f43b9c1", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8" + }, + "require-dev": { + "captainhook/captainhook": "^5.3", + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", + "ergebnis/composer-normalize": "^2.6", + "fakerphp/faker": "^1.5", + "hamcrest/hamcrest-php": "^2", + "jangregor/phpstan-prophecy": "^0.8", + "mockery/mockery": "^1.3", + "phpstan/extension-installer": "^1", + "phpstan/phpstan": "^0.12.32", + "phpstan/phpstan-mockery": "^0.12.5", + "phpstan/phpstan-phpunit": "^0.12.11", + "phpunit/phpunit": "^8.5 || ^9", + "psy/psysh": "^0.10.4", + "slevomat/coding-standard": "^6.3", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^4.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Ramsey\\Collection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + } + ], + "description": "A PHP 7.2+ library for representing and manipulating collections.", + "keywords": [ + "array", + "collection", + "hash", + "map", + "queue", + "set" + ], + "time": "2021-01-21T17:40:04+00:00" + }, { "name": "ramsey/uuid", - "version": "3.9.3", + "version": "4.1.1", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "7e1633a6964b48589b142d60542f9ed31bd37a92" + "reference": "cd4032040a750077205918c86049aa0f43d22947" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/7e1633a6964b48589b142d60542f9ed31bd37a92", - "reference": "7e1633a6964b48589b142d60542f9ed31bd37a92", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/cd4032040a750077205918c86049aa0f43d22947", + "reference": "cd4032040a750077205918c86049aa0f43d22947", "shasum": "" }, "require": { + "brick/math": "^0.8 || ^0.9", "ext-json": "*", - "paragonie/random_compat": "^1 | ^2 | 9.99.99", - "php": "^5.4 | ^7 | ^8", + "php": "^7.2 || ^8", + "ramsey/collection": "^1.0", "symfony/polyfill-ctype": "^1.8" }, "replace": { "rhumsaa/uuid": "self.version" }, "require-dev": { - "codeception/aspect-mock": "^1 | ^2", - "doctrine/annotations": "^1.2", - "goaop/framework": "1.0.0-alpha.2 | ^1 | ^2.1", - "jakub-onderka/php-parallel-lint": "^1", - "mockery/mockery": "^0.9.11 | ^1", + "codeception/aspect-mock": "^3", + "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7.0", + "doctrine/annotations": "^1.8", + "goaop/framework": "^2", + "mockery/mockery": "^1.3", "moontoast/math": "^1.1", "paragonie/random-lib": "^2", - "php-mock/php-mock-phpunit": "^0.3 | ^1.1", - "phpunit/phpunit": "^4.8 | ^5.4 | ^6.5", - "squizlabs/php_codesniffer": "^3.5" + "php-mock/php-mock-mockery": "^1.3", + "php-mock/php-mock-phpunit": "^2.5", + "php-parallel-lint/php-parallel-lint": "^1.1", + "phpbench/phpbench": "^0.17.1", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-mockery": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpunit/phpunit": "^8.5", + "psy/psysh": "^0.10.0", + "slevomat/coding-standard": "^6.0", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "3.9.4" }, "suggest": { - "ext-ctype": "Provides support for PHP Ctype functions", - "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator", - "ext-openssl": "Provides the OpenSSL extension for use with the OpenSslGenerator", - "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator", - "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).", + "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", + "ext-ctype": "Enables faster processing of character classification using ctype functions.", + "ext-gmp": "Enables faster math with arbitrary-precision integers using GMP.", + "ext-uuid": "Enables the use of PeclUuidTimeGenerator and PeclUuidRandomGenerator.", "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter", - "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid", "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.x-dev" + "dev-master": "4.x-dev" } }, "autoload": { @@ -4098,49 +3905,34 @@ "license": [ "MIT" ], - "authors": [ - { - "name": "Ben Ramsey", - "email": "ben@benramsey.com", - "homepage": "https://benramsey.com" - }, - { - "name": "Marijn Huizendveld", - "email": "marijn.huizendveld@gmail.com" - }, - { - "name": "Thibaud Fabre", - "email": "thibaud@aztech.io" - } - ], - "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).", + "description": "A PHP library for generating and working with universally unique identifiers (UUIDs).", "homepage": "https://github.com/ramsey/uuid", "keywords": [ "guid", "identifier", "uuid" ], - "time": "2020-02-21T04:36:14+00:00" + "time": "2020-08-18T17:17:46+00:00" }, { "name": "sebastian/code-unit", - "version": "1.0.0", + "version": "1.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "8d8f09bd47c75159921e6e84fdef146343962866" + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/8d8f09bd47c75159921e6e84fdef146343962866", - "reference": "8d8f09bd47c75159921e6e84fdef146343962866", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", "shasum": "" }, "require": { - "php": "^7.3" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { @@ -4166,27 +3958,27 @@ ], "description": "Collection of value objects that represent the PHP code units", "homepage": "https://github.com/sebastianbergmann/code-unit", - "time": "2020-03-30T11:59:20+00:00" + "time": "2020-10-26T13:08:54+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", - "version": "2.0.0", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "5b5dbe0044085ac41df47e79d34911a15b96d82e" + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5b5dbe0044085ac41df47e79d34911a15b96d82e", - "reference": "5b5dbe0044085ac41df47e79d34911a15b96d82e", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", "shasum": "" }, "require": { - "php": "^7.3" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { @@ -4211,29 +4003,29 @@ ], "description": "Looks up which function or method a line of code belongs to", "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "time": "2020-02-07T06:20:13+00:00" + "time": "2020-09-28T05:30:19+00:00" }, { "name": "sebastian/comparator", - "version": "4.0.0", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "85b3435da967696ed618ff745f32be3ff4a2b8e8" + "reference": "55f4261989e546dc112258c7a75935a81a7ce382" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/85b3435da967696ed618ff745f32be3ff4a2b8e8", - "reference": "85b3435da967696ed618ff745f32be3ff4a2b8e8", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55f4261989e546dc112258c7a75935a81a7ce382", + "reference": "55f4261989e546dc112258c7a75935a81a7ce382", "shasum": "" }, "require": { - "php": "^7.3", + "php": ">=7.3", "sebastian/diff": "^4.0", "sebastian/exporter": "^4.0" }, "require-dev": { - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { @@ -4275,28 +4067,28 @@ "compare", "equality" ], - "time": "2020-02-07T06:08:51+00:00" + "time": "2020-10-26T15:49:45+00:00" }, { "name": "sebastian/diff", - "version": "4.0.0", + "version": "4.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "c0c26c9188b538bfa985ae10c9f05d278f12060d" + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c0c26c9188b538bfa985ae10c9f05d278f12060d", - "reference": "c0c26c9188b538bfa985ae10c9f05d278f12060d", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", "shasum": "" }, "require": { - "php": "^7.3" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^9.0", - "symfony/process": "^4 || ^5" + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" }, "type": "library", "extra": { @@ -4331,27 +4123,27 @@ "unidiff", "unified diff" ], - "time": "2020-02-07T06:09:38+00:00" + "time": "2020-10-26T13:10:38+00:00" }, { "name": "sebastian/environment", - "version": "5.1.0", + "version": "5.1.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "c753f04d68cd489b6973cf9b4e505e191af3b05c" + "reference": "388b6ced16caa751030f6a69e588299fa09200ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/c753f04d68cd489b6973cf9b4e505e191af3b05c", - "reference": "c753f04d68cd489b6973cf9b4e505e191af3b05c", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/388b6ced16caa751030f6a69e588299fa09200ac", + "reference": "388b6ced16caa751030f6a69e588299fa09200ac", "shasum": "" }, "require": { - "php": "^7.3" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" }, "suggest": { "ext-posix": "*" @@ -4359,7 +4151,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "5.1-dev" } }, "autoload": { @@ -4384,29 +4176,29 @@ "environment", "hhvm" ], - "time": "2020-04-14T13:36:52+00:00" + "time": "2020-09-28T05:52:38+00:00" }, { "name": "sebastian/exporter", - "version": "4.0.0", + "version": "4.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "80c26562e964016538f832f305b2286e1ec29566" + "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/80c26562e964016538f832f305b2286e1ec29566", - "reference": "80c26562e964016538f832f305b2286e1ec29566", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/d89cc98761b8cb5a1a235a6b703ae50d34080e65", + "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65", "shasum": "" }, "require": { - "php": "^7.3", + "php": ">=7.3", "sebastian/recursion-context": "^4.0" }, "require-dev": { "ext-mbstring": "*", - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { @@ -4451,7 +4243,7 @@ "export", "exporter" ], - "time": "2020-02-07T06:10:52+00:00" + "time": "2020-09-28T05:24:23+00:00" }, { "name": "sebastian/global-state", @@ -4509,25 +4301,25 @@ }, { "name": "sebastian/object-enumerator", - "version": "4.0.0", + "version": "4.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "e67516b175550abad905dc952f43285957ef4363" + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/e67516b175550abad905dc952f43285957ef4363", - "reference": "e67516b175550abad905dc952f43285957ef4363", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", "shasum": "" }, "require": { - "php": "^7.3", + "php": ">=7.3", "sebastian/object-reflector": "^2.0", "sebastian/recursion-context": "^4.0" }, "require-dev": { - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { @@ -4552,27 +4344,27 @@ ], "description": "Traverses array structures and object graphs to enumerate all referenced objects", "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2020-02-07T06:12:23+00:00" + "time": "2020-10-26T13:12:34+00:00" }, { "name": "sebastian/object-reflector", - "version": "2.0.0", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "f4fd0835cabb0d4a6546d9fe291e5740037aa1e7" + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/f4fd0835cabb0d4a6546d9fe291e5740037aa1e7", - "reference": "f4fd0835cabb0d4a6546d9fe291e5740037aa1e7", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", "shasum": "" }, "require": { - "php": "^7.3" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { @@ -4597,27 +4389,27 @@ ], "description": "Allows reflection of object attributes, including inherited and non-public ones", "homepage": "https://github.com/sebastianbergmann/object-reflector/", - "time": "2020-02-07T06:19:40+00:00" + "time": "2020-10-26T13:14:26+00:00" }, { "name": "sebastian/recursion-context", - "version": "4.0.0", + "version": "4.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "cdd86616411fc3062368b720b0425de10bd3d579" + "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/cdd86616411fc3062368b720b0425de10bd3d579", - "reference": "cdd86616411fc3062368b720b0425de10bd3d579", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/cd9d8cf3c5804de4341c283ed787f099f5506172", + "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172", "shasum": "" }, "require": { - "php": "^7.3" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { @@ -4650,24 +4442,24 @@ ], "description": "Provides functionality to recursively process PHP variables", "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2020-02-07T06:18:20+00:00" + "time": "2020-10-26T13:17:30+00:00" }, { "name": "sebastian/resource-operations", - "version": "3.0.0", + "version": "3.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "8c98bf0dfa1f9256d0468b9803a1e1df31b6fa98" + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/8c98bf0dfa1f9256d0468b9803a1e1df31b6fa98", - "reference": "8c98bf0dfa1f9256d0468b9803a1e1df31b6fa98", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", "shasum": "" }, "require": { - "php": "^7.3" + "php": ">=7.3" }, "require-dev": { "phpunit/phpunit": "^9.0" @@ -4695,32 +4487,32 @@ ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2020-02-07T06:13:02+00:00" + "time": "2020-09-28T06:45:17+00:00" }, { "name": "sebastian/type", - "version": "2.0.0", + "version": "2.3.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "9e8f42f740afdea51f5f4e8cec2035580e797ee1" + "reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/9e8f42f740afdea51f5f4e8cec2035580e797ee1", - "reference": "9e8f42f740afdea51f5f4e8cec2035580e797ee1", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/81cd61ab7bbf2de744aba0ea61fae32f721df3d2", + "reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2", "shasum": "" }, "require": { - "php": "^7.3" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "2.3-dev" } }, "autoload": { @@ -4741,24 +4533,24 @@ ], "description": "Collection of value objects that represent the types of the PHP type system", "homepage": "https://github.com/sebastianbergmann/type", - "time": "2020-02-07T06:13:43+00:00" + "time": "2020-10-26T13:18:59+00:00" }, { "name": "sebastian/version", - "version": "3.0.0", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", - "reference": "0411bde656dce64202b39c2f4473993a9081d39e" + "reference": "c6c1022351a901512170118436c764e473f6de8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/0411bde656dce64202b39c2f4473993a9081d39e", - "reference": "0411bde656dce64202b39c2f4473993a9081d39e", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", "shasum": "" }, "require": { - "php": "^7.3" + "php": ">=7.3" }, "type": "library", "extra": { @@ -4784,24 +4576,24 @@ ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", - "time": "2020-01-21T06:36:37+00:00" + "time": "2020-09-28T06:39:44+00:00" }, { "name": "seld/jsonlint", - "version": "1.7.2", + "version": "1.8.3", "source": { "type": "git", "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "e2e5d290e4d2a4f0eb449f510071392e00e10d19" + "reference": "9ad6ce79c342fbd44df10ea95511a1b24dee5b57" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/e2e5d290e4d2a4f0eb449f510071392e00e10d19", - "reference": "e2e5d290e4d2a4f0eb449f510071392e00e10d19", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/9ad6ce79c342fbd44df10ea95511a1b24dee5b57", + "reference": "9ad6ce79c342fbd44df10ea95511a1b24dee5b57", "shasum": "" }, "require": { - "php": "^5.3 || ^7.0" + "php": "^5.3 || ^7.0 || ^8.0" }, "require-dev": { "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" @@ -4833,20 +4625,20 @@ "parser", "validator" ], - "time": "2019-10-24T14:27:39+00:00" + "time": "2020-11-11T09:19:24+00:00" }, { "name": "seld/phar-utils", - "version": "1.1.0", + "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/Seldaek/phar-utils.git", - "reference": "8800503d56b9867d43d9c303b9cbcc26016e82f0" + "reference": "8674b1d84ffb47cc59a101f5d5a3b61e87d23796" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/8800503d56b9867d43d9c303b9cbcc26016e82f0", - "reference": "8800503d56b9867d43d9c303b9cbcc26016e82f0", + "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/8674b1d84ffb47cc59a101f5d5a3b61e87d23796", + "reference": "8674b1d84ffb47cc59a101f5d5a3b61e87d23796", "shasum": "" }, "require": { @@ -4877,7 +4669,7 @@ "keywords": [ "phar" ], - "time": "2020-02-14T15:25:33+00:00" + "time": "2020-07-07T18:42:57+00:00" }, { "name": "spomky-labs/otphp", @@ -4952,22 +4744,23 @@ }, { "name": "symfony/console", - "version": "v4.4.7", + "version": "v4.4.18", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "10bb3ee3c97308869d53b3e3d03f6ac23ff985f7" + "reference": "12e071278e396cc3e1c149857337e9e192deca0b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/10bb3ee3c97308869d53b3e3d03f6ac23ff985f7", - "reference": "10bb3ee3c97308869d53b3e3d03f6ac23ff985f7", + "url": "https://api.github.com/repos/symfony/console/zipball/12e071278e396cc3e1c149857337e9e192deca0b", + "reference": "12e071278e396cc3e1c149857337e9e192deca0b", "shasum": "" }, "require": { - "php": "^7.1.3", + "php": ">=7.1.3", "symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-php73": "^1.8", + "symfony/polyfill-php80": "^1.15", "symfony/service-contracts": "^1.1|^2" }, "conflict": { @@ -4995,11 +4788,6 @@ "symfony/process": "" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Console\\": "" @@ -5024,31 +4812,26 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2020-03-30T11:41:10+00:00" + "time": "2020-12-18T07:41:31+00:00" }, { "name": "symfony/css-selector", - "version": "v5.0.7", + "version": "v5.2.1", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "5f8d5271303dad260692ba73dfa21777d38e124e" + "reference": "f789e7ead4c79e04ca9a6d6162fc629c89bd8054" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/5f8d5271303dad260692ba73dfa21777d38e124e", - "reference": "5f8d5271303dad260692ba73dfa21777d38e124e", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/f789e7ead4c79e04ca9a6d6162fc629c89bd8054", + "reference": "f789e7ead4c79e04ca9a6d6162fc629c89bd8054", "shasum": "" }, "require": { - "php": "^7.2.5" + "php": ">=7.2.5" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\CssSelector\\": "" @@ -5077,20 +4860,20 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "time": "2020-03-27T16:56:45+00:00" + "time": "2020-12-08T17:02:38+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v2.1.3", + "version": "v2.2.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "5e20b83385a77593259c9f8beb2c43cd03b2ac14" + "reference": "5fa56b4074d1ae755beb55617ddafe6f5d78f665" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5e20b83385a77593259c9f8beb2c43cd03b2ac14", - "reference": "5e20b83385a77593259c9f8beb2c43cd03b2ac14", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5fa56b4074d1ae755beb55617ddafe6f5d78f665", + "reference": "5fa56b4074d1ae755beb55617ddafe6f5d78f665", "shasum": "" }, "require": { @@ -5099,7 +4882,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1-dev" + "dev-master": "2.2-dev" }, "thanks": { "name": "symfony/contracts", @@ -5127,24 +4910,24 @@ ], "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", - "time": "2020-06-06T08:49:21+00:00" + "time": "2020-09-07T11:33:47+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v4.4.7", + "version": "v4.4.18", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "abc8e3618bfdb55e44c8c6a00abd333f831bbfed" + "reference": "5d4c874b0eb1c32d40328a09dbc37307a5a910b0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/abc8e3618bfdb55e44c8c6a00abd333f831bbfed", - "reference": "abc8e3618bfdb55e44c8c6a00abd333f831bbfed", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/5d4c874b0eb1c32d40328a09dbc37307a5a910b0", + "reference": "5d4c874b0eb1c32d40328a09dbc37307a5a910b0", "shasum": "" }, "require": { - "php": "^7.1.3", + "php": ">=7.1.3", "symfony/event-dispatcher-contracts": "^1.1" }, "conflict": { @@ -5158,6 +4941,7 @@ "psr/log": "~1.0", "symfony/config": "^3.4|^4.0|^5.0", "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/error-handler": "~3.4|~4.4", "symfony/expression-language": "^3.4|^4.0|^5.0", "symfony/http-foundation": "^3.4|^4.0|^5.0", "symfony/service-contracts": "^1.1|^2", @@ -5168,11 +4952,6 @@ "symfony/http-kernel": "" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\EventDispatcher\\": "" @@ -5197,24 +4976,24 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2020-03-27T16:54:36+00:00" + "time": "2020-12-18T07:41:31+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v1.1.7", + "version": "v1.1.9", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "c43ab685673fb6c8d84220c77897b1d6cdbe1d18" + "reference": "84e23fdcd2517bf37aecbd16967e83f0caee25a7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/c43ab685673fb6c8d84220c77897b1d6cdbe1d18", - "reference": "c43ab685673fb6c8d84220c77897b1d6cdbe1d18", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/84e23fdcd2517bf37aecbd16967e83f0caee25a7", + "reference": "84e23fdcd2517bf37aecbd16967e83f0caee25a7", "shasum": "" }, "require": { - "php": "^7.1.3" + "php": ">=7.1.3" }, "suggest": { "psr/event-dispatcher": "", @@ -5224,6 +5003,10 @@ "extra": { "branch-alias": { "dev-master": "1.1-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -5255,32 +5038,27 @@ "interoperability", "standards" ], - "time": "2019-09-17T09:54:03+00:00" + "time": "2020-07-06T13:19:58+00:00" }, { "name": "symfony/filesystem", - "version": "v5.0.7", + "version": "v5.2.1", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "ca3b87dd09fff9b771731637f5379965fbfab420" + "reference": "fa8f8cab6b65e2d99a118e082935344c5ba8c60d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/ca3b87dd09fff9b771731637f5379965fbfab420", - "reference": "ca3b87dd09fff9b771731637f5379965fbfab420", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/fa8f8cab6b65e2d99a118e082935344c5ba8c60d", + "reference": "fa8f8cab6b65e2d99a118e082935344c5ba8c60d", "shasum": "" }, "require": { - "php": "^7.2.5", + "php": ">=7.2.5", "symfony/polyfill-ctype": "~1.8" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Filesystem\\": "" @@ -5305,31 +5083,26 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2020-03-27T16:56:45+00:00" + "time": "2020-11-30T17:05:38+00:00" }, { "name": "symfony/finder", - "version": "v5.0.7", + "version": "v5.2.1", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "600a52c29afc0d1caa74acbec8d3095ca7e9910d" + "reference": "0b9231a5922fd7287ba5b411893c0ecd2733e5ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/600a52c29afc0d1caa74acbec8d3095ca7e9910d", - "reference": "600a52c29afc0d1caa74acbec8d3095ca7e9910d", + "url": "https://api.github.com/repos/symfony/finder/zipball/0b9231a5922fd7287ba5b411893c0ecd2733e5ba", + "reference": "0b9231a5922fd7287ba5b411893c0ecd2733e5ba", "shasum": "" }, "require": { - "php": "^7.2.5" + "php": ">=7.2.5" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Finder\\": "" @@ -5354,20 +5127,20 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2020-03-27T16:56:45+00:00" + "time": "2020-12-08T17:02:38+00:00" }, { "name": "symfony/http-foundation", - "version": "v5.1.2", + "version": "v5.2.1", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "f93055171b847915225bd5b0a5792888419d8d75" + "reference": "a1f6218b29897ab52acba58cfa905b83625bef8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/f93055171b847915225bd5b0a5792888419d8d75", - "reference": "f93055171b847915225bd5b0a5792888419d8d75", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/a1f6218b29897ab52acba58cfa905b83625bef8d", + "reference": "a1f6218b29897ab52acba58cfa905b83625bef8d", "shasum": "" }, "require": { @@ -5386,11 +5159,6 @@ "symfony/mime": "To use the file extension guesser" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.1-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\HttpFoundation\\": "" @@ -5415,40 +5183,41 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2020-06-15T06:52:54+00:00" + "time": "2020-12-18T10:00:10+00:00" }, { "name": "symfony/mime", - "version": "v5.0.7", + "version": "v5.2.1", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "481b7d6da88922fb1e0d86a943987722b08f3955" + "reference": "de97005aef7426ba008c46ba840fc301df577ada" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/481b7d6da88922fb1e0d86a943987722b08f3955", - "reference": "481b7d6da88922fb1e0d86a943987722b08f3955", + "url": "https://api.github.com/repos/symfony/mime/zipball/de97005aef7426ba008c46ba840fc301df577ada", + "reference": "de97005aef7426ba008c46ba840fc301df577ada", "shasum": "" }, "require": { - "php": "^7.2.5", + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", "symfony/polyfill-intl-idn": "^1.10", - "symfony/polyfill-mbstring": "^1.0" + "symfony/polyfill-mbstring": "^1.0", + "symfony/polyfill-php80": "^1.15" }, "conflict": { "symfony/mailer": "<4.4" }, "require-dev": { "egulias/email-validator": "^2.1.10", - "symfony/dependency-injection": "^4.4|^5.0" + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/property-access": "^4.4|^5.1", + "symfony/property-info": "^4.4|^5.1", + "symfony/serializer": "^5.2" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Mime\\": "" @@ -5477,24 +5246,24 @@ "mime", "mime-type" ], - "time": "2020-03-27T16:56:45+00:00" + "time": "2020-12-09T18:54:12+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.15.0", + "version": "v1.22.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "4719fa9c18b0464d399f1a63bf624b42b6fa8d14" + "reference": "c6c942b1ac76c82448322025e084cadc56048b4e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/4719fa9c18b0464d399f1a63bf624b42b6fa8d14", - "reference": "4719fa9c18b0464d399f1a63bf624b42b6fa8d14", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/c6c942b1ac76c82448322025e084cadc56048b4e", + "reference": "c6c942b1ac76c82448322025e084cadc56048b4e", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.1" }, "suggest": { "ext-ctype": "For best performance" @@ -5502,7 +5271,11 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.15-dev" + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { @@ -5535,25 +5308,25 @@ "polyfill", "portable" ], - "time": "2020-02-27T09:26:54+00:00" + "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.15.0", + "version": "v1.22.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf" + "reference": "0eb8293dbbcd6ef6bf81404c9ce7d95bcdf34f44" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf", - "reference": "47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/0eb8293dbbcd6ef6bf81404c9ce7d95bcdf34f44", + "reference": "0eb8293dbbcd6ef6bf81404c9ce7d95bcdf34f44", "shasum": "" }, "require": { - "php": ">=5.3.3", - "symfony/polyfill-mbstring": "^1.3", + "php": ">=7.1", + "symfony/polyfill-intl-normalizer": "^1.10", "symfony/polyfill-php72": "^1.10" }, "suggest": { @@ -5562,7 +5335,11 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.15-dev" + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { @@ -5582,6 +5359,10 @@ "name": "Laurent Bassin", "email": "laurent@bassin.info" }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" @@ -5597,24 +5378,91 @@ "portable", "shim" ], - "time": "2020-03-09T19:04:49+00:00" + "time": "2021-01-07T16:49:33+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.22.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "6e971c891537eb617a00bb07a43d182a6915faba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/6e971c891537eb617a00bb07a43d182a6915faba", + "reference": "6e971c891537eb617a00bb07a43d182a6915faba", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "time": "2021-01-07T17:09:11+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.15.0", + "version": "v1.22.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac" + "reference": "f377a3dd1fde44d37b9831d68dc8dea3ffd28e13" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/81ffd3a9c6d707be22e3012b827de1c9775fc5ac", - "reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/f377a3dd1fde44d37b9831d68dc8dea3ffd28e13", + "reference": "f377a3dd1fde44d37b9831d68dc8dea3ffd28e13", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.1" }, "suggest": { "ext-mbstring": "For best performance" @@ -5622,7 +5470,11 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.15-dev" + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { @@ -5656,29 +5508,33 @@ "portable", "shim" ], - "time": "2020-03-09T19:04:49+00:00" + "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.15.0", + "version": "v1.22.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "37b0976c78b94856543260ce09b460a7bc852747" + "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/37b0976c78b94856543260ce09b460a7bc852747", - "reference": "37b0976c78b94856543260ce09b460a7bc852747", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", + "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.15-dev" + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { @@ -5711,29 +5567,33 @@ "portable", "shim" ], - "time": "2020-02-27T09:26:54+00:00" + "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.15.0", + "version": "v1.22.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7" + "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7", - "reference": "0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", + "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.15-dev" + "dev-main": "1.22-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { @@ -5769,29 +5629,29 @@ "portable", "shim" ], - "time": "2020-02-27T09:26:54+00:00" + "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.17.1", + "version": "v1.22.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "4a5b6bba3259902e386eb80dd1956181ee90b5b2" + "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4a5b6bba3259902e386eb80dd1956181ee90b5b2", - "reference": "4a5b6bba3259902e386eb80dd1956181ee90b5b2", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dc3063ba22c2a1fd2f45ed856374d79114998f91", + "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91", "shasum": "" }, "require": { - "php": ">=7.0.8" + "php": ">=7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.17-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -5835,31 +5695,26 @@ "portable", "shim" ], - "time": "2020-06-06T08:46:27+00:00" + "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/process", - "version": "v4.4.7", + "version": "v4.4.18", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "3e40e87a20eaf83a1db825e1fa5097ae89042db3" + "reference": "075316ff72233ce3d04a9743414292e834f2cb4a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/3e40e87a20eaf83a1db825e1fa5097ae89042db3", - "reference": "3e40e87a20eaf83a1db825e1fa5097ae89042db3", + "url": "https://api.github.com/repos/symfony/process/zipball/075316ff72233ce3d04a9743414292e834f2cb4a", + "reference": "075316ff72233ce3d04a9743414292e834f2cb4a", "shasum": "" }, "require": { - "php": "^7.1.3" + "php": ">=7.1.3" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Process\\": "" @@ -5884,24 +5739,24 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2020-03-27T16:54:36+00:00" + "time": "2020-12-08T16:59:59+00:00" }, { "name": "symfony/service-contracts", - "version": "v2.0.1", + "version": "v2.2.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "144c5e51266b281231e947b51223ba14acf1a749" + "reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/144c5e51266b281231e947b51223ba14acf1a749", - "reference": "144c5e51266b281231e947b51223ba14acf1a749", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d15da7ba4957ffb8f1747218be9e1a121fd298a1", + "reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1", "shasum": "" }, "require": { - "php": "^7.2.5", + "php": ">=7.2.5", "psr/container": "^1.0" }, "suggest": { @@ -5910,7 +5765,11 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "2.2-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -5942,24 +5801,24 @@ "interoperability", "standards" ], - "time": "2019-11-18T17:27:11+00:00" + "time": "2020-09-07T11:33:47+00:00" }, { "name": "symfony/yaml", - "version": "v4.4.7", + "version": "v4.4.18", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "ef166890d821518106da3560086bfcbeb4fadfec" + "reference": "bbce94f14d73732340740366fcbe63363663a403" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/ef166890d821518106da3560086bfcbeb4fadfec", - "reference": "ef166890d821518106da3560086bfcbeb4fadfec", + "url": "https://api.github.com/repos/symfony/yaml/zipball/bbce94f14d73732340740366fcbe63363663a403", + "reference": "bbce94f14d73732340740366fcbe63363663a403", "shasum": "" }, "require": { - "php": "^7.1.3", + "php": ">=7.1.3", "symfony/polyfill-ctype": "~1.8" }, "conflict": { @@ -5972,11 +5831,6 @@ "symfony/console": "For validating YAML files using the lint command" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Yaml\\": "" @@ -6001,20 +5855,20 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2020-03-30T11:41:10+00:00" + "time": "2020-12-08T16:59:59+00:00" }, { "name": "thecodingmachine/safe", - "version": "v1.1", + "version": "v1.3.3", "source": { "type": "git", "url": "https://github.com/thecodingmachine/safe.git", - "reference": "f440677bad66c0ef42fa3f875bf05718028af5d3" + "reference": "a8ab0876305a4cdaef31b2350fcb9811b5608dbc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/f440677bad66c0ef42fa3f875bf05718028af5d3", - "reference": "f440677bad66c0ef42fa3f875bf05718028af5d3", + "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/a8ab0876305a4cdaef31b2350fcb9811b5608dbc", + "reference": "a8ab0876305a4cdaef31b2350fcb9811b5608dbc", "shasum": "" }, "require": { @@ -6035,15 +5889,21 @@ "psr-4": { "Safe\\": [ "lib/", + "deprecated/", "generated/" ] }, "files": [ + "deprecated/apc.php", + "deprecated/libevent.php", + "deprecated/mssql.php", + "deprecated/stats.php", + "lib/special_cases.php", "generated/apache.php", - "generated/apc.php", "generated/apcu.php", "generated/array.php", "generated/bzip2.php", + "generated/calendar.php", "generated/classobj.php", "generated/com.php", "generated/cubrid.php", @@ -6072,14 +5932,12 @@ "generated/inotify.php", "generated/json.php", "generated/ldap.php", - "generated/libevent.php", "generated/libxml.php", "generated/lzf.php", "generated/mailparse.php", "generated/mbstring.php", "generated/misc.php", "generated/msql.php", - "generated/mssql.php", "generated/mysql.php", "generated/mysqli.php", "generated/mysqlndMs.php", @@ -6098,6 +5956,7 @@ "generated/ps.php", "generated/pspell.php", "generated/readline.php", + "generated/rpminfo.php", "generated/rrd.php", "generated/sem.php", "generated/session.php", @@ -6110,7 +5969,6 @@ "generated/sqlsrv.php", "generated/ssdeep.php", "generated/ssh2.php", - "generated/stats.php", "generated/stream.php", "generated/strings.php", "generated/swoole.php", @@ -6124,8 +5982,7 @@ "generated/yaml.php", "generated/yaz.php", "generated/zip.php", - "generated/zlib.php", - "lib/special_cases.php" + "generated/zlib.php" ] }, "notification-url": "https://packagist.org/downloads/", @@ -6133,27 +5990,27 @@ "MIT" ], "description": "PHP core functions that throw exceptions instead of returning FALSE on error", - "time": "2020-03-24T13:59:42+00:00" + "time": "2020-10-28T17:51:34+00:00" }, { "name": "theseer/tokenizer", - "version": "1.1.3", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9" + "reference": "75a63c33a8577608444246075ea0af0d052e452a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9", - "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/75a63c33a8577608444246075ea0af0d052e452a", + "reference": "75a63c33a8577608444246075ea0af0d052e452a", "shasum": "" }, "require": { "ext-dom": "*", "ext-tokenizer": "*", "ext-xmlwriter": "*", - "php": "^7.0" + "php": "^7.2 || ^8.0" }, "type": "library", "autoload": { @@ -6173,30 +6030,30 @@ } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "time": "2019-06-13T22:48:21+00:00" + "time": "2020-07-12T23:59:07+00:00" }, { "name": "vlucas/phpdotenv", - "version": "v2.6.3", + "version": "v2.6.7", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "df4c4d08a639be4ef5d6d1322868f9e477553679" + "reference": "b786088918a884258c9e3e27405c6a4cf2ee246e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/df4c4d08a639be4ef5d6d1322868f9e477553679", - "reference": "df4c4d08a639be4ef5d6d1322868f9e477553679", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/b786088918a884258c9e3e27405c6a4cf2ee246e", + "reference": "b786088918a884258c9e3e27405c6a4cf2ee246e", "shasum": "" }, "require": { - "php": ">=5.3.9", - "symfony/polyfill-ctype": "^1.9" + "php": "^5.3.9 || ^7.0 || ^8.0", + "symfony/polyfill-ctype": "^1.17" }, "require-dev": { "ext-filter": "*", "ext-pcre": "*", - "phpunit/phpunit": "^4.8.35 || ^5.0" + "phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20" }, "suggest": { "ext-filter": "Required to use the boolean validator.", @@ -6218,10 +6075,15 @@ "BSD-3-Clause" ], "authors": [ + { + "name": "Graham Campbell", + "email": "graham@alt-three.com", + "homepage": "https://gjcampbell.co.uk/" + }, { "name": "Vance Lucas", "email": "vance@vancelucas.com", - "homepage": "http://www.vancelucas.com" + "homepage": "https://vancelucas.com/" } ], "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", @@ -6230,27 +6092,28 @@ "env", "environment" ], - "time": "2020-04-12T15:11:38+00:00" + "time": "2021-01-20T14:39:13+00:00" }, { "name": "webmozart/assert", - "version": "1.8.0", + "version": "1.9.1", "source": { "type": "git", - "url": "https://github.com/webmozart/assert.git", - "reference": "ab2cb0b3b559010b75981b1bdce728da3ee90ad6" + "url": "https://github.com/webmozarts/assert.git", + "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/ab2cb0b3b559010b75981b1bdce728da3ee90ad6", - "reference": "ab2cb0b3b559010b75981b1bdce728da3ee90ad6", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389", + "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0", + "php": "^5.3.3 || ^7.0 || ^8.0", "symfony/polyfill-ctype": "^1.8" }, "conflict": { + "phpstan/phpstan": "<0.12.20", "vimeo/psalm": "<3.9.1" }, "require-dev": { @@ -6278,7 +6141,7 @@ "check", "validate" ], - "time": "2020-04-18T12:12:48+00:00" + "time": "2020-07-08T17:02:28+00:00" }, { "name": "weew/helpers-array", @@ -6479,28 +6342,99 @@ "description": "Experimental Mocking Framework powered by Aspects", "time": "2020-02-29T15:39:49+00:00" }, + { + "name": "doctrine/cache", + "version": "v1.6.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/cache.git", + "reference": "eb152c5100571c7a45470ff2a35095ab3f3b900b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/cache/zipball/eb152c5100571c7a45470ff2a35095ab3f3b900b", + "reference": "eb152c5100571c7a45470ff2a35095ab3f3b900b", + "shasum": "" + }, + "require": { + "php": "~5.5|~7.0" + }, + "conflict": { + "doctrine/common": ">2.2,<2.4" + }, + "require-dev": { + "phpunit/phpunit": "~4.8|~5.0", + "predis/predis": "~1.0", + "satooshi/php-coveralls": "~0.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Caching library offering an object-oriented API for many cache backends", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "cache", + "caching" + ], + "time": "2017-07-22T12:49:21+00:00" + }, { "name": "gitonomy/gitlib", - "version": "v1.2.1", + "version": "v1.2.3", "source": { "type": "git", "url": "https://github.com/gitonomy/gitlib.git", - "reference": "718ca021c67f3ea8f6a5fa5d231ec49675068868" + "reference": "d22f212b97fdb631ac73dfae65c194dc4cb0d227" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/gitonomy/gitlib/zipball/718ca021c67f3ea8f6a5fa5d231ec49675068868", - "reference": "718ca021c67f3ea8f6a5fa5d231ec49675068868", + "url": "https://api.github.com/repos/gitonomy/gitlib/zipball/d22f212b97fdb631ac73dfae65c194dc4cb0d227", + "reference": "d22f212b97fdb631ac73dfae65c194dc4cb0d227", "shasum": "" }, "require": { "ext-pcre": "*", - "php": "^5.6 || ^7.0", + "php": "^5.6 || ^7.0 || ^8.0", "symfony/polyfill-mbstring": "^1.7", - "symfony/process": "^3.4|^4.0|^5.0" + "symfony/process": "^3.4 || ^4.0 || ^5.0" }, "require-dev": { - "phpunit/phpunit": "^5.7|^6.5|^7.0", + "ext-fileinfo": "*", + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.0 || ^8.0 || ^9.0", "psr/log": "^1.0" }, "suggest": { @@ -6508,11 +6442,6 @@ "psr/log": "Required to use loggers for reporting of execution" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2-dev" - } - }, "autoload": { "psr-4": { "Gitonomy\\Git\\": "src/Gitonomy/Git/" @@ -6541,7 +6470,7 @@ } ], "description": "Library for accessing git", - "time": "2020-03-23T12:43:44+00:00" + "time": "2020-12-29T16:48:45+00:00" }, { "name": "goaop/framework", @@ -6613,20 +6542,20 @@ }, { "name": "goaop/parser-reflection", - "version": "2.1.1", + "version": "2.1.3", "source": { "type": "git", "url": "https://github.com/goaop/parser-reflection.git", - "reference": "e9628006b321c8a62a8ad22085bc61eec0c21558" + "reference": "2e837e150e15d38f7004b0dbcd0af4abe034c9e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/goaop/parser-reflection/zipball/e9628006b321c8a62a8ad22085bc61eec0c21558", - "reference": "e9628006b321c8a62a8ad22085bc61eec0c21558", + "url": "https://api.github.com/repos/goaop/parser-reflection/zipball/2e837e150e15d38f7004b0dbcd0af4abe034c9e2", + "reference": "2e837e150e15d38f7004b0dbcd0af4abe034c9e2", "shasum": "" }, "require": { - "nikic/php-parser": "^4.0", + "nikic/php-parser": "^4.0 <4.7.0", "php": ">=7.1" }, "require-dev": { @@ -6635,7 +6564,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.x-dev" + "dev-master": "3.x-dev" } }, "autoload": { @@ -6660,7 +6589,7 @@ } ], "description": "Provides reflection information, based on raw source", - "time": "2020-02-21T19:52:39+00:00" + "time": "2020-08-13T21:02:42+00:00" }, { "name": "guzzle/guzzle", @@ -6812,16 +6741,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.4.0", + "version": "v4.6.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "bd43ec7152eaaab3bd8c6d0aa95ceeb1df8ee120" + "reference": "c346bbfafe2ff60680258b631afb730d186ed864" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/bd43ec7152eaaab3bd8c6d0aa95ceeb1df8ee120", - "reference": "bd43ec7152eaaab3bd8c6d0aa95ceeb1df8ee120", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/c346bbfafe2ff60680258b631afb730d186ed864", + "reference": "c346bbfafe2ff60680258b631afb730d186ed864", "shasum": "" }, "require": { @@ -6860,20 +6789,20 @@ "parser", "php" ], - "time": "2020-04-10T16:34:50+00:00" + "time": "2020-07-02T17:12:47+00:00" }, { "name": "pdepend/pdepend", - "version": "2.7.1", + "version": "2.8.0", "source": { "type": "git", "url": "https://github.com/pdepend/pdepend.git", - "reference": "daba1cf0a6edaf172fa02a17807ae29f4c1c7471" + "reference": "c64472f8e76ca858c79ad9a4cf1e2734b3f8cc38" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pdepend/pdepend/zipball/daba1cf0a6edaf172fa02a17807ae29f4c1c7471", - "reference": "daba1cf0a6edaf172fa02a17807ae29f4c1c7471", + "url": "https://api.github.com/repos/pdepend/pdepend/zipball/c64472f8e76ca858c79ad9a4cf1e2734b3f8cc38", + "reference": "c64472f8e76ca858c79ad9a4cf1e2734b3f8cc38", "shasum": "" }, "require": { @@ -6907,7 +6836,7 @@ "BSD-3-Clause" ], "description": "Official version of pdepend to be handled with Composer", - "time": "2020-02-08T12:06:13+00:00" + "time": "2020-06-20T10:53:13+00:00" }, { "name": "php-coveralls/php-coveralls", @@ -6972,16 +6901,16 @@ }, { "name": "phpmd/phpmd", - "version": "2.8.2", + "version": "2.9.1", "source": { "type": "git", "url": "https://github.com/phpmd/phpmd.git", - "reference": "714629ed782537f638fe23c4346637659b779a77" + "reference": "ce10831d4ddc2686c1348a98069771dd314534a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpmd/phpmd/zipball/714629ed782537f638fe23c4346637659b779a77", - "reference": "714629ed782537f638fe23c4346637659b779a77", + "url": "https://api.github.com/repos/phpmd/phpmd/zipball/ce10831d4ddc2686c1348a98069771dd314534a8", + "reference": "ce10831d4ddc2686c1348a98069771dd314534a8", "shasum": "" }, "require": { @@ -6992,6 +6921,8 @@ }, "require-dev": { "easy-doc/easy-doc": "0.0.0 || ^1.3.2", + "ext-json": "*", + "ext-simplexml": "*", "gregwar/rst": "^1.0", "mikey179/vfsstream": "^1.6.4", "phpunit/phpunit": "^4.8.36 || ^5.7.27", @@ -7038,7 +6969,7 @@ "phpmd", "pmd" ], - "time": "2020-02-16T20:15:50+00:00" + "time": "2020-09-23T22:06:32+00:00" }, { "name": "rregeer/phpunit-coverage-check", @@ -7182,16 +7113,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.5.5", + "version": "3.5.8", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "73e2e7f57d958e7228fce50dc0c61f58f017f9f6" + "reference": "9d583721a7157ee997f235f327de038e7ea6dac4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/73e2e7f57d958e7228fce50dc0c61f58f017f9f6", - "reference": "73e2e7f57d958e7228fce50dc0c61f58f017f9f6", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/9d583721a7157ee997f235f327de038e7ea6dac4", + "reference": "9d583721a7157ee997f235f327de038e7ea6dac4", "shasum": "" }, "require": { @@ -7229,24 +7160,24 @@ "phpcs", "standards" ], - "time": "2020-04-17T01:09:41+00:00" + "time": "2020-10-23T02:01:07+00:00" }, { "name": "symfony/config", - "version": "v4.4.7", + "version": "v4.4.18", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "3f4a3de1af498ed0ea653d4dc2317794144e6ca4" + "reference": "e501c56d2fa70798075b9811d0eb4c27de491459" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/3f4a3de1af498ed0ea653d4dc2317794144e6ca4", - "reference": "3f4a3de1af498ed0ea653d4dc2317794144e6ca4", + "url": "https://api.github.com/repos/symfony/config/zipball/e501c56d2fa70798075b9811d0eb4c27de491459", + "reference": "e501c56d2fa70798075b9811d0eb4c27de491459", "shasum": "" }, "require": { - "php": "^7.1.3", + "php": ">=7.1.3", "symfony/filesystem": "^3.4|^4.0|^5.0", "symfony/polyfill-ctype": "~1.8" }, @@ -7264,11 +7195,6 @@ "symfony/yaml": "To use the yaml reference dumper" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Config\\": "" @@ -7293,24 +7219,24 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2020-03-27T16:54:36+00:00" + "time": "2020-12-09T08:58:17+00:00" }, { "name": "symfony/dependency-injection", - "version": "v4.4.7", + "version": "v4.4.18", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "755b18859be26b90f4bf63753432d3387458bf31" + "reference": "3860f64c6deb2cb48b1ada27460c58ae479bdc0f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/755b18859be26b90f4bf63753432d3387458bf31", - "reference": "755b18859be26b90f4bf63753432d3387458bf31", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/3860f64c6deb2cb48b1ada27460c58ae479bdc0f", + "reference": "3860f64c6deb2cb48b1ada27460c58ae479bdc0f", "shasum": "" }, "require": { - "php": "^7.1.3", + "php": ">=7.1.3", "psr/container": "^1.0", "symfony/service-contracts": "^1.1.6|^2" }, @@ -7337,11 +7263,6 @@ "symfony/yaml": "" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\DependencyInjection\\": "" @@ -7366,31 +7287,26 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2020-03-30T10:09:30+00:00" + "time": "2020-12-18T07:41:31+00:00" }, { "name": "symfony/stopwatch", - "version": "v3.4.39", + "version": "v3.4.47", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "a7a98f40dcc382a332c3729a6d04b298ffbb8f1f" + "reference": "298b81faad4ce60e94466226b2abbb8c9bca7462" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/a7a98f40dcc382a332c3729a6d04b298ffbb8f1f", - "reference": "a7a98f40dcc382a332c3729a6d04b298ffbb8f1f", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/298b81faad4ce60e94466226b2abbb8c9bca7462", + "reference": "298b81faad4ce60e94466226b2abbb8c9bca7462", "shasum": "" }, "require": { "php": "^5.5.9|>=7.0.8" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.4-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Stopwatch\\": "" @@ -7415,7 +7331,7 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", - "time": "2020-03-15T09:38:08+00:00" + "time": "2020-10-24T10:57:07+00:00" }, { "name": "theseer/fdomdocument", From 57e515a88c0dcbbc3e15f6928fda7cb29e58f19f Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 25 Jan 2021 12:56:34 -0600 Subject: [PATCH 588/888] MQE-2463: Mftf test extends from a skipped parent should be skipped --- .../Test/Util/ObjectExtensionUtilTest.php | 35 +++++++++++++++++++ dev/tests/unit/Util/TestDataArrayBuilder.php | 22 ++++++++++++ .../Test/Util/ObjectExtensionUtil.php | 10 +++--- 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ObjectExtensionUtilTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ObjectExtensionUtilTest.php index 4b9830a59..6bf2da577 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ObjectExtensionUtilTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ObjectExtensionUtilTest.php @@ -346,6 +346,41 @@ public function testExtendingExtendedActionGroup() } } + /** + * Tests generating a test that extends a skipped parent test + * + * @throws \Exception + */ + public function testExtendedTestSkippedParent() + { + $testDataArrayBuilder = new TestDataArrayBuilder(); + $mockParentTest = $testDataArrayBuilder + ->withName('baseTest') + ->withAnnotations([ + 'skip' => ['nodeName' => 'skip', 'issueId' => [['nodeName' => 'issueId', 'value' => 'someIssue']]] + ]) + ->build(); + + $testDataArrayBuilder->reset(); + $mockExtendedTest = $testDataArrayBuilder + ->withName('extendTest') + ->withTestReference("baseTest") + ->build(); + + $mockTestData = array_merge($mockParentTest, $mockExtendedTest); + $this->setMockTestOutput($mockTestData); + + // parse and generate test object with mocked data + TestObjectHandler::getInstance()->getObject('extendTest'); + + // validate log statement + TestLoggingUtil::getInstance()->validateMockLogStatement( + 'debug', + "extendTest is skipped due to ParentTestIsSkipped", + [] + ); + } + /** * Function used to set mock for parser return and force init method to run between tests. * diff --git a/dev/tests/unit/Util/TestDataArrayBuilder.php b/dev/tests/unit/Util/TestDataArrayBuilder.php index eb192e040..e40d80e83 100644 --- a/dev/tests/unit/Util/TestDataArrayBuilder.php +++ b/dev/tests/unit/Util/TestDataArrayBuilder.php @@ -232,6 +232,28 @@ public function withTestReference($reference = null) return $this; } + /** + * Reset data array builder + * + * @return void + */ + public function reset() + { + // reset + $this->testName = 'testTest'; + $this->filename = null; + $this->testActionBeforeName = 'testActionBefore'; + $this->testActionAfterName = 'testActionAfter'; + $this->testActionFailedName = 'testActionFailed'; + $this->testActionType = 'testAction'; + $this->annotations = []; + $this->beforeHook = []; + $this->afterHook = []; + $this->failedHook = []; + $this->testReference = null; + $this->testActions = []; + } + /** * Output the resulting test data array based on parameters set in the object * diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/ObjectExtensionUtil.php b/src/Magento/FunctionalTestingFramework/Test/Util/ObjectExtensionUtil.php index f0a36955b..1be3c895f 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/ObjectExtensionUtil.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/ObjectExtensionUtil.php @@ -42,13 +42,13 @@ public function extendTest($testObject) try { $parentTest = TestObjectHandler::getInstance()->getObject($testObject->getParentName()); } catch (TestReferenceException $error) { + $skippedTest = $this->skipTest($testObject, 'ParentTestDoesNotExist'); if (MftfApplicationConfig::getConfig()->verboseEnabled()) { LoggingUtil::getInstance()->getLogger(ObjectExtensionUtil::class)->debug( "parent test not defined. test will be skipped", ["parent" => $testObject->getParentName(), "test" => $testObject->getName()] ); } - $skippedTest = $this->skipTest($testObject, 'ParentTestDoesNotExist'); return $skippedTest; } @@ -236,9 +236,11 @@ public function skipTest($testObject, $skipReason = null) $testObject->getParentName() ); - LoggingUtil::getInstance()->getLogger(ObjectExtensionUtil::class)->info( - "\nMQE-2463 LOGGING: {$testObject->getName()} is skipped due to {$skipReason}\n" - ); + if (MftfApplicationConfig::getConfig()->verboseEnabled()) { + LoggingUtil::getInstance()->getLogger(ObjectExtensionUtil::class)->debug( + "{$testObject->getName()} is skipped due to {$skipReason}" + ); + } return $skippedTest; } From bffcda1bfbfc8bc810752aad880b3924eadcae91 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 25 Jan 2021 13:46:39 -0600 Subject: [PATCH 589/888] MQE-2463: Mftf test extends from a skipped parent should be skipped --- .../Resources/ExtendingSkippedTest.txt | 32 ++----------------- 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/dev/tests/verification/Resources/ExtendingSkippedTest.txt b/dev/tests/verification/Resources/ExtendingSkippedTest.txt index 553131988..0202f6d4f 100644 --- a/dev/tests/verification/Resources/ExtendingSkippedTest.txt +++ b/dev/tests/verification/Resources/ExtendingSkippedTest.txt @@ -19,33 +19,6 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ExtendingSkippedTestCest { - /** - * @param AcceptanceTester $I - * @throws \Exception - */ - public function _before(AcceptanceTester $I) - { - $I->amOnPage("/beforeUrl"); // stepKey: beforeAmOnPageKey - } - - /** - * @param AcceptanceTester $I - * @throws \Exception - */ - public function _after(AcceptanceTester $I) - { - $I->amOnPage("/afterUrl"); // stepKey: afterAmOnPageKey - } - - /** - * @param AcceptanceTester $I - * @throws \Exception - */ - public function _failed(AcceptanceTester $I) - { - $I->saveScreenshot(); // stepKey: saveScreenshot - } - /** * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) @@ -55,9 +28,8 @@ class ExtendingSkippedTestCest * @return void * @throws \Exception */ - public function ExtendingSkippedTest(AcceptanceTester $I) + public function ExtendingSkippedTest(AcceptanceTester $I, \Codeception\Scenario $scenario) { - $I->comment("text"); - $I->comment("child"); + $scenario->skip("This test is skipped due to the following issues:\nParentTestIsSkipped"); } } From 9d7f3a731e1cd6079b20d5d16bde8eb59b18e01d Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 25 Jan 2021 15:20:58 -0600 Subject: [PATCH 590/888] MQE-2463: Mftf test extends from a skipped parent should be skipped --- docs/extending.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/extending.md b/docs/extending.md index fe06d9637..3e71ca78f 100644 --- a/docs/extending.md +++ b/docs/extending.md @@ -15,6 +15,11 @@ Specify needed variations for a parent object and produce a copy of the original Unlike merging, the parent test (or action group) will still exist after the test generation. </div> +<div class="bs-callout-warning" markdown="1"> +<br> +Note: The extended test will be skipped if the parent test is not defined or is skipped. +</div> + ## Extending tests ### Update a test step From 8728739e83fb7575b2ccd6781b128fb364cc5dfb Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 27 Jan 2021 10:08:49 -0600 Subject: [PATCH 591/888] MQE-2436: bin/static-checks fails if xdebug 3 is enabled --- docs/extending.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/extending.md b/docs/extending.md index 3e71ca78f..576bfdb24 100644 --- a/docs/extending.md +++ b/docs/extending.md @@ -17,7 +17,7 @@ Unlike merging, the parent test (or action group) will still exist after the tes <div class="bs-callout-warning" markdown="1"> <br> -Note: The extended test will be skipped if the parent test is not defined or is skipped. +Note: The extended test will be skipped if the parent test is skipped. </div> ## Extending tests From 83ec71c64e2f3514ad7654ed46688f7186e9dae2 Mon Sep 17 00:00:00 2001 From: Dan Mooney <30629803+danmooney2@users.noreply.github.com> Date: Thu, 28 Jan 2021 15:01:11 -0600 Subject: [PATCH 592/888] Update mftf.md Wrap `--filter` example in code markdown so double dash hopefully isn't inadvertently converted to single dash via some frontend JavaScript magic. --- docs/commands/mftf.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 6105c0d19..c632dea6b 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -160,7 +160,7 @@ vendor/bin/mftf generate:tests [option] [<test name>] [<test name>] [--remove] | Option | Description| | ---| --- | | `--config=[<default> or <singleRun> or <parallel>]` | Creates a single manifest file with a list of all tests. The default location is `tests/functional/Magento/FunctionalTest/_generated/testManifest.txt`.<br/> You can split the list into multiple groups using `--config=parallel`; the groups will be generated in `_generated/groups/` like `_generated/groups/group1.txt, group2.txt, ...`.<br/> Available values: `default` (default), `singleRun`(same as `default`), and `parallel`.<br/> Example: `generate:tests --config=parallel`. | -| `--filter` | Option to filter tests to be generated.<br/>Template: '<filterName>:<filterValue>'.<br/>Existing filter types: severity.<br/>Existing severity values: BLOCKER, CRITICAL, MAJOR, AVERAGE, MINOR.<br/>Example: --filter=severity:CRITICAL| +| `--filter` | Option to filter tests to be generated.<br/>Template: '<filterName>:<filterValue>'.<br/>Existing filter types: severity.<br/>Existing severity values: BLOCKER, CRITICAL, MAJOR, AVERAGE, MINOR.<br/>Example: `--filter=severity:CRITICAL`| | `--force` | Forces test generation, regardless of the module merge order defined in the Magento instance. Example: `generate:tests --force`. | | `-i,--time` | Set time in minutes to determine the group size when `--config=parallel` is used. The __default value__ is `10`. Example: `generate:tests --config=parallel --time=15`| | `--tests` | Defines the test configuration as a JSON string.| From a86189e59aa60550c992995326a5e0b7122a655f Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Fri, 29 Jan 2021 12:52:01 -0600 Subject: [PATCH 593/888] MQE-2483: Upgrade csharpru/vault-php to 4.1+ --- composer.json | 3 +- composer.lock | 435 ++++++++++++++++++++++---------------------------- 2 files changed, 189 insertions(+), 249 deletions(-) diff --git a/composer.json b/composer.json index ea0d546a9..f7a45716c 100755 --- a/composer.json +++ b/composer.json @@ -35,7 +35,8 @@ "symfony/mime": "^5.0", "symfony/process": "^4.4", "vlucas/phpdotenv": "^2.4", - "weew/helpers-array": "^1.3" + "weew/helpers-array": "^1.3", + "nikic/php-parser": "~4.4.0" }, "require-dev": { "brainmaestro/composer-git-hooks": "^2.3.1", diff --git a/composer.lock b/composer.lock index ebda85333..f35be69fb 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "14b197b885fe321b5f2c9f65892922d3", + "content-hash": "b1b71952843bcfa90ae55704c023b1ae", "packages": [ { "name": "allure-framework/allure-codeception", @@ -2515,16 +2515,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.10.4", + "version": "v4.4.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "c6d052fc58cb876152f89f532b95a8d7907e7f0e" + "reference": "bd43ec7152eaaab3bd8c6d0aa95ceeb1df8ee120" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/c6d052fc58cb876152f89f532b95a8d7907e7f0e", - "reference": "c6d052fc58cb876152f89f532b95a8d7907e7f0e", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/bd43ec7152eaaab3bd8c6d0aa95ceeb1df8ee120", + "reference": "bd43ec7152eaaab3bd8c6d0aa95ceeb1df8ee120", "shasum": "" }, "require": { @@ -2532,8 +2532,8 @@ "php": ">=7.0" }, "require-dev": { - "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + "ircmaxell/php-yacc": "0.0.5", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0" }, "bin": [ "bin/php-parse" @@ -2541,7 +2541,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.9-dev" + "dev-master": "4.3-dev" } }, "autoload": { @@ -2563,7 +2563,7 @@ "parser", "php" ], - "time": "2020-12-20T10:01:03+00:00" + "time": "2020-04-10T16:34:50+00:00" }, { "name": "paragonie/constant_time_encoding", @@ -2629,29 +2629,28 @@ }, { "name": "phar-io/manifest", - "version": "2.0.1", + "version": "1.0.3", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133" + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/85265efd3af7ba3ca4b2a2c34dbfc5788dd29133", - "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", "shasum": "" }, "require": { "ext-dom": "*", "ext-phar": "*", - "ext-xmlwriter": "*", - "phar-io/version": "^3.0.1", - "php": "^7.2 || ^8.0" + "phar-io/version": "^2.0", + "php": "^5.6 || ^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { @@ -2681,24 +2680,24 @@ } ], "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "time": "2020-06-27T14:33:11+00:00" + "time": "2018-07-08T19:23:20+00:00" }, { "name": "phar-io/version", - "version": "3.0.4", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/phar-io/version.git", - "reference": "e4782611070e50613683d2b9a57730e9a3ba5451" + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/e4782611070e50613683d2b9a57730e9a3ba5451", - "reference": "e4782611070e50613683d2b9a57730e9a3ba5451", + "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0" + "php": "^5.6 || ^7.0" }, "type": "library", "autoload": { @@ -2728,7 +2727,7 @@ } ], "description": "Library for handling version information and constraints", - "time": "2020-12-13T23:18:30+00:00" + "time": "2018-07-08T19:19:57+00:00" }, { "name": "php-webdriver/webdriver", @@ -3109,35 +3108,32 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.5", + "version": "8.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "f3e026641cc91909d421802dd3ac7827ebfd97e1" + "reference": "ca6647ffddd2add025ab3f21644a441d7c146cdc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f3e026641cc91909d421802dd3ac7827ebfd97e1", - "reference": "f3e026641cc91909d421802dd3ac7827ebfd97e1", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca6647ffddd2add025ab3f21644a441d7c146cdc", + "reference": "ca6647ffddd2add025ab3f21644a441d7c146cdc", "shasum": "" }, "require": { "ext-dom": "*", - "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.10.2", - "php": ">=7.3", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-text-template": "^2.0.2", - "sebastian/code-unit-reverse-lookup": "^2.0.2", - "sebastian/complexity": "^2.0", - "sebastian/environment": "^5.1.2", - "sebastian/lines-of-code": "^1.0.3", - "sebastian/version": "^3.0.1", - "theseer/tokenizer": "^1.2.0" + "php": "^7.3", + "phpunit/php-file-iterator": "^3.0", + "phpunit/php-text-template": "^2.0", + "phpunit/php-token-stream": "^4.0", + "sebastian/code-unit-reverse-lookup": "^2.0", + "sebastian/environment": "^5.0", + "sebastian/version": "^3.0", + "theseer/tokenizer": "^1.1.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^9.0" }, "suggest": { "ext-pcov": "*", @@ -3146,7 +3142,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.2-dev" + "dev-master": "8.0-dev" } }, "autoload": { @@ -3178,7 +3174,7 @@ "type": "github" } ], - "time": "2020-11-28T06:44:49+00:00" + "time": "2020-05-23T08:02:54+00:00" }, { "name": "phpunit/php-file-iterator", @@ -3387,18 +3383,74 @@ ], "time": "2020-10-26T13:16:10+00:00" }, + { + "name": "phpunit/php-token-stream", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/a853a0e183b9db7eed023d7933a858fa1c8d25a3", + "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "abandoned": true, + "time": "2020-08-04T08:28:15+00:00" + }, { "name": "phpunit/phpunit", - "version": "9.5.1", + "version": "9.2.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "e7bdf4085de85a825f4424eae52c99a1cec2f360" + "reference": "1c6a9e4312e209e659f1fce3ce88dd197c2448f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e7bdf4085de85a825f4424eae52c99a1cec2f360", - "reference": "e7bdf4085de85a825f4424eae52c99a1cec2f360", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1c6a9e4312e209e659f1fce3ce88dd197c2448f6", + "reference": "1c6a9e4312e209e659f1fce3ce88dd197c2448f6", "shasum": "" }, "require": { @@ -3409,31 +3461,30 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.10.1", - "phar-io/manifest": "^2.0.1", - "phar-io/version": "^3.0.2", - "php": ">=7.3", - "phpspec/prophecy": "^1.12.1", - "phpunit/php-code-coverage": "^9.2.3", - "phpunit/php-file-iterator": "^3.0.5", - "phpunit/php-invoker": "^3.1.1", - "phpunit/php-text-template": "^2.0.3", - "phpunit/php-timer": "^5.0.2", - "sebastian/cli-parser": "^1.0.1", - "sebastian/code-unit": "^1.0.6", - "sebastian/comparator": "^4.0.5", - "sebastian/diff": "^4.0.3", - "sebastian/environment": "^5.1.3", - "sebastian/exporter": "^4.0.3", - "sebastian/global-state": "^5.0.1", - "sebastian/object-enumerator": "^4.0.3", - "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^2.3", - "sebastian/version": "^3.0.2" + "myclabs/deep-copy": "^1.9.5", + "phar-io/manifest": "^1.0.3", + "phar-io/version": "^2.0.1", + "php": "^7.3", + "phpspec/prophecy": "^1.10.3", + "phpunit/php-code-coverage": "^8.0.2", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-invoker": "^3.0.2", + "phpunit/php-text-template": "^2.0.2", + "phpunit/php-timer": "^5.0.1", + "sebastian/code-unit": "^1.0.5", + "sebastian/comparator": "^4.0.3", + "sebastian/diff": "^4.0.1", + "sebastian/environment": "^5.1.2", + "sebastian/exporter": "^4.0.2", + "sebastian/global-state": "^4.0", + "sebastian/object-enumerator": "^4.0.2", + "sebastian/resource-operations": "^3.0.2", + "sebastian/type": "^2.1.1", + "sebastian/version": "^3.0.1" }, "require-dev": { "ext-pdo": "*", - "phpspec/prophecy-phpunit": "^2.0.1" + "phpspec/prophecy-phpunit": "^2.0" }, "suggest": { "ext-soap": "*", @@ -3445,7 +3496,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.5-dev" + "dev-master": "9.2-dev" } }, "autoload": { @@ -3484,7 +3535,7 @@ "type": "github" } ], - "time": "2021-01-17T07:42:25+00:00" + "time": "2020-07-13T17:55:55+00:00" }, { "name": "psr/cache", @@ -3963,58 +4014,6 @@ ], "time": "2020-08-18T17:17:46+00:00" }, - { - "name": "sebastian/cli-parser", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for parsing CLI options", - "homepage": "https://github.com/sebastianbergmann/cli-parser", - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T06:08:49+00:00" - }, { "name": "sebastian/code-unit", "version": "1.0.8", @@ -4170,59 +4169,6 @@ ], "time": "2020-10-26T15:49:45+00:00" }, - { - "name": "sebastian/complexity", - "version": "2.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.7", - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for calculating the complexity of PHP code units", - "homepage": "https://github.com/sebastianbergmann/complexity", - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T15:52:27+00:00" - }, { "name": "sebastian/diff", "version": "4.0.4", @@ -4401,26 +4347,26 @@ }, { "name": "sebastian/global-state", - "version": "5.0.2", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "a90ccbddffa067b51f574dea6eb25d5680839455" + "reference": "bdb1e7c79e592b8c82cb1699be3c8743119b8a72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/a90ccbddffa067b51f574dea6eb25d5680839455", - "reference": "a90ccbddffa067b51f574dea6eb25d5680839455", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bdb1e7c79e592b8c82cb1699be3c8743119b8a72", + "reference": "bdb1e7c79e592b8c82cb1699be3c8743119b8a72", "shasum": "" }, "require": { - "php": ">=7.3", + "php": "^7.3", "sebastian/object-reflector": "^2.0", "sebastian/recursion-context": "^4.0" }, "require-dev": { "ext-dom": "*", - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^9.0" }, "suggest": { "ext-uopz": "*" @@ -4428,7 +4374,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -4451,66 +4397,7 @@ "keywords": [ "global state" ], - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T15:55:19+00:00" - }, - { - "name": "sebastian/lines-of-code", - "version": "1.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.6", - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for counting the lines of code in PHP source code", - "homepage": "https://github.com/sebastianbergmann/lines-of-code", - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-11-28T06:42:11+00:00" + "time": "2020-02-07T06:11:37+00:00" }, { "name": "sebastian/object-enumerator", @@ -6883,20 +6770,20 @@ }, { "name": "goaop/parser-reflection", - "version": "2.1.2", + "version": "2.1.3", "source": { "type": "git", "url": "https://github.com/goaop/parser-reflection.git", - "reference": "d4257ee557484ac886bee46bd41ebecb7c4bfa16" + "reference": "2e837e150e15d38f7004b0dbcd0af4abe034c9e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/goaop/parser-reflection/zipball/d4257ee557484ac886bee46bd41ebecb7c4bfa16", - "reference": "d4257ee557484ac886bee46bd41ebecb7c4bfa16", + "url": "https://api.github.com/repos/goaop/parser-reflection/zipball/2e837e150e15d38f7004b0dbcd0af4abe034c9e2", + "reference": "2e837e150e15d38f7004b0dbcd0af4abe034c9e2", "shasum": "" }, "require": { - "nikic/php-parser": "^4.0", + "nikic/php-parser": "^4.0 <4.7.0", "php": ">=7.1" }, "require-dev": { @@ -6930,7 +6817,7 @@ } ], "description": "Provides reflection information, based on raw source", - "time": "2020-08-13T00:19:00+00:00" + "time": "2020-08-13T21:02:42+00:00" }, { "name": "guzzle/guzzle", @@ -7302,6 +7189,58 @@ ], "time": "2018-07-29T13:27:58+00:00" }, + { + "name": "sebastian/cli-parser", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:08:49+00:00" + }, { "name": "sebastian/phpcpd", "version": "6.0.3", From 7836c009d28a92ed0d447c7d0f3e9a516b50ccba Mon Sep 17 00:00:00 2001 From: Dan Mooney <dmooney@adobe.com> Date: Mon, 1 Feb 2021 14:10:43 -0600 Subject: [PATCH 594/888] Add support for admin WebAPI token refresh --- .../DataTransport/Auth/WebApiAuth.php | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php b/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php index 377913cfb..938cf2627 100644 --- a/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php +++ b/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php @@ -36,6 +36,13 @@ class WebApiAuth */ private static $adminAuthTokens = []; + /** + * Timestamps of when admin user tokens were created. They need to be refreshed every ~4 hours + * + * @var int[] + */ + private static $adminAuthTokenTimestamps = []; + /** * Return the API token for an admin user * Use MAGENTO_ADMIN_USERNAME and MAGENTO_ADMIN_PASSWORD when $username and/or $password is/are omitted @@ -63,7 +70,12 @@ public static function getAdminToken($username = null, $password = null) } if (isset(self::$adminAuthTokens[$login])) { - return self::$adminAuthTokens[$login]; + $threeHours = 60 * 60 * 3; + $isTokenAboutToExpire = time() - self::$adminAuthTokenTimestamps[$login] > $threeHours; + + if (!$isTokenAboutToExpire) { + return self::$adminAuthTokens[$login]; + } } try { @@ -97,6 +109,7 @@ public static function getAdminToken($username = null, $password = null) $token = json_decode($response); if ($token !== null) { self::$adminAuthTokens[$login] = $token; + self::$adminAuthTokenTimestamps[$login] = time(); return $token; } $errMessage = "Invalid response: {$response}"; From 6035ee00101a56817b1fa2ed50a10c4619f6d46e Mon Sep 17 00:00:00 2001 From: Soumya Unnikrishnan <sunnikri@adobe.com> Date: Wed, 3 Feb 2021 13:07:51 -0600 Subject: [PATCH 595/888] MQE-2466: Test generation error in a split suite group (--config=parallel) Added todo --- src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php index e8af3f20c..1f8fec586 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php @@ -273,6 +273,7 @@ private function generateSplitSuiteFromTest($suiteName, $suiteContent) // There are suites that include tests that reference tests from other Magento editions // To keep backward compatibility, we will catch such exceptions with no error. // This might inevitably hide some suite errors that are resulted by tests with broken references + //TODO MQE-2484 } } } From d82197bba48b2138943d71c14b1bc57c3c234059 Mon Sep 17 00:00:00 2001 From: Dan Mooney <dmooney@adobe.com> Date: Thu, 4 Feb 2021 12:00:25 -0600 Subject: [PATCH 596/888] Add support for admin WebAPI token refresh --- etc/config/.env.example | 4 ++++ .../DataTransport/Auth/WebApiAuth.php | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/etc/config/.env.example b/etc/config/.env.example index 64a287adc..1c181cf8f 100644 --- a/etc/config/.env.example +++ b/etc/config/.env.example @@ -72,4 +72,8 @@ BROWSER_LOG_BLOCKLIST=other #*** Elastic Search version used for test ***# ELASTICSEARCH_VERSION=7 + +#*** Lifetime (in seconds) of Magento Admin WebAPI Token; if token is older than this value a refresh attempt will be made just before the next WebAPI call ***# +#MAGENTO_ADMIN_WEBAPI_TOKEN_LIFETIME=10800 + #*** End of .env ***# diff --git a/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php b/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php index 938cf2627..aad298c50 100644 --- a/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php +++ b/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php @@ -70,8 +70,9 @@ public static function getAdminToken($username = null, $password = null) } if (isset(self::$adminAuthTokens[$login])) { - $threeHours = 60 * 60 * 3; - $isTokenAboutToExpire = time() - self::$adminAuthTokenTimestamps[$login] > $threeHours; + $tokenLifetime = getenv('MAGENTO_ADMIN_WEBAPI_TOKEN_LIFETIME'); + + $isTokenAboutToExpire = $tokenLifetime && time() - self::$adminAuthTokenTimestamps[$login] > $tokenLifetime; if (!$isTokenAboutToExpire) { return self::$adminAuthTokens[$login]; From 3831461bc841246f5c2248d0a4d564a152d5781f Mon Sep 17 00:00:00 2001 From: Dan Mooney <dmooney@adobe.com> Date: Thu, 4 Feb 2021 12:12:27 -0600 Subject: [PATCH 597/888] Add support for admin WebAPI token refresh --- .../DataTransport/Auth/WebApiAuth.php | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php b/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php index aad298c50..be81cb35d 100644 --- a/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php +++ b/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php @@ -69,14 +69,8 @@ public static function getAdminToken($username = null, $password = null) throw new FastFailException($message, $context); } - if (isset(self::$adminAuthTokens[$login])) { - $tokenLifetime = getenv('MAGENTO_ADMIN_WEBAPI_TOKEN_LIFETIME'); - - $isTokenAboutToExpire = $tokenLifetime && time() - self::$adminAuthTokenTimestamps[$login] > $tokenLifetime; - - if (!$isTokenAboutToExpire) { - return self::$adminAuthTokens[$login]; - } + if (self::hasExistingToken($login)) { + return self::$adminAuthTokens[$login]; } try { @@ -131,4 +125,23 @@ public static function getAdminToken($username = null, $password = null) $context = ['url' => $authUrl]; throw new FastFailException($message, $context); } + + /** + * Is there an existing WebAPI admin token for this login? + * + * @param string $login + * @return bool + */ + private static function hasExistingToken(string $login) + { + if (!isset(self::$adminAuthTokens[$login])) { + return false; + } + + $tokenLifetime = getenv('MAGENTO_ADMIN_WEBAPI_TOKEN_LIFETIME'); + + $isTokenExpired = $tokenLifetime && time() - self::$adminAuthTokenTimestamps[$login] > $tokenLifetime; + + return !$isTokenExpired; + } } From 3faa2fa861d35b8d754db26e1a7afdc27ae0b57b Mon Sep 17 00:00:00 2001 From: Dan Mooney <dmooney@adobe.com> Date: Thu, 4 Feb 2021 12:16:00 -0600 Subject: [PATCH 598/888] Add support for admin WebAPI token refresh --- .../DataTransport/Auth/WebApiAuth.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php b/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php index be81cb35d..be29a7e19 100644 --- a/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php +++ b/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php @@ -130,7 +130,7 @@ public static function getAdminToken($username = null, $password = null) * Is there an existing WebAPI admin token for this login? * * @param string $login - * @return bool + * @return boolean */ private static function hasExistingToken(string $login) { From f11ef1dc372a2c29d29b0900f9db06fa3d501f34 Mon Sep 17 00:00:00 2001 From: Dan Mooney <dmooney@adobe.com> Date: Thu, 4 Feb 2021 13:34:14 -0600 Subject: [PATCH 599/888] Add support for admin WebAPI token refresh --- docs/configuration.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/configuration.md b/docs/configuration.md index d64a68500..4eb273824 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -408,6 +408,16 @@ Example: REMOTE_STORAGE_AWSS3_PREFIX=local ``` +### MAGENTO_ADMIN_WEBAPI_TOKEN_LIFETIME + +The lifetime (in seconds) of Magento Admin WebAPI token; if token is older than this value a refresh attempt will be made just before the next WebAPI call. + +Example: + +```conf +MAGENTO_ADMIN_WEBAPI_TOKEN_LIFETIME=10800 +``` + <!-- Link definitions --> [`MAGENTO_CLI_COMMAND_PATH`]: #magento_cli_command_path From 38c6f11fbeba311cdf0ade0b296ba2195452cbec Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 10 Feb 2021 15:18:26 -0600 Subject: [PATCH 600/888] MQE-2506: updated CHANGELOG.md and composer files for 3.3.0 --- CHANGELOG.md | 13 +++ composer.json | 2 +- composer.lock | 219 +------------------------------------------------- 3 files changed, 16 insertions(+), 218 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e676e89b..3f00a9138 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,19 @@ Magento Functional Testing Framework Changelog ================================================ +3.3.0 +--------- + +### Enhancements + +* [#815](https://github.com/magento/magento2-functional-testing-framework/pull/815) -- Upgrade csharpru/vault-php to 4.1 +* [#817](https://github.com/magento/magento2-functional-testing-framework/pull/817) -- Add support for admin WebAPI token refresh + +### Fixes + +* Fixed test generation error in a split suite group (--config=parallel) to allow generation of subsequent groups. +* Fixed an issue where test extends from a skipped parent is not properly skipped. + 3.2.1 --------- diff --git a/composer.json b/composer.json index f7a45716c..b10b9de18 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "3.2.1", + "version": "3.3.0", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index f35be69fb..e046e99cb 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b1b71952843bcfa90ae55704c023b1ae", + "content-hash": "f2963f8ed8ee0f3f92d28b016a832931", "packages": [ { "name": "allure-framework/allure-codeception", @@ -444,12 +444,6 @@ "functional testing", "unit testing" ], - "funding": [ - { - "url": "https://opencollective.com/codeception", - "type": "open_collective" - } - ], "time": "2021-01-26T07:25:32+00:00" }, { @@ -857,20 +851,6 @@ "dependency", "package" ], - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], "time": "2021-01-27T14:41:06+00:00" }, { @@ -3168,12 +3148,6 @@ "testing", "xunit" ], - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], "time": "2020-05-23T08:02:54+00:00" }, { @@ -3375,12 +3349,6 @@ "keywords": [ "timer" ], - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], "time": "2020-10-26T13:16:10+00:00" }, { @@ -3430,12 +3398,6 @@ "keywords": [ "tokenizer" ], - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], "abandoned": true, "time": "2020-08-04T08:28:15+00:00" }, @@ -3525,16 +3487,6 @@ "testing", "xunit" ], - "funding": [ - { - "url": "https://phpunit.de/donate.html", - "type": "custom" - }, - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], "time": "2020-07-13T17:55:55+00:00" }, { @@ -4912,20 +4864,6 @@ ], "description": "Eases the creation of beautiful and testable command line interfaces", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2021-01-27T09:09:26+00:00" }, { @@ -4974,20 +4912,6 @@ ], "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2021-01-27T10:01:46+00:00" }, { @@ -5104,20 +5028,6 @@ ], "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2021-01-27T09:09:26+00:00" }, { @@ -5225,20 +5135,6 @@ ], "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2021-01-27T10:01:46+00:00" }, { @@ -5283,20 +5179,6 @@ ], "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2021-01-27T10:01:46+00:00" }, { @@ -5353,20 +5235,6 @@ ], "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2021-01-27T11:19:04+00:00" }, { @@ -5432,20 +5300,6 @@ "mime", "mime-type" ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2021-01-25T14:08:25+00:00" }, { @@ -5939,20 +5793,6 @@ ], "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2021-01-27T09:09:26+00:00" }, { @@ -6069,20 +5909,6 @@ ], "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2021-01-27T09:09:26+00:00" }, { @@ -7233,12 +7059,6 @@ ], "description": "Library for parsing CLI options", "homepage": "https://github.com/sebastianbergmann/cli-parser", - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], "time": "2020-09-28T06:08:49+00:00" }, { @@ -7290,12 +7110,6 @@ ], "description": "Copy/Paste Detector (CPD) for PHP code.", "homepage": "https://github.com/sebastianbergmann/phpcpd", - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], "time": "2020-12-07T05:39:23+00:00" }, { @@ -7406,20 +7220,6 @@ ], "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2021-01-27T09:09:26+00:00" }, { @@ -7488,20 +7288,6 @@ ], "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], "time": "2021-01-27T09:09:26+00:00" }, { @@ -7562,6 +7348,5 @@ "ext-json": "*", "ext-openssl": "*" }, - "platform-dev": [], - "plugin-api-version": "1.1.0" + "platform-dev": [] } From 9754a9208f0cba82b2bba521dff1600e454fa933 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 11 Feb 2021 08:58:10 -0600 Subject: [PATCH 601/888] MQE-2506: updated CHANGELOG.md and composer files for 3.3.0 --- CHANGELOG.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f00a9138..19793478f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,13 @@ Magento Functional Testing Framework Changelog ### Enhancements -* [#815](https://github.com/magento/magento2-functional-testing-framework/pull/815) -- Upgrade csharpru/vault-php to 4.1 -* [#817](https://github.com/magento/magento2-functional-testing-framework/pull/817) -- Add support for admin WebAPI token refresh - +* Usability + * [#817](https://github.com/magento/magento2-functional-testing-framework/pull/817) -- Add support for admin WebAPI token refresh + +* Maintainability + * [#814](https://github.com/magento/magento2-functional-testing-framework/pull/814) -- Update dependencies in order to make mftf php8 compatible, fix running phpcpd + * [#815](https://github.com/magento/magento2-functional-testing-framework/pull/815) -- Upgrade csharpru/vault-php to 4.1 + ### Fixes * Fixed test generation error in a split suite group (--config=parallel) to allow generation of subsequent groups. From a2dc74e35cd6336def23cf6b0d29899f7492a9e4 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 25 Feb 2021 16:00:33 -0600 Subject: [PATCH 602/888] MQE-2519: support composer 2 --- composer.json | 2 +- composer.lock | 24 ++++++++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index b10b9de18..7a85587a5 100755 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "codeception/module-asserts": "^1.1", "codeception/module-sequence": "^1.0", "codeception/module-webdriver": "^1.0", - "composer/composer": "^1.9", + "composer/composer": "^1.9|^2.0", "csharpru/vault-php": "^4.1.0", "csharpru/vault-php-guzzle6-transport": "^2.0", "hoa/console": "~3.0", diff --git a/composer.lock b/composer.lock index e046e99cb..56e8188c5 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f2963f8ed8ee0f3f92d28b016a832931", + "content-hash": "495bdea528e61523605e1d8c760b998e", "packages": [ { "name": "allure-framework/allure-codeception", @@ -851,6 +851,25 @@ "dependency", "package" ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/composer/issues", + "source": "https://github.com/composer/composer/tree/1.10.20" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], "time": "2021-01-27T14:41:06+00:00" }, { @@ -7348,5 +7367,6 @@ "ext-json": "*", "ext-openssl": "*" }, - "platform-dev": [] + "platform-dev": [], + "plugin-api-version": "2.0.0" } From a169bc622854fe1dd1a48f93080b6eadb6b45706 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 3 Mar 2021 12:17:01 -0600 Subject: [PATCH 603/888] MQE-2519: support composer 2 --- composer.json | 2 +- composer.lock | 24 ++---------------------- 2 files changed, 3 insertions(+), 23 deletions(-) diff --git a/composer.json b/composer.json index 7a85587a5..5da2cef26 100755 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "codeception/module-asserts": "^1.1", "codeception/module-sequence": "^1.0", "codeception/module-webdriver": "^1.0", - "composer/composer": "^1.9|^2.0", + "composer/composer": "^1.9||^2.0", "csharpru/vault-php": "^4.1.0", "csharpru/vault-php-guzzle6-transport": "^2.0", "hoa/console": "~3.0", diff --git a/composer.lock b/composer.lock index 56e8188c5..42f03b72f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "495bdea528e61523605e1d8c760b998e", + "content-hash": "9802fb26902cdb3358259336c23cb9ab", "packages": [ { "name": "allure-framework/allure-codeception", @@ -851,25 +851,6 @@ "dependency", "package" ], - "support": { - "irc": "irc://irc.freenode.org/composer", - "issues": "https://github.com/composer/composer/issues", - "source": "https://github.com/composer/composer/tree/1.10.20" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], "time": "2021-01-27T14:41:06+00:00" }, { @@ -7367,6 +7348,5 @@ "ext-json": "*", "ext-openssl": "*" }, - "platform-dev": [], - "plugin-api-version": "2.0.0" + "platform-dev": [] } From f7ca3ddd13066150056c6b6107cabd69e3f8c7e7 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 4 Mar 2021 12:40:14 -0600 Subject: [PATCH 604/888] MQE-2519: support composer 2 --- CHANGELOG.md | 8 ++++++++ composer.json | 2 +- composer.lock | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19793478f..c61d0b1fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ Magento Functional Testing Framework Changelog ================================================ +3.4.0 +--------- + +### Enhancements + +* Maintainability + * Added support for composer 2. + 3.3.0 --------- diff --git a/composer.json b/composer.json index 5da2cef26..4d86275c2 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "3.3.0", + "version": "3.4.0", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index 42f03b72f..6ceeaba39 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "9802fb26902cdb3358259336c23cb9ab", + "content-hash": "d5b40409dd42db97a03df32090136b11", "packages": [ { "name": "allure-framework/allure-codeception", From c33994e4132a28b0637f9573c355050453938004 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 9 Mar 2021 12:58:47 -0600 Subject: [PATCH 605/888] MQE-2519: support composer 2 --- .github/workflows/main.yml | 3 ++- CHANGELOG.md | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e98ab3bc5..e75a0f228 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -21,6 +21,7 @@ jobs: with: php-version: ${{ matrix.php-versions }} extensions: curl, dom, intl, json, openssl + coverage: xdebug - name: Cache Composer packages id: composer-cache @@ -40,7 +41,7 @@ jobs: - name: Monitor coverage if: github.event_name == 'pull_request' - uses: slavcodev/coverage-monitor-action@1.1.0 + uses: slavcodev/coverage-monitor-action@1.2.0 with: github_token: ${{ secrets.GITHUB_TOKEN }} clover_file: "clover.xml" diff --git a/CHANGELOG.md b/CHANGELOG.md index c61d0b1fa..00133590f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ Magento Functional Testing Framework Changelog ### Enhancements * Maintainability - * Added support for composer 2. + * Added support for composer 2. 3.3.0 --------- From 6c54343723402a363de92a43aa5eea6482ffc33b Mon Sep 17 00:00:00 2001 From: Christian Jung <christian.jung@klarna.com> Date: Fri, 12 Mar 2021 08:43:42 +0100 Subject: [PATCH 606/888] fix typo in doc --- docs/introduction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/introduction.md b/docs/introduction.md index e5ce67d35..73b068ba0 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -62,7 +62,7 @@ Test ## Use cases -- Contributor: changes the core behaviour, fixing the annoing bug. +- Contributor: changes the core behaviour, fixing the annoying bug. He wants to have automated "supervisor" which is going to verify his work continuously across the stages of bug fixing. Finally, when fix is done - Functional Test is also proof of work done. - Extension Developer: offers extension that changes core behaviour. He can easily write new tests to make sure that after enabling the feature, Magento behaves properly. Everything with just extending existing tests. As a result he don't need to write coverage from scratch. From 6f76b0b959ca47b634578786092a93339d8d3cf8 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 17 Mar 2021 11:21:53 -0500 Subject: [PATCH 607/888] MQE-2495: config parallel by number of groups --- .../Tests/SuiteGenerationTest.php | 4 +- .../Console/GenerateTestsCommand.php | 48 ++++-- ...ifest.php => BaseParallelTestManifest.php} | 45 ++--- .../Manifest/ParallelByGroupTestManifest.php | 47 ++++++ .../Manifest/ParallelByTimeTestManifest.php | 52 ++++++ .../Util/Manifest/TestManifestFactory.php | 7 +- .../Util/Sorter/ParallelGroupSorter.php | 156 +++++++++++++++++- 7 files changed, 310 insertions(+), 49 deletions(-) rename src/Magento/FunctionalTestingFramework/Util/Manifest/{ParallelTestManifest.php => BaseParallelTestManifest.php} (76%) create mode 100644 src/Magento/FunctionalTestingFramework/Util/Manifest/ParallelByGroupTestManifest.php create mode 100644 src/Magento/FunctionalTestingFramework/Util/Manifest/ParallelByTimeTestManifest.php diff --git a/dev/tests/verification/Tests/SuiteGenerationTest.php b/dev/tests/verification/Tests/SuiteGenerationTest.php index f21e91f78..75d395fa7 100644 --- a/dev/tests/verification/Tests/SuiteGenerationTest.php +++ b/dev/tests/verification/Tests/SuiteGenerationTest.php @@ -10,7 +10,7 @@ use Magento\FunctionalTestingFramework\Suite\SuiteGenerator; use Magento\FunctionalTestingFramework\Util\Filesystem\DirSetupUtil; use Magento\FunctionalTestingFramework\Util\Manifest\DefaultTestManifest; -use Magento\FunctionalTestingFramework\Util\Manifest\ParallelTestManifest; +use Magento\FunctionalTestingFramework\Util\Manifest\ParallelByTimeTestManifest; use Magento\FunctionalTestingFramework\Util\Manifest\TestManifestFactory; use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Symfony\Component\Yaml\Yaml; @@ -121,7 +121,7 @@ public function testSuiteGenerationParallel() $expectedContents = SuiteTestReferences::$data[$groupName]; //createParallelManifest - /** @var ParallelTestManifest $parallelManifest */ + /** @var ParallelByTimeTestManifest $parallelManifest */ $parallelManifest = TestManifestFactory::makeManifest("parallel", ["functionalSuite1" => []]); // Generate the Suite diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php index 03aa39462..7520e3501 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php @@ -15,7 +15,7 @@ use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; -use Magento\FunctionalTestingFramework\Util\Manifest\ParallelTestManifest; +use Magento\FunctionalTestingFramework\Util\Manifest\ParallelByTimeTestManifest; use Magento\FunctionalTestingFramework\Util\Manifest\TestManifestFactory; use Magento\FunctionalTestingFramework\Util\TestGenerator; use Symfony\Component\Console\Input\InputArgument; @@ -29,6 +29,8 @@ */ class GenerateTestsCommand extends BaseGenerateCommand { + const PARALLEL_DEFAULT_TIME = 10; + /** * Configures the current command. * @@ -43,13 +45,23 @@ protected function configure() 'name', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, 'name(s) of specific tests to generate' - )->addOption("config", 'c', InputOption::VALUE_REQUIRED, 'default, singleRun, or parallel', 'default') - ->addOption( + )->addOption( + "config", + 'c', + InputOption::VALUE_REQUIRED, + 'default, singleRun, or parallel', + 'default' + )->addOption( 'time', 'i', InputOption::VALUE_REQUIRED, 'Used in combination with a parallel configuration, determines desired group size (in minutes)', - 10 + self::PARALLEL_DEFAULT_TIME + )->addOption( + 'groups', + 'g', + InputOption::VALUE_REQUIRED, + 'Used in combination with a parallel configuration, determines desired number of groups' )->addOption( 'tests', 't', @@ -86,6 +98,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $json = $input->getOption('tests'); // for backward compatibility $force = $input->getOption('force'); $time = $input->getOption('time') * 60 * 1000; // convert from minutes to milliseconds + $groups = $input->getOption('groups'); $debug = $input->getOption('debug') ?? MftfApplicationConfig::LEVEL_DEVELOPER; // for backward compatibility $remove = $input->getOption('remove'); $verbose = $output->isVerbose(); @@ -119,9 +132,25 @@ protected function execute(InputInterface $input, OutputInterface $output) throw new TestFrameworkException("JSON could not be parsed: " . json_last_error_msg()); } - if ($config === 'parallel' && $time <= 0) { - // stop execution if the user has given us an invalid argument for time argument during parallel generation - throw new TestFrameworkException("time option cannot be less than or equal to 0"); + $configNumber = null; + if ($config === 'parallel') { + $config = 'parallelByTime'; + if ($groups) { + $groups = $groups * 1; + $config = 'parallelByGroup'; + if ($time !== self::PARALLEL_DEFAULT_TIME * 60 * 1000) { + throw new TestFrameworkException( + "'time' and 'groups' options are mutually exclusive, only one can be used at a time" + ); + } + if (!is_int($groups) || $groups <= 0) { + throw new TestFrameworkException("'groups' option must be an integer and greater than 0"); + } + } elseif ($time <= 0) { + throw new TestFrameworkException("'time' option cannot be less than or equal to 0"); + } + + $configNumber = $groups ?? $time; } // Remove previous GENERATED_DIR if --remove option is used @@ -153,9 +182,8 @@ protected function execute(InputInterface $input, OutputInterface $output) } catch (\Exception $e) { } - if ($config == 'parallel') { - /** @var ParallelTestManifest $testManifest */ - $testManifest->createTestGroups($time); + if (strpos($config, 'parallel') !== false) { + $testManifest->createTestGroups($configNumber); } SuiteGenerator::getInstance()->generateAllSuites($testManifest); diff --git a/src/Magento/FunctionalTestingFramework/Util/Manifest/ParallelTestManifest.php b/src/Magento/FunctionalTestingFramework/Util/Manifest/BaseParallelTestManifest.php similarity index 76% rename from src/Magento/FunctionalTestingFramework/Util/Manifest/ParallelTestManifest.php rename to src/Magento/FunctionalTestingFramework/Util/Manifest/BaseParallelTestManifest.php index 201e002a2..da0f9d353 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Manifest/ParallelTestManifest.php +++ b/src/Magento/FunctionalTestingFramework/Util/Manifest/BaseParallelTestManifest.php @@ -6,60 +6,53 @@ namespace Magento\FunctionalTestingFramework\Util\Manifest; -use Codeception\Suite; use Magento\Framework\Exception\RuntimeException; -use Magento\FunctionalTestingFramework\Suite\Handlers\SuiteObjectHandler; -use Magento\FunctionalTestingFramework\Suite\Objects\SuiteObject; -use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; use Magento\FunctionalTestingFramework\Util\Filesystem\DirSetupUtil; use Magento\FunctionalTestingFramework\Util\Sorter\ParallelGroupSorter; -use RecursiveArrayIterator; -use RecursiveIteratorIterator; -class ParallelTestManifest extends BaseTestManifest +abstract class BaseParallelTestManifest extends BaseTestManifest { - const PARALLEL_CONFIG = 'parallel'; - /** * An associate array of test name to size of test. * * @var string[] */ - private $testNameToSize = []; + protected $testNameToSize = []; /** * Class variable to store resulting group config. * * @var array */ - private $testGroups; + protected $testGroups; /** * An instance of the group sorter which will take suites and tests organizing them to be run together. * * @var ParallelGroupSorter */ - private $parallelGroupSorter; + protected $parallelGroupSorter; /** * Path to the directory that will contain all test group files * * @var string */ - private $dirPath; + protected $dirPath; /** - * TestManifest constructor. + * BaseParallelTestManifest constructor. * * @param array $suiteConfiguration + * @param string $runConfig * @param string $testPath */ - public function __construct($suiteConfiguration, $testPath) + public function __construct($suiteConfiguration, $runConfig, $testPath) { $this->dirPath = dirname($testPath) . DIRECTORY_SEPARATOR . 'groups'; $this->parallelGroupSorter = new ParallelGroupSorter(); - parent::__construct($testPath, self::PARALLEL_CONFIG, $suiteConfiguration); + parent::__construct($testPath, $runConfig, $suiteConfiguration); } /** @@ -74,22 +67,12 @@ public function addTest($testObject) } /** - * Function which generates test groups based on arg passed. The function builds groups using the args as an upper - * limit. + * Function which generates test groups based on arg passed. * - * @param integer $time + * @param integer $number * @return void */ - public function createTestGroups($time) - { - $this->testGroups = $this->parallelGroupSorter->getTestsGroupedBySize( - $this->getSuiteConfig(), - $this->testNameToSize, - $time - ); - - $this->suiteConfiguration = $this->parallelGroupSorter->getResultingSuiteConfig(); - } + abstract public function createTestGroups($number); /** * Function which generates the actual manifest once the relevant tests have been added to the array. @@ -126,7 +109,7 @@ public function getSorter() * @param array $suites * @return void */ - private function generateGroupFile($testGroup, $nodeNumber, $suites) + protected function generateGroupFile($testGroup, $nodeNumber, $suites) { foreach ($testGroup as $entryName => $testValue) { $fileResource = fopen($this->dirPath . DIRECTORY_SEPARATOR . "group{$nodeNumber}.txt", 'a'); @@ -149,7 +132,7 @@ private function generateGroupFile($testGroup, $nodeNumber, $suites) * @param array $multiDimensionalSuites * @return array */ - private function getFlattenedSuiteConfiguration($multiDimensionalSuites) + protected function getFlattenedSuiteConfiguration($multiDimensionalSuites) { $suites = []; foreach ($multiDimensionalSuites as $suiteName => $suiteContent) { diff --git a/src/Magento/FunctionalTestingFramework/Util/Manifest/ParallelByGroupTestManifest.php b/src/Magento/FunctionalTestingFramework/Util/Manifest/ParallelByGroupTestManifest.php new file mode 100644 index 000000000..1baced519 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/Manifest/ParallelByGroupTestManifest.php @@ -0,0 +1,47 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\FunctionalTestingFramework\Util\Manifest; + +use Magento\Framework\Exception\RuntimeException; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Test\Objects\TestObject; +use Magento\FunctionalTestingFramework\Util\Filesystem\DirSetupUtil; +use Magento\FunctionalTestingFramework\Util\Sorter\ParallelGroupSorter; + +class ParallelByGroupTestManifest extends BaseParallelTestManifest +{ + const PARALLEL_CONFIG = 'parallelByGroup'; + + /** + * ParallelByGroupTestManifest constructor. + * + * @param array $suiteConfiguration + * @param string $testPath + */ + public function __construct($suiteConfiguration, $testPath) + { + parent::__construct($suiteConfiguration, self::PARALLEL_CONFIG, $testPath); + } + + /** + * Function which generates test groups based on arg passed. + * + * @param integer $totalGroups + * @return void + * @throws TestFrameworkException + */ + public function createTestGroups($totalGroups) + { + $this->testGroups = $this->parallelGroupSorter->getTestsGroupedByFixedGroupCount( + $this->getSuiteConfig(), + $this->testNameToSize, + $totalGroups + ); + + $this->suiteConfiguration = $this->parallelGroupSorter->getResultingSuiteConfig(); + } +} diff --git a/src/Magento/FunctionalTestingFramework/Util/Manifest/ParallelByTimeTestManifest.php b/src/Magento/FunctionalTestingFramework/Util/Manifest/ParallelByTimeTestManifest.php new file mode 100644 index 000000000..2a0984280 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/Manifest/ParallelByTimeTestManifest.php @@ -0,0 +1,52 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\FunctionalTestingFramework\Util\Manifest; + +use Codeception\Suite; +use Magento\Framework\Exception\RuntimeException; +use Magento\FunctionalTestingFramework\Suite\Handlers\SuiteObjectHandler; +use Magento\FunctionalTestingFramework\Suite\Objects\SuiteObject; +use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; +use Magento\FunctionalTestingFramework\Test\Objects\TestObject; +use Magento\FunctionalTestingFramework\Util\Filesystem\DirSetupUtil; +use Magento\FunctionalTestingFramework\Util\Sorter\ParallelGroupSorter; +use RecursiveArrayIterator; +use RecursiveIteratorIterator; + +class ParallelByTimeTestManifest extends BaseParallelTestManifest +{ + const PARALLEL_CONFIG = 'parallelByTime'; + + /** + * GroupBasedParallelTestManifest constructor. + * + * @param array $suiteConfiguration + * @param string $testPath + */ + public function __construct($suiteConfiguration, $testPath) + { + parent::__construct($suiteConfiguration, self::PARALLEL_CONFIG, $testPath); + } + + /** + * Function which generates test groups based on arg passed. The function builds groups using the args as an upper + * limit. + * + * @param integer $time + * @return void + */ + public function createTestGroups($time) + { + $this->testGroups = $this->parallelGroupSorter->getTestsGroupedBySize( + $this->getSuiteConfig(), + $this->testNameToSize, + $time + ); + + $this->suiteConfiguration = $this->parallelGroupSorter->getResultingSuiteConfig(); + } +} diff --git a/src/Magento/FunctionalTestingFramework/Util/Manifest/TestManifestFactory.php b/src/Magento/FunctionalTestingFramework/Util/Manifest/TestManifestFactory.php index fd7d885bf..e07007264 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Manifest/TestManifestFactory.php +++ b/src/Magento/FunctionalTestingFramework/Util/Manifest/TestManifestFactory.php @@ -41,8 +41,11 @@ public static function makeManifest($runConfig, $suiteConfiguration, $testPath = case 'singleRun': return new SingleRunTestManifest($suiteConfiguration, $testDirFullPath); - case 'parallel': - return new ParallelTestManifest($suiteConfiguration, $testDirFullPath); + case 'parallelByTime': + return new ParallelByTimeTestManifest($suiteConfiguration, $testDirFullPath); + + case 'parallelByGroup': + return new ParallelByGroupTestManifest($suiteConfiguration, $testDirFullPath); default: return new DefaultTestManifest($suiteConfiguration, $testDirFullPath); diff --git a/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php b/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php index fa30837cb..5ef63e652 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php +++ b/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php @@ -5,7 +5,7 @@ */ namespace Magento\FunctionalTestingFramework\Util\Sorter; -use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Exceptions\FastFailException; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; class ParallelGroupSorter @@ -26,19 +26,19 @@ public function __construct() } /** - * Function which returns tests and suites split according to desired number of lines divded into groups. + * Function which returns tests and suites split according to desired number of lines divided into groups. * * @param array $suiteConfiguration * @param array $testNameToSize * @param integer $time * @return array - * @throws TestFrameworkException + * @throws FastFailException */ public function getTestsGroupedBySize($suiteConfiguration, $testNameToSize, $time) { // we must have the lines argument in order to create the test groups if ($time == 0) { - throw new TestFrameworkException( + throw new FastFailException( "Please provide the argument '--time' to the robo command in order to". " generate grouped tests manifests for a parallel execution" ); @@ -75,6 +75,154 @@ public function getTestsGroupedBySize($suiteConfiguration, $testNameToSize, $tim return $testGroups; } + /** + * Function which returns tests and suites split according to desired number of groups. + * + * @param array $suiteConfiguration + * @param array $testNameToSize + * @param integer $groupTotal + * @return array + * @throws FastFailException + */ + public function getTestsGroupedByFixedGroupCount($suiteConfiguration, $testNameToSize, $groupTotal) + { + $suiteNameToTestSize = $this->getSuiteNameToTestSize($suiteConfiguration); + $suiteNameToSize = $this->getSuiteToSize($suiteNameToTestSize); + + $minRequiredGroupCount = count($suiteNameToTestSize); + if (!empty($testNameToSize)) { + $minRequiredGroupCount += 1; + } + + if ($groupTotal < $minRequiredGroupCount) { + throw new FastFailException( + "Invalid parameter 'groupTotal': must be greater than {$minRequiredGroupCount}\n" + ); + } + + // Calculate the minimum possible group time + $minGroupTime = ceil((array_sum($testNameToSize) + array_sum($suiteNameToSize)) / $groupTotal); + + // Find maximum suite time + $maxSuiteTime = max($suiteNameToSize); + + // Calculate 2 possible suite group times + $ceilSuiteGroupNumber = ceil($maxSuiteTime / $minGroupTime); + $ceilSuiteGroupTime = max(ceil($maxSuiteTime / $ceilSuiteGroupNumber), $minGroupTime); + $floorSuiteGroupNumber = floor($maxSuiteTime / $minGroupTime); + if ($floorSuiteGroupNumber != 0.0) { + $floorSuiteGroupTime = max(ceil($maxSuiteTime / $floorSuiteGroupNumber), $minGroupTime); + } + + // Calculate test group time for ceiling + $ceilSuiteNameToGroupCount = $this->getSuiteNameToGroupCount($suiteNameToSize, $ceilSuiteGroupTime); + $ceilSuiteGroupTotal = array_sum($ceilSuiteNameToGroupCount); + $ceilTestGroupTotal = $groupTotal - $ceilSuiteGroupTotal; + $ceilTestGroupTime = ceil(array_sum($testNameToSize) / $ceilTestGroupTotal); + // Set suite group total to ceiling + $suiteNameToGroupCount = $ceilSuiteNameToGroupCount; + + if (isset($floorSuiteGroupTime) && $ceilSuiteGroupTime != $floorSuiteGroupTime) { + // Calculate test group time for floor + $floorSuiteNameToGroupCount = $this->getSuiteNameToGroupCount($suiteNameToSize, $floorSuiteGroupTime); + $floorSuiteGroupTotal = array_sum($floorSuiteNameToGroupCount); + $floorTestGroupTotal = $groupTotal - $floorSuiteGroupTotal; + $floorTestGroupTime = ceil(array_sum($testNameToSize) / $floorTestGroupTotal); + + // Choose the closer value between test group time and suite group time + $ceilDiff = abs($ceilTestGroupTime - $ceilSuiteGroupTime); + $floorDiff = abs($floorTestGroupTime - $floorSuiteGroupTime); + if ($ceilDiff > $floorDiff) { + // Adjust suite group total to floor + $suiteNameToGroupCount = $floorSuiteNameToGroupCount; + } + } + + // Calculate test group total + $testGroupTotal = $groupTotal - array_sum($suiteNameToGroupCount); + + // Split tests and suites + $testGroups = $this->splitTestsIntoGroups($testNameToSize, $testGroupTotal); + $testGroups = array_merge( + $testGroups, + $this->splitSuitesIntoGroups($suiteNameToTestSize, $suiteNameToGroupCount) + ); + + return $testGroups; + } + + /** + * Return array contains suitename to number of groups to be split based on time. + * + * @param array $suites + * @param integer $time + * @return array + */ + private function getSuiteNameToGroupCount($suites, $time) + { + $suiteNameToGroupCount = []; + foreach ($suites as $suiteName => $suiteTime) { + if ($suiteTime <= $time) { + $suiteNameToGroupCount[$suiteName] = 1; + } else { + $suiteNameToGroupCount[$suiteName] = ceil($suiteTime/$time); + } + } + return $suiteNameToGroupCount; + } + + /** + * Split tests into given number of groups. + * + * @param array $tests + * @param integer $groupCnt + * @return array + */ + private function splitTestsIntoGroups($tests, $groupCnt) + { + arsort($tests); + $groups = []; + + $cnt = -1; + foreach ($tests as $test => $size) { + $cnt += 1; + $index = $cnt % (2 * $groupCnt); + if ($index <= $groupCnt - 1) { + $groups[$index][$test] = $size; + } else { + $groups[intval(2 * $groupCnt - 1 - $index)][$test] = $size; + } + } + return $groups; + } + + /** + * Split suites into given number of groups. + * + * @param array $suiteNameToTestSize + * @param array $suiteNameToGroupCount + * @return array + */ + private function splitSuitesIntoGroups($suiteNameToTestSize, $suiteNameToGroupCount) + { + $groups = []; + foreach ($suiteNameToTestSize as $suiteName => $suiteTests) { + $suiteCnt = $suiteNameToGroupCount[$suiteName]; + if ($suiteCnt == 1) { + $groups[][$suiteName] = array_sum($suiteTests); + $this->addSuiteToConfig($suiteName, null, $suiteTests); + } elseif ($suiteCnt > 1) { + $suiteGroups = $this->splitTestsIntoGroups($suiteTests, $suiteCnt); + foreach ($suiteGroups as $index => $tests) { + $newSuiteName = $suiteName . '_' . strval($index) . '_G'; + $groups[][$newSuiteName] = array_sum($tests); + $this->addSuiteToConfig($suiteName, $newSuiteName, $tests); + } + } + } + return $groups; + } + /** * Function which returns the newly formed suite objects created as a part of the sort * From 58e81106be7772b61482c0be9f2210030615d377 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 22 Mar 2021 09:40:17 -0500 Subject: [PATCH 608/888] MQE-2495: config parallel by number of groups --- .../verification/Tests/SuiteGenerationTest.php | 2 +- .../Util/Sorter/ParallelGroupSorter.php | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/dev/tests/verification/Tests/SuiteGenerationTest.php b/dev/tests/verification/Tests/SuiteGenerationTest.php index 75d395fa7..fb99971a4 100644 --- a/dev/tests/verification/Tests/SuiteGenerationTest.php +++ b/dev/tests/verification/Tests/SuiteGenerationTest.php @@ -122,7 +122,7 @@ public function testSuiteGenerationParallel() //createParallelManifest /** @var ParallelByTimeTestManifest $parallelManifest */ - $parallelManifest = TestManifestFactory::makeManifest("parallel", ["functionalSuite1" => []]); + $parallelManifest = TestManifestFactory::makeManifest("parallelByTime", ["functionalSuite1" => []]); // Generate the Suite $parallelManifest->createTestGroups(1); diff --git a/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php b/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php index 5ef63e652..a08e61d66 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php +++ b/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php @@ -180,18 +180,17 @@ private function getSuiteNameToGroupCount($suites, $time) */ private function splitTestsIntoGroups($tests, $groupCnt) { + // Reverse sort the test array by size arsort($tests); - $groups = []; + $groups = array_fill(0, $groupCnt, []); - $cnt = -1; foreach ($tests as $test => $size) { - $cnt += 1; - $index = $cnt % (2 * $groupCnt); - if ($index <= $groupCnt - 1) { - $groups[$index][$test] = $size; - } else { - $groups[intval(2 * $groupCnt - 1 - $index)][$test] = $size; + for ($i = 0; $i < $groupCnt; $i++) { + $sums[$i] = array_sum($groups[$i]); } + asort($sums); + // Always add the next test to the group with the smallest sum + $groups[array_keys($sums)[0]][$test] = $size; } return $groups; } From 3a95153aa681387ae1a593154183481d06f5d896 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 23 Mar 2021 10:32:12 -0500 Subject: [PATCH 609/888] MQE-2495: config parallel by number of groups --- .../Util/Sorter/ParallelGroupSorterTest.php | 151 +++++++++++++++++- .../Tests/SuiteGenerationTest.php | 54 ++++++- .../Util/Sorter/ParallelGroupSorter.php | 75 ++++++--- 3 files changed, 256 insertions(+), 24 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Sorter/ParallelGroupSorterTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Sorter/ParallelGroupSorterTest.php index 0b274f87e..bb639de51 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Sorter/ParallelGroupSorterTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Sorter/ParallelGroupSorterTest.php @@ -18,7 +18,7 @@ class ParallelGroupSorterTest extends MagentoTestCase /** * Test a basic sort of available tests based on size */ - public function testBasicTestGroupSort() + public function testBasicTestGroupSplitByTime() { $sampleTestArray = [ 'test1' => 100, @@ -55,7 +55,7 @@ public function testBasicTestGroupSort() /** * Test a sort of both tests and a suite which is larger than the given line limitation */ - public function testSortWithSuites() + public function testTestsAndSuitesSplitByTime() { // mock tests for test object handler. $numberOfCalls = 0; @@ -112,4 +112,151 @@ public function testSortWithSuites() $this->assertEquals($expectedResults[$groupNum], array_keys($group)); } } + + /** + * Test a basic sort of available tests based on size + */ + public function testBasicTestGroupSplitByGroup() + { + $sampleTestArray = [ + 'test1' => 100, + 'test2' => 300, + 'test3' => 50, + 'test4' => 60, + 'test5' => 25, + 'test6' => 125, + 'test7' => 250, + 'test8' => 1, + 'test9' => 80, + 'test10' => 25, + 'test11' => 89, + 'test12' => 69, + 'test13' => 23, + 'test14' => 15, + 'test15' => 25, + 'test16' => 71, + 'test17' => 67, + 'test18' => 34, + 'test19' => 45, + 'test20' => 58, + 'test21' => 9, + ]; + + $expectedResult = [ + 0 => ['test2', 'test8'], + 1 => ['test11', 'test9', 'test17', 'test19', 'test13'], + 2 => ['test7', 'test18', 'test14', 'test21'], + 3 => ['test6', 'test12', 'test20', 'test5', 'test10'], + 4 => ['test1', 'test16', 'test4', 'test3', 'test15'] + ]; + + $testSorter = new ParallelGroupSorter(); + $actualResult = $testSorter->getTestsGroupedByFixedGroupCount([], $sampleTestArray, 5); + + $this->assertCount(5, $actualResult); + + foreach ($actualResult as $gropuNumber => $actualTests) { + $expectedTests = $expectedResult[$gropuNumber]; + $this->assertEquals($expectedTests, array_keys($actualTests)); + } + } + + /** + * Test a sort of both tests and a suite which is larger than the given line limitation + */ + public function testTestsAndSuitesSplitByGroup() + { + // mock tests for test object handler. + $numberOfCalls = 0; + $mockTest1 = AspectMock::double( + TestObject::class, + ['getEstimatedDuration' => function () use (&$numberOfCalls) { + $actionCount = [300, 275]; + $result = $actionCount[$numberOfCalls]; + $numberOfCalls++; + + return $result; + }] + )->make(); + + $mockHandler = AspectMock::double( + TestObjectHandler::class, + ['getObject' => function () use ($mockTest1) { + return $mockTest1; + }] + )->make(); + + AspectMock::double(TestObjectHandler::class, ['getInstance' => $mockHandler])->make(); + + // create test to size array + $sampleTestArray = [ + 'test1' => 1, + 'test2' => 125, + 'test3' => 35, + 'test4' => 111, + 'test5' => 43, + 'test6' => 321, + 'test7' => 260, + 'test8' => 5, + 'test9' => 189, + 'test10' => 246, + 'test11' => 98, + 'test12' => 96, + 'test13' => 232, + 'test14' => 51, + 'test15' => 52, + 'test16' => 127, + 'test17' => 76, + 'test18' => 43, + 'test19' => 154, + 'test20' => 85, + 'test21' => 219, + 'test22' => 87, + 'test23' => 65, + 'test24' => 216, + 'test25' => 271, + 'test26' => 99, + 'test27' => 102, + 'test28' => 179, + 'test29' => 243, + 'test30' => 93, + 'test31' => 330, + 'test32' => 85, + 'test33' => 291, + ]; + + // create mock suite references + $sampleSuiteArray = [ + 'mockSuite1' => ['mockTest1', 'mockTest2'] + ]; + + // perform sort + $testSorter = new ParallelGroupSorter(); + $actualResult = $testSorter->getTestsGroupedByFixedGroupCount($sampleSuiteArray, $sampleTestArray, 15); + + // verify the resulting groups + $this->assertCount(15, $actualResult); + + $expectedResults = [ + 0 => ['test31', 'test8', 'test1'], + 1 => ['test6', 'test5'], + 2 => ['test33', 'test17'], + 3 => ['test25', 'test32'], + 4 => ['test7', 'test22'], + 5 => ['test10', 'test30'], + 6 => ['test29', 'test12'], + 7 => ['test13', 'test11', 'test3'], + 8 => ['test21', 'test26', 'test14'], + 9 => ['test24', 'test27', 'test18'], + 10 => ['test9', 'test4', 'test23'], + 11 => ['test28', 'test2', 'test15'], + 12 => ['test19', 'test16', 'test20'], + 13 => ['mockSuite1_0_G'], + 14 => ['mockSuite1_1_G'], + ]; + + foreach ($actualResult as $groupNum => $group) { + $this->assertEquals($expectedResults[$groupNum], array_keys($group)); + } + } } diff --git a/dev/tests/verification/Tests/SuiteGenerationTest.php b/dev/tests/verification/Tests/SuiteGenerationTest.php index fb99971a4..1b0176a48 100644 --- a/dev/tests/verification/Tests/SuiteGenerationTest.php +++ b/dev/tests/verification/Tests/SuiteGenerationTest.php @@ -11,6 +11,7 @@ use Magento\FunctionalTestingFramework\Util\Filesystem\DirSetupUtil; use Magento\FunctionalTestingFramework\Util\Manifest\DefaultTestManifest; use Magento\FunctionalTestingFramework\Util\Manifest\ParallelByTimeTestManifest; +use Magento\FunctionalTestingFramework\Util\Manifest\ParallelByGroupTestManifest; use Magento\FunctionalTestingFramework\Util\Manifest\TestManifestFactory; use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Symfony\Component\Yaml\Yaml; @@ -107,7 +108,7 @@ public function testSuiteGeneration1() /** * Test generation of parallel suite groups */ - public function testSuiteGenerationParallel() + public function testSuiteGenerationParallelByTime() { $groupName = 'functionalSuite1'; @@ -157,6 +158,57 @@ public function testSuiteGenerationParallel() } } + /** + * Test generation of parallel suite groups + */ + public function testSuiteGenerationParallelByGroup() + { + $groupName = 'functionalSuite1'; + + $expectedGroups = [ + 'functionalSuite1_0_G', + 'functionalSuite1_1_G', + ]; + + $expectedContents = SuiteTestReferences::$data[$groupName]; + + //createParallelManifest + /** @var ParallelByGroupTestManifest $parallelManifest */ + $parallelManifest = TestManifestFactory::makeManifest("parallelByGroup", ["functionalSuite1" => []]); + + // Generate the Suite + $parallelManifest->createTestGroups(2); + SuiteGenerator::getInstance()->generateAllSuites($parallelManifest); + + // Validate log message (for final group) and add group name for later deletion + $expectedGroup = $expectedGroups[count($expectedGroups)-1] ; + TestLoggingUtil::getInstance()->validateMockLogStatement( + 'info', + "suite generated", + ['suite' => $expectedGroup, 'relative_path' => "_generated" . DIRECTORY_SEPARATOR . $expectedGroup] + ); + + self::$TEST_GROUPS[] = $groupName; + + // Validate Yaml file updated + $yml = Yaml::parse(file_get_contents(self::CONFIG_YML_FILE)); + $this->assertEquals(array_intersect($expectedGroups, array_keys($yml['groups'])), $expectedGroups); + + foreach ($expectedGroups as $expectedFolder) { + $suiteResultBaseDir = self::GENERATE_RESULT_DIR . + DIRECTORY_SEPARATOR . + $expectedFolder . + DIRECTORY_SEPARATOR; + + // Validate tests have been generated + $dirContents = array_diff(scandir($suiteResultBaseDir), ['..', '.']); + + //Validate two test has been added to each group since lines are set to 1 + $this->assertEquals(2, count($dirContents)); + $this->assertContains(array_values($dirContents)[0], $expectedContents); + } + } + /** * Test hook groups generated during suite generation */ diff --git a/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php b/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php index a08e61d66..042416f83 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php +++ b/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php @@ -87,19 +87,48 @@ public function getTestsGroupedBySize($suiteConfiguration, $testNameToSize, $tim public function getTestsGroupedByFixedGroupCount($suiteConfiguration, $testNameToSize, $groupTotal) { $suiteNameToTestSize = $this->getSuiteNameToTestSize($suiteConfiguration); - $suiteNameToSize = $this->getSuiteToSize($suiteNameToTestSize); $minRequiredGroupCount = count($suiteNameToTestSize); if (!empty($testNameToSize)) { $minRequiredGroupCount += 1; } - if ($groupTotal < $minRequiredGroupCount) { throw new FastFailException( "Invalid parameter 'groupTotal': must be greater than {$minRequiredGroupCount}\n" ); } + if (empty($suiteConfiguration)) { + return $this->splitTestsIntoGroups($testNameToSize, $groupTotal); + } + + // Calculate suite group totals + $suiteNameToSize = $this->getSuiteToSize($suiteNameToTestSize); + $suiteNameToGroupCount = $this->getSuiteGroupCounts($suiteNameToSize, $testNameToSize, $groupTotal); + + // Calculate test group total + $testGroupTotal = $groupTotal - array_sum($suiteNameToGroupCount); + + // Split tests and suites + $testGroups = $this->splitTestsIntoGroups($testNameToSize, $testGroupTotal); + $testGroups = array_merge( + $testGroups, + $this->splitSuitesIntoGroups($suiteNameToTestSize, $suiteNameToGroupCount) + ); + + return $testGroups; + } + + /** + * Return suite's group counts from a group total + * + * @param $suiteNameToSize + * @param $testNameToSize + * @param $groupTotal + * @return array + */ + private function getSuiteGroupCounts($suiteNameToSize, $testNameToSize, $groupTotal) + { // Calculate the minimum possible group time $minGroupTime = ceil((array_sum($testNameToSize) + array_sum($suiteNameToSize)) / $groupTotal); @@ -110,24 +139,37 @@ public function getTestsGroupedByFixedGroupCount($suiteConfiguration, $testNameT $ceilSuiteGroupNumber = ceil($maxSuiteTime / $minGroupTime); $ceilSuiteGroupTime = max(ceil($maxSuiteTime / $ceilSuiteGroupNumber), $minGroupTime); $floorSuiteGroupNumber = floor($maxSuiteTime / $minGroupTime); - if ($floorSuiteGroupNumber != 0.0) { + if ($floorSuiteGroupNumber != 0) { $floorSuiteGroupTime = max(ceil($maxSuiteTime / $floorSuiteGroupNumber), $minGroupTime); } // Calculate test group time for ceiling - $ceilSuiteNameToGroupCount = $this->getSuiteNameToGroupCount($suiteNameToSize, $ceilSuiteGroupTime); + $ceilSuiteNameToGroupCount = $this->getSuiteGroupCountFromGroupTime($suiteNameToSize, $ceilSuiteGroupTime); $ceilSuiteGroupTotal = array_sum($ceilSuiteNameToGroupCount); $ceilTestGroupTotal = $groupTotal - $ceilSuiteGroupTotal; - $ceilTestGroupTime = ceil(array_sum($testNameToSize) / $ceilTestGroupTotal); + + if ($ceilTestGroupTotal == 0) { + $ceilTestGroupTime = 0; + } else { + $ceilTestGroupTime = ceil(array_sum($testNameToSize) / $ceilTestGroupTotal); + } + // Set suite group total to ceiling $suiteNameToGroupCount = $ceilSuiteNameToGroupCount; if (isset($floorSuiteGroupTime) && $ceilSuiteGroupTime != $floorSuiteGroupTime) { // Calculate test group time for floor - $floorSuiteNameToGroupCount = $this->getSuiteNameToGroupCount($suiteNameToSize, $floorSuiteGroupTime); + $floorSuiteNameToGroupCount = $this->getSuiteGroupCountFromGroupTime( + $suiteNameToSize, + $floorSuiteGroupTime + ); $floorSuiteGroupTotal = array_sum($floorSuiteNameToGroupCount); $floorTestGroupTotal = $groupTotal - $floorSuiteGroupTotal; - $floorTestGroupTime = ceil(array_sum($testNameToSize) / $floorTestGroupTotal); + if ($floorTestGroupTotal == 0) { + $floorTestGroupTime = 0; + } else { + $floorTestGroupTime = ceil(array_sum($testNameToSize) / $floorTestGroupTotal); + } // Choose the closer value between test group time and suite group time $ceilDiff = abs($ceilTestGroupTime - $ceilSuiteGroupTime); @@ -138,17 +180,7 @@ public function getTestsGroupedByFixedGroupCount($suiteConfiguration, $testNameT } } - // Calculate test group total - $testGroupTotal = $groupTotal - array_sum($suiteNameToGroupCount); - - // Split tests and suites - $testGroups = $this->splitTestsIntoGroups($testNameToSize, $testGroupTotal); - $testGroups = array_merge( - $testGroups, - $this->splitSuitesIntoGroups($suiteNameToTestSize, $suiteNameToGroupCount) - ); - - return $testGroups; + return $suiteNameToGroupCount; } /** @@ -158,7 +190,7 @@ public function getTestsGroupedByFixedGroupCount($suiteConfiguration, $testNameT * @param integer $time * @return array */ - private function getSuiteNameToGroupCount($suites, $time) + private function getSuiteGroupCountFromGroupTime($suites, $time) { $suiteNameToGroupCount = []; foreach ($suites as $suiteName => $suiteTime) { @@ -190,9 +222,10 @@ private function splitTestsIntoGroups($tests, $groupCnt) } asort($sums); // Always add the next test to the group with the smallest sum - $groups[array_keys($sums)[0]][$test] = $size; + $groups[array_key_first($sums)][$test] = $size; } - return $groups; + // Filter empty array + return array_filter($groups); } /** From 544410fbacd893c88f74406a74d3251500158349 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 24 Mar 2021 09:18:35 -0500 Subject: [PATCH 610/888] MQE-2495: config parallel by number of groups --- dev/tests/util/MftfTestCase.php | 12 ++++++++++++ dev/tests/verification/Tests/SuiteGenerationTest.php | 4 ++++ .../Util/Sorter/ParallelGroupSorter.php | 6 +++--- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/dev/tests/util/MftfTestCase.php b/dev/tests/util/MftfTestCase.php index ae9e4dd79..a563186b3 100644 --- a/dev/tests/util/MftfTestCase.php +++ b/dev/tests/util/MftfTestCase.php @@ -6,6 +6,8 @@ namespace tests\util; use Magento\FunctionalTestingFramework\ObjectManager; +use Magento\FunctionalTestingFramework\Suite\Handlers\SuiteObjectHandler; +use Magento\FunctionalTestingFramework\Suite\SuiteGenerator; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; use Magento\FunctionalTestingFramework\Util\TestGenerator; use PHPUnit\Framework\TestCase; @@ -118,5 +120,15 @@ private function clearHandler() $property = new \ReflectionProperty(ObjectManager::class, 'instance'); $property->setAccessible(true); $property->setValue(null); + + // clear suite generator to force recollection of test data + $property = new \ReflectionProperty(SuiteGenerator::class, 'instance'); + $property->setAccessible(true); + $property->setValue(null); + + // clear suite object handler to force recollection of test data + $property = new \ReflectionProperty(SuiteObjectHandler::class, 'instance'); + $property->setAccessible(true); + $property->setValue(null); } } diff --git a/dev/tests/verification/Tests/SuiteGenerationTest.php b/dev/tests/verification/Tests/SuiteGenerationTest.php index 1b0176a48..85fbbacc9 100644 --- a/dev/tests/verification/Tests/SuiteGenerationTest.php +++ b/dev/tests/verification/Tests/SuiteGenerationTest.php @@ -490,6 +490,10 @@ public function tearDown(): void $fileSystem->remove( self::CONFIG_YML_FILE ); + + $property = new \ReflectionProperty(DirSetupUtil::class, "DIR_CONTEXT"); + $property->setAccessible(true); + $property->setValue([]); } /** diff --git a/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php b/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php index 042416f83..ab14e1523 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php +++ b/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php @@ -122,9 +122,9 @@ public function getTestsGroupedByFixedGroupCount($suiteConfiguration, $testNameT /** * Return suite's group counts from a group total * - * @param $suiteNameToSize - * @param $testNameToSize - * @param $groupTotal + * @param array $suiteNameToSize + * @param array $testNameToSize + * @param integer $groupTotal * @return array */ private function getSuiteGroupCounts($suiteNameToSize, $testNameToSize, $groupTotal) From f5065a0a8197ca173364f900d1277d4e9806416d Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 24 Mar 2021 15:04:47 -0500 Subject: [PATCH 611/888] MQE-2495: config parallel by number of groups --- docs/commands/mftf.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 6105c0d19..46eefbe6e 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -163,6 +163,7 @@ vendor/bin/mftf generate:tests [option] [<test name>] [<test name>] [--remove] | `--filter` | Option to filter tests to be generated.<br/>Template: '<filterName>:<filterValue>'.<br/>Existing filter types: severity.<br/>Existing severity values: BLOCKER, CRITICAL, MAJOR, AVERAGE, MINOR.<br/>Example: --filter=severity:CRITICAL| | `--force` | Forces test generation, regardless of the module merge order defined in the Magento instance. Example: `generate:tests --force`. | | `-i,--time` | Set time in minutes to determine the group size when `--config=parallel` is used. The __default value__ is `10`. Example: `generate:tests --config=parallel --time=15`| +| `-g,--groups` | Set number of groups to be split into when `--config=parallel` is used. `--time` and `--groups` options are mutually exclusive. Example: `generate:tests --config=parallel --groups=300`| | `--tests` | Defines the test configuration as a JSON string.| | `--allow-skipped` | Allows MFTF to generate and run tests marked with `<skip>.`| | `--debug` | Performs schema validations on XML files. <br/> DEFAULT: `generate:tests` implicitly performs schema validation on merged files. It does not indicate the file name where the error is encountered. <br/> DEVELOPER: `--debug` performs per-file validation and returns additional debug information (such as the filename where an error occurred) when test generation fails because of an invalid XML schema. This option takes extra processing time. Use it after test generation has failed once.<br/>| From 5c95d7ddfba75b747d2559e479df003297867fb2 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 24 Mar 2021 15:18:08 -0500 Subject: [PATCH 612/888] MQE-2585: use --no-sandbox chrome options for functional suite. --- etc/config/functional.suite.dist.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/config/functional.suite.dist.yml b/etc/config/functional.suite.dist.yml index fefcec410..d5dbde466 100644 --- a/etc/config/functional.suite.dist.yml +++ b/etc/config/functional.suite.dist.yml @@ -38,4 +38,4 @@ modules: capabilities: unhandledPromptBehavior: "ignore" chromeOptions: - args: ["--window-size=1280,1024", "--disable-extensions", "--enable-automation", "--disable-gpu", "--enable-Passthrough", "--disable-dev-shm-usage", "--ignore-certificate-errors"] + args: ["--no-sandbox", "--window-size=1280,1024", "--disable-extensions", "--enable-automation", "--disable-gpu", "--enable-Passthrough", "--disable-dev-shm-usage", "--ignore-certificate-errors"] From 684e793e0ab7b44b529bda1aef0288decbe806b2 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 25 Mar 2021 17:58:13 -0500 Subject: [PATCH 613/888] MQE-2495: config parallel by number of groups --- .../Console/GenerateTestsCommand.php | 70 +++++++++++++------ 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php index 7520e3501..dfaaeba1f 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php @@ -56,7 +56,6 @@ protected function configure() 'i', InputOption::VALUE_REQUIRED, 'Used in combination with a parallel configuration, determines desired group size (in minutes)', - self::PARALLEL_DEFAULT_TIME )->addOption( 'groups', 'g', @@ -97,7 +96,8 @@ protected function execute(InputInterface $input, OutputInterface $output) $config = $input->getOption('config'); $json = $input->getOption('tests'); // for backward compatibility $force = $input->getOption('force'); - $time = $input->getOption('time') * 60 * 1000; // convert from minutes to milliseconds + $time = $input->getOption('time'); + //$time = $input->getOption('time') * 60 * 1000; // convert from minutes to milliseconds $groups = $input->getOption('groups'); $debug = $input->getOption('debug') ?? MftfApplicationConfig::LEVEL_DEVELOPER; // for backward compatibility $remove = $input->getOption('remove'); @@ -132,25 +132,8 @@ protected function execute(InputInterface $input, OutputInterface $output) throw new TestFrameworkException("JSON could not be parsed: " . json_last_error_msg()); } - $configNumber = null; if ($config === 'parallel') { - $config = 'parallelByTime'; - if ($groups) { - $groups = $groups * 1; - $config = 'parallelByGroup'; - if ($time !== self::PARALLEL_DEFAULT_TIME * 60 * 1000) { - throw new TestFrameworkException( - "'time' and 'groups' options are mutually exclusive, only one can be used at a time" - ); - } - if (!is_int($groups) || $groups <= 0) { - throw new TestFrameworkException("'groups' option must be an integer and greater than 0"); - } - } elseif ($time <= 0) { - throw new TestFrameworkException("'time' option cannot be less than or equal to 0"); - } - - $configNumber = $groups ?? $time; + list($config, $configNumber) = $this->parseConfigureParalleOptions($time, $groups); } // Remove previous GENERATED_DIR if --remove option is used @@ -279,4 +262,51 @@ private function parseTestsConfigJson($json, array $testConfiguration) $jsonTestConfiguration['suites'] = $testConfigArray['suites'] ?? null; return $jsonTestConfiguration; } + + /** + * Parse console command options --time and/or --groups and return config type and config number in an array + * + * @param mixed $time + * @param mixed $groups + * @return array + * @throws FastFailException + */ + private function parseConfigureParalleOptions($time, $groups) + { + $config = null; + $configNumber = null; + if ($time !== null && $groups !== null) { + throw new FastFailException( + "'time' and 'groups' options are mutually exclusive. " + . "Only one can be specified for 'config parallel'" + ); + } elseif ($time === null && $groups === null) { + $config = 'parallelByTime'; + $configNumber = self::PARALLEL_DEFAULT_TIME * 60 * 1000; // convert from minutes to milliseconds + } elseif ($time) { + if (is_numeric($time)) { + $time = $time * 60 * 1000; // convert from minutes to milliseconds + if (is_int($time) && $time > 0) { + $config = 'parallelByTime'; + $configNumber = $time; + } + } + } else { + if (is_numeric($groups)) { + $groups = $groups * 1; + if (is_int($groups) && $groups > 0) { + $config = 'parallelByGroup'; + $configNumber = $groups; + } + } + } + + if ($config && $configNumber) { + return [$config, $configNumber]; + } elseif ($time) { + throw new FastFailException("'time' option must be an integer and greater than 0"); + } else { + throw new FastFailException("'groups' option must be an integer and greater than 0"); + } + } } From 38690e694bc27bc581ad3d52374f5bd67cd5fb76 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 25 Mar 2021 18:01:32 -0500 Subject: [PATCH 614/888] MQE-2495: config parallel by number of groups --- .../Console/GenerateTestsCommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php index dfaaeba1f..ff4e4418e 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php @@ -133,7 +133,7 @@ protected function execute(InputInterface $input, OutputInterface $output) } if ($config === 'parallel') { - list($config, $configNumber) = $this->parseConfigureParalleOptions($time, $groups); + list($config, $configNumber) = $this->parseConfigParallelOptions($time, $groups); } // Remove previous GENERATED_DIR if --remove option is used @@ -271,7 +271,7 @@ private function parseTestsConfigJson($json, array $testConfiguration) * @return array * @throws FastFailException */ - private function parseConfigureParalleOptions($time, $groups) + private function parseConfigParallelOptions($time, $groups) { $config = null; $configNumber = null; From 628ab28a767fe615fb241ed48d53eeee57ed8623 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Fri, 26 Mar 2021 14:14:53 -0500 Subject: [PATCH 615/888] MQE-2495: config parallel by number of groups --- .../Console/GenerateTestsCommandTest.php | 80 +++++ .../Util/Sorter/ParallelGroupSorterTest.php | 274 ++++++++++++++++-- docs/commands/mftf.md | 4 +- .../Console/GenerateTestsCommand.php | 32 +- .../Util/Sorter/ParallelGroupSorter.php | 45 ++- 5 files changed, 380 insertions(+), 55 deletions(-) create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/Console/GenerateTestsCommandTest.php diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Console/GenerateTestsCommandTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Console/GenerateTestsCommandTest.php new file mode 100644 index 000000000..40a96e774 --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Console/GenerateTestsCommandTest.php @@ -0,0 +1,80 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace tests\unit\Magento\FunctionalTestFramework\Console; + +use PHPUnit\Framework\TestCase; +use Magento\FunctionalTestingFramework\Exceptions\FastFailException; +use Magento\FunctionalTestingFramework\Console\GenerateTestsCommand; + +class GenerateTestsCommandTest extends TestCase +{ + /** + * @param mixed $time + * @param mixed $groups + * @param mixed $expected + * @return void + * @dataProvider configParallelOptions + */ + public function testParseConfigParallelOptions($time, $groups, $expected): void + { + $command = new GenerateTestsCommand(); + $class = new \ReflectionClass($command); + $method = $class->getMethod('parseConfigParallelOptions'); + $method->setAccessible(true); + + if (is_array($expected)) { + $actual = $method->invokeArgs($command, [$time, $groups]); + $this->assertEquals($expected, $actual); + } else { + $this->expectException(FastFailException::class); + $this->expectExceptionMessage($expected); + $method->invokeArgs($command, [$time, $groups]); + } + } + + /** + * Data provider for testParseConfigParallelOptions() + * + * @return array + */ + public function configParallelOptions(): array + { + return [ + [null, null, ['parallelByTime', 600000]], /* #0 */ + ['20', null, ['parallelByTime', 1200000]], /* #1 */ + [5, null, ['parallelByTime', 300000]], /* #2 */ + [null, '300', ['parallelByGroup', 300]], /* #3 */ + [null, 1000, ['parallelByGroup', 1000]], /* #4 */ + [0.5, null, "'time' option must be an integer and greater than 0"], /* #5 */ + [0, null, "'time' option must be an integer and greater than 0"], /* #6 */ + ['0', null, "'time' option must be an integer and greater than 0"], /* #7 */ + [0.0, null, "'time' option must be an integer and greater than 0"], /* #8 */ + ['0.0', null, "'time' option must be an integer and greater than 0"], /* #9 */ + [-10, null, "'time' option must be an integer and greater than 0"], /* #10 */ + ['-10', null, "'time' option must be an integer and greater than 0"], /* #11 */ + ['12x', null, "'time' option must be an integer and greater than 0"], /* #12 */ + [null, 0.5, "'groups' option must be an integer and greater than 0"], /* #13 */ + [null, 0, "'groups' option must be an integer and greater than 0"], /* #14 */ + [null, 0.0, "'groups' option must be an integer and greater than 0"], /* #15 */ + [null, '0', "'groups' option must be an integer and greater than 0"], /* #16 */ + [null, '0.0', "'groups' option must be an integer and greater than 0"], /* #17 */ + [null, -10, "'groups' option must be an integer and greater than 0"], /* #18 */ + [null, '-10', "'groups' option must be an integer and greater than 0"], /* #19 */ + [null, '12x', "'groups' option must be an integer and greater than 0"], /* #20 */ + ['20', '300', "'time' and 'groups' options are mutually exclusive. " + . "Only one can be specified for 'config parallel'" + ], /* #21 */ + [20, 300, "'time' and 'groups' options are mutually exclusive. " + . "Only one can be specified for 'config parallel'" + ], /* #22 */ + ['0', 0, "'time' and 'groups' options are mutually exclusive. " + . "Only one can be specified for 'config parallel'" + ], /* #23 */ + [[1], null, "'time' option must be an integer and greater than 0"], /* #24 */ + [null, [-1], "'groups' option must be an integer and greater than 0"], /* #25 */ + ]; + } +} diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Sorter/ParallelGroupSorterTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Sorter/ParallelGroupSorterTest.php index bb639de51..6b25a837a 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Sorter/ParallelGroupSorterTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Sorter/ParallelGroupSorterTest.php @@ -6,6 +6,7 @@ namespace tests\unit\Magento\FunctionalTestFramework\Util\Sorter; use AspectMock\Test as AspectMock; +use Magento\FunctionalTestingFramework\Exceptions\FastFailException; use Magento\FunctionalTestingFramework\Suite\Handlers\SuiteObjectHandler; use Magento\FunctionalTestingFramework\Suite\Objects\SuiteObject; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; @@ -18,7 +19,7 @@ class ParallelGroupSorterTest extends MagentoTestCase /** * Test a basic sort of available tests based on size */ - public function testBasicTestGroupSplitByTime() + public function testBasicTestsSplitByTime() { $sampleTestArray = [ 'test1' => 100, @@ -114,9 +115,9 @@ public function testTestsAndSuitesSplitByTime() } /** - * Test a basic sort of available tests based on size + * Test splitting tests based on a fixed group number */ - public function testBasicTestGroupSplitByGroup() + public function testBasicTestsSplitByGroup() { $sampleTestArray = [ 'test1' => 100, @@ -143,11 +144,11 @@ public function testBasicTestGroupSplitByGroup() ]; $expectedResult = [ - 0 => ['test2', 'test8'], - 1 => ['test11', 'test9', 'test17', 'test19', 'test13'], - 2 => ['test7', 'test18', 'test14', 'test21'], - 3 => ['test6', 'test12', 'test20', 'test5', 'test10'], - 4 => ['test1', 'test16', 'test4', 'test3', 'test15'] + 1 => ['test2', 'test8'], + 2 => ['test11', 'test9', 'test17', 'test19', 'test13'], + 3 => ['test7', 'test18', 'test14', 'test21'], + 4 => ['test6', 'test12', 'test20', 'test5', 'test10'], + 5 => ['test1', 'test16', 'test4', 'test3', 'test15'] ]; $testSorter = new ParallelGroupSorter(); @@ -162,7 +163,67 @@ public function testBasicTestGroupSplitByGroup() } /** - * Test a sort of both tests and a suite which is larger than the given line limitation + * Test splitting tests based a group number bigger than ever needed + */ + public function testBasicTestsSplitByBigGroupNumber() + { + $sampleTestArray = [ + 'test1' => 100, + 'test2' => 300, + 'test3' => 50, + 'test4' => 60, + 'test5' => 25, + ]; + + $expectedResult = [ + 1 => ['test2'], + 2 => ['test1'], + 3 => ['test4'], + 4 => ['test3'], + 5 => ['test5'] + ]; + + $testSorter = new ParallelGroupSorter(); + $actualResult = $testSorter->getTestsGroupedByFixedGroupCount([], $sampleTestArray, 10); + + $this->assertCount(5, $actualResult); + + foreach ($actualResult as $gropuNumber => $actualTests) { + $expectedTests = $expectedResult[$gropuNumber]; + $this->assertEquals($expectedTests, array_keys($actualTests)); + } + } + + /** + * Test splitting tests based a minimum group number + */ + public function testBasicTestsSplitByMinGroupNumber() + { + $sampleTestArray = [ + 'test1' => 100, + 'test2' => 300, + 'test3' => 50, + 'test4' => 60, + 'test5' => 25, + ]; + + $expectedResult = [ + 1 => ['test2', 'test1', 'test4', 'test3', 'test5'] + ]; + + $testSorter = new ParallelGroupSorter(); + $actualResult = $testSorter->getTestsGroupedByFixedGroupCount([], $sampleTestArray, 1); + + $this->assertCount(1, $actualResult); + + foreach ($actualResult as $gropuNumber => $actualTests) { + $expectedTests = $expectedResult[$gropuNumber]; + $this->assertEquals($expectedTests, array_keys($actualTests)); + } + } + + /** + * Test splitting tests and suites based on a fixed group number */ public function testTestsAndSuitesSplitByGroup() { @@ -171,7 +232,7 @@ public function testTestsAndSuitesSplitByGroup() $mockTest1 = AspectMock::double( TestObject::class, ['getEstimatedDuration' => function () use (&$numberOfCalls) { - $actionCount = [300, 275]; + $actionCount = [300, 275, 300, 275]; $result = $actionCount[$numberOfCalls]; $numberOfCalls++; @@ -238,25 +299,188 @@ public function testTestsAndSuitesSplitByGroup() $this->assertCount(15, $actualResult); $expectedResults = [ - 0 => ['test31', 'test8', 'test1'], - 1 => ['test6', 'test5'], - 2 => ['test33', 'test17'], - 3 => ['test25', 'test32'], - 4 => ['test7', 'test22'], - 5 => ['test10', 'test30'], - 6 => ['test29', 'test12'], - 7 => ['test13', 'test11', 'test3'], - 8 => ['test21', 'test26', 'test14'], - 9 => ['test24', 'test27', 'test18'], - 10 => ['test9', 'test4', 'test23'], - 11 => ['test28', 'test2', 'test15'], - 12 => ['test19', 'test16', 'test20'], - 13 => ['mockSuite1_0_G'], - 14 => ['mockSuite1_1_G'], + 1 => ['test31', 'test8', 'test1'], + 2 => ['test6', 'test5'], + 3 => ['test33', 'test17'], + 4 => ['test25', 'test32'], + 5 => ['test7', 'test22'], + 6 => ['test10', 'test30'], + 7 => ['test29', 'test12'], + 8 => ['test13', 'test11', 'test3'], + 9 => ['test21', 'test26', 'test14'], + 10 => ['test24', 'test27', 'test18'], + 11 => ['test9', 'test4', 'test23'], + 12 => ['test28', 'test2', 'test15'], + 13 => ['test19', 'test16', 'test20'], + 14 => ['mockSuite1_0_G'], + 15 => ['mockSuite1_1_G'], + ]; + + foreach ($actualResult as $groupNum => $group) { + $this->assertEquals($expectedResults[$groupNum], array_keys($group)); + } + } + + /** + * Test splitting tests and suites based a group number bigger than ever needed + */ + public function testTestsAndSuitesSplitByBigGroupNumber() + { + // mock tests for test object handler. + $numberOfCalls = 0; + $mockTest1 = AspectMock::double( + TestObject::class, + ['getEstimatedDuration' => function () use (&$numberOfCalls) { + $actionCount = [300, 275, 300, 275]; + $result = $actionCount[$numberOfCalls]; + $numberOfCalls++; + + return $result; + }] + )->make(); + + $mockHandler = AspectMock::double( + TestObjectHandler::class, + ['getObject' => function () use ($mockTest1) { + return $mockTest1; + }] + )->make(); + + AspectMock::double(TestObjectHandler::class, ['getInstance' => $mockHandler])->make(); + + // create test to size array + $sampleTestArray = [ + 'test1' => 275, + 'test2' => 190, + 'test3' => 200, + ]; + + // create mock suite references + $sampleSuiteArray = [ + 'mockSuite1' => ['mockTest1', 'mockTest2'] + ]; + + // perform sort + $testSorter = new ParallelGroupSorter(); + $actualResult = $testSorter->getTestsGroupedByFixedGroupCount($sampleSuiteArray, $sampleTestArray, 10); + + // verify the resulting groups + $this->assertCount(5, $actualResult); + + $expectedResults = [ + 1 => ['test1'], + 2 => ['test3'], + 3 => ['test2'], + 4 => ['mockSuite1_0_G'], + 5 => ['mockSuite1_1_G'], + ]; + + foreach ($actualResult as $groupNum => $group) { + $this->assertEquals($expectedResults[$groupNum], array_keys($group)); + } + } + + /** + * Test splitting tests and suites based a minimum group number + */ + public function testTestsAndSuitesSplitByMinGroupNumber() + { + // mock tests for test object handler. + $numberOfCalls = 0; + $mockTest1 = AspectMock::double( + TestObject::class, + ['getEstimatedDuration' => function () use (&$numberOfCalls) { + $actionCount = [300, 275, 300, 275]; + $result = $actionCount[$numberOfCalls]; + $numberOfCalls++; + + return $result; + }] + )->make(); + + $mockHandler = AspectMock::double( + TestObjectHandler::class, + ['getObject' => function () use ($mockTest1) { + return $mockTest1; + }] + )->make(); + + AspectMock::double(TestObjectHandler::class, ['getInstance' => $mockHandler])->make(); + + // create test to size array + $sampleTestArray = [ + 'test1' => 1, + 'test2' => 125, + 'test3' => 35, + ]; + + // create mock suite references + $sampleSuiteArray = [ + 'mockSuite1' => ['mockTest1', 'mockTest2'] + ]; + + // perform sort + $testSorter = new ParallelGroupSorter(); + $actualResult = $testSorter->getTestsGroupedByFixedGroupCount($sampleSuiteArray, $sampleTestArray, 3); + + // verify the resulting groups + $this->assertCount(3, $actualResult); + + $expectedResults = [ + 1 => ['test2', 'test3', 'test1'], + 2 => ['mockSuite1_0_G'], + 3 => ['mockSuite1_1_G'], ]; foreach ($actualResult as $groupNum => $group) { $this->assertEquals($expectedResults[$groupNum], array_keys($group)); } } + + /** + * Test splitting tests and suites with invalid group number + */ + public function testTestsAndSuitesSplitByInvalidGroupNumber() + { + // mock tests for test object handler. + $numberOfCalls = 0; + $mockTest1 = AspectMock::double( + TestObject::class, + ['getEstimatedDuration' => function () use (&$numberOfCalls) { + $actionCount = [300, 275, 300, 275]; + $result = $actionCount[$numberOfCalls]; + $numberOfCalls++; + + return $result; + }] + )->make(); + + $mockHandler = AspectMock::double( + TestObjectHandler::class, + ['getObject' => function () use ($mockTest1) { + return $mockTest1; + }] + )->make(); + + AspectMock::double(TestObjectHandler::class, ['getInstance' => $mockHandler])->make(); + + // create test to size array + $sampleTestArray = [ + 'test1' => 1, + 'test2' => 125, + 'test3' => 35, + ]; + + // create mock suite references + $sampleSuiteArray = [ + 'mockSuite1' => ['mockTest1', 'mockTest2'] + ]; + + $this->expectException(FastFailException::class); + $this->expectExceptionMessage("Invalid parameter 'groupTotal': must be equal or greater than 2"); + + // perform sort + $testSorter = new ParallelGroupSorter(); + $testSorter->getTestsGroupedByFixedGroupCount($sampleSuiteArray, $sampleTestArray, 1); + } } diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 46eefbe6e..893f053d6 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -162,8 +162,8 @@ vendor/bin/mftf generate:tests [option] [<test name>] [<test name>] [--remove] | `--config=[<default> or <singleRun> or <parallel>]` | Creates a single manifest file with a list of all tests. The default location is `tests/functional/Magento/FunctionalTest/_generated/testManifest.txt`.<br/> You can split the list into multiple groups using `--config=parallel`; the groups will be generated in `_generated/groups/` like `_generated/groups/group1.txt, group2.txt, ...`.<br/> Available values: `default` (default), `singleRun`(same as `default`), and `parallel`.<br/> Example: `generate:tests --config=parallel`. | | `--filter` | Option to filter tests to be generated.<br/>Template: '<filterName>:<filterValue>'.<br/>Existing filter types: severity.<br/>Existing severity values: BLOCKER, CRITICAL, MAJOR, AVERAGE, MINOR.<br/>Example: --filter=severity:CRITICAL| | `--force` | Forces test generation, regardless of the module merge order defined in the Magento instance. Example: `generate:tests --force`. | -| `-i,--time` | Set time in minutes to determine the group size when `--config=parallel` is used. The __default value__ is `10`. Example: `generate:tests --config=parallel --time=15`| -| `-g,--groups` | Set number of groups to be split into when `--config=parallel` is used. `--time` and `--groups` options are mutually exclusive. Example: `generate:tests --config=parallel --groups=300`| +| `-i,--time` | Set time in minutes to determine the group size when `--config=parallel` is used. <br/>Example: `generate:tests --config=parallel --time=15` <br/>Option `--time` will be the default and the __default value__ is `10` when neither `--time` nor `--groups` is specified. <br/>Example: `generate:tests --config=parallel`| +| `-g,--groups` | Set number of groups to be split into when `--config=parallel` is used. <br>Example: `generate:tests --config=parallel --groups=300` <br/>Options `--time` and `--groups` are mutually exclusive and only one should be used.| | `--tests` | Defines the test configuration as a JSON string.| | `--allow-skipped` | Allows MFTF to generate and run tests marked with `<skip>.`| | `--debug` | Performs schema validations on XML files. <br/> DEFAULT: `generate:tests` implicitly performs schema validation on merged files. It does not indicate the file name where the error is encountered. <br/> DEVELOPER: `--debug` performs per-file validation and returns additional debug information (such as the filename where an error occurred) when test generation fails because of an invalid XML schema. This option takes extra processing time. Use it after test generation has failed once.<br/>| diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php index ff4e4418e..e783415f3 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php @@ -55,12 +55,16 @@ protected function configure() 'time', 'i', InputOption::VALUE_REQUIRED, - 'Used in combination with a parallel configuration, determines desired group size (in minutes)', + 'Used in combination with a parallel configuration, determines desired group size (in minutes)' + . PHP_EOL . 'Option "--time" will be the default and the default value is ' + . self::PARALLEL_DEFAULT_TIME + . ' when neither "--time" nor "--groups" is specified' )->addOption( 'groups', 'g', InputOption::VALUE_REQUIRED, 'Used in combination with a parallel configuration, determines desired number of groups' + . PHP_EOL . 'Options "--time" and "--groups" are mutually exclusive and only one should be used' )->addOption( 'tests', 't', @@ -283,27 +287,23 @@ private function parseConfigParallelOptions($time, $groups) } elseif ($time === null && $groups === null) { $config = 'parallelByTime'; $configNumber = self::PARALLEL_DEFAULT_TIME * 60 * 1000; // convert from minutes to milliseconds - } elseif ($time) { - if (is_numeric($time)) { - $time = $time * 60 * 1000; // convert from minutes to milliseconds - if (is_int($time) && $time > 0) { - $config = 'parallelByTime'; - $configNumber = $time; - } + } elseif ($time !== null && is_numeric($time)) { + $time = $time * 60 * 1000; // convert from minutes to milliseconds + if (is_int($time) && $time > 0) { + $config = 'parallelByTime'; + $configNumber = $time; } - } else { - if (is_numeric($groups)) { - $groups = $groups * 1; - if (is_int($groups) && $groups > 0) { - $config = 'parallelByGroup'; - $configNumber = $groups; - } + } elseif ($groups !== null && is_numeric($groups)) { + $groups = $groups * 1; + if (is_int($groups) && $groups > 0) { + $config = 'parallelByGroup'; + $configNumber = $groups; } } if ($config && $configNumber) { return [$config, $configNumber]; - } elseif ($time) { + } elseif ($time !== null) { throw new FastFailException("'time' option must be an integer and greater than 0"); } else { throw new FastFailException("'groups' option must be an integer and greater than 0"); diff --git a/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php b/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php index ab14e1523..925a2eceb 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php +++ b/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php @@ -94,17 +94,17 @@ public function getTestsGroupedByFixedGroupCount($suiteConfiguration, $testNameT } if ($groupTotal < $minRequiredGroupCount) { throw new FastFailException( - "Invalid parameter 'groupTotal': must be greater than {$minRequiredGroupCount}\n" + "Invalid parameter 'groupTotal': must be equal or greater than {$minRequiredGroupCount}" ); } if (empty($suiteConfiguration)) { - return $this->splitTestsIntoGroups($testNameToSize, $groupTotal); + return $this->convertArrayIndexStartingAtOne($this->splitTestsIntoGroups($testNameToSize, $groupTotal)); } // Calculate suite group totals $suiteNameToSize = $this->getSuiteToSize($suiteNameToTestSize); - $suiteNameToGroupCount = $this->getSuiteGroupCounts($suiteNameToSize, $testNameToSize, $groupTotal); + $suiteNameToGroupCount = $this->getSuiteGroupCounts($suiteNameToTestSize, $testNameToSize, $groupTotal); // Calculate test group total $testGroupTotal = $groupTotal - array_sum($suiteNameToGroupCount); @@ -116,19 +116,21 @@ public function getTestsGroupedByFixedGroupCount($suiteConfiguration, $testNameT $this->splitSuitesIntoGroups($suiteNameToTestSize, $suiteNameToGroupCount) ); - return $testGroups; + return $this->convertArrayIndexStartingAtOne($testGroups); } /** * Return suite's group counts from a group total * - * @param array $suiteNameToSize + * @param array $suiteNameToTestSize * @param array $testNameToSize * @param integer $groupTotal * @return array */ - private function getSuiteGroupCounts($suiteNameToSize, $testNameToSize, $groupTotal) + private function getSuiteGroupCounts($suiteNameToTestSize, $testNameToSize, $groupTotal) { + $suiteNameToSize = $this->getSuiteToSize($suiteNameToTestSize); + // Calculate the minimum possible group time $minGroupTime = ceil((array_sum($testNameToSize) + array_sum($suiteNameToSize)) / $groupTotal); @@ -144,7 +146,7 @@ private function getSuiteGroupCounts($suiteNameToSize, $testNameToSize, $groupTo } // Calculate test group time for ceiling - $ceilSuiteNameToGroupCount = $this->getSuiteGroupCountFromGroupTime($suiteNameToSize, $ceilSuiteGroupTime); + $ceilSuiteNameToGroupCount = $this->getSuiteGroupCountFromGroupTime($suiteNameToTestSize, $ceilSuiteGroupTime); $ceilSuiteGroupTotal = array_sum($ceilSuiteNameToGroupCount); $ceilTestGroupTotal = $groupTotal - $ceilSuiteGroupTotal; @@ -160,7 +162,7 @@ private function getSuiteGroupCounts($suiteNameToSize, $testNameToSize, $groupTo if (isset($floorSuiteGroupTime) && $ceilSuiteGroupTime != $floorSuiteGroupTime) { // Calculate test group time for floor $floorSuiteNameToGroupCount = $this->getSuiteGroupCountFromGroupTime( - $suiteNameToSize, + $suiteNameToTestSize, $floorSuiteGroupTime ); $floorSuiteGroupTotal = array_sum($floorSuiteNameToGroupCount); @@ -186,18 +188,20 @@ private function getSuiteGroupCounts($suiteNameToSize, $testNameToSize, $groupTo /** * Return array contains suitename to number of groups to be split based on time. * - * @param array $suites + * @param array $suiteNameToTestSize * @param integer $time * @return array */ - private function getSuiteGroupCountFromGroupTime($suites, $time) + private function getSuiteGroupCountFromGroupTime($suiteNameToTestSize, $time) { $suiteNameToGroupCount = []; - foreach ($suites as $suiteName => $suiteTime) { + foreach ($suiteNameToTestSize as $suiteName => $tests) { + $maxCount = count($tests); + $suiteTime = array_sum($tests); if ($suiteTime <= $time) { $suiteNameToGroupCount[$suiteName] = 1; } else { - $suiteNameToGroupCount[$suiteName] = ceil($suiteTime/$time); + $suiteNameToGroupCount[$suiteName] = min(ceil($suiteTime/$time), $maxCount); } } return $suiteNameToGroupCount; @@ -461,4 +465,21 @@ private function addSuiteToConfig($originalSuiteName, $newSuiteName, $tests) $this->suiteConfig[$originalSuiteName][$newSuiteName] = array_keys($tests); } + + /** + * Convert array index starting at 1 + * + * @param array $inArray + * @return array + */ + private function convertArrayIndexStartingAtOne($inArray) + { + $outArray = []; + $index = 1; + foreach ($inArray as $value) { + $outArray[$index] = $value; + $index += 1; + } + return $outArray; + } } From 6b2b486fa771a10b000edb258183fc944055f8b9 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Fri, 26 Mar 2021 14:18:16 -0500 Subject: [PATCH 616/888] MQE-2495: config parallel by number of groups --- .../Util/Sorter/ParallelGroupSorter.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php b/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php index 925a2eceb..a0651e051 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php +++ b/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php @@ -103,7 +103,6 @@ public function getTestsGroupedByFixedGroupCount($suiteConfiguration, $testNameT } // Calculate suite group totals - $suiteNameToSize = $this->getSuiteToSize($suiteNameToTestSize); $suiteNameToGroupCount = $this->getSuiteGroupCounts($suiteNameToTestSize, $testNameToSize, $groupTotal); // Calculate test group total @@ -129,9 +128,8 @@ public function getTestsGroupedByFixedGroupCount($suiteConfiguration, $testNameT */ private function getSuiteGroupCounts($suiteNameToTestSize, $testNameToSize, $groupTotal) { - $suiteNameToSize = $this->getSuiteToSize($suiteNameToTestSize); - // Calculate the minimum possible group time + $suiteNameToSize = $this->getSuiteToSize($suiteNameToTestSize); $minGroupTime = ceil((array_sum($testNameToSize) + array_sum($suiteNameToSize)) / $groupTotal); // Find maximum suite time From db586720e9bdcfbcb1e62a798e5b669f1157da9b Mon Sep 17 00:00:00 2001 From: Ihor Sviziev <ihor.sviziev@ven.com> Date: Tue, 30 Mar 2021 09:19:45 +0300 Subject: [PATCH 617/888] Update allure-codeception in order to support php8 --- composer.json | 2 +- composer.lock | 1279 +++++++++++++++++++++++++++++++++++++------------ 2 files changed, 978 insertions(+), 303 deletions(-) diff --git a/composer.json b/composer.json index 4d86275c2..c7f59d5c1 100755 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ "ext-intl": "*", "ext-json": "*", "ext-openssl": "*", - "allure-framework/allure-codeception": "~1.4.0", + "allure-framework/allure-codeception": "~1.5.0", "aws/aws-sdk-php": "^3.132", "codeception/codeception": "~4.1.4", "codeception/module-asserts": "^1.1", diff --git a/composer.lock b/composer.lock index 6ceeaba39..85f94a112 100644 --- a/composer.lock +++ b/composer.lock @@ -4,28 +4,33 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "d5b40409dd42db97a03df32090136b11", + "content-hash": "de918da1e98d166f168d0db3d14d4082", "packages": [ { "name": "allure-framework/allure-codeception", - "version": "1.4.5", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/allure-framework/allure-codeception.git", - "reference": "ac3d471902d2903856bbd0a95e7546788319ed22" + "reference": "5ccfa4cdc826ef43ddba42b817dab4c0a8be7de2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/allure-framework/allure-codeception/zipball/ac3d471902d2903856bbd0a95e7546788319ed22", - "reference": "ac3d471902d2903856bbd0a95e7546788319ed22", + "url": "https://api.github.com/repos/allure-framework/allure-codeception/zipball/5ccfa4cdc826ef43ddba42b817dab4c0a8be7de2", + "reference": "5ccfa4cdc826ef43ddba42b817dab4c0a8be7de2", "shasum": "" }, "require": { - "allure-framework/allure-php-api": "~1.2.1", - "codeception/codeception": "^2.3|^3.0|^4.0", - "php": ">=5.6", - "symfony/filesystem": ">=2.6", - "symfony/finder": ">=2.6" + "allure-framework/allure-php-api": "^1.3", + "codeception/codeception": "^2.5 | ^3 | ^4", + "ext-json": "*", + "php": ">=7.1.3", + "symfony/filesystem": "^2.7 | ^3 | ^4 | ^5", + "symfony/finder": "^2.7 | ^3 | ^4 | ^5" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^7.2 | ^8 | ^9" }, "type": "library", "autoload": { @@ -40,11 +45,11 @@ "authors": [ { "name": "Ivan Krutov", - "email": "vania-pooh@yandex-team.ru", + "email": "vania-pooh@aerokube.com", "role": "Developer" } ], - "description": "A Codeception adapter for Allure report.", + "description": "Allure Codeception integration", "homepage": "http://allure.qatools.ru/", "keywords": [ "allure", @@ -55,30 +60,35 @@ "steps", "testing" ], - "time": "2020-11-26T11:41:53+00:00" + "support": { + "email": "allure@qameta.io", + "issues": "https://github.com/allure-framework/allure-codeception/issues", + "source": "https://github.com/allure-framework/allure-codeception" + }, + "time": "2021-03-26T16:11:53+00:00" }, { "name": "allure-framework/allure-php-api", - "version": "1.2.1", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/allure-framework/allure-php-commons.git", - "reference": "13ef45d83ce4f5ef70499ff87ed0c3d1c192ab80" + "reference": "f64b69afeff472c564a4e2379efb2b69c430ec5a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/allure-framework/allure-php-commons/zipball/13ef45d83ce4f5ef70499ff87ed0c3d1c192ab80", - "reference": "13ef45d83ce4f5ef70499ff87ed0c3d1c192ab80", + "url": "https://api.github.com/repos/allure-framework/allure-php-commons/zipball/f64b69afeff472c564a4e2379efb2b69c430ec5a", + "reference": "f64b69afeff472c564a4e2379efb2b69c430ec5a", "shasum": "" }, "require": { - "jms/serializer": "^0.16 || ^1.0", - "php": ">=5.4.0", - "ramsey/uuid": "^3.0 || ^4.0", - "symfony/http-foundation": "^2.0 || ^3.0 || ^4.0 || ^5.0" + "jms/serializer": "^1 | ^2 | ^3", + "php": ">=7.1.3", + "ramsey/uuid": "^3 | ^4", + "symfony/mime": "^4.3 | ^5" }, "require-dev": { - "phpunit/phpunit": "^4.0.0" + "phpunit/phpunit": "^7 | ^8 | ^9" }, "type": "library", "autoload": { @@ -108,7 +118,12 @@ "php", "report" ], - "time": "2020-11-26T09:20:44+00:00" + "support": { + "email": "allure@yandex-team.ru", + "issues": "https://github.com/allure-framework/allure-php-commons/issues", + "source": "https://github.com/allure-framework/allure-php-api" + }, + "time": "2021-03-26T14:32:27+00:00" }, { "name": "aws/aws-sdk-php", @@ -258,25 +273,26 @@ }, { "name": "behat/gherkin", - "version": "v4.7.1", + "version": "v4.8.0", "source": { "type": "git", "url": "https://github.com/Behat/Gherkin.git", - "reference": "987bcdc3d29ba433e6bd4b1db4ae59737ba3dacd" + "reference": "2391482cd003dfdc36b679b27e9f5326bd656acd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Behat/Gherkin/zipball/987bcdc3d29ba433e6bd4b1db4ae59737ba3dacd", - "reference": "987bcdc3d29ba433e6bd4b1db4ae59737ba3dacd", + "url": "https://api.github.com/repos/Behat/Gherkin/zipball/2391482cd003dfdc36b679b27e9f5326bd656acd", + "reference": "2391482cd003dfdc36b679b27e9f5326bd656acd", "shasum": "" }, "require": { - "php": ">=5.6" + "php": "~7.2|~8.0" }, "require-dev": { - "phpunit/phpunit": "~5.7|~6|~7", - "symfony/phpunit-bridge": "~2.7|~3|~4", - "symfony/yaml": "~2.3|~3|~4" + "cucumber/cucumber": "dev-gherkin-16.0.0", + "phpunit/phpunit": "~8|~9", + "symfony/phpunit-bridge": "~3|~4|~5", + "symfony/yaml": "~3|~4|~5" }, "suggest": { "symfony/yaml": "If you want to parse features, represented in YAML files" @@ -313,7 +329,11 @@ "gherkin", "parser" ], - "time": "2021-01-26T16:24:32+00:00" + "support": { + "issues": "https://github.com/Behat/Gherkin/issues", + "source": "https://github.com/Behat/Gherkin/tree/v4.8.0" + }, + "time": "2021-02-04T12:44:21+00:00" }, { "name": "brick/math", @@ -359,20 +379,30 @@ "brick", "math" ], + "support": { + "issues": "https://github.com/brick/math/issues", + "source": "https://github.com/brick/math/tree/0.9.2" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/brick/math", + "type": "tidelift" + } + ], "time": "2021-01-20T22:51:39+00:00" }, { "name": "codeception/codeception", - "version": "4.1.16", + "version": "4.1.19", "source": { "type": "git", "url": "https://github.com/Codeception/Codeception.git", - "reference": "daf4fe110b33855252009a0dcab87ce8bcf7c009" + "reference": "138dc9345a81ec994dcd6b9680c501a752a37b00" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/Codeception/zipball/daf4fe110b33855252009a0dcab87ce8bcf7c009", - "reference": "daf4fe110b33855252009a0dcab87ce8bcf7c009", + "url": "https://api.github.com/repos/Codeception/Codeception/zipball/138dc9345a81ec994dcd6b9680c501a752a37b00", + "reference": "138dc9345a81ec994dcd6b9680c501a752a37b00", "shasum": "" }, "require": { @@ -444,7 +474,17 @@ "functional testing", "unit testing" ], - "time": "2021-01-26T07:25:32+00:00" + "support": { + "issues": "https://github.com/Codeception/Codeception/issues", + "source": "https://github.com/Codeception/Codeception/tree/4.1.19" + }, + "funding": [ + { + "url": "https://opencollective.com/codeception", + "type": "open_collective" + } + ], + "time": "2021-03-28T13:26:08+00:00" }, { "name": "codeception/lib-asserts", @@ -494,6 +534,10 @@ "keywords": [ "codeception" ], + "support": { + "issues": "https://github.com/Codeception/lib-asserts/issues", + "source": "https://github.com/Codeception/lib-asserts/tree/1.13.2" + }, "time": "2020-10-21T16:26:20+00:00" }, { @@ -684,6 +728,10 @@ } ], "description": "PHPUnit classes used by Codeception", + "support": { + "issues": "https://github.com/Codeception/phpunit-wrapper/issues", + "source": "https://github.com/Codeception/phpunit-wrapper/tree/9.0.6" + }, "time": "2020-12-28T13:59:47+00:00" }, { @@ -714,6 +762,10 @@ "MIT" ], "description": "Flexible Stub wrapper for PHPUnit's Mock Builder", + "support": { + "issues": "https://github.com/Codeception/Stub/issues", + "source": "https://github.com/Codeception/Stub/tree/3.7.0" + }, "time": "2020-07-03T15:54:43+00:00" }, { @@ -1110,16 +1162,16 @@ }, { "name": "doctrine/annotations", - "version": "1.11.1", + "version": "1.12.1", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "ce77a7ba1770462cd705a91a151b6c3746f9c6ad" + "reference": "b17c5014ef81d212ac539f07a1001832df1b6d3b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/ce77a7ba1770462cd705a91a151b6c3746f9c6ad", - "reference": "ce77a7ba1770462cd705a91a151b6c3746f9c6ad", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/b17c5014ef81d212ac539f07a1001832df1b6d3b", + "reference": "b17c5014ef81d212ac539f07a1001832df1b6d3b", "shasum": "" }, "require": { @@ -1134,11 +1186,6 @@ "phpunit/phpunit": "^7.5 || ^9.1.5" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.11.x-dev" - } - }, "autoload": { "psr-4": { "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" @@ -1177,7 +1224,11 @@ "docblock", "parser" ], - "time": "2020-10-26T10:28:16+00:00" + "support": { + "issues": "https://github.com/doctrine/annotations/issues", + "source": "https://github.com/doctrine/annotations/tree/1.12.1" + }, + "time": "2021-02-21T21:00:45+00:00" }, { "name": "doctrine/instantiator", @@ -1228,6 +1279,24 @@ "constructor", "instantiate" ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/1.4.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } + ], "time": "2020-11-10T18:47:58+00:00" }, { @@ -1290,6 +1359,24 @@ "parser", "php" ], + "support": { + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/1.2.1" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", + "type": "tidelift" + } + ], "time": "2020-05-25T17:44:05+00:00" }, { @@ -1412,16 +1499,16 @@ }, { "name": "guzzlehttp/psr7", - "version": "1.7.0", + "version": "1.8.1", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "53330f47520498c0ae1f61f7e2c90f55690c06a3" + "reference": "35ea11d335fd638b5882ff1725228b3d35496ab1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/53330f47520498c0ae1f61f7e2c90f55690c06a3", - "reference": "53330f47520498c0ae1f61f7e2c90f55690c06a3", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/35ea11d335fd638b5882ff1725228b3d35496ab1", + "reference": "35ea11d335fd638b5882ff1725228b3d35496ab1", "shasum": "" }, "require": { @@ -1479,7 +1566,11 @@ "uri", "url" ], - "time": "2020-09-30T07:37:11+00:00" + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/1.8.1" + }, + "time": "2021-03-21T16:25:00+00:00" }, { "name": "hoa/consistency", @@ -1542,6 +1633,14 @@ "keyword", "library" ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/Consistency", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/Consistency/issues", + "source": "https://central.hoa-project.net/Resource/Library/Consistency" + }, "time": "2017-05-02T12:18:12+00:00" }, { @@ -1674,6 +1773,14 @@ "listener", "observer" ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/Event", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/Event/issues", + "source": "https://central.hoa-project.net/Resource/Library/Event" + }, "time": "2017-01-13T15:30:50+00:00" }, { @@ -1728,6 +1835,14 @@ "exception", "library" ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/Exception", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/Exception/issues", + "source": "https://central.hoa-project.net/Resource/Library/Exception" + }, "time": "2017-01-16T07:53:27+00:00" }, { @@ -1790,6 +1905,14 @@ "link", "temporary" ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/File", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/File/issues", + "source": "https://central.hoa-project.net/Resource/Library/File" + }, "time": "2017-07-11T07:42:15+00:00" }, { @@ -1844,6 +1967,14 @@ "iterator", "library" ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/Iterator", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/Iterator/issues", + "source": "https://central.hoa-project.net/Resource/Library/Iterator" + }, "time": "2017-01-10T10:34:47+00:00" }, { @@ -1904,6 +2035,14 @@ "stream", "wrapper" ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/Protocol", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/Protocol/issues", + "source": "https://central.hoa-project.net/Resource/Library/Protocol" + }, "time": "2017-01-14T12:26:10+00:00" }, { @@ -1968,6 +2107,14 @@ "stream", "wrapper" ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/Stream", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/Stream/issues", + "source": "https://central.hoa-project.net/Resource/Library/Stream" + }, "time": "2017-02-21T16:01:06+00:00" }, { @@ -2028,37 +2175,50 @@ "string", "unicode" ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/Ustring", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/Ustring/issues", + "source": "https://central.hoa-project.net/Resource/Library/Ustring" + }, "time": "2017-01-16T07:08:25+00:00" }, { "name": "jms/metadata", - "version": "1.7.0", + "version": "2.5.0", "source": { "type": "git", "url": "https://github.com/schmittjoh/metadata.git", - "reference": "e5854ab1aa643623dc64adde718a8eec32b957a8" + "reference": "b5c52549807b2d855b3d7e36ec164c00eb547338" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/metadata/zipball/e5854ab1aa643623dc64adde718a8eec32b957a8", - "reference": "e5854ab1aa643623dc64adde718a8eec32b957a8", + "url": "https://api.github.com/repos/schmittjoh/metadata/zipball/b5c52549807b2d855b3d7e36ec164c00eb547338", + "reference": "b5c52549807b2d855b3d7e36ec164c00eb547338", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": "^7.2|^8.0" }, "require-dev": { - "doctrine/cache": "~1.0", - "symfony/cache": "~3.1" + "doctrine/cache": "^1.0", + "doctrine/coding-standard": "^8.0", + "mikey179/vfsstream": "^1.6.7", + "phpunit/phpunit": "^8.5|^9.0", + "psr/container": "^1.0", + "symfony/cache": "^3.1|^4.0|^5.0", + "symfony/dependency-injection": "^3.1|^4.0|^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.5.x-dev" + "dev-master": "2.x-dev" } }, "autoload": { - "psr-0": { + "psr-4": { "Metadata\\": "src/" } }, @@ -2067,13 +2227,13 @@ "MIT" ], "authors": [ - { - "name": "Asmir Mustafic", - "email": "goetas@gmail.com" - }, { "name": "Johannes M. Schmitt", "email": "schmittjoh@gmail.com" + }, + { + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" } ], "description": "Class/method/property metadata management in PHP", @@ -2083,100 +2243,68 @@ "xml", "yaml" ], - "time": "2018-10-26T12:40:10+00:00" - }, - { - "name": "jms/parser-lib", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/schmittjoh/parser-lib.git", - "reference": "c509473bc1b4866415627af0e1c6cc8ac97fa51d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/parser-lib/zipball/c509473bc1b4866415627af0e1c6cc8ac97fa51d", - "reference": "c509473bc1b4866415627af0e1c6cc8ac97fa51d", - "shasum": "" - }, - "require": { - "phpoption/phpoption": ">=0.9,<2.0-dev" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "psr-0": { - "JMS\\": "src/" - } + "support": { + "issues": "https://github.com/schmittjoh/metadata/issues", + "source": "https://github.com/schmittjoh/metadata/tree/2.5.0" }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache2" - ], - "description": "A library for easily creating recursive-descent parsers.", - "time": "2012-11-18T18:08:43+00:00" + "time": "2021-03-07T19:20:09+00:00" }, { "name": "jms/serializer", - "version": "1.14.1", + "version": "3.12.2", "source": { "type": "git", "url": "https://github.com/schmittjoh/serializer.git", - "reference": "ba908d278fff27ec01fb4349f372634ffcd697c0" + "reference": "ea54838a0acd960839b7401bfd83fcd6ebe34aed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/ba908d278fff27ec01fb4349f372634ffcd697c0", - "reference": "ba908d278fff27ec01fb4349f372634ffcd697c0", + "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/ea54838a0acd960839b7401bfd83fcd6ebe34aed", + "reference": "ea54838a0acd960839b7401bfd83fcd6ebe34aed", "shasum": "" }, "require": { "doctrine/annotations": "^1.0", "doctrine/instantiator": "^1.0.3", - "jms/metadata": "^1.3", - "jms/parser-lib": "1.*", - "php": "^5.5|^7.0", - "phpcollection/phpcollection": "~0.1", - "phpoption/phpoption": "^1.1" - }, - "conflict": { - "twig/twig": "<1.12" + "doctrine/lexer": "^1.1", + "jms/metadata": "^2.0", + "php": "^7.2||^8.0", + "phpstan/phpdoc-parser": "^0.4" }, "require-dev": { + "doctrine/coding-standard": "^8.1", "doctrine/orm": "~2.1", + "doctrine/persistence": "^1.3.3|^2.0|^3.0", "doctrine/phpcr-odm": "^1.3|^2.0", "ext-pdo_sqlite": "*", "jackalope/jackalope-doctrine-dbal": "^1.1.5", - "phpunit/phpunit": "^4.8|^5.0", - "propel/propel1": "~1.7", + "ocramius/proxy-manager": "^1.0|^2.0", + "phpstan/phpstan": "^0.12.65", + "phpunit/phpunit": "^8.0||^9.0", "psr/container": "^1.0", - "symfony/dependency-injection": "^2.7|^3.3|^4.0", - "symfony/expression-language": "^2.6|^3.0", - "symfony/filesystem": "^2.1", - "symfony/form": "~2.1|^3.0", - "symfony/translation": "^2.1|^3.0", - "symfony/validator": "^2.2|^3.0", - "symfony/yaml": "^2.1|^3.0", - "twig/twig": "~1.12|~2.0" + "symfony/dependency-injection": "^3.0|^4.0|^5.0", + "symfony/expression-language": "^3.0|^4.0|^5.0", + "symfony/filesystem": "^3.0|^4.0|^5.0", + "symfony/form": "^3.0|^4.0|^5.0", + "symfony/translation": "^3.0|^4.0|^5.0", + "symfony/validator": "^3.1.9|^4.0|^5.0", + "symfony/yaml": "^3.3|^4.0|^5.0", + "twig/twig": "~1.34|~2.4|^3.0" }, "suggest": { "doctrine/cache": "Required if you like to use cache functionality.", "doctrine/collections": "Required if you like to use doctrine collection types as ArrayCollection.", - "symfony/yaml": "Required if you'd like to serialize data to YAML format." + "symfony/yaml": "Required if you'd like to use the YAML metadata format." }, "type": "library", "extra": { "branch-alias": { - "dev-1.x": "1.14-dev" + "dev-master": "3.12-dev" } }, "autoload": { - "psr-0": { - "JMS\\Serializer": "src/" + "psr-4": { + "JMS\\Serializer\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2202,7 +2330,17 @@ "serialization", "xml" ], - "time": "2020-02-22T20:59:37+00:00" + "support": { + "issues": "https://github.com/schmittjoh/serializer/issues", + "source": "https://github.com/schmittjoh/serializer/tree/3.12.2" + }, + "funding": [ + { + "url": "https://github.com/goetas", + "type": "github" + } + ], + "time": "2021-03-23T12:37:04+00:00" }, { "name": "justinrainbow/json-schema", @@ -2491,6 +2629,16 @@ "object", "object graph" ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.10.2" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], "time": "2020-11-13T09:40:50+00:00" }, { @@ -2543,6 +2691,10 @@ "parser", "php" ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/master" + }, "time": "2020-04-10T16:34:50+00:00" }, { @@ -2660,6 +2812,10 @@ } ], "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/master" + }, "time": "2018-07-08T19:23:20+00:00" }, { @@ -2707,6 +2863,10 @@ } ], "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/master" + }, "time": "2018-07-08T19:19:57+00:00" }, { @@ -2774,54 +2934,6 @@ ], "time": "2020-03-04T14:40:12+00:00" }, - { - "name": "phpcollection/phpcollection", - "version": "0.5.0", - "source": { - "type": "git", - "url": "https://github.com/schmittjoh/php-collection.git", - "reference": "f2bcff45c0da7c27991bbc1f90f47c4b7fb434a6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-collection/zipball/f2bcff45c0da7c27991bbc1f90f47c4b7fb434a6", - "reference": "f2bcff45c0da7c27991bbc1f90f47c4b7fb434a6", - "shasum": "" - }, - "require": { - "phpoption/phpoption": "1.*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.4-dev" - } - }, - "autoload": { - "psr-0": { - "PhpCollection": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache2" - ], - "authors": [ - { - "name": "Johannes M. Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "General-Purpose Collection Library for PHP", - "keywords": [ - "collection", - "list", - "map", - "sequence", - "set" - ], - "time": "2015-05-17T12:39:23+00:00" - }, { "name": "phpdocumentor/reflection-common", "version": "2.2.0", @@ -2869,6 +2981,10 @@ "reflection", "static analysis" ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + }, "time": "2020-06-27T09:03:43+00:00" }, { @@ -2921,6 +3037,10 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/master" + }, "time": "2020-09-03T19:13:55+00:00" }, { @@ -2966,125 +3086,128 @@ } ], "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.4.0" + }, "time": "2020-09-17T18:55:26+00:00" }, { - "name": "phpoption/phpoption", - "version": "1.7.5", + "name": "phpspec/prophecy", + "version": "1.13.0", "source": { "type": "git", - "url": "https://github.com/schmittjoh/php-option.git", - "reference": "994ecccd8f3283ecf5ac33254543eb0ac946d525" + "url": "https://github.com/phpspec/prophecy.git", + "reference": "be1996ed8adc35c3fd795488a653f4b518be70ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/994ecccd8f3283ecf5ac33254543eb0ac946d525", - "reference": "994ecccd8f3283ecf5ac33254543eb0ac946d525", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/be1996ed8adc35c3fd795488a653f4b518be70ea", + "reference": "be1996ed8adc35c3fd795488a653f4b518be70ea", "shasum": "" }, "require": { - "php": "^5.5.9 || ^7.0 || ^8.0" + "doctrine/instantiator": "^1.2", + "php": "^7.2 || ~8.0, <8.1", + "phpdocumentor/reflection-docblock": "^5.2", + "sebastian/comparator": "^3.0 || ^4.0", + "sebastian/recursion-context": "^3.0 || ^4.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.4.1", - "phpunit/phpunit": "^4.8.35 || ^5.7.27 || ^6.5.6 || ^7.0 || ^8.0 || ^9.0" + "phpspec/phpspec": "^6.0", + "phpunit/phpunit": "^8.0 || ^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7-dev" + "dev-master": "1.11.x-dev" } }, "autoload": { "psr-4": { - "PhpOption\\": "src/PhpOption/" + "Prophecy\\": "src/Prophecy" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "Apache-2.0" + "MIT" ], "authors": [ { - "name": "Johannes M. Schmitt", - "email": "schmittjoh@gmail.com" + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" }, { - "name": "Graham Campbell", - "email": "graham@alt-three.com" + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" } ], - "description": "Option Type for PHP", + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", "keywords": [ - "language", - "option", - "php", - "type" + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" ], - "time": "2020-07-20T17:29:33+00:00" + "support": { + "issues": "https://github.com/phpspec/prophecy/issues", + "source": "https://github.com/phpspec/prophecy/tree/1.13.0" + }, + "time": "2021-03-17T13:42:18+00:00" }, { - "name": "phpspec/prophecy", - "version": "1.12.2", + "name": "phpstan/phpdoc-parser", + "version": "0.4.14", "source": { "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "245710e971a030f42e08f4912863805570f23d39" + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "cf4fc7d2aeca6910fba061901ffd7d107ccfdbcc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/245710e971a030f42e08f4912863805570f23d39", - "reference": "245710e971a030f42e08f4912863805570f23d39", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/cf4fc7d2aeca6910fba061901ffd7d107ccfdbcc", + "reference": "cf4fc7d2aeca6910fba061901ffd7d107ccfdbcc", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.2", - "php": "^7.2 || ~8.0, <8.1", - "phpdocumentor/reflection-docblock": "^5.2", - "sebastian/comparator": "^3.0 || ^4.0", - "sebastian/recursion-context": "^3.0 || ^4.0" + "php": "^7.1 || ^8.0" }, "require-dev": { - "phpspec/phpspec": "^6.0", - "phpunit/phpunit": "^8.0 || ^9.0" + "phing/phing": "^2.16.3", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.12.60", + "phpstan/phpstan-strict-rules": "^0.12.5", + "phpunit/phpunit": "^7.5.20", + "symfony/process": "^5.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.11.x-dev" + "dev-master": "0.4-dev" } }, "autoload": { "psr-4": { - "Prophecy\\": "src/Prophecy" + "PHPStan\\PhpDocParser\\": [ + "src/" + ] } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - }, - { - "name": "Marcello Duarte", - "email": "marcello.duarte@gmail.com" - } - ], - "description": "Highly opinionated mocking framework for PHP 5.3+", - "homepage": "https://github.com/phpspec/prophecy", - "keywords": [ - "Double", - "Dummy", - "fake", - "mock", - "spy", - "stub" - ], - "time": "2020-12-19T10:15:11+00:00" + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/0.4.14" + }, + "time": "2021-03-19T10:54:14+00:00" }, { "name": "phpunit/php-code-coverage", @@ -3148,6 +3271,16 @@ "testing", "xunit" ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/8.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-05-23T08:02:54+00:00" }, { @@ -3198,6 +3331,16 @@ "filesystem", "iterator" ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-09-28T05:57:25+00:00" }, { @@ -3251,6 +3394,16 @@ "keywords": [ "process" ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-09-28T05:58:55+00:00" }, { @@ -3300,6 +3453,16 @@ "keywords": [ "template" ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-10-26T05:33:50+00:00" }, { @@ -3349,6 +3512,16 @@ "keywords": [ "timer" ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-10-26T13:16:10+00:00" }, { @@ -3398,6 +3571,16 @@ "keywords": [ "tokenizer" ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-token-stream/issues", + "source": "https://github.com/sebastianbergmann/php-token-stream/tree/master" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "abandoned": true, "time": "2020-08-04T08:28:15+00:00" }, @@ -3487,6 +3670,20 @@ "testing", "xunit" ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.2.6" + }, + "funding": [ + { + "url": "https://phpunit.de/donate.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-07-13T17:55:55+00:00" }, { @@ -3533,31 +3730,29 @@ "psr", "psr-6" ], + "support": { + "source": "https://github.com/php-fig/cache/tree/master" + }, "time": "2016-08-06T20:24:11+00:00" }, { "name": "psr/container", - "version": "1.0.0", + "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/php-fig/container.git", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf", + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=7.2.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, "autoload": { "psr-4": { "Psr\\Container\\": "src/" @@ -3570,7 +3765,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common Container Interface (PHP FIG PSR-11)", @@ -3582,7 +3777,11 @@ "container-interop", "psr" ], - "time": "2017-02-14T16:28:37+00:00" + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.1" + }, + "time": "2021-03-05T17:36:06+00:00" }, { "name": "psr/http-client", @@ -3733,6 +3932,9 @@ "request", "response" ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/master" + }, "time": "2016-08-06T14:39:51+00:00" }, { @@ -3820,6 +4022,10 @@ } ], "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, "time": "2019-03-08T08:55:37+00:00" }, { @@ -3883,6 +4089,20 @@ "queue", "set" ], + "support": { + "issues": "https://github.com/ramsey/collection/issues", + "source": "https://github.com/ramsey/collection/tree/1.1.3" + }, + "funding": [ + { + "url": "https://github.com/ramsey", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/ramsey/collection", + "type": "tidelift" + } + ], "time": "2021-01-21T17:40:04+00:00" }, { @@ -3964,6 +4184,17 @@ "identifier", "uuid" ], + "support": { + "issues": "https://github.com/ramsey/uuid/issues", + "rss": "https://github.com/ramsey/uuid/releases.atom", + "source": "https://github.com/ramsey/uuid" + }, + "funding": [ + { + "url": "https://github.com/ramsey", + "type": "github" + } + ], "time": "2020-08-18T17:17:46+00:00" }, { @@ -4010,6 +4241,16 @@ ], "description": "Collection of value objects that represent the PHP code units", "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-10-26T13:08:54+00:00" }, { @@ -4055,6 +4296,16 @@ ], "description": "Looks up which function or method a line of code belongs to", "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-09-28T05:30:19+00:00" }, { @@ -4119,6 +4370,16 @@ "compare", "equality" ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-10-26T15:49:45+00:00" }, { @@ -4175,6 +4436,16 @@ "unidiff", "unified diff" ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-10-26T13:10:38+00:00" }, { @@ -4228,6 +4499,16 @@ "environment", "hhvm" ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-09-28T05:52:38+00:00" }, { @@ -4295,6 +4576,16 @@ "export", "exporter" ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-09-28T05:24:23+00:00" }, { @@ -4349,6 +4640,10 @@ "keywords": [ "global state" ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/master" + }, "time": "2020-02-07T06:11:37+00:00" }, { @@ -4396,6 +4691,16 @@ ], "description": "Traverses array structures and object graphs to enumerate all referenced objects", "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-10-26T13:12:34+00:00" }, { @@ -4441,6 +4746,16 @@ ], "description": "Allows reflection of object attributes, including inherited and non-public ones", "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-10-26T13:14:26+00:00" }, { @@ -4494,6 +4809,16 @@ ], "description": "Provides functionality to recursively process PHP variables", "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-10-26T13:17:30+00:00" }, { @@ -4539,6 +4864,16 @@ ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "support": { + "issues": "https://github.com/sebastianbergmann/resource-operations/issues", + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-09-28T06:45:17+00:00" }, { @@ -4585,6 +4920,16 @@ ], "description": "Collection of value objects that represent the types of the PHP type system", "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/2.3.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-10-26T13:18:59+00:00" }, { @@ -4628,6 +4973,16 @@ ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-09-28T06:39:44+00:00" }, { @@ -4796,16 +5151,16 @@ }, { "name": "symfony/console", - "version": "v4.4.19", + "version": "v4.4.21", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "24026c44fc37099fa145707fecd43672831b837a" + "reference": "1ba4560dbbb9fcf5ae28b61f71f49c678086cf23" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/24026c44fc37099fa145707fecd43672831b837a", - "reference": "24026c44fc37099fa145707fecd43672831b837a", + "url": "https://api.github.com/repos/symfony/console/zipball/1ba4560dbbb9fcf5ae28b61f71f49c678086cf23", + "reference": "1ba4560dbbb9fcf5ae28b61f71f49c678086cf23", "shasum": "" }, "require": { @@ -4864,11 +5219,28 @@ ], "description": "Eases the creation of beautiful and testable command line interfaces", "homepage": "https://symfony.com", - "time": "2021-01-27T09:09:26+00:00" + "support": { + "source": "https://github.com/symfony/console/tree/v4.4.21" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-03-26T09:23:24+00:00" }, { "name": "symfony/css-selector", - "version": "v5.2.2", + "version": "v5.2.4", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", @@ -4912,6 +5284,23 @@ ], "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/css-selector/tree/v5.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2021-01-27T10:01:46+00:00" }, { @@ -4962,11 +5351,28 @@ ], "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/master" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-09-07T11:33:47+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v4.4.19", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", @@ -5028,6 +5434,23 @@ ], "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.20" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2021-01-27T09:09:26+00:00" }, { @@ -5090,20 +5513,37 @@ "interoperability", "standards" ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v1.1.9" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-07-06T13:19:58+00:00" }, { "name": "symfony/filesystem", - "version": "v5.2.2", + "version": "v5.2.6", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "262d033b57c73e8b59cd6e68a45c528318b15038" + "reference": "8c86a82f51658188119e62cff0a050a12d09836f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/262d033b57c73e8b59cd6e68a45c528318b15038", - "reference": "262d033b57c73e8b59cd6e68a45c528318b15038", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/8c86a82f51658188119e62cff0a050a12d09836f", + "reference": "8c86a82f51658188119e62cff0a050a12d09836f", "shasum": "" }, "require": { @@ -5135,20 +5575,37 @@ ], "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", - "time": "2021-01-27T10:01:46+00:00" + "support": { + "source": "https://github.com/symfony/filesystem/tree/v5.2.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-03-28T14:30:26+00:00" }, { "name": "symfony/finder", - "version": "v5.2.2", + "version": "v5.2.4", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "196f45723b5e618bf0e23b97e96d11652696ea9e" + "reference": "0d639a0943822626290d169965804f79400e6a04" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/196f45723b5e618bf0e23b97e96d11652696ea9e", - "reference": "196f45723b5e618bf0e23b97e96d11652696ea9e", + "url": "https://api.github.com/repos/symfony/finder/zipball/0d639a0943822626290d169965804f79400e6a04", + "reference": "0d639a0943822626290d169965804f79400e6a04", "shasum": "" }, "require": { @@ -5179,7 +5636,24 @@ ], "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", - "time": "2021-01-27T10:01:46+00:00" + "support": { + "source": "https://github.com/symfony/finder/tree/v5.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-02-15T18:55:04+00:00" }, { "name": "symfony/http-foundation", @@ -5239,16 +5713,16 @@ }, { "name": "symfony/mime", - "version": "v5.2.2", + "version": "v5.2.6", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "37bade585ea100d235c031b258eff93b5b6bb9a9" + "reference": "1b2092244374cbe48ae733673f2ca0818b37197b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/37bade585ea100d235c031b258eff93b5b6bb9a9", - "reference": "37bade585ea100d235c031b258eff93b5b6bb9a9", + "url": "https://api.github.com/repos/symfony/mime/zipball/1b2092244374cbe48ae733673f2ca0818b37197b", + "reference": "1b2092244374cbe48ae733673f2ca0818b37197b", "shasum": "" }, "require": { @@ -5259,12 +5733,13 @@ "symfony/polyfill-php80": "^1.15" }, "conflict": { + "egulias/email-validator": "~3.0.0", "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", "symfony/mailer": "<4.4" }, "require-dev": { - "egulias/email-validator": "^2.1.10", + "egulias/email-validator": "^2.1.10|^3.1", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", "symfony/dependency-injection": "^4.4|^5.0", "symfony/property-access": "^4.4|^5.1", @@ -5300,11 +5775,28 @@ "mime", "mime-type" ], - "time": "2021-01-25T14:08:25+00:00" + "support": { + "source": "https://github.com/symfony/mime/tree/v5.2.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-03-12T13:18:39+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.22.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", @@ -5362,20 +5854,37 @@ "polyfill", "portable" ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.22.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "0eb8293dbbcd6ef6bf81404c9ce7d95bcdf34f44" + "reference": "2d63434d922daf7da8dd863e7907e67ee3031483" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/0eb8293dbbcd6ef6bf81404c9ce7d95bcdf34f44", - "reference": "0eb8293dbbcd6ef6bf81404c9ce7d95bcdf34f44", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/2d63434d922daf7da8dd863e7907e67ee3031483", + "reference": "2d63434d922daf7da8dd863e7907e67ee3031483", "shasum": "" }, "require": { @@ -5432,20 +5941,37 @@ "portable", "shim" ], - "time": "2021-01-07T16:49:33+00:00" + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.22.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-01-22T09:19:47+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.22.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "6e971c891537eb617a00bb07a43d182a6915faba" + "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/6e971c891537eb617a00bb07a43d182a6915faba", - "reference": "6e971c891537eb617a00bb07a43d182a6915faba", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/43a0283138253ed1d48d352ab6d0bdb3f809f248", + "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248", "shasum": "" }, "require": { @@ -5499,20 +6025,37 @@ "portable", "shim" ], - "time": "2021-01-07T17:09:11+00:00" + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.22.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-01-22T09:19:47+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.22.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "f377a3dd1fde44d37b9831d68dc8dea3ffd28e13" + "reference": "5232de97ee3b75b0360528dae24e73db49566ab1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/f377a3dd1fde44d37b9831d68dc8dea3ffd28e13", - "reference": "f377a3dd1fde44d37b9831d68dc8dea3ffd28e13", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/5232de97ee3b75b0360528dae24e73db49566ab1", + "reference": "5232de97ee3b75b0360528dae24e73db49566ab1", "shasum": "" }, "require": { @@ -5562,11 +6105,28 @@ "portable", "shim" ], - "time": "2021-01-07T16:49:33+00:00" + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.22.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-01-22T09:19:47+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.22.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", @@ -5621,11 +6181,28 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.22.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.22.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", @@ -5683,11 +6260,28 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.22.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.22.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", @@ -5749,6 +6343,23 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.22.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2021-01-07T16:49:33+00:00" }, { @@ -5855,20 +6466,37 @@ "interoperability", "standards" ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/master" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-09-07T11:33:47+00:00" }, { "name": "symfony/yaml", - "version": "v4.4.19", + "version": "v4.4.21", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "17ed9f14c1aa05b1a5cf2e2c5ef2d0be28058ef9" + "reference": "3871c720871029f008928244e56cf43497da7e9d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/17ed9f14c1aa05b1a5cf2e2c5ef2d0be28058ef9", - "reference": "17ed9f14c1aa05b1a5cf2e2c5ef2d0be28058ef9", + "url": "https://api.github.com/repos/symfony/yaml/zipball/3871c720871029f008928244e56cf43497da7e9d", + "reference": "3871c720871029f008928244e56cf43497da7e9d", "shasum": "" }, "require": { @@ -5909,7 +6537,24 @@ ], "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", - "time": "2021-01-27T09:09:26+00:00" + "support": { + "source": "https://github.com/symfony/yaml/tree/v4.4.21" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-03-05T17:58:50+00:00" }, { "name": "thecodingmachine/safe", @@ -6084,6 +6729,16 @@ } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/master" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], "time": "2020-07-12T23:59:07+00:00" }, { @@ -6150,30 +6805,35 @@ }, { "name": "webmozart/assert", - "version": "1.9.1", + "version": "1.10.0", "source": { "type": "git", "url": "https://github.com/webmozarts/assert.git", - "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389" + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389", - "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0 || ^8.0", + "php": "^7.2 || ^8.0", "symfony/polyfill-ctype": "^1.8" }, "conflict": { "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<3.9.1" + "vimeo/psalm": "<4.6.1 || 4.6.2" }, "require-dev": { - "phpunit/phpunit": "^4.8.36 || ^7.5.13" + "phpunit/phpunit": "^8.5.13" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, "autoload": { "psr-4": { "Webmozart\\Assert\\": "src/" @@ -6195,7 +6855,11 @@ "check", "validate" ], - "time": "2020-07-08T17:02:28+00:00" + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.10.0" + }, + "time": "2021-03-09T10:59:23+00:00" }, { "name": "weew/helpers-array", @@ -7059,6 +7723,16 @@ ], "description": "Library for parsing CLI options", "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-09-28T06:08:49+00:00" }, { @@ -7348,5 +8022,6 @@ "ext-json": "*", "ext-openssl": "*" }, - "platform-dev": [] + "platform-dev": [], + "plugin-api-version": "2.0.0" } From 357f1cef42d2554eefdcfff8aba2f4942057d21f Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 31 Mar 2021 17:30:56 -0500 Subject: [PATCH 618/888] MQE-2613: assertions.md doc update --- docs/test/assertions.md | 80 ++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/docs/test/assertions.md b/docs/test/assertions.md index 4588dc8ec..a3e97cf51 100644 --- a/docs/test/assertions.md +++ b/docs/test/assertions.md @@ -91,7 +91,7 @@ It must be in typical array format like `[1,2,3,4,5]` or `[alpha, brontosaurus, ### assertArrayHasKey -See [assertArrayHasKey docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertArrayHasKey) +See [assertArrayHasKey docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertArrayHasKey) Attribute|Type|Use|Description ---|---|---|--- @@ -102,7 +102,7 @@ Attribute|Type|Use|Description ### assertArrayNotHasKey -See [assertArrayNotHasKey docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertArrayNotHasKey). +See [assertArrayNotHasKey docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertArrayNotHasKey). Attribute|Type|Use|Description ---|---|---|--- @@ -113,7 +113,7 @@ Attribute|Type|Use|Description ### assertContains -See [assertContains docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertContains). +See [assertContains docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertContains). Attribute|Type|Use|Description ---|---|---|--- @@ -124,7 +124,7 @@ Attribute|Type|Use|Description ### assertStringContainsString -See [assertStringContainsString docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertStringContainsString). +See [assertStringContainsString docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertStringContainsString). Example: @@ -144,7 +144,7 @@ Attribute|Type|Use|Description ### assertStringContainsStringIgnoringCase -See [assertStringContainsStringIgnoringCase docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertStringContainsStringIgnoringCase). +See [assertStringContainsStringIgnoringCase docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertStringContainsStringIgnoringCase). Example: @@ -164,7 +164,7 @@ Attribute|Type|Use|Description ### assertCount -See [assertCount docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertCount). +See [assertCount docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertCount). Attribute|Type|Use|Description ---|---|---|--- @@ -175,7 +175,7 @@ Attribute|Type|Use|Description ### assertEmpty -See [assertEmpty docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertEmpty). +See [assertEmpty docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertEmpty). Example: @@ -194,7 +194,7 @@ Attribute|Type|Use|Description ### assertEquals -See [assertEquals docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertEquals). +See [assertEquals docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertEquals). Example: @@ -214,7 +214,7 @@ Attribute|Type|Use|Description ### assertEqualsWithDelta -See [assertEqualsWithDelta docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertEqualsWithDelta). +See [assertEqualsWithDelta docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertEqualsWithDelta). Attribute|Type|Use|Description ---|---|---|--- @@ -226,7 +226,7 @@ Attribute|Type|Use|Description ### assertEqualsCanonicalizing -See [assertEqualsCanonicalizing docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertEqualsCanonicalizing). +See [assertEqualsCanonicalizing docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertEqualsCanonicalizing). Attribute|Type|Use|Description ---|---|---|--- @@ -237,7 +237,7 @@ Attribute|Type|Use|Description ### assertEqualsIgnoringCase -See [assertEqualsIgnoringCase docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertEqualsIgnoringCase). +See [assertEqualsIgnoringCase docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertEqualsIgnoringCase). Attribute|Type|Use|Description ---|---|---|--- @@ -248,7 +248,7 @@ Attribute|Type|Use|Description ### assertFalse -See [assertFalse docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertFalse). +See [assertFalse docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertFalse). Attribute|Type|Use|Description ---|---|---|--- @@ -259,7 +259,7 @@ Attribute|Type|Use|Description ### assertFileExists -See [assertFileExists docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertFileExists). +See [assertFileExists docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertFileExists). Attribute|Type|Use|Description ---|---|---|--- @@ -270,7 +270,7 @@ Attribute|Type|Use|Description ### assertFileNotExists -See [assertFileNotExists docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertFileNotExists). +See [assertFileNotExists docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertFileNotExists). Attribute|Type|Use|Description ---|---|---|--- @@ -281,7 +281,7 @@ Attribute|Type|Use|Description ### assertGreaterOrEquals -See [assertGreaterOrEquals docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertGreaterOrEquals). +See [assertGreaterOrEquals docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertGreaterOrEquals). Example: @@ -301,7 +301,7 @@ Attribute|Type|Use|Description ### assertGreaterThan -See [assertGreaterThan docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertGreaterThan). +See [assertGreaterThan docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertGreaterThan). Example: @@ -321,7 +321,7 @@ Attribute|Type|Use|Description ### assertGreaterThanOrEqual -See [assertGreaterThanOrEqual docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertGreaterThanOrEqual). +See [assertGreaterThanOrEqual docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertGreaterThanOrEqual). Example: @@ -341,7 +341,7 @@ Attribute|Type|Use|Description ### assertInstanceOf -See [assertInstanceOf docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertInstanceOf). +See [assertInstanceOf docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertInstanceOf). Attribute|Type|Use|Description ---|---|---|--- @@ -352,7 +352,7 @@ Attribute|Type|Use|Description ### assertIsEmpty -See [assertIsEmpty docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertIsEmpty). +See [assertIsEmpty docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertIsEmpty). Attribute|Type|Use|Description ---|---|---|--- @@ -363,7 +363,7 @@ Attribute|Type|Use|Description ### assertLessOrEquals -See [assertLessOrEquals docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertLessOrEquals). +See [assertLessOrEquals docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertLessOrEquals). Example: @@ -383,7 +383,7 @@ Attribute|Type|Use|Description ### assertLessThan -See [assertLessThan docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertLessThan). +See [assertLessThan docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertLessThan). Example: @@ -403,7 +403,7 @@ Attribute|Type|Use|Description ### assertLessThanOrEqual -See [assertLessThanOrEqual docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertLessThanOrEqual). +See [assertLessThanOrEqual docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertLessThanOrEqual). Example: @@ -423,7 +423,7 @@ Attribute|Type|Use|Description ### assertNotContains -See [assertNotContains docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertNotContains). +See [assertNotContains docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertNotContains). Example: @@ -443,7 +443,7 @@ Attribute|Type|Use|Description ### assertStringNotContainsString -See [assertStringNotContainsString docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertStringNotContainsString). +See [assertStringNotContainsString docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertStringNotContainsString). Example: @@ -463,7 +463,7 @@ Attribute|Type|Use|Description ### assertStringContainsStringIgnoringCase -See [assertStringNotContainsStringIgnoringCase docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertStringNotContainsStringIgnoringCase). +See [assertStringNotContainsStringIgnoringCase docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertStringNotContainsStringIgnoringCase). Example: @@ -483,7 +483,7 @@ Attribute|Type|Use|Description ### assertNotEmpty -See [assertNotEmpty docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertNotEmpty). +See [assertNotEmpty docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertNotEmpty). Example: @@ -502,7 +502,7 @@ Attribute|Type|Use|Description ### assertNotEquals -See [assertNotEquals docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertNotEquals). +See [assertNotEquals docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertNotEquals). Example: @@ -522,7 +522,7 @@ Attribute|Type|Use|Description ### assertNotEqualsWithDelta -See [assertNotEqualsWithDelta docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertNotEqualsWithDelta). +See [assertNotEqualsWithDelta docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertNotEqualsWithDelta). Attribute|Type|Use|Description ---|---|---|--- @@ -534,7 +534,7 @@ Attribute|Type|Use|Description ### assertNotEqualsCanonicalizing -See [assertNotEqualsCanonicalizing docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertNotEqualsCanonicalizing). +See [assertNotEqualsCanonicalizing docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertNotEqualsCanonicalizing). Attribute|Type|Use|Description ---|---|---|--- @@ -545,7 +545,7 @@ Attribute|Type|Use|Description ### assertNotEqualsIgnoringCase -See [assertNotEqualsIgnoringCase docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertNotEqualsIgnoringCase). +See [assertNotEqualsIgnoringCase docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertNotEqualsIgnoringCase). Attribute|Type|Use|Description ---|---|---|--- @@ -556,7 +556,7 @@ Attribute|Type|Use|Description ### assertNotInstanceOf -See [assertNotInstanceOf docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertNotInstanceOf). +See [assertNotInstanceOf docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertNotInstanceOf). Attribute|Type|Use|Description ---|---|---|--- @@ -567,7 +567,7 @@ Attribute|Type|Use|Description ### assertNotNull -See [assertNotNull docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertNotNull). +See [assertNotNull docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertNotNull). Attribute|Type|Use|Description ---|---|---|--- @@ -578,7 +578,7 @@ Attribute|Type|Use|Description ### assertNotRegExp -See [assertNotRegExp docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertNotRegExp). +See [assertNotRegExp docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertNotRegExp). Example: @@ -598,7 +598,7 @@ Attribute|Type|Use|Description ### assertNotSame -See [assertNotSame docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertNotSame). +See [assertNotSame docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertNotSame). Attribute|Type|Use|Description ---|---|---|--- @@ -609,7 +609,7 @@ Attribute|Type|Use|Description ### assertNull -See [assertNull docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertNull). +See [assertNull docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertNull). Attribute|Type|Use|Description ---|---|---|--- @@ -620,7 +620,7 @@ Attribute|Type|Use|Description ### assertRegExp -See [assertRegExp docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertRegExp). +See [assertRegExp docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertRegExp). Example: @@ -640,7 +640,7 @@ Attribute|Type|Use|Description ### assertSame -See [assertSame docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertSame). +See [assertSame docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertSame). Attribute|Type|Use|Description ---|---|---|--- @@ -651,7 +651,7 @@ Attribute|Type|Use|Description ### assertStringStartsNotWith -See [assertStringStartsNotWith docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertStringStartsNotWith). +See [assertStringStartsNotWith docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertStringStartsNotWith). Attribute|Type|Use|Description ---|---|---|--- @@ -662,7 +662,7 @@ Attribute|Type|Use|Description ### assertStringStartsWith -See [assertStringStartsWith docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertStringStartsWith). +See [assertStringStartsWith docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertStringStartsWith). Attribute|Type|Use|Description ---|---|---|--- @@ -673,7 +673,7 @@ Attribute|Type|Use|Description ### assertTrue -See [assertTrue docs on codeception.com](http://codeception.com/docs/modules/Asserts#assertTrue). +See [assertTrue docs on codeception.com](https://codeception.com/docs/modules/Asserts#assertTrue). Attribute|Type|Use|Description ---|---|---|--- From 987f4c846d9e9443938c8b4b573f2f42370b7f0f Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 1 Apr 2021 11:24:38 -0500 Subject: [PATCH 619/888] MQE-2613: assertions.md doc update --- .../verification/Resources/AssertTest.txt | 8 ++++++ .../TestModule/Test/AssertTest.xml | 28 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/dev/tests/verification/Resources/AssertTest.txt b/dev/tests/verification/Resources/AssertTest.txt index d2d470139..c8435675b 100644 --- a/dev/tests/verification/Resources/AssertTest.txt +++ b/dev/tests/verification/Resources/AssertTest.txt @@ -151,5 +151,13 @@ class AssertTestCest $I->assertNotEqualsCanonicalizing(["5", "8", "7", "9"], ["1", "2", "3", "4"], "pass"); // stepKey: a4 $I->assertEqualsIgnoringCase("Cat", "cat", "pass"); // stepKey: a5 $I->assertNotEqualsIgnoringCase("Cat", "Dog", "pass"); // stepKey: a6 + $I->comment("assertions.md examples"); + $I->assertElementContainsAttribute(".admin__menu-overlay", "style", "color: #333;"); // stepKey: assertElementContainsAttribute + $I->assertStringContainsString("Buy 5 for $5.00 each and save 50%", $DropDownTierPriceTextProduct1); // stepKey: assertDropDownTierPriceTextProduct1 + $I->assertEmpty("$grabSearchButtonAttribute"); // stepKey: assertSearchButtonEnabled + $I->assertGreaterThanOrEqual($getOrderStatusFirstRow, $getOrderStatusSecondRow); // stepKey: checkStatusSortOrderAsc + $I->assertNotEquals($grabTotalBefore, $grabTotalAfter); // stepKey: assertNotEqualsExample + $I->assertNotRegExp('/placeholder\/thumbnail\.jpg/', $getSimpleProductThumbnail); // stepKey: simpleThumbnailIsNotDefault + $I->assertRegExp("#var\s+adminAnalyticsMetadata\s+=\s+{\s+(\"[\w_]+\":\s+\"[^\"]*?\",\s+)*?(\"[\w_]+\":\s+\"[^\"]*?\"\s+)};#s", $pageSource, "adminAnalyticsMetadata object is invalid"); // stepKey: validateadminAnalyticsMetadata } } diff --git a/dev/tests/verification/TestModule/Test/AssertTest.xml b/dev/tests/verification/TestModule/Test/AssertTest.xml index 4000c3897..03d9ca0c7 100644 --- a/dev/tests/verification/TestModule/Test/AssertTest.xml +++ b/dev/tests/verification/TestModule/Test/AssertTest.xml @@ -400,5 +400,33 @@ <expectedResult type="string">Cat</expectedResult> <actualResult type="string">Dog</actualResult> </assertNotEqualsIgnoringCase> + + <!-- assertions.md examples --> + <assertElementContainsAttribute stepKey="assertElementContainsAttribute"> + <expectedResult selector=".admin__menu-overlay" attribute="style" type="string">color: #333;</expectedResult> + </assertElementContainsAttribute> + <assertStringContainsString stepKey="assertDropDownTierPriceTextProduct1"> + <expectedResult type="string">Buy 5 for $5.00 each and save 50%</expectedResult> + <actualResult type="variable">DropDownTierPriceTextProduct1</actualResult> + </assertStringContainsString> + <assertEmpty stepKey="assertSearchButtonEnabled"> + <actualResult type="string">$grabSearchButtonAttribute</actualResult> + </assertEmpty> + <assertGreaterThanOrEqual stepKey="checkStatusSortOrderAsc"> + <actualResult type="const">$getOrderStatusSecondRow</actualResult> + <expectedResult type="const">$getOrderStatusFirstRow</expectedResult> + </assertGreaterThanOrEqual> + <assertNotEquals stepKey="assertNotEqualsExample"> + <actualResult type="string">{$grabTotalAfter}</actualResult> + <expectedResult type="string">{$grabTotalBefore}</expectedResult> + </assertNotEquals> + <assertNotRegExp stepKey="simpleThumbnailIsNotDefault"> + <actualResult type="const">$getSimpleProductThumbnail</actualResult> + <expectedResult type="const">'/placeholder\/thumbnail\.jpg/'</expectedResult> + </assertNotRegExp> + <assertRegExp message="adminAnalyticsMetadata object is invalid" stepKey="validateadminAnalyticsMetadata"> + <expectedResult type="string">#var\s+adminAnalyticsMetadata\s+=\s+{\s+("[\w_]+":\s+"[^"]*?",\s+)*?("[\w_]+":\s+"[^"]*?"\s+)};#s</expectedResult> + <actualResult type="variable">$pageSource</actualResult> + </assertRegExp> </test> </tests> From a0c4c0ba56ee5a394e96147ed35b8dcebc107868 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 5 Apr 2021 14:41:58 -0500 Subject: [PATCH 620/888] MQE-2618: 3.5.0 CHANGELOG.md and version bump. --- CHANGELOG.md | 20 +- composer.json | 2 +- composer.lock | 1176 ++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 1194 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 00133590f..c9262a14c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,24 @@ Magento Functional Testing Framework Changelog ================================================ +3.5.0 +--------- + +### Enhancements + +* Customizability + * Added new `config:parallel --groups` option in `generate:tests` command to generate and split tests/suites into required number of execution time balanced groups. + +### Fixes + +* Added --no-sandbox chrome option in functional suite configuration. + +### GitHub Pull Requests: + +* [#824](https://github.com/magento/magento2-functional-testing-framework/pull/824) -- Fix typo in introduction.md +* [#816](https://github.com/magento/magento2-functional-testing-framework/pull/816) -- Update mftf.md +* [#812](https://github.com/magento/magento2-functional-testing-framework/pull/812) -- Added examples and modified url links in assertions.md + 3.4.0 --------- @@ -15,7 +33,7 @@ Magento Functional Testing Framework Changelog ### Enhancements * Usability - * [#817](https://github.com/magento/magento2-functional-testing-framework/pull/817) -- Add support for admin WebAPI token refresh + * [#817](https://github.com/magento/magento2-functional-testing-framework/pull/817) -- Add support for admin WebAPI token refresh. * Maintainability * [#814](https://github.com/magento/magento2-functional-testing-framework/pull/814) -- Update dependencies in order to make mftf php8 compatible, fix running phpcpd diff --git a/composer.json b/composer.json index 4d86275c2..97b6d1232 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "3.4.0", + "version": "3.5.0", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index 6ceeaba39..e1707aee4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "d5b40409dd42db97a03df32090136b11", + "content-hash": "389747bccb60abcadaa9b25f4c2d8856", "packages": [ { "name": "allure-framework/allure-codeception", @@ -55,6 +55,11 @@ "steps", "testing" ], + "support": { + "email": "allure@yandex-team.ru", + "issues": "https://github.com/allure-framework/allure-codeception/issues", + "source": "https://github.com/allure-framework/allure-codeception" + }, "time": "2020-11-26T11:41:53+00:00" }, { @@ -108,6 +113,11 @@ "php", "report" ], + "support": { + "email": "allure@yandex-team.ru", + "issues": "https://github.com/allure-framework/allure-php-commons/issues", + "source": "https://github.com/allure-framework/allure-php-api" + }, "time": "2020-11-26T09:20:44+00:00" }, { @@ -193,6 +203,11 @@ "s3", "sdk" ], + "support": { + "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", + "issues": "https://github.com/aws/aws-sdk-php/issues", + "source": "https://github.com/aws/aws-sdk-php/tree/3.172.3" + }, "time": "2021-01-28T19:14:55+00:00" }, { @@ -254,6 +269,10 @@ "assertion", "validation" ], + "support": { + "issues": "https://github.com/beberlei/assert/issues", + "source": "https://github.com/beberlei/assert/tree/v3.3.0" + }, "time": "2020-11-13T20:02:54+00:00" }, { @@ -313,6 +332,10 @@ "gherkin", "parser" ], + "support": { + "issues": "https://github.com/Behat/Gherkin/issues", + "source": "https://github.com/Behat/Gherkin/tree/v4.7.1" + }, "time": "2021-01-26T16:24:32+00:00" }, { @@ -359,6 +382,16 @@ "brick", "math" ], + "support": { + "issues": "https://github.com/brick/math/issues", + "source": "https://github.com/brick/math/tree/0.9.2" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/brick/math", + "type": "tidelift" + } + ], "time": "2021-01-20T22:51:39+00:00" }, { @@ -444,6 +477,16 @@ "functional testing", "unit testing" ], + "support": { + "issues": "https://github.com/Codeception/Codeception/issues", + "source": "https://github.com/Codeception/Codeception/tree/4.1.16" + }, + "funding": [ + { + "url": "https://opencollective.com/codeception", + "type": "open_collective" + } + ], "time": "2021-01-26T07:25:32+00:00" }, { @@ -494,6 +537,10 @@ "keywords": [ "codeception" ], + "support": { + "issues": "https://github.com/Codeception/lib-asserts/issues", + "source": "https://github.com/Codeception/lib-asserts/tree/1.13.2" + }, "time": "2020-10-21T16:26:20+00:00" }, { @@ -547,6 +594,10 @@ "asserts", "codeception" ], + "support": { + "issues": "https://github.com/Codeception/module-asserts/issues", + "source": "https://github.com/Codeception/module-asserts/tree/1.3.1" + }, "time": "2020-10-21T16:48:15+00:00" }, { @@ -587,6 +638,10 @@ "keywords": [ "codeception" ], + "support": { + "issues": "https://github.com/Codeception/module-sequence/issues", + "source": "https://github.com/Codeception/module-sequence/tree/1.0.1" + }, "time": "2020-10-31T18:36:26+00:00" }, { @@ -639,6 +694,10 @@ "browser-testing", "codeception" ], + "support": { + "issues": "https://github.com/Codeception/module-webdriver/issues", + "source": "https://github.com/Codeception/module-webdriver/tree/1.2.0" + }, "time": "2021-01-17T19:23:20+00:00" }, { @@ -684,6 +743,10 @@ } ], "description": "PHPUnit classes used by Codeception", + "support": { + "issues": "https://github.com/Codeception/phpunit-wrapper/issues", + "source": "https://github.com/Codeception/phpunit-wrapper/tree/9.0.6" + }, "time": "2020-12-28T13:59:47+00:00" }, { @@ -714,6 +777,10 @@ "MIT" ], "description": "Flexible Stub wrapper for PHPUnit's Mock Builder", + "support": { + "issues": "https://github.com/Codeception/Stub/issues", + "source": "https://github.com/Codeception/Stub/tree/3.7.0" + }, "time": "2020-07-03T15:54:43+00:00" }, { @@ -771,6 +838,25 @@ "ssl", "tls" ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/ca-bundle/issues", + "source": "https://github.com/composer/ca-bundle/tree/1.2.9" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], "time": "2021-01-12T12:10:35+00:00" }, { @@ -851,6 +937,25 @@ "dependency", "package" ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/composer/issues", + "source": "https://github.com/composer/composer/tree/1.10.20" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], "time": "2021-01-27T14:41:06+00:00" }, { @@ -912,6 +1017,25 @@ "validation", "versioning" ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/1.7.2" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], "time": "2020-12-03T15:47:16+00:00" }, { @@ -972,6 +1096,25 @@ "spdx", "validator" ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/spdx-licenses/issues", + "source": "https://github.com/composer/spdx-licenses/tree/1.5.5" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], "time": "2020-12-03T16:04:16+00:00" }, { @@ -1016,6 +1159,25 @@ "Xdebug", "performance" ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/xdebug-handler/issues", + "source": "https://github.com/composer/xdebug-handler/tree/1.4.5" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], "time": "2020-11-13T08:04:11+00:00" }, { @@ -1068,6 +1230,10 @@ } ], "description": "Best Vault client for PHP that you can find", + "support": { + "issues": "https://github.com/CSharpRU/vault-php/issues", + "source": "https://github.com/CSharpRU/vault-php/tree/4.2.0" + }, "time": "2020-11-27T09:07:28+00:00" }, { @@ -1106,6 +1272,10 @@ } ], "description": "Guzzle6 transport for Vault PHP client", + "support": { + "issues": "https://github.com/CSharpRU/vault-php-guzzle6-transport/issues", + "source": "https://github.com/CSharpRU/vault-php-guzzle6-transport/tree/master" + }, "time": "2019-03-10T06:17:37+00:00" }, { @@ -1177,6 +1347,10 @@ "docblock", "parser" ], + "support": { + "issues": "https://github.com/doctrine/annotations/issues", + "source": "https://github.com/doctrine/annotations/tree/1.11.1" + }, "time": "2020-10-26T10:28:16+00:00" }, { @@ -1228,6 +1402,24 @@ "constructor", "instantiate" ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/1.4.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } + ], "time": "2020-11-10T18:47:58+00:00" }, { @@ -1290,6 +1482,24 @@ "parser", "php" ], + "support": { + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/1.2.1" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", + "type": "tidelift" + } + ], "time": "2020-05-25T17:44:05+00:00" }, { @@ -1357,6 +1567,10 @@ "rest", "web service" ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/6.5" + }, "time": "2020-06-16T21:01:06+00:00" }, { @@ -1408,6 +1622,10 @@ "keywords": [ "promise" ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/1.4.0" + }, "time": "2020-09-30T07:37:28+00:00" }, { @@ -1479,6 +1697,10 @@ "uri", "url" ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/1.7.0" + }, "time": "2020-09-30T07:37:11+00:00" }, { @@ -1542,6 +1764,14 @@ "keyword", "library" ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/Consistency", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/Consistency/issues", + "source": "https://central.hoa-project.net/Resource/Library/Consistency" + }, "time": "2017-05-02T12:18:12+00:00" }, { @@ -1618,6 +1848,14 @@ "tput", "window" ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/Console", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/Console/issues", + "source": "https://central.hoa-project.net/Resource/Library/Console" + }, "time": "2017-05-02T12:26:19+00:00" }, { @@ -1674,6 +1912,14 @@ "listener", "observer" ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/Event", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/Event/issues", + "source": "https://central.hoa-project.net/Resource/Library/Event" + }, "time": "2017-01-13T15:30:50+00:00" }, { @@ -1728,6 +1974,14 @@ "exception", "library" ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/Exception", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/Exception/issues", + "source": "https://central.hoa-project.net/Resource/Library/Exception" + }, "time": "2017-01-16T07:53:27+00:00" }, { @@ -1790,6 +2044,14 @@ "link", "temporary" ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/File", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/File/issues", + "source": "https://central.hoa-project.net/Resource/Library/File" + }, "time": "2017-07-11T07:42:15+00:00" }, { @@ -1844,6 +2106,14 @@ "iterator", "library" ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/Iterator", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/Iterator/issues", + "source": "https://central.hoa-project.net/Resource/Library/Iterator" + }, "time": "2017-01-10T10:34:47+00:00" }, { @@ -1904,6 +2174,14 @@ "stream", "wrapper" ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/Protocol", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/Protocol/issues", + "source": "https://central.hoa-project.net/Resource/Library/Protocol" + }, "time": "2017-01-14T12:26:10+00:00" }, { @@ -1968,6 +2246,14 @@ "stream", "wrapper" ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/Stream", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/Stream/issues", + "source": "https://central.hoa-project.net/Resource/Library/Stream" + }, "time": "2017-02-21T16:01:06+00:00" }, { @@ -2028,6 +2314,14 @@ "string", "unicode" ], + "support": { + "docs": "https://central.hoa-project.net/Documentation/Library/Ustring", + "email": "support@hoa-project.net", + "forum": "https://users.hoa-project.net/", + "irc": "irc://chat.freenode.net/hoaproject", + "issues": "https://github.com/hoaproject/Ustring/issues", + "source": "https://central.hoa-project.net/Resource/Library/Ustring" + }, "time": "2017-01-16T07:08:25+00:00" }, { @@ -2083,6 +2377,10 @@ "xml", "yaml" ], + "support": { + "issues": "https://github.com/schmittjoh/metadata/issues", + "source": "https://github.com/schmittjoh/metadata/tree/1.x" + }, "time": "2018-10-26T12:40:10+00:00" }, { @@ -2118,6 +2416,10 @@ "Apache2" ], "description": "A library for easily creating recursive-descent parsers.", + "support": { + "issues": "https://github.com/schmittjoh/parser-lib/issues", + "source": "https://github.com/schmittjoh/parser-lib/tree/1.0.0" + }, "time": "2012-11-18T18:08:43+00:00" }, { @@ -2202,6 +2504,10 @@ "serialization", "xml" ], + "support": { + "issues": "https://github.com/schmittjoh/serializer/issues", + "source": "https://github.com/schmittjoh/serializer/tree/1.14.1" + }, "time": "2020-02-22T20:59:37+00:00" }, { @@ -2268,6 +2574,10 @@ "json", "schema" ], + "support": { + "issues": "https://github.com/justinrainbow/json-schema/issues", + "source": "https://github.com/justinrainbow/json-schema/tree/5.2.10" + }, "time": "2020-05-27T16:41:55+00:00" }, { @@ -2340,6 +2650,20 @@ "logging", "psr-3" ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/1.26.0" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], "time": "2020-12-14T12:56:38+00:00" }, { @@ -2397,6 +2721,10 @@ "json", "jsonpath" ], + "support": { + "issues": "https://github.com/jmespath/jmespath.php/issues", + "source": "https://github.com/jmespath/jmespath.php/tree/2.6.0" + }, "time": "2020-07-31T21:01:56+00:00" }, { @@ -2443,6 +2771,10 @@ "mustache", "templating" ], + "support": { + "issues": "https://github.com/bobthecow/mustache.php/issues", + "source": "https://github.com/bobthecow/mustache.php/tree/master" + }, "time": "2019-11-23T21:40:31+00:00" }, { @@ -2491,6 +2823,16 @@ "object", "object graph" ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.10.2" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], "time": "2020-11-13T09:40:50+00:00" }, { @@ -2543,6 +2885,10 @@ "parser", "php" ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/master" + }, "time": "2020-04-10T16:34:50+00:00" }, { @@ -2605,6 +2951,11 @@ "hex2bin", "rfc4648" ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/constant_time_encoding/issues", + "source": "https://github.com/paragonie/constant_time_encoding" + }, "time": "2020-12-06T15:14:20+00:00" }, { @@ -2660,6 +3011,10 @@ } ], "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/master" + }, "time": "2018-07-08T19:23:20+00:00" }, { @@ -2707,6 +3062,10 @@ } ], "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/master" + }, "time": "2018-07-08T19:19:57+00:00" }, { @@ -2772,6 +3131,10 @@ "selenium", "webdriver" ], + "support": { + "issues": "https://github.com/php-webdriver/php-webdriver/issues", + "source": "https://github.com/php-webdriver/php-webdriver/tree/1.8.2" + }, "time": "2020-03-04T14:40:12+00:00" }, { @@ -2820,6 +3183,10 @@ "sequence", "set" ], + "support": { + "issues": "https://github.com/schmittjoh/php-collection/issues", + "source": "https://github.com/schmittjoh/php-collection/tree/master" + }, "time": "2015-05-17T12:39:23+00:00" }, { @@ -2869,6 +3236,10 @@ "reflection", "static analysis" ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + }, "time": "2020-06-27T09:03:43+00:00" }, { @@ -2921,6 +3292,10 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/master" + }, "time": "2020-09-03T19:13:55+00:00" }, { @@ -2966,6 +3341,10 @@ } ], "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.4.0" + }, "time": "2020-09-17T18:55:26+00:00" }, { @@ -3021,6 +3400,20 @@ "php", "type" ], + "support": { + "issues": "https://github.com/schmittjoh/php-option/issues", + "source": "https://github.com/schmittjoh/php-option/tree/1.7.5" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", + "type": "tidelift" + } + ], "time": "2020-07-20T17:29:33+00:00" }, { @@ -3084,6 +3477,10 @@ "spy", "stub" ], + "support": { + "issues": "https://github.com/phpspec/prophecy/issues", + "source": "https://github.com/phpspec/prophecy/tree/1.12.2" + }, "time": "2020-12-19T10:15:11+00:00" }, { @@ -3148,6 +3545,16 @@ "testing", "xunit" ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/8.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-05-23T08:02:54+00:00" }, { @@ -3198,6 +3605,16 @@ "filesystem", "iterator" ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-09-28T05:57:25+00:00" }, { @@ -3251,6 +3668,16 @@ "keywords": [ "process" ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-09-28T05:58:55+00:00" }, { @@ -3300,6 +3727,16 @@ "keywords": [ "template" ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-10-26T05:33:50+00:00" }, { @@ -3349,6 +3786,16 @@ "keywords": [ "timer" ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-10-26T13:16:10+00:00" }, { @@ -3398,6 +3845,16 @@ "keywords": [ "tokenizer" ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-token-stream/issues", + "source": "https://github.com/sebastianbergmann/php-token-stream/tree/master" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "abandoned": true, "time": "2020-08-04T08:28:15+00:00" }, @@ -3487,6 +3944,20 @@ "testing", "xunit" ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.2.6" + }, + "funding": [ + { + "url": "https://phpunit.de/donate.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-07-13T17:55:55+00:00" }, { @@ -3533,6 +4004,9 @@ "psr", "psr-6" ], + "support": { + "source": "https://github.com/php-fig/cache/tree/master" + }, "time": "2016-08-06T20:24:11+00:00" }, { @@ -3582,6 +4056,10 @@ "container-interop", "psr" ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/master" + }, "time": "2017-02-14T16:28:37+00:00" }, { @@ -3631,6 +4109,9 @@ "psr", "psr-18" ], + "support": { + "source": "https://github.com/php-fig/http-client/tree/master" + }, "time": "2020-06-29T06:28:15+00:00" }, { @@ -3683,6 +4164,9 @@ "request", "response" ], + "support": { + "source": "https://github.com/php-fig/http-factory/tree/master" + }, "time": "2019-04-30T12:38:16+00:00" }, { @@ -3733,6 +4217,9 @@ "request", "response" ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/master" + }, "time": "2016-08-06T14:39:51+00:00" }, { @@ -3780,6 +4267,9 @@ "psr", "psr-3" ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.3" + }, "time": "2020-03-23T09:12:05+00:00" }, { @@ -3820,6 +4310,10 @@ } ], "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, "time": "2019-03-08T08:55:37+00:00" }, { @@ -3883,6 +4377,20 @@ "queue", "set" ], + "support": { + "issues": "https://github.com/ramsey/collection/issues", + "source": "https://github.com/ramsey/collection/tree/1.1.3" + }, + "funding": [ + { + "url": "https://github.com/ramsey", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/ramsey/collection", + "type": "tidelift" + } + ], "time": "2021-01-21T17:40:04+00:00" }, { @@ -3964,6 +4472,17 @@ "identifier", "uuid" ], + "support": { + "issues": "https://github.com/ramsey/uuid/issues", + "rss": "https://github.com/ramsey/uuid/releases.atom", + "source": "https://github.com/ramsey/uuid" + }, + "funding": [ + { + "url": "https://github.com/ramsey", + "type": "github" + } + ], "time": "2020-08-18T17:17:46+00:00" }, { @@ -4010,6 +4529,16 @@ ], "description": "Collection of value objects that represent the PHP code units", "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-10-26T13:08:54+00:00" }, { @@ -4055,6 +4584,16 @@ ], "description": "Looks up which function or method a line of code belongs to", "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-09-28T05:30:19+00:00" }, { @@ -4119,6 +4658,16 @@ "compare", "equality" ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-10-26T15:49:45+00:00" }, { @@ -4175,6 +4724,16 @@ "unidiff", "unified diff" ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-10-26T13:10:38+00:00" }, { @@ -4228,6 +4787,16 @@ "environment", "hhvm" ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-09-28T05:52:38+00:00" }, { @@ -4295,6 +4864,16 @@ "export", "exporter" ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-09-28T05:24:23+00:00" }, { @@ -4349,6 +4928,10 @@ "keywords": [ "global state" ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/master" + }, "time": "2020-02-07T06:11:37+00:00" }, { @@ -4396,6 +4979,16 @@ ], "description": "Traverses array structures and object graphs to enumerate all referenced objects", "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-10-26T13:12:34+00:00" }, { @@ -4441,6 +5034,16 @@ ], "description": "Allows reflection of object attributes, including inherited and non-public ones", "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-10-26T13:14:26+00:00" }, { @@ -4494,6 +5097,16 @@ ], "description": "Provides functionality to recursively process PHP variables", "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-10-26T13:17:30+00:00" }, { @@ -4539,6 +5152,16 @@ ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "support": { + "issues": "https://github.com/sebastianbergmann/resource-operations/issues", + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-09-28T06:45:17+00:00" }, { @@ -4585,6 +5208,16 @@ ], "description": "Collection of value objects that represent the types of the PHP type system", "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/2.3.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-10-26T13:18:59+00:00" }, { @@ -4628,6 +5261,16 @@ ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-09-28T06:39:44+00:00" }, { @@ -4677,6 +5320,20 @@ "parser", "validator" ], + "support": { + "issues": "https://github.com/Seldaek/jsonlint/issues", + "source": "https://github.com/Seldaek/jsonlint/tree/1.8.3" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/seld/jsonlint", + "type": "tidelift" + } + ], "time": "2020-11-11T09:19:24+00:00" }, { @@ -4721,6 +5378,10 @@ "keywords": [ "phar" ], + "support": { + "issues": "https://github.com/Seldaek/phar-utils/issues", + "source": "https://github.com/Seldaek/phar-utils/tree/master" + }, "time": "2020-07-07T18:42:57+00:00" }, { @@ -4792,6 +5453,10 @@ "otp", "totp" ], + "support": { + "issues": "https://github.com/Spomky-Labs/otphp/issues", + "source": "https://github.com/Spomky-Labs/otphp/tree/v10.0.1" + }, "time": "2020-01-28T09:24:19+00:00" }, { @@ -4864,6 +5529,23 @@ ], "description": "Eases the creation of beautiful and testable command line interfaces", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/console/tree/v4.4.19" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2021-01-27T09:09:26+00:00" }, { @@ -4912,6 +5594,23 @@ ], "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/css-selector/tree/v5.2.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2021-01-27T10:01:46+00:00" }, { @@ -4962,6 +5661,23 @@ ], "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/master" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-09-07T11:33:47+00:00" }, { @@ -5028,6 +5744,23 @@ ], "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.19" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2021-01-27T09:09:26+00:00" }, { @@ -5090,6 +5823,23 @@ "interoperability", "standards" ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v1.1.9" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-07-06T13:19:58+00:00" }, { @@ -5135,6 +5885,23 @@ ], "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v5.2.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2021-01-27T10:01:46+00:00" }, { @@ -5179,6 +5946,23 @@ ], "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v5.2.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2021-01-27T10:01:46+00:00" }, { @@ -5235,6 +6019,23 @@ ], "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-foundation/tree/v5.2.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2021-01-27T11:19:04+00:00" }, { @@ -5300,6 +6101,23 @@ "mime", "mime-type" ], + "support": { + "source": "https://github.com/symfony/mime/tree/v5.2.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2021-01-25T14:08:25+00:00" }, { @@ -5362,6 +6180,23 @@ "polyfill", "portable" ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2021-01-07T16:49:33+00:00" }, { @@ -5432,6 +6267,23 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.22.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2021-01-07T16:49:33+00:00" }, { @@ -5499,6 +6351,23 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.22.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2021-01-07T17:09:11+00:00" }, { @@ -5562,6 +6431,23 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.22.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2021-01-07T16:49:33+00:00" }, { @@ -5621,6 +6507,23 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.22.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2021-01-07T16:49:33+00:00" }, { @@ -5683,6 +6586,23 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.22.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2021-01-07T16:49:33+00:00" }, { @@ -5749,6 +6669,23 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.22.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2021-01-07T16:49:33+00:00" }, { @@ -5793,6 +6730,23 @@ ], "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v4.4.19" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2021-01-27T09:09:26+00:00" }, { @@ -5855,6 +6809,23 @@ "interoperability", "standards" ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/master" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-09-07T11:33:47+00:00" }, { @@ -5909,6 +6880,23 @@ ], "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v4.4.19" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2021-01-27T09:09:26+00:00" }, { @@ -6044,6 +7032,10 @@ "MIT" ], "description": "PHP core functions that throw exceptions instead of returning FALSE on error", + "support": { + "issues": "https://github.com/thecodingmachine/safe/issues", + "source": "https://github.com/thecodingmachine/safe/tree/v1.3.3" + }, "time": "2020-10-28T17:51:34+00:00" }, { @@ -6084,6 +7076,16 @@ } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/master" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], "time": "2020-07-12T23:59:07+00:00" }, { @@ -6146,6 +7148,20 @@ "env", "environment" ], + "support": { + "issues": "https://github.com/vlucas/phpdotenv/issues", + "source": "https://github.com/vlucas/phpdotenv/tree/v2.6.7" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } + ], "time": "2021-01-20T14:39:13+00:00" }, { @@ -6195,6 +7211,10 @@ "check", "validate" ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.9.1" + }, "time": "2020-07-08T17:02:28+00:00" }, { @@ -6232,6 +7252,10 @@ } ], "description": "Useful collection of php array helpers.", + "support": { + "issues": "https://github.com/weew/helpers-array/issues", + "source": "https://github.com/weew/helpers-array/tree/master" + }, "time": "2016-07-21T11:18:01+00:00" } ], @@ -6303,6 +7327,10 @@ "composer", "git" ], + "support": { + "issues": "https://github.com/BrainMaestro/composer-git-hooks/issues", + "source": "https://github.com/BrainMaestro/composer-git-hooks/tree/v2.8.4" + }, "time": "2021-01-26T14:47:34+00:00" }, { @@ -6349,6 +7377,10 @@ ], "description": "Sends PHP test coverage information to Codacy.", "homepage": "https://github.com/codacy/php-codacy-coverage", + "support": { + "issues": "https://github.com/codacy/php-codacy-coverage/issues", + "source": "https://github.com/codacy/php-codacy-coverage/tree/master" + }, "abandoned": true, "time": "2020-01-10T10:52:12+00:00" }, @@ -6394,6 +7426,10 @@ } ], "description": "Experimental Mocking Framework powered by Aspects", + "support": { + "issues": "https://github.com/Codeception/AspectMock/issues", + "source": "https://github.com/Codeception/AspectMock/tree/master" + }, "time": "2020-02-29T15:39:49+00:00" }, { @@ -6464,6 +7500,10 @@ "cache", "caching" ], + "support": { + "issues": "https://github.com/doctrine/cache/issues", + "source": "https://github.com/doctrine/cache/tree/1.6.x" + }, "time": "2017-07-22T12:49:21+00:00" }, { @@ -6524,6 +7564,16 @@ } ], "description": "Library for accessing git", + "support": { + "issues": "https://github.com/gitonomy/gitlib/issues", + "source": "https://github.com/gitonomy/gitlib/tree/v1.2.3" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/gitonomy/gitlib", + "type": "tidelift" + } + ], "time": "2020-12-29T16:48:45+00:00" }, { @@ -6592,6 +7642,10 @@ "library", "php" ], + "support": { + "issues": "https://github.com/goaop/framework/issues", + "source": "https://github.com/goaop/framework/tree/2.3.4" + }, "time": "2020-04-06T09:46:21+00:00" }, { @@ -6643,6 +7697,10 @@ } ], "description": "Provides reflection information, based on raw source", + "support": { + "issues": "https://github.com/goaop/parser-reflection/issues", + "source": "https://github.com/goaop/parser-reflection/tree/2.x" + }, "time": "2020-08-13T21:02:42+00:00" }, { @@ -6735,6 +7793,10 @@ "rest", "web service" ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/master" + }, "abandoned": "guzzlehttp/guzzle", "time": "2014-01-28T22:29:15+00:00" }, @@ -6791,6 +7853,10 @@ "parser", "parsing" ], + "support": { + "issues": "https://github.com/jakubledl/dissect/issues", + "source": "https://github.com/jakubledl/dissect/tree/v1.0.1" + }, "time": "2013-01-29T21:29:14+00:00" }, { @@ -6838,6 +7904,16 @@ "BSD-3-Clause" ], "description": "Official version of pdepend to be handled with Composer", + "support": { + "issues": "https://github.com/pdepend/pdepend/issues", + "source": "https://github.com/pdepend/pdepend/tree/master" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/pdepend/pdepend", + "type": "tidelift" + } + ], "time": "2020-06-20T10:53:13+00:00" }, { @@ -6899,6 +7975,10 @@ "github", "test" ], + "support": { + "issues": "https://github.com/php-coveralls/php-coveralls/issues", + "source": "https://github.com/php-coveralls/php-coveralls/tree/1.1" + }, "time": "2017-12-06T23:17:56+00:00" }, { @@ -6971,6 +8051,17 @@ "phpmd", "pmd" ], + "support": { + "irc": "irc://irc.freenode.org/phpmd", + "issues": "https://github.com/phpmd/phpmd/issues", + "source": "https://github.com/phpmd/phpmd/tree/2.9.1" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/phpmd/phpmd", + "type": "tidelift" + } + ], "time": "2020-09-23T22:06:32+00:00" }, { @@ -7013,6 +8104,10 @@ "testing", "unittest" ], + "support": { + "issues": "https://github.com/richardregeer/phpunit-coverage-check/issues", + "source": "https://github.com/richardregeer/phpunit-coverage-check/tree/master" + }, "time": "2018-07-29T13:27:58+00:00" }, { @@ -7059,6 +8154,16 @@ ], "description": "Library for parsing CLI options", "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-09-28T06:08:49+00:00" }, { @@ -7110,6 +8215,16 @@ ], "description": "Copy/Paste Detector (CPD) for PHP code.", "homepage": "https://github.com/sebastianbergmann/phpcpd", + "support": { + "issues": "https://github.com/sebastianbergmann/phpcpd/issues", + "source": "https://github.com/sebastianbergmann/phpcpd/tree/6.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], "time": "2020-12-07T05:39:23+00:00" }, { @@ -7161,6 +8276,11 @@ "phpcs", "standards" ], + "support": { + "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", + "source": "https://github.com/squizlabs/PHP_CodeSniffer", + "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" + }, "time": "2020-10-23T02:01:07+00:00" }, { @@ -7220,6 +8340,23 @@ ], "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/config/tree/v4.4.19" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2021-01-27T09:09:26+00:00" }, { @@ -7288,6 +8425,23 @@ ], "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dependency-injection/tree/v4.4.19" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2021-01-27T09:09:26+00:00" }, { @@ -7332,6 +8486,23 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/stopwatch/tree/v3.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], "time": "2020-10-24T10:57:07+00:00" } ], @@ -7348,5 +8519,6 @@ "ext-json": "*", "ext-openssl": "*" }, - "platform-dev": [] + "platform-dev": [], + "plugin-api-version": "2.0.0" } From e688fd6b494334e45055889f4fd3cc11b96a0a14 Mon Sep 17 00:00:00 2001 From: "Kristof Ringleff, Fooman" <kristof@fooman.co.nz> Date: Sun, 9 May 2021 15:03:08 +1200 Subject: [PATCH 621/888] Add ability to configure multiple OTPs --- .../Resources/BasicFunctionalTest.txt | 1 + .../BasicFunctionalTest.xml | 1 + .../DataTransport/Auth/Tfa/OTP.php | 27 +++++++++++-------- .../Module/MagentoWebDriver.php | 5 ++-- .../Test/etc/Actions/customActions.xsd | 1 + .../Util/TestGenerator.php | 3 ++- 6 files changed, 24 insertions(+), 14 deletions(-) diff --git a/dev/tests/verification/Resources/BasicFunctionalTest.txt b/dev/tests/verification/Resources/BasicFunctionalTest.txt index 2a67888f6..29cfd9baf 100644 --- a/dev/tests/verification/Resources/BasicFunctionalTest.txt +++ b/dev/tests/verification/Resources/BasicFunctionalTest.txt @@ -113,6 +113,7 @@ class BasicFunctionalTestCest $generateDateKey2 = $date->format("H:i:s"); $getOtp = $I->getOTP(); // stepKey: getOtp + $getOtpWithInput = $I->getOTP("someInput"); // stepKey: getOtpWithInput $grabAttributeFromKey1 = $I->grabAttributeFrom(".functionalTestSelector", "someInput"); // stepKey: grabAttributeFromKey1 $grabCookieKey1 = $I->grabCookie("grabCookieInput", ['domain' => 'www.google.com']); // stepKey: grabCookieKey1 $grabFromCurrentUrlKey1 = $I->grabFromCurrentUrl("/grabCurrentUrl"); // stepKey: grabFromCurrentUrlKey1 diff --git a/dev/tests/verification/TestModule/Test/BasicFunctionalTest/BasicFunctionalTest.xml b/dev/tests/verification/TestModule/Test/BasicFunctionalTest/BasicFunctionalTest.xml index 81a43ca12..53bd1f7ef 100644 --- a/dev/tests/verification/TestModule/Test/BasicFunctionalTest/BasicFunctionalTest.xml +++ b/dev/tests/verification/TestModule/Test/BasicFunctionalTest/BasicFunctionalTest.xml @@ -69,6 +69,7 @@ <generateDate date="Now" format="H:i:s" stepKey="generateDateKey"/> <generateDate date="Now" format="H:i:s" stepKey="generateDateKey2" timezone="UTC"/> <getOTP stepKey="getOtp"/> + <getOTP stepKey="getOtpWithInput" userInput="someInput"/> <grabAttributeFrom selector=".functionalTestSelector" userInput="someInput" stepKey="grabAttributeFromKey1" /> <grabCookie userInput="grabCookieInput" parameterArray="['domain' => 'www.google.com']" stepKey="grabCookieKey1" /> <grabFromCurrentUrl regex="/grabCurrentUrl" stepKey="grabFromCurrentUrlKey1" /> diff --git a/src/Magento/FunctionalTestingFramework/DataTransport/Auth/Tfa/OTP.php b/src/Magento/FunctionalTestingFramework/DataTransport/Auth/Tfa/OTP.php index dcd6715c9..32c1f6b81 100644 --- a/src/Magento/FunctionalTestingFramework/DataTransport/Auth/Tfa/OTP.php +++ b/src/Magento/FunctionalTestingFramework/DataTransport/Auth/Tfa/OTP.php @@ -20,42 +20,47 @@ class OTP /** * TOTP object * - * @var TOTP + * @var TOTP[] */ - private static $totp = null; + private static $totps = []; /** * Return OTP for custom secret stored in `magento/tfa/OTP_SHARED_SECRET` * + * @param string|null $path * @return string * @throws TestFrameworkException */ - public static function getOTP() + public static function getOTP($path = null) { - return self::create()->now(); + if ($path === null) { + $path = self::OTP_SHARED_SECRET_PATH; + } + return self::create($path)->now(); } /** * Create TOTP object * + * @param string $path * @return TOTP * @throws TestFrameworkException */ - private static function create() + private static function create($path) { - if (self::$totp === null) { + if (!isset(self::$totps[$path])) { try { // Get shared secret from Credential storage - $encryptedSecret = CredentialStore::getInstance()->getSecret(self::OTP_SHARED_SECRET_PATH); + $encryptedSecret = CredentialStore::getInstance()->getSecret($path); $secret = CredentialStore::getInstance()->decryptSecretValue($encryptedSecret); } catch (TestFrameworkException $e) { throw new TestFrameworkException('Unable to get OTP' . PHP_EOL . $e->getMessage()); } - self::$totp = TOTP::create($secret); - self::$totp->setIssuer('MFTF'); - self::$totp->setLabel('MFTF Testing'); + self::$totps[$path] = TOTP::create($secret); + self::$totps[$path]->setIssuer('MFTF'); + self::$totps[$path]->setLabel('MFTF Testing'); } - return self::$totp; + return self::$totps[$path]; } } diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 00e295606..7a3220921 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -970,12 +970,13 @@ public function makeScreenshot($name = null) /** * Return OTP based on a shared secret * + * @param string|null $secretsPath * @return string * @throws TestFrameworkException */ - public function getOTP() + public function getOTP($secretsPath = null) { - return OTP::getOTP(); + return OTP::getOTP($secretsPath); } /** diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd index b1d6e1b02..2ea291cd8 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd @@ -335,6 +335,7 @@ </xs:annotation> <xs:simpleContent> <xs:extension base="xs:string"> + <xs:attribute ref="userInput"/> <xs:attributeGroup ref="commonActionAttributes"/> </xs:extension> </xs:simpleContent> diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 31035c8f6..492373340 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1262,7 +1262,8 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $testSteps .= $this->wrapFunctionCallWithReturnValue( $stepKey, $actor, - $actionObject + $actionObject, + $input ); break; case "resizeWindow": From e64f13cde5e6df48781778a33278b8063c2d965f Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 14 Jun 2021 11:55:31 -0500 Subject: [PATCH 622/888] MQE-2750: Update composer dependencies to be PHP 8 compatible --- composer.json | 29 +- composer.lock | 1566 +++++++++++++++++++++++++++++-------------------- 2 files changed, 951 insertions(+), 644 deletions(-) diff --git a/composer.json b/composer.json index 26dd6b06a..f435e6f21 100755 --- a/composer.json +++ b/composer.json @@ -9,25 +9,25 @@ "sort-packages": true }, "require": { - "php": "^7.3", + "php": "^7.3||^8.0", "ext-curl": "*", "ext-dom": "*", "ext-intl": "*", "ext-json": "*", "ext-openssl": "*", - "allure-framework/allure-codeception": "~1.4.0||~1.5.0", + "allure-framework/allure-codeception": "^1.4", "aws/aws-sdk-php": "^3.132", - "codeception/codeception": "~4.1.4", + "codeception/codeception": "^4.1", "codeception/module-asserts": "^1.1", "codeception/module-sequence": "^1.0", "codeception/module-webdriver": "^1.0", "composer/composer": "^1.9||^2.0", "csharpru/vault-php": "^4.1.0", "csharpru/vault-php-guzzle6-transport": "^2.0", - "hoa/console": "~3.0", + "hoa/console": "^3.0", "monolog/monolog": "^1.17", - "mustache/mustache": "~2.5", - "php-webdriver/webdriver": "^1.8.0", + "mustache/mustache": "^2.5", + "php-webdriver/webdriver": "^1.11.0", "spomky-labs/otphp": "^10.0", "symfony/console": "^4.4", "symfony/finder": "^5.0", @@ -36,24 +36,19 @@ "symfony/process": "^4.4", "vlucas/phpdotenv": "^2.4", "weew/helpers-array": "^1.3", - "nikic/php-parser": "~4.4.0" + "nikic/php-parser": "^4.4" }, "require-dev": { "brainmaestro/composer-git-hooks": "^2.3.1", "codacy/coverage": "^1.4", - "codeception/aspect-mock": "^3.0", - "doctrine/cache": "<1.7.0", - "goaop/framework": "~2.3.4", - "php-coveralls/php-coveralls": "^1.0", + "codeception/aspect-mock": "^4.0", + "php-coveralls/php-coveralls": "^2.2", "phpmd/phpmd": "^2.8.0", "phpunit/phpunit": "^9.0", "rregeer/phpunit-coverage-check": "^0.1.4", - "sebastian/phpcpd": "~6.0.0", - "squizlabs/php_codesniffer": "~3.5.4", - "symfony/stopwatch": "~3.4.6" - }, - "replace": { - "facebook/webdriver": "^1.7.1" + "sebastian/phpcpd": "^6.0", + "squizlabs/php_codesniffer": "^3.5", + "symfony/stopwatch": "^3.4" }, "autoload": { "files": ["src/Magento/FunctionalTestingFramework/_bootstrap.php"], diff --git a/composer.lock b/composer.lock index 8711d6d8e..9475b893a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ec8d82a1a84dbf04502a26273da1cb0f", + "content-hash": "2497eb0016466f4c6e66135bd3e8d505", "packages": [ { "name": "allure-framework/allure-codeception", - "version": "1.5.0", + "version": "1.5.2", "source": { "type": "git", "url": "https://github.com/allure-framework/allure-codeception.git", - "reference": "5ccfa4cdc826ef43ddba42b817dab4c0a8be7de2" + "reference": "a6156aef942a4e4de0add34a73d066a9458cefc6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/allure-framework/allure-codeception/zipball/5ccfa4cdc826ef43ddba42b817dab4c0a8be7de2", - "reference": "5ccfa4cdc826ef43ddba42b817dab4c0a8be7de2", + "url": "https://api.github.com/repos/allure-framework/allure-codeception/zipball/a6156aef942a4e4de0add34a73d066a9458cefc6", + "reference": "a6156aef942a4e4de0add34a73d066a9458cefc6", "shasum": "" }, "require": { @@ -65,7 +65,7 @@ "issues": "https://github.com/allure-framework/allure-codeception/issues", "source": "https://github.com/allure-framework/allure-codeception" }, - "time": "2021-03-26T16:11:53+00:00" + "time": "2021-06-04T13:24:36+00:00" }, { "name": "allure-framework/allure-php-api", @@ -127,16 +127,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.180.1", + "version": "3.184.2", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "7801112fd8be227954a6ecfbfd85b01ee4a7cae4" + "reference": "78fe691ab466fecf195209672f6c00c5d4ed219a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/7801112fd8be227954a6ecfbfd85b01ee4a7cae4", - "reference": "7801112fd8be227954a6ecfbfd85b01ee4a7cae4", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/78fe691ab466fecf195209672f6c00c5d4ed219a", + "reference": "78fe691ab466fecf195209672f6c00c5d4ed219a", "shasum": "" }, "require": { @@ -211,9 +211,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.180.1" + "source": "https://github.com/aws/aws-sdk-php/tree/3.184.2" }, - "time": "2021-05-04T18:14:38+00:00" + "time": "2021-06-11T18:20:15+00:00" }, { "name": "beberlei/assert", @@ -404,16 +404,16 @@ }, { "name": "codeception/codeception", - "version": "4.1.20", + "version": "4.1.21", "source": { "type": "git", "url": "https://github.com/Codeception/Codeception.git", - "reference": "d8b16e13e1781dbc3a7ae8292117d520c89a9c5a" + "reference": "c25f20d842a7e3fa0a8e6abf0828f102c914d419" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/Codeception/zipball/d8b16e13e1781dbc3a7ae8292117d520c89a9c5a", - "reference": "d8b16e13e1781dbc3a7ae8292117d520c89a9c5a", + "url": "https://api.github.com/repos/Codeception/Codeception/zipball/c25f20d842a7e3fa0a8e6abf0828f102c914d419", + "reference": "c25f20d842a7e3fa0a8e6abf0828f102c914d419", "shasum": "" }, "require": { @@ -433,11 +433,11 @@ "symfony/yaml": ">=2.7 <6.0" }, "require-dev": { - "codeception/module-asserts": "*@dev", - "codeception/module-cli": "*@dev", - "codeception/module-db": "*@dev", - "codeception/module-filesystem": "*@dev", - "codeception/module-phpbrowser": "*@dev", + "codeception/module-asserts": "1.*@dev", + "codeception/module-cli": "1.*@dev", + "codeception/module-db": "1.*@dev", + "codeception/module-filesystem": "1.*@dev", + "codeception/module-phpbrowser": "1.*@dev", "codeception/specify": "~0.3", "codeception/util-universalframework": "*@dev", "monolog/monolog": "~1.8", @@ -487,7 +487,7 @@ ], "support": { "issues": "https://github.com/Codeception/Codeception/issues", - "source": "https://github.com/Codeception/Codeception/tree/4.1.20" + "source": "https://github.com/Codeception/Codeception/tree/4.1.21" }, "funding": [ { @@ -495,7 +495,7 @@ "type": "open_collective" } ], - "time": "2021-04-02T16:41:51+00:00" + "time": "2021-05-28T17:43:39+00:00" }, { "name": "codeception/lib-asserts", @@ -793,16 +793,16 @@ }, { "name": "composer/ca-bundle", - "version": "1.2.9", + "version": "1.2.10", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5" + "reference": "9fdb22c2e97a614657716178093cd1da90a64aa8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/78a0e288fdcebf92aa2318a8d3656168da6ac1a5", - "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/9fdb22c2e97a614657716178093cd1da90a64aa8", + "reference": "9fdb22c2e97a614657716178093cd1da90a64aa8", "shasum": "" }, "require": { @@ -849,7 +849,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.2.9" + "source": "https://github.com/composer/ca-bundle/tree/1.2.10" }, "funding": [ { @@ -865,20 +865,20 @@ "type": "tidelift" } ], - "time": "2021-01-12T12:10:35+00:00" + "time": "2021-06-07T13:58:28+00:00" }, { "name": "composer/composer", - "version": "2.0.13", + "version": "2.1.3", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "986e8b86b7b570632ad0a905c3726c33dd4c0efb" + "reference": "fc5c4573aafce3a018eb7f1f8f91cea423970f2e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/986e8b86b7b570632ad0a905c3726c33dd4c0efb", - "reference": "986e8b86b7b570632ad0a905c3726c33dd4c0efb", + "url": "https://api.github.com/repos/composer/composer/zipball/fc5c4573aafce3a018eb7f1f8f91cea423970f2e", + "reference": "fc5c4573aafce3a018eb7f1f8f91cea423970f2e", "shasum": "" }, "require": { @@ -886,21 +886,21 @@ "composer/metadata-minifier": "^1.0", "composer/semver": "^3.0", "composer/spdx-licenses": "^1.2", - "composer/xdebug-handler": "^1.1", + "composer/xdebug-handler": "^2.0", "justinrainbow/json-schema": "^5.2.10", "php": "^5.3.2 || ^7.0 || ^8.0", "psr/log": "^1.0", "react/promise": "^1.2 || ^2.7", "seld/jsonlint": "^1.4", "seld/phar-utils": "^1.0", - "symfony/console": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0", - "symfony/filesystem": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0", - "symfony/finder": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0", - "symfony/process": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0" + "symfony/console": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0", + "symfony/filesystem": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0", + "symfony/finder": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0", + "symfony/process": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0" }, "require-dev": { "phpspec/prophecy": "^1.10", - "symfony/phpunit-bridge": "^4.2 || ^5.0" + "symfony/phpunit-bridge": "^4.2 || ^5.0 || ^6.0" }, "suggest": { "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages", @@ -913,7 +913,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "2.1-dev" } }, "autoload": { @@ -947,7 +947,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/composer/issues", - "source": "https://github.com/composer/composer/tree/2.0.13" + "source": "https://github.com/composer/composer/tree/2.1.3" }, "funding": [ { @@ -963,7 +963,7 @@ "type": "tidelift" } ], - "time": "2021-04-27T11:11:08+00:00" + "time": "2021-06-09T14:31:20+00:00" }, { "name": "composer/metadata-minifier", @@ -1036,16 +1036,16 @@ }, { "name": "composer/semver", - "version": "3.2.4", + "version": "3.2.5", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "a02fdf930a3c1c3ed3a49b5f63859c0c20e10464" + "reference": "31f3ea725711245195f62e54ffa402d8ef2fdba9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/a02fdf930a3c1c3ed3a49b5f63859c0c20e10464", - "reference": "a02fdf930a3c1c3ed3a49b5f63859c0c20e10464", + "url": "https://api.github.com/repos/composer/semver/zipball/31f3ea725711245195f62e54ffa402d8ef2fdba9", + "reference": "31f3ea725711245195f62e54ffa402d8ef2fdba9", "shasum": "" }, "require": { @@ -1097,7 +1097,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.2.4" + "source": "https://github.com/composer/semver/tree/3.2.5" }, "funding": [ { @@ -1113,7 +1113,7 @@ "type": "tidelift" } ], - "time": "2020-11-13T08:59:24+00:00" + "time": "2021-05-24T12:41:47+00:00" }, { "name": "composer/spdx-licenses", @@ -1196,16 +1196,16 @@ }, { "name": "composer/xdebug-handler", - "version": "1.4.6", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "f27e06cd9675801df441b3656569b328e04aa37c" + "reference": "964adcdd3a28bf9ed5d9ac6450064e0d71ed7496" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/f27e06cd9675801df441b3656569b328e04aa37c", - "reference": "f27e06cd9675801df441b3656569b328e04aa37c", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/964adcdd3a28bf9ed5d9ac6450064e0d71ed7496", + "reference": "964adcdd3a28bf9ed5d9ac6450064e0d71ed7496", "shasum": "" }, "require": { @@ -1240,7 +1240,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/1.4.6" + "source": "https://github.com/composer/xdebug-handler/tree/2.0.1" }, "funding": [ { @@ -1256,25 +1256,25 @@ "type": "tidelift" } ], - "time": "2021-03-25T17:01:18+00:00" + "time": "2021-05-05T19:37:51+00:00" }, { "name": "csharpru/vault-php", - "version": "4.2.0", + "version": "4.2.1", "source": { "type": "git", "url": "https://github.com/CSharpRU/vault-php.git", - "reference": "de812a9667a1111c4f4d4080b2c9166692ee9efe" + "reference": "89b393ecf65f61a44d3a1872547f65085982b481" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CSharpRU/vault-php/zipball/de812a9667a1111c4f4d4080b2c9166692ee9efe", - "reference": "de812a9667a1111c4f4d4080b2c9166692ee9efe", + "url": "https://api.github.com/repos/CSharpRU/vault-php/zipball/89b393ecf65f61a44d3a1872547f65085982b481", + "reference": "89b393ecf65f61a44d3a1872547f65085982b481", "shasum": "" }, "require": { "ext-json": "*", - "php": "^7.2", + "php": "^7.2 || ^8.0", "psr/cache": "^1.0", "psr/http-client": "^1.0", "psr/http-factory": "^1.0", @@ -1282,11 +1282,13 @@ "weew/helpers-array": "^1.3" }, "require-dev": { - "alextartan/guzzle-psr18-adapter": "^1.2", + "alextartan/guzzle-psr18-adapter": "^1.2 || ^2.0", "cache/array-adapter": "^1.0", - "codeception/codeception": "^2.2", + "codeception/codeception": "^4.1", + "codeception/module-asserts": "^1.3", "laminas/laminas-diactoros": "^2.3", - "php-vcr/php-vcr": "dev-issues/289 as 1.4.5" + "php-vcr/php-vcr": "^1.5", + "symfony/event-dispatcher": "<5.0" }, "suggest": { "cache/array-adapter": "For usage with CachedClient class" @@ -1308,11 +1310,16 @@ } ], "description": "Best Vault client for PHP that you can find", + "keywords": [ + "hashicorp", + "secrets", + "vault" + ], "support": { "issues": "https://github.com/CSharpRU/vault-php/issues", - "source": "https://github.com/CSharpRU/vault-php/tree/4.2.0" + "source": "https://github.com/CSharpRU/vault-php/tree/4.2.1" }, - "time": "2020-11-27T09:07:28+00:00" + "time": "2021-05-21T06:39:35+00:00" }, { "name": "csharpru/vault-php-guzzle6-transport", @@ -1358,28 +1365,30 @@ }, { "name": "doctrine/annotations", - "version": "1.12.1", + "version": "1.13.1", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "b17c5014ef81d212ac539f07a1001832df1b6d3b" + "reference": "e6e7b7d5b45a2f2abc5460cc6396480b2b1d321f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/b17c5014ef81d212ac539f07a1001832df1b6d3b", - "reference": "b17c5014ef81d212ac539f07a1001832df1b6d3b", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/e6e7b7d5b45a2f2abc5460cc6396480b2b1d321f", + "reference": "e6e7b7d5b45a2f2abc5460cc6396480b2b1d321f", "shasum": "" }, "require": { "doctrine/lexer": "1.*", "ext-tokenizer": "*", - "php": "^7.1 || ^8.0" + "php": "^7.1 || ^8.0", + "psr/cache": "^1 || ^2 || ^3" }, "require-dev": { - "doctrine/cache": "1.*", + "doctrine/cache": "^1.11 || ^2.0", "doctrine/coding-standard": "^6.0 || ^8.1", "phpstan/phpstan": "^0.12.20", - "phpunit/phpunit": "^7.5 || ^9.1.5" + "phpunit/phpunit": "^7.5 || ^8.0 || ^9.1.5", + "symfony/cache": "^4.4 || ^5.2" }, "type": "library", "autoload": { @@ -1422,9 +1431,9 @@ ], "support": { "issues": "https://github.com/doctrine/annotations/issues", - "source": "https://github.com/doctrine/annotations/tree/1.12.1" + "source": "https://github.com/doctrine/annotations/tree/1.13.1" }, - "time": "2021-02-21T21:00:45+00:00" + "time": "2021-05-16T18:07:53+00:00" }, { "name": "doctrine/instantiator", @@ -2626,16 +2635,16 @@ }, { "name": "monolog/monolog", - "version": "1.26.0", + "version": "1.26.1", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "2209ddd84e7ef1256b7af205d0717fb62cfc9c33" + "reference": "c6b00f05152ae2c9b04a448f99c7590beb6042f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/2209ddd84e7ef1256b7af205d0717fb62cfc9c33", - "reference": "2209ddd84e7ef1256b7af205d0717fb62cfc9c33", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/c6b00f05152ae2c9b04a448f99c7590beb6042f5", + "reference": "c6b00f05152ae2c9b04a448f99c7590beb6042f5", "shasum": "" }, "require": { @@ -2696,7 +2705,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/1.26.0" + "source": "https://github.com/Seldaek/monolog/tree/1.26.1" }, "funding": [ { @@ -2708,7 +2717,7 @@ "type": "tidelift" } ], - "time": "2020-12-14T12:56:38+00:00" + "time": "2021-05-28T08:32:12+00:00" }, { "name": "mtdowling/jmespath.php", @@ -2881,16 +2890,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.4.0", + "version": "v4.10.5", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "bd43ec7152eaaab3bd8c6d0aa95ceeb1df8ee120" + "reference": "4432ba399e47c66624bc73c8c0f811e5c109576f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/bd43ec7152eaaab3bd8c6d0aa95ceeb1df8ee120", - "reference": "bd43ec7152eaaab3bd8c6d0aa95ceeb1df8ee120", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4432ba399e47c66624bc73c8c0f811e5c109576f", + "reference": "4432ba399e47c66624bc73c8c0f811e5c109576f", "shasum": "" }, "require": { @@ -2898,8 +2907,8 @@ "php": ">=7.0" }, "require-dev": { - "ircmaxell/php-yacc": "0.0.5", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0" + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" }, "bin": [ "bin/php-parse" @@ -2907,7 +2916,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "4.9-dev" } }, "autoload": { @@ -2931,9 +2940,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/master" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.10.5" }, - "time": "2020-04-10T16:34:50+00:00" + "time": "2021-05-03T19:11:20+00:00" }, { "name": "paragonie/constant_time_encoding", @@ -3004,28 +3013,29 @@ }, { "name": "phar-io/manifest", - "version": "1.0.3", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" + "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", - "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/85265efd3af7ba3ca4b2a2c34dbfc5788dd29133", + "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133", "shasum": "" }, "require": { "ext-dom": "*", "ext-phar": "*", - "phar-io/version": "^2.0", - "php": "^5.6 || ^7.0" + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -3059,24 +3069,24 @@ "issues": "https://github.com/phar-io/manifest/issues", "source": "https://github.com/phar-io/manifest/tree/master" }, - "time": "2018-07-08T19:23:20+00:00" + "time": "2020-06-27T14:33:11+00:00" }, { "name": "phar-io/version", - "version": "2.0.1", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/phar-io/version.git", - "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" + "reference": "bae7c545bef187884426f042434e561ab1ddb182" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", - "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "url": "https://api.github.com/repos/phar-io/version/zipball/bae7c545bef187884426f042434e561ab1ddb182", + "reference": "bae7c545bef187884426f042434e561ab1ddb182", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "php": "^7.2 || ^8.0" }, "type": "library", "autoload": { @@ -3108,40 +3118,42 @@ "description": "Library for handling version information and constraints", "support": { "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/master" + "source": "https://github.com/phar-io/version/tree/3.1.0" }, - "time": "2018-07-08T19:19:57+00:00" + "time": "2021-02-23T14:00:09+00:00" }, { "name": "php-webdriver/webdriver", - "version": "1.8.2", + "version": "1.11.1", "source": { "type": "git", "url": "https://github.com/php-webdriver/php-webdriver.git", - "reference": "3308a70be084d6d7fd1ee5787b4c2e6eb4b70aab" + "reference": "da16e39968f8dd5cfb7d07eef91dc2b731c69880" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/3308a70be084d6d7fd1ee5787b4c2e6eb4b70aab", - "reference": "3308a70be084d6d7fd1ee5787b4c2e6eb4b70aab", + "url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/da16e39968f8dd5cfb7d07eef91dc2b731c69880", + "reference": "da16e39968f8dd5cfb7d07eef91dc2b731c69880", "shasum": "" }, "require": { "ext-curl": "*", "ext-json": "*", "ext-zip": "*", - "php": "^5.6 || ~7.0", + "php": "^5.6 || ~7.0 || ^8.0", "symfony/polyfill-mbstring": "^1.12", "symfony/process": "^2.8 || ^3.1 || ^4.0 || ^5.0" }, + "replace": { + "facebook/webdriver": "*" + }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.0", - "jakub-onderka/php-parallel-lint": "^1.0", - "php-coveralls/php-coveralls": "^2.0", - "php-mock/php-mock-phpunit": "^1.1", - "phpunit/phpunit": "^5.7", - "sebastian/environment": "^1.3.4 || ^2.0 || ^3.0", - "sminnee/phpunit-mock-objects": "^3.4", + "ondram/ci-detector": "^2.1 || ^3.5 || ^4.0", + "php-coveralls/php-coveralls": "^2.4", + "php-mock/php-mock-phpunit": "^1.1 || ^2.0", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpunit/phpunit": "^5.7 || ^7 || ^8 || ^9", "squizlabs/php_codesniffer": "^3.5", "symfony/var-dumper": "^3.3 || ^4.0 || ^5.0" }, @@ -3149,11 +3161,6 @@ "ext-SimpleXML": "For Firefox profile creation" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.8.x-dev" - } - }, "autoload": { "psr-4": { "Facebook\\WebDriver\\": "lib/" @@ -3177,9 +3184,9 @@ ], "support": { "issues": "https://github.com/php-webdriver/php-webdriver/issues", - "source": "https://github.com/php-webdriver/php-webdriver/tree/1.8.2" + "source": "https://github.com/php-webdriver/php-webdriver/tree/1.11.1" }, - "time": "2020-03-04T14:40:12+00:00" + "time": "2021-05-21T15:12:49+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -3408,28 +3415,27 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "0.5.4", + "version": "0.5.5", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "e352d065af1ae9b41c12d1dfd309e90f7b1f55c9" + "reference": "ea0b17460ec38e20d7eb64e7ec49b5d44af5d28c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/e352d065af1ae9b41c12d1dfd309e90f7b1f55c9", - "reference": "e352d065af1ae9b41c12d1dfd309e90f7b1f55c9", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/ea0b17460ec38e20d7eb64e7ec49b5d44af5d28c", + "reference": "ea0b17460ec38e20d7eb64e7ec49b5d44af5d28c", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "require-dev": { - "phing/phing": "^2.16.3", "php-parallel-lint/php-parallel-lint": "^1.2", "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^0.12.60", + "phpstan/phpstan": "^0.12.87", "phpstan/phpstan-strict-rules": "^0.12.5", - "phpunit/phpunit": "^7.5.20", + "phpunit/phpunit": "^9.5", "symfony/process": "^5.2" }, "type": "library", @@ -3452,38 +3458,41 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/0.5.4" + "source": "https://github.com/phpstan/phpdoc-parser/tree/0.5.5" }, - "time": "2021-04-03T14:46:19+00:00" + "time": "2021-06-11T13:24:46+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "8.0.2", + "version": "9.2.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "ca6647ffddd2add025ab3f21644a441d7c146cdc" + "reference": "f6293e1b30a2354e8428e004689671b83871edde" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca6647ffddd2add025ab3f21644a441d7c146cdc", - "reference": "ca6647ffddd2add025ab3f21644a441d7c146cdc", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f6293e1b30a2354e8428e004689671b83871edde", + "reference": "f6293e1b30a2354e8428e004689671b83871edde", "shasum": "" }, "require": { "ext-dom": "*", + "ext-libxml": "*", "ext-xmlwriter": "*", - "php": "^7.3", - "phpunit/php-file-iterator": "^3.0", - "phpunit/php-text-template": "^2.0", - "phpunit/php-token-stream": "^4.0", - "sebastian/code-unit-reverse-lookup": "^2.0", - "sebastian/environment": "^5.0", - "sebastian/version": "^3.0", - "theseer/tokenizer": "^1.1.3" + "nikic/php-parser": "^4.10.2", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-text-template": "^2.0.2", + "sebastian/code-unit-reverse-lookup": "^2.0.2", + "sebastian/complexity": "^2.0", + "sebastian/environment": "^5.1.2", + "sebastian/lines-of-code": "^1.0.3", + "sebastian/version": "^3.0.1", + "theseer/tokenizer": "^1.2.0" }, "require-dev": { - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" }, "suggest": { "ext-pcov": "*", @@ -3492,7 +3501,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "8.0-dev" + "dev-master": "9.2-dev" } }, "autoload": { @@ -3520,7 +3529,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/8.0.2" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.6" }, "funding": [ { @@ -3528,7 +3537,7 @@ "type": "github" } ], - "time": "2020-05-23T08:02:54+00:00" + "time": "2021-03-28T07:26:59+00:00" }, { "name": "phpunit/php-file-iterator", @@ -3771,78 +3780,18 @@ ], "time": "2020-10-26T13:16:10+00:00" }, - { - "name": "phpunit/php-token-stream", - "version": "4.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/a853a0e183b9db7eed023d7933a858fa1c8d25a3", - "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": "^7.3 || ^8.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", - "keywords": [ - "tokenizer" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-token-stream/issues", - "source": "https://github.com/sebastianbergmann/php-token-stream/tree/master" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "abandoned": true, - "time": "2020-08-04T08:28:15+00:00" - }, { "name": "phpunit/phpunit", - "version": "9.2.6", + "version": "9.5.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "1c6a9e4312e209e659f1fce3ce88dd197c2448f6" + "reference": "89ff45ea9d70e35522fb6654a2ebc221158de276" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1c6a9e4312e209e659f1fce3ce88dd197c2448f6", - "reference": "1c6a9e4312e209e659f1fce3ce88dd197c2448f6", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/89ff45ea9d70e35522fb6654a2ebc221158de276", + "reference": "89ff45ea9d70e35522fb6654a2ebc221158de276", "shasum": "" }, "require": { @@ -3853,30 +3802,31 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.9.5", - "phar-io/manifest": "^1.0.3", - "phar-io/version": "^2.0.1", - "php": "^7.3", - "phpspec/prophecy": "^1.10.3", - "phpunit/php-code-coverage": "^8.0.2", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-invoker": "^3.0.2", - "phpunit/php-text-template": "^2.0.2", - "phpunit/php-timer": "^5.0.1", - "sebastian/code-unit": "^1.0.5", - "sebastian/comparator": "^4.0.3", - "sebastian/diff": "^4.0.1", - "sebastian/environment": "^5.1.2", - "sebastian/exporter": "^4.0.2", - "sebastian/global-state": "^4.0", - "sebastian/object-enumerator": "^4.0.2", - "sebastian/resource-operations": "^3.0.2", - "sebastian/type": "^2.1.1", - "sebastian/version": "^3.0.1" + "myclabs/deep-copy": "^1.10.1", + "phar-io/manifest": "^2.0.1", + "phar-io/version": "^3.0.2", + "php": ">=7.3", + "phpspec/prophecy": "^1.12.1", + "phpunit/php-code-coverage": "^9.2.3", + "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-invoker": "^3.1.1", + "phpunit/php-text-template": "^2.0.3", + "phpunit/php-timer": "^5.0.2", + "sebastian/cli-parser": "^1.0.1", + "sebastian/code-unit": "^1.0.6", + "sebastian/comparator": "^4.0.5", + "sebastian/diff": "^4.0.3", + "sebastian/environment": "^5.1.3", + "sebastian/exporter": "^4.0.3", + "sebastian/global-state": "^5.0.1", + "sebastian/object-enumerator": "^4.0.3", + "sebastian/resource-operations": "^3.0.3", + "sebastian/type": "^2.3.2", + "sebastian/version": "^3.0.2" }, "require-dev": { "ext-pdo": "*", - "phpspec/prophecy-phpunit": "^2.0" + "phpspec/prophecy-phpunit": "^2.0.1" }, "suggest": { "ext-soap": "*", @@ -3888,7 +3838,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.2-dev" + "dev-master": "9.5-dev" } }, "autoload": { @@ -3919,7 +3869,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.2.6" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.5" }, "funding": [ { @@ -3931,7 +3881,7 @@ "type": "github" } ], - "time": "2020-07-13T17:55:55+00:00" + "time": "2021-06-05T04:49:07+00:00" }, { "name": "psr/cache", @@ -4503,6 +4453,62 @@ }, "time": "2020-05-12T15:16:56+00:00" }, + { + "name": "sebastian/cli-parser", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:08:49+00:00" + }, { "name": "sebastian/code-unit", "version": "1.0.8", @@ -4688,6 +4694,63 @@ ], "time": "2020-10-26T15:49:45+00:00" }, + { + "name": "sebastian/complexity", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.7", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T15:52:27+00:00" + }, { "name": "sebastian/diff", "version": "4.0.4", @@ -4896,26 +4959,26 @@ }, { "name": "sebastian/global-state", - "version": "4.0.0", + "version": "5.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bdb1e7c79e592b8c82cb1699be3c8743119b8a72" + "reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bdb1e7c79e592b8c82cb1699be3c8743119b8a72", - "reference": "bdb1e7c79e592b8c82cb1699be3c8743119b8a72", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/23bd5951f7ff26f12d4e3242864df3e08dec4e49", + "reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49", "shasum": "" }, "require": { - "php": "^7.3", + "php": ">=7.3", "sebastian/object-reflector": "^2.0", "sebastian/recursion-context": "^4.0" }, "require-dev": { "ext-dom": "*", - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" }, "suggest": { "ext-uopz": "*" @@ -4923,7 +4986,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -4948,9 +5011,72 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/master" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-06-11T13:31:12+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.6", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } }, - "time": "2020-02-07T06:11:37+00:00" + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-28T06:42:11+00:00" }, { "name": "sebastian/object-enumerator", @@ -5184,16 +5310,16 @@ }, { "name": "sebastian/type", - "version": "2.3.1", + "version": "2.3.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2" + "reference": "0d1c587401514d17e8f9258a27e23527cb1b06c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/81cd61ab7bbf2de744aba0ea61fae32f721df3d2", - "reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/0d1c587401514d17e8f9258a27e23527cb1b06c1", + "reference": "0d1c587401514d17e8f9258a27e23527cb1b06c1", "shasum": "" }, "require": { @@ -5228,7 +5354,7 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/2.3.1" + "source": "https://github.com/sebastianbergmann/type/tree/2.3.2" }, "funding": [ { @@ -5236,7 +5362,7 @@ "type": "github" } ], - "time": "2020-10-26T13:18:59+00:00" + "time": "2021-06-04T13:02:07+00:00" }, { "name": "sebastian/version", @@ -5479,16 +5605,16 @@ }, { "name": "symfony/console", - "version": "v4.4.22", + "version": "v4.4.25", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "36bbd079b69b94bcc9c9c9e1e37ca3b1e7971625" + "reference": "a62acecdf5b50e314a4f305cd01b5282126f3095" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/36bbd079b69b94bcc9c9c9e1e37ca3b1e7971625", - "reference": "36bbd079b69b94bcc9c9c9e1e37ca3b1e7971625", + "url": "https://api.github.com/repos/symfony/console/zipball/a62acecdf5b50e314a4f305cd01b5282126f3095", + "reference": "a62acecdf5b50e314a4f305cd01b5282126f3095", "shasum": "" }, "require": { @@ -5548,7 +5674,7 @@ "description": "Eases the creation of beautiful and testable command line interfaces", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/console/tree/v4.4.22" + "source": "https://github.com/symfony/console/tree/v4.4.25" }, "funding": [ { @@ -5564,20 +5690,20 @@ "type": "tidelift" } ], - "time": "2021-04-16T17:32:19+00:00" + "time": "2021-05-26T11:20:16+00:00" }, { "name": "symfony/css-selector", - "version": "v5.2.7", + "version": "v5.3.0", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "59a684f5ac454f066ecbe6daecce6719aed283fb" + "reference": "fcd0b29a7a0b1bb5bfbedc6231583d77fea04814" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/59a684f5ac454f066ecbe6daecce6719aed283fb", - "reference": "59a684f5ac454f066ecbe6daecce6719aed283fb", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/fcd0b29a7a0b1bb5bfbedc6231583d77fea04814", + "reference": "fcd0b29a7a0b1bb5bfbedc6231583d77fea04814", "shasum": "" }, "require": { @@ -5613,7 +5739,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v5.3.0-BETA1" + "source": "https://github.com/symfony/css-selector/tree/v5.3.0" }, "funding": [ { @@ -5629,7 +5755,7 @@ "type": "tidelift" } ], - "time": "2021-04-07T16:07:52+00:00" + "time": "2021-05-26T17:40:38+00:00" }, { "name": "symfony/deprecation-contracts", @@ -5700,16 +5826,16 @@ }, { "name": "symfony/event-dispatcher", - "version": "v4.4.20", + "version": "v4.4.25", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "c352647244bd376bf7d31efbd5401f13f50dad0c" + "reference": "047773e7016e4fd45102cedf4bd2558ae0d0c32f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/c352647244bd376bf7d31efbd5401f13f50dad0c", - "reference": "c352647244bd376bf7d31efbd5401f13f50dad0c", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/047773e7016e4fd45102cedf4bd2558ae0d0c32f", + "reference": "047773e7016e4fd45102cedf4bd2558ae0d0c32f", "shasum": "" }, "require": { @@ -5763,7 +5889,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.20" + "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.25" }, "funding": [ { @@ -5779,7 +5905,7 @@ "type": "tidelift" } ], - "time": "2021-01-27T09:09:26+00:00" + "time": "2021-05-26T17:39:37+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -5862,16 +5988,16 @@ }, { "name": "symfony/filesystem", - "version": "v5.2.7", + "version": "v5.3.0", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "056e92acc21d977c37e6ea8e97374b2a6c8551b0" + "reference": "348116319d7fb7d1faa781d26a48922428013eb2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/056e92acc21d977c37e6ea8e97374b2a6c8551b0", - "reference": "056e92acc21d977c37e6ea8e97374b2a6c8551b0", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/348116319d7fb7d1faa781d26a48922428013eb2", + "reference": "348116319d7fb7d1faa781d26a48922428013eb2", "shasum": "" }, "require": { @@ -5904,7 +6030,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.2.7" + "source": "https://github.com/symfony/filesystem/tree/v5.3.0" }, "funding": [ { @@ -5920,20 +6046,20 @@ "type": "tidelift" } ], - "time": "2021-04-01T10:42:13+00:00" + "time": "2021-05-26T17:43:10+00:00" }, { "name": "symfony/finder", - "version": "v5.2.4", + "version": "v5.3.0", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "0d639a0943822626290d169965804f79400e6a04" + "reference": "0ae3f047bed4edff6fd35b26a9a6bfdc92c953c6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/0d639a0943822626290d169965804f79400e6a04", - "reference": "0d639a0943822626290d169965804f79400e6a04", + "url": "https://api.github.com/repos/symfony/finder/zipball/0ae3f047bed4edff6fd35b26a9a6bfdc92c953c6", + "reference": "0ae3f047bed4edff6fd35b26a9a6bfdc92c953c6", "shasum": "" }, "require": { @@ -5965,7 +6091,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.2.4" + "source": "https://github.com/symfony/finder/tree/v5.3.0" }, "funding": [ { @@ -5981,20 +6107,20 @@ "type": "tidelift" } ], - "time": "2021-02-15T18:55:04+00:00" + "time": "2021-05-26T12:52:38+00:00" }, { "name": "symfony/http-foundation", - "version": "v5.2.7", + "version": "v5.3.1", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "a416487a73bb9c9d120e9ba3a60547f4a3fb7a1f" + "reference": "8827b90cf8806e467124ad476acd15216c2fceb6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/a416487a73bb9c9d120e9ba3a60547f4a3fb7a1f", - "reference": "a416487a73bb9c9d120e9ba3a60547f4a3fb7a1f", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/8827b90cf8806e467124ad476acd15216c2fceb6", + "reference": "8827b90cf8806e467124ad476acd15216c2fceb6", "shasum": "" }, "require": { @@ -6038,7 +6164,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v5.2.7" + "source": "https://github.com/symfony/http-foundation/tree/v5.3.1" }, "funding": [ { @@ -6054,20 +6180,20 @@ "type": "tidelift" } ], - "time": "2021-05-01T13:46:24+00:00" + "time": "2021-06-02T09:32:00+00:00" }, { "name": "symfony/mime", - "version": "v5.2.7", + "version": "v5.3.0", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "7af452bf51c46f18da00feb32e1ad36db9426515" + "reference": "ed710d297b181f6a7194d8172c9c2423d58e4852" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/7af452bf51c46f18da00feb32e1ad36db9426515", - "reference": "7af452bf51c46f18da00feb32e1ad36db9426515", + "url": "https://api.github.com/repos/symfony/mime/zipball/ed710d297b181f6a7194d8172c9c2423d58e4852", + "reference": "ed710d297b181f6a7194d8172c9c2423d58e4852", "shasum": "" }, "require": { @@ -6121,7 +6247,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v5.2.7" + "source": "https://github.com/symfony/mime/tree/v5.3.0" }, "funding": [ { @@ -6137,20 +6263,20 @@ "type": "tidelift" } ], - "time": "2021-04-29T20:47:09+00:00" + "time": "2021-05-26T17:43:10+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.22.1", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "c6c942b1ac76c82448322025e084cadc56048b4e" + "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/c6c942b1ac76c82448322025e084cadc56048b4e", - "reference": "c6c942b1ac76c82448322025e084cadc56048b4e", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce", + "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce", "shasum": "" }, "require": { @@ -6162,7 +6288,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -6200,7 +6326,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0" }, "funding": [ { @@ -6216,20 +6342,20 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2021-02-19T12:13:01+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.22.1", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "2d63434d922daf7da8dd863e7907e67ee3031483" + "reference": "65bd267525e82759e7d8c4e8ceea44f398838e65" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/2d63434d922daf7da8dd863e7907e67ee3031483", - "reference": "2d63434d922daf7da8dd863e7907e67ee3031483", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/65bd267525e82759e7d8c4e8ceea44f398838e65", + "reference": "65bd267525e82759e7d8c4e8ceea44f398838e65", "shasum": "" }, "require": { @@ -6243,7 +6369,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -6287,7 +6413,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.23.0" }, "funding": [ { @@ -6303,20 +6429,20 @@ "type": "tidelift" } ], - "time": "2021-01-22T09:19:47+00:00" + "time": "2021-05-27T09:27:20+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.22.1", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248" + "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/43a0283138253ed1d48d352ab6d0bdb3f809f248", - "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8", + "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8", "shasum": "" }, "require": { @@ -6328,7 +6454,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -6371,7 +6497,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.23.0" }, "funding": [ { @@ -6387,20 +6513,20 @@ "type": "tidelift" } ], - "time": "2021-01-22T09:19:47+00:00" + "time": "2021-02-19T12:13:01+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.22.1", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "5232de97ee3b75b0360528dae24e73db49566ab1" + "reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/5232de97ee3b75b0360528dae24e73db49566ab1", - "reference": "5232de97ee3b75b0360528dae24e73db49566ab1", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2df51500adbaebdc4c38dea4c89a2e131c45c8a1", + "reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1", "shasum": "" }, "require": { @@ -6412,7 +6538,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -6451,7 +6577,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.0" }, "funding": [ { @@ -6467,20 +6593,20 @@ "type": "tidelift" } ], - "time": "2021-01-22T09:19:47+00:00" + "time": "2021-05-27T09:27:20+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.22.1", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9" + "reference": "9a142215a36a3888e30d0a9eeea9766764e96976" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", - "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9a142215a36a3888e30d0a9eeea9766764e96976", + "reference": "9a142215a36a3888e30d0a9eeea9766764e96976", "shasum": "" }, "require": { @@ -6489,7 +6615,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -6527,7 +6653,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-php72/tree/v1.23.0" }, "funding": [ { @@ -6543,20 +6669,20 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2021-05-27T09:17:38+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.22.1", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2" + "reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", - "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fba8933c384d6476ab14fb7b8526e5287ca7e010", + "reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010", "shasum": "" }, "require": { @@ -6565,7 +6691,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -6606,7 +6732,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.23.0" }, "funding": [ { @@ -6622,20 +6748,20 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2021-02-19T12:13:01+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.22.1", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91" + "reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dc3063ba22c2a1fd2f45ed856374d79114998f91", - "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/eca0bf41ed421bed1b57c4958bab16aa86b757d0", + "reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0", "shasum": "" }, "require": { @@ -6644,7 +6770,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -6689,7 +6815,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.23.0" }, "funding": [ { @@ -6705,20 +6831,20 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2021-02-19T12:13:01+00:00" }, { "name": "symfony/process", - "version": "v4.4.22", + "version": "v4.4.25", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "f5481b22729d465acb1cea3455fc04ce84b0148b" + "reference": "cd61e6dd273975c6625316de9d141ebd197f93c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/f5481b22729d465acb1cea3455fc04ce84b0148b", - "reference": "f5481b22729d465acb1cea3455fc04ce84b0148b", + "url": "https://api.github.com/repos/symfony/process/zipball/cd61e6dd273975c6625316de9d141ebd197f93c9", + "reference": "cd61e6dd273975c6625316de9d141ebd197f93c9", "shasum": "" }, "require": { @@ -6750,7 +6876,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v4.4.22" + "source": "https://github.com/symfony/process/tree/v4.4.25" }, "funding": [ { @@ -6766,7 +6892,7 @@ "type": "tidelift" } ], - "time": "2021-04-07T16:22:29+00:00" + "time": "2021-05-26T11:20:16+00:00" }, { "name": "symfony/service-contracts", @@ -6849,31 +6975,35 @@ }, { "name": "symfony/yaml", - "version": "v4.4.22", + "version": "v5.3.0", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "1c2fd24147961525eaefb65b11987cab75adab59" + "reference": "3bbcf262fceb3d8f48175302e6ba0ac96e3a5a11" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/1c2fd24147961525eaefb65b11987cab75adab59", - "reference": "1c2fd24147961525eaefb65b11987cab75adab59", + "url": "https://api.github.com/repos/symfony/yaml/zipball/3bbcf262fceb3d8f48175302e6ba0ac96e3a5a11", + "reference": "3bbcf262fceb3d8f48175302e6ba0ac96e3a5a11", "shasum": "" }, "require": { - "php": ">=7.1.3", + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", "symfony/polyfill-ctype": "~1.8" }, "conflict": { - "symfony/console": "<3.4" + "symfony/console": "<4.4" }, "require-dev": { - "symfony/console": "^3.4|^4.0|^5.0" + "symfony/console": "^4.4|^5.0" }, "suggest": { "symfony/console": "For validating YAML files using the lint command" }, + "bin": [ + "Resources/bin/yaml-lint" + ], "type": "library", "autoload": { "psr-4": { @@ -6900,7 +7030,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v4.4.22" + "source": "https://github.com/symfony/yaml/tree/v5.3.0" }, "funding": [ { @@ -6916,7 +7046,7 @@ "type": "tidelift" } ], - "time": "2021-04-23T12:09:37+00:00" + "time": "2021-05-26T17:43:10+00:00" }, { "name": "thecodingmachine/safe", @@ -7410,28 +7540,28 @@ }, { "name": "codeception/aspect-mock", - "version": "3.1.1", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/Codeception/AspectMock.git", - "reference": "eef5e5e9ebd66c89d6184416e83851c354963e9c" + "reference": "b8658c620400dce1d06b6cc1d5c9c19e6d2509c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/AspectMock/zipball/eef5e5e9ebd66c89d6184416e83851c354963e9c", - "reference": "eef5e5e9ebd66c89d6184416e83851c354963e9c", + "url": "https://api.github.com/repos/Codeception/AspectMock/zipball/b8658c620400dce1d06b6cc1d5c9c19e6d2509c2", + "reference": "b8658c620400dce1d06b6cc1d5c9c19e6d2509c2", "shasum": "" }, "require": { - "goaop/framework": "^2.2.0", - "php": "^7.0", - "phpunit/phpunit": "> 6.0.0", - "symfony/finder": ">=2.4 <6.0" + "goaop/framework": "^3.0", + "php": "^7.4", + "phpunit/phpunit": "^9.5", + "symfony/finder": ">=4.4 <6.0" }, "require-dev": { - "codeception/codeception": "^4.0", - "codeception/specify": "^1.0", - "codeception/verify": "^1.2" + "codeception/codeception": "^4.1", + "codeception/specify": "^1.4", + "codeception/verify": "^2.1" }, "type": "library", "autoload": { @@ -7452,41 +7582,45 @@ "description": "Experimental Mocking Framework powered by Aspects", "support": { "issues": "https://github.com/Codeception/AspectMock/issues", - "source": "https://github.com/Codeception/AspectMock/tree/3.1.1" + "source": "https://github.com/Codeception/AspectMock/tree/4.0.0" }, - "time": "2021-04-10T19:47:51+00:00" + "time": "2021-04-16T19:07:56+00:00" }, { "name": "doctrine/cache", - "version": "v1.6.2", + "version": "1.11.3", "source": { "type": "git", "url": "https://github.com/doctrine/cache.git", - "reference": "eb152c5100571c7a45470ff2a35095ab3f3b900b" + "reference": "3bb5588cec00a0268829cc4a518490df6741af9d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/eb152c5100571c7a45470ff2a35095ab3f3b900b", - "reference": "eb152c5100571c7a45470ff2a35095ab3f3b900b", + "url": "https://api.github.com/repos/doctrine/cache/zipball/3bb5588cec00a0268829cc4a518490df6741af9d", + "reference": "3bb5588cec00a0268829cc4a518490df6741af9d", "shasum": "" }, "require": { - "php": "~5.5|~7.0" + "php": "~7.1 || ^8.0" }, "conflict": { - "doctrine/common": ">2.2,<2.4" + "doctrine/common": ">2.2,<2.4", + "psr/cache": ">=3" }, "require-dev": { - "phpunit/phpunit": "~4.8|~5.0", + "alcaeus/mongo-php-adapter": "^1.1", + "cache/integration-tests": "dev-master", + "doctrine/coding-standard": "^8.0", + "mongodb/mongodb": "^1.1", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", "predis/predis": "~1.0", - "satooshi/php-coveralls": "~0.6" + "psr/cache": "^1.0 || ^2.0", + "symfony/cache": "^4.4 || ^5.2" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.6.x-dev" - } + "suggest": { + "alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver" }, + "type": "library", "autoload": { "psr-4": { "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" @@ -7497,6 +7631,10 @@ "MIT" ], "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -7505,10 +7643,6 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -7518,17 +7652,38 @@ "email": "schmittjoh@gmail.com" } ], - "description": "Caching library offering an object-oriented API for many cache backends", - "homepage": "http://www.doctrine-project.org", + "description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.", + "homepage": "https://www.doctrine-project.org/projects/cache.html", "keywords": [ + "abstraction", + "apcu", "cache", - "caching" + "caching", + "couchdb", + "memcached", + "php", + "redis", + "xcache" ], "support": { "issues": "https://github.com/doctrine/cache/issues", - "source": "https://github.com/doctrine/cache/tree/1.6.x" + "source": "https://github.com/doctrine/cache/tree/1.11.3" }, - "time": "2017-07-22T12:49:21+00:00" + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcache", + "type": "tidelift" + } + ], + "time": "2021-05-25T09:01:55+00:00" }, { "name": "gitonomy/gitlib", @@ -7602,33 +7757,35 @@ }, { "name": "goaop/framework", - "version": "2.3.4", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/goaop/framework.git", - "reference": "f980f249c55637acba0d5fdcfd2b5182c419f3d1" + "reference": "596fcaefc18dfc4e3982b3ee552b0a3ceca9a8b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/goaop/framework/zipball/f980f249c55637acba0d5fdcfd2b5182c419f3d1", - "reference": "f980f249c55637acba0d5fdcfd2b5182c419f3d1", + "url": "https://api.github.com/repos/goaop/framework/zipball/596fcaefc18dfc4e3982b3ee552b0a3ceca9a8b1", + "reference": "596fcaefc18dfc4e3982b3ee552b0a3ceca9a8b1", "shasum": "" }, "require": { - "doctrine/annotations": "^1.2.3", - "doctrine/cache": "^1.5", - "goaop/parser-reflection": "~2.0", + "doctrine/annotations": "^1.11.1", + "doctrine/cache": "^1.10", + "goaop/parser-reflection": "^3.0.1", "jakubledl/dissect": "~1.0", - "php": "~7.0", - "symfony/finder": "^3.4|^4.2|^5.0" + "laminas/laminas-code": "^4.0", + "php": "^7.4.0", + "symfony/finder": "^4.4|^5.1" }, "require-dev": { - "adlawson/vfs": "^0.12", + "adlawson/vfs": "^0.12.1", "doctrine/orm": "^2.5", - "phpunit/phpunit": "^5.7", - "symfony/console": "^2.7|^3.0", - "symfony/filesystem": "^3.3", - "symfony/process": "^3.3", + "phpstan/phpstan": "^0.12.64", + "phpunit/phpunit": "^9.5", + "symfony/console": "^4.4|^5.1", + "symfony/filesystem": "^4.4|^5.1", + "symfony/process": "^4.4|^5.1", "webmozart/glob": "^4.1" }, "suggest": { @@ -7640,7 +7797,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -7668,30 +7825,36 @@ ], "support": { "issues": "https://github.com/goaop/framework/issues", - "source": "https://github.com/goaop/framework/tree/2.3.4" + "source": "https://github.com/goaop/framework/tree/3.0.0" }, - "time": "2020-04-06T09:46:21+00:00" + "funding": [ + { + "url": "https://github.com/lisachenko", + "type": "github" + } + ], + "time": "2021-01-08T13:54:33+00:00" }, { "name": "goaop/parser-reflection", - "version": "2.1.3", + "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/goaop/parser-reflection.git", - "reference": "2e837e150e15d38f7004b0dbcd0af4abe034c9e2" + "reference": "c06ae32c4f5664dbd5829ab417485929eded0657" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/goaop/parser-reflection/zipball/2e837e150e15d38f7004b0dbcd0af4abe034c9e2", - "reference": "2e837e150e15d38f7004b0dbcd0af4abe034c9e2", + "url": "https://api.github.com/repos/goaop/parser-reflection/zipball/c06ae32c4f5664dbd5829ab417485929eded0657", + "reference": "c06ae32c4f5664dbd5829ab417485929eded0657", "shasum": "" }, "require": { - "nikic/php-parser": "^4.0 <4.7.0", - "php": ">=7.1" + "nikic/php-parser": "^4.0", + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "~4.0" + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { @@ -7723,106 +7886,9 @@ "description": "Provides reflection information, based on raw source", "support": { "issues": "https://github.com/goaop/parser-reflection/issues", - "source": "https://github.com/goaop/parser-reflection/tree/2.x" - }, - "time": "2020-08-13T21:02:42+00:00" - }, - { - "name": "guzzle/guzzle", - "version": "v3.8.1", - "source": { - "type": "git", - "url": "https://github.com/guzzle/guzzle.git", - "reference": "4de0618a01b34aa1c8c33a3f13f396dcd3882eba" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/4de0618a01b34aa1c8c33a3f13f396dcd3882eba", - "reference": "4de0618a01b34aa1c8c33a3f13f396dcd3882eba", - "shasum": "" - }, - "require": { - "ext-curl": "*", - "php": ">=5.3.3", - "symfony/event-dispatcher": ">=2.1" - }, - "replace": { - "guzzle/batch": "self.version", - "guzzle/cache": "self.version", - "guzzle/common": "self.version", - "guzzle/http": "self.version", - "guzzle/inflection": "self.version", - "guzzle/iterator": "self.version", - "guzzle/log": "self.version", - "guzzle/parser": "self.version", - "guzzle/plugin": "self.version", - "guzzle/plugin-async": "self.version", - "guzzle/plugin-backoff": "self.version", - "guzzle/plugin-cache": "self.version", - "guzzle/plugin-cookie": "self.version", - "guzzle/plugin-curlauth": "self.version", - "guzzle/plugin-error-response": "self.version", - "guzzle/plugin-history": "self.version", - "guzzle/plugin-log": "self.version", - "guzzle/plugin-md5": "self.version", - "guzzle/plugin-mock": "self.version", - "guzzle/plugin-oauth": "self.version", - "guzzle/service": "self.version", - "guzzle/stream": "self.version" - }, - "require-dev": { - "doctrine/cache": "*", - "monolog/monolog": "1.*", - "phpunit/phpunit": "3.7.*", - "psr/log": "1.0.*", - "symfony/class-loader": "*", - "zendframework/zend-cache": "<2.3", - "zendframework/zend-log": "<2.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.8-dev" - } - }, - "autoload": { - "psr-0": { - "Guzzle": "src/", - "Guzzle\\Tests": "tests/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "Guzzle Community", - "homepage": "https://github.com/guzzle/guzzle/contributors" - } - ], - "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients", - "homepage": "http://guzzlephp.org/", - "keywords": [ - "client", - "curl", - "framework", - "http", - "http client", - "rest", - "web service" - ], - "support": { - "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/master" + "source": "https://github.com/goaop/parser-reflection/tree/3.0.1" }, - "abandoned": "guzzlehttp/guzzle", - "time": "2014-01-28T22:29:15+00:00" + "time": "2021-01-03T18:16:54+00:00" }, { "name": "jakubledl/dissect", @@ -7883,6 +7949,205 @@ }, "time": "2013-01-29T21:29:14+00:00" }, + { + "name": "laminas/laminas-code", + "version": "4.3.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-code.git", + "reference": "1beb4447f9efd26041eba7eff50614e798c353fd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-code/zipball/1beb4447f9efd26041eba7eff50614e798c353fd", + "reference": "1beb4447f9efd26041eba7eff50614e798c353fd", + "shasum": "" + }, + "require": { + "laminas/laminas-eventmanager": "^3.3", + "php": "^7.4 || ~8.0.0" + }, + "conflict": { + "phpspec/prophecy": "<1.9.0" + }, + "replace": { + "zendframework/zend-code": "self.version" + }, + "require-dev": { + "doctrine/annotations": "^1.10.4", + "ext-phar": "*", + "laminas/laminas-coding-standard": "^2.1.4", + "laminas/laminas-stdlib": "^3.3.0", + "phpunit/phpunit": "^9.4.2", + "psalm/plugin-phpunit": "^0.14.0", + "vimeo/psalm": "^4.3.1" + }, + "suggest": { + "doctrine/annotations": "Doctrine\\Common\\Annotations >=1.0 for annotation features", + "laminas/laminas-stdlib": "Laminas\\Stdlib component", + "laminas/laminas-zendframework-bridge": "A bridge with Zend Framework" + }, + "type": "library", + "autoload": { + "psr-4": { + "Laminas\\Code\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Extensions to the PHP Reflection API, static code scanning, and code generation", + "homepage": "https://laminas.dev", + "keywords": [ + "code", + "laminas", + "laminasframework" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-code/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-code/issues", + "rss": "https://github.com/laminas/laminas-code/releases.atom", + "source": "https://github.com/laminas/laminas-code" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "time": "2021-05-12T12:41:03+00:00" + }, + { + "name": "laminas/laminas-eventmanager", + "version": "3.3.1", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-eventmanager.git", + "reference": "966c859b67867b179fde1eff0cd38df51472ce4a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-eventmanager/zipball/966c859b67867b179fde1eff0cd38df51472ce4a", + "reference": "966c859b67867b179fde1eff0cd38df51472ce4a", + "shasum": "" + }, + "require": { + "laminas/laminas-zendframework-bridge": "^1.0", + "php": "^7.3 || ^8.0" + }, + "replace": { + "zendframework/zend-eventmanager": "^3.2.1" + }, + "require-dev": { + "container-interop/container-interop": "^1.1", + "laminas/laminas-coding-standard": "~1.0.0", + "laminas/laminas-stdlib": "^2.7.3 || ^3.0", + "phpbench/phpbench": "^0.17.1", + "phpunit/phpunit": "^8.5.8" + }, + "suggest": { + "container-interop/container-interop": "^1.1, to use the lazy listeners feature", + "laminas/laminas-stdlib": "^2.7.3 || ^3.0, to use the FilterChain feature" + }, + "type": "library", + "autoload": { + "psr-4": { + "Laminas\\EventManager\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Trigger and listen to events within a PHP application", + "homepage": "https://laminas.dev", + "keywords": [ + "event", + "eventmanager", + "events", + "laminas" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-eventmanager/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-eventmanager/issues", + "rss": "https://github.com/laminas/laminas-eventmanager/releases.atom", + "source": "https://github.com/laminas/laminas-eventmanager" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "time": "2021-03-08T15:24:29+00:00" + }, + { + "name": "laminas/laminas-zendframework-bridge", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-zendframework-bridge.git", + "reference": "6cccbddfcfc742eb02158d6137ca5687d92cee32" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/6cccbddfcfc742eb02158d6137ca5687d92cee32", + "reference": "6cccbddfcfc742eb02158d6137ca5687d92cee32", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.1 || ^9.3", + "psalm/plugin-phpunit": "^0.15.1", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^4.6" + }, + "type": "library", + "extra": { + "laminas": { + "module": "Laminas\\ZendFrameworkBridge" + } + }, + "autoload": { + "files": [ + "src/autoload.php" + ], + "psr-4": { + "Laminas\\ZendFrameworkBridge\\": "src//" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Alias legacy ZF class names to Laminas Project equivalents.", + "keywords": [ + "ZendFramework", + "autoloading", + "laminas", + "zf" + ], + "support": { + "forum": "https://discourse.laminas.dev/", + "issues": "https://github.com/laminas/laminas-zendframework-bridge/issues", + "rss": "https://github.com/laminas/laminas-zendframework-bridge/releases.atom", + "source": "https://github.com/laminas/laminas-zendframework-bridge" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "time": "2021-02-25T21:54:58+00:00" + }, { "name": "pdepend/pdepend", "version": "2.9.1", @@ -7942,42 +8207,43 @@ }, { "name": "php-coveralls/php-coveralls", - "version": "v1.1.0", + "version": "v2.4.3", "source": { "type": "git", "url": "https://github.com/php-coveralls/php-coveralls.git", - "reference": "37f8f83fe22224eb9d9c6d593cdeb33eedd2a9ad" + "reference": "909381bd40a17ae6e9076051f0d73293c1c091af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-coveralls/php-coveralls/zipball/37f8f83fe22224eb9d9c6d593cdeb33eedd2a9ad", - "reference": "37f8f83fe22224eb9d9c6d593cdeb33eedd2a9ad", + "url": "https://api.github.com/repos/php-coveralls/php-coveralls/zipball/909381bd40a17ae6e9076051f0d73293c1c091af", + "reference": "909381bd40a17ae6e9076051f0d73293c1c091af", "shasum": "" }, "require": { "ext-json": "*", "ext-simplexml": "*", - "guzzle/guzzle": "^2.8 || ^3.0", - "php": "^5.3.3 || ^7.0", + "guzzlehttp/guzzle": "^6.0 || ^7.0", + "php": "^5.5 || ^7.0 || ^8.0", "psr/log": "^1.0", - "symfony/config": "^2.1 || ^3.0 || ^4.0", - "symfony/console": "^2.1 || ^3.0 || ^4.0", - "symfony/stopwatch": "^2.0 || ^3.0 || ^4.0", - "symfony/yaml": "^2.0 || ^3.0 || ^4.0" + "symfony/config": "^2.1 || ^3.0 || ^4.0 || ^5.0", + "symfony/console": "^2.1 || ^3.0 || ^4.0 || ^5.0", + "symfony/stopwatch": "^2.0 || ^3.0 || ^4.0 || ^5.0", + "symfony/yaml": "^2.0.5 || ^3.0 || ^4.0 || ^5.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.4.3 || ^6.0" + "phpunit/phpunit": "^4.8.35 || ^5.4.3 || ^6.0 || ^7.0 || ^8.0 || ^9.0", + "sanmai/phpunit-legacy-adapter": "^6.1 || ^8.0" }, "suggest": { "symfony/http-kernel": "Allows Symfony integration" }, "bin": [ - "bin/coveralls" + "bin/php-coveralls" ], "type": "library", "autoload": { "psr-4": { - "Satooshi\\": "src/Satooshi/" + "PhpCoveralls\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -7988,7 +8254,24 @@ { "name": "Kitamura Satoshi", "email": "with.no.parachute@gmail.com", - "homepage": "https://www.facebook.com/satooshi.jp" + "homepage": "https://www.facebook.com/satooshi.jp", + "role": "Original creator" + }, + { + "name": "Takashi Matsuo", + "email": "tmatsuo@google.com" + }, + { + "name": "Google Inc" + }, + { + "name": "Dariusz Ruminski", + "email": "dariusz.ruminski@gmail.com", + "homepage": "https://github.com/keradus" + }, + { + "name": "Contributors", + "homepage": "https://github.com/php-coveralls/php-coveralls/graphs/contributors" } ], "description": "PHP client library for Coveralls API", @@ -8001,26 +8284,26 @@ ], "support": { "issues": "https://github.com/php-coveralls/php-coveralls/issues", - "source": "https://github.com/php-coveralls/php-coveralls/tree/1.1" + "source": "https://github.com/php-coveralls/php-coveralls/tree/v2.4.3" }, - "time": "2017-12-06T23:17:56+00:00" + "time": "2020-12-24T09:17:03+00:00" }, { "name": "phpmd/phpmd", - "version": "2.10.0", + "version": "2.10.1", "source": { "type": "git", "url": "https://github.com/phpmd/phpmd.git", - "reference": "58ef9e746a1ab50ad3360d5d301e1229ed2612cb" + "reference": "bd5ef43d1dcaf7272605027c959c1c5ff3761f7a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpmd/phpmd/zipball/58ef9e746a1ab50ad3360d5d301e1229ed2612cb", - "reference": "58ef9e746a1ab50ad3360d5d301e1229ed2612cb", + "url": "https://api.github.com/repos/phpmd/phpmd/zipball/bd5ef43d1dcaf7272605027c959c1c5ff3761f7a", + "reference": "bd5ef43d1dcaf7272605027c959c1c5ff3761f7a", "shasum": "" }, "require": { - "composer/xdebug-handler": "^1.0", + "composer/xdebug-handler": "^1.0 || ^2.0", "ext-xml": "*", "pdepend/pdepend": "^2.9.1", "php": ">=5.3.9" @@ -8078,7 +8361,7 @@ "support": { "irc": "irc://irc.freenode.org/phpmd", "issues": "https://github.com/phpmd/phpmd/issues", - "source": "https://github.com/phpmd/phpmd/tree/2.10.0" + "source": "https://github.com/phpmd/phpmd/tree/2.10.1" }, "funding": [ { @@ -8086,7 +8369,7 @@ "type": "tidelift" } ], - "time": "2021-04-26T18:44:44+00:00" + "time": "2021-05-11T17:16:16+00:00" }, { "name": "rregeer/phpunit-coverage-check", @@ -8134,62 +8417,6 @@ }, "time": "2018-07-29T13:27:58+00:00" }, - { - "name": "sebastian/cli-parser", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for parsing CLI options", - "homepage": "https://github.com/sebastianbergmann/cli-parser", - "support": { - "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T06:08:49+00:00" - }, { "name": "sebastian/phpcpd", "version": "6.0.3", @@ -8253,16 +8480,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.5.8", + "version": "3.6.0", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "9d583721a7157ee997f235f327de038e7ea6dac4" + "reference": "ffced0d2c8fa8e6cdc4d695a743271fab6c38625" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/9d583721a7157ee997f235f327de038e7ea6dac4", - "reference": "9d583721a7157ee997f235f327de038e7ea6dac4", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ffced0d2c8fa8e6cdc4d695a743271fab6c38625", + "reference": "ffced0d2c8fa8e6cdc4d695a743271fab6c38625", "shasum": "" }, "require": { @@ -8305,36 +8532,39 @@ "source": "https://github.com/squizlabs/PHP_CodeSniffer", "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" }, - "time": "2020-10-23T02:01:07+00:00" + "time": "2021-04-09T00:54:41+00:00" }, { "name": "symfony/config", - "version": "v4.4.22", + "version": "v5.3.0", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "f6d8318c14e4be81525ae47b30e618f0bed4c7b3" + "reference": "9f4a448c2d7fd2c90882dfff930b627ddbe16810" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/f6d8318c14e4be81525ae47b30e618f0bed4c7b3", - "reference": "f6d8318c14e4be81525ae47b30e618f0bed4c7b3", + "url": "https://api.github.com/repos/symfony/config/zipball/9f4a448c2d7fd2c90882dfff930b627ddbe16810", + "reference": "9f4a448c2d7fd2c90882dfff930b627ddbe16810", "shasum": "" }, "require": { - "php": ">=7.1.3", - "symfony/filesystem": "^3.4|^4.0|^5.0", - "symfony/polyfill-ctype": "~1.8" + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/filesystem": "^4.4|^5.0", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.15", + "symfony/polyfill-php81": "^1.22" }, "conflict": { - "symfony/finder": "<3.4" + "symfony/finder": "<4.4" }, "require-dev": { - "symfony/event-dispatcher": "^3.4|^4.0|^5.0", - "symfony/finder": "^3.4|^4.0|^5.0", - "symfony/messenger": "^4.1|^5.0", + "symfony/event-dispatcher": "^4.4|^5.0", + "symfony/finder": "^4.4|^5.0", + "symfony/messenger": "^4.4|^5.0", "symfony/service-contracts": "^1.1|^2", - "symfony/yaml": "^3.4|^4.0|^5.0" + "symfony/yaml": "^4.4|^5.0" }, "suggest": { "symfony/yaml": "To use the yaml reference dumper" @@ -8365,7 +8595,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v4.4.22" + "source": "https://github.com/symfony/config/tree/v5.3.0" }, "funding": [ { @@ -8381,41 +8611,44 @@ "type": "tidelift" } ], - "time": "2021-04-07T15:47:03+00:00" + "time": "2021-05-26T17:43:10+00:00" }, { "name": "symfony/dependency-injection", - "version": "v4.4.22", + "version": "v5.3.0", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "778b140b3e8f6890f43dc2c978e58e69f188909a" + "reference": "94d973cb742d8c5c5dcf9534220e6b73b09af1d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/778b140b3e8f6890f43dc2c978e58e69f188909a", - "reference": "778b140b3e8f6890f43dc2c978e58e69f188909a", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/94d973cb742d8c5c5dcf9534220e6b73b09af1d4", + "reference": "94d973cb742d8c5c5dcf9534220e6b73b09af1d4", "shasum": "" }, "require": { - "php": ">=7.1.3", - "psr/container": "^1.0", + "php": ">=7.2.5", + "psr/container": "^1.1.1", + "symfony/deprecation-contracts": "^2.1", + "symfony/polyfill-php80": "^1.15", "symfony/service-contracts": "^1.1.6|^2" }, "conflict": { - "symfony/config": "<4.3|>=5.0", - "symfony/finder": "<3.4", - "symfony/proxy-manager-bridge": "<3.4", - "symfony/yaml": "<3.4" + "ext-psr": "<1.1|>=2", + "symfony/config": "<5.3", + "symfony/finder": "<4.4", + "symfony/proxy-manager-bridge": "<4.4", + "symfony/yaml": "<4.4" }, "provide": { "psr/container-implementation": "1.0", "symfony/service-implementation": "1.0|2.0" }, "require-dev": { - "symfony/config": "^4.3", - "symfony/expression-language": "^3.4|^4.0|^5.0", - "symfony/yaml": "^3.4|^4.0|^5.0" + "symfony/config": "^5.3", + "symfony/expression-language": "^4.4|^5.0", + "symfony/yaml": "^4.4|^5.0" }, "suggest": { "symfony/config": "", @@ -8450,7 +8683,86 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v4.4.22" + "source": "https://github.com/symfony/dependency-injection/tree/v5.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-05-26T17:57:12+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.23.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "e66119f3de95efc359483f810c4c3e6436279436" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/e66119f3de95efc359483f810c4c3e6436279436", + "reference": "e66119f3de95efc359483f810c4c3e6436279436", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.23.0" }, "funding": [ { @@ -8466,7 +8778,7 @@ "type": "tidelift" } ], - "time": "2021-04-07T15:47:03+00:00" + "time": "2021-05-21T13:25:03+00:00" }, { "name": "symfony/stopwatch", @@ -8536,7 +8848,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^7.3", + "php": "^7.3||^8.0", "ext-curl": "*", "ext-dom": "*", "ext-intl": "*", From 0c0f3d6cc0ad470d0b6916a8b7ca2cb9dfe7298d Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 14 Jun 2021 12:01:02 -0500 Subject: [PATCH 623/888] MQE-2750: Update composer dependencies to be PHP 8 compatible --- composer.json | 2 +- composer.lock | 279 +++++++------------------------------------------- 2 files changed, 40 insertions(+), 241 deletions(-) diff --git a/composer.json b/composer.json index f435e6f21..1df037098 100755 --- a/composer.json +++ b/composer.json @@ -41,7 +41,7 @@ "require-dev": { "brainmaestro/composer-git-hooks": "^2.3.1", "codacy/coverage": "^1.4", - "codeception/aspect-mock": "^4.0", + "codeception/aspect-mock": "^3.0", "php-coveralls/php-coveralls": "^2.2", "phpmd/phpmd": "^2.8.0", "phpunit/phpunit": "^9.0", diff --git a/composer.lock b/composer.lock index 9475b893a..3972b78a0 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "2497eb0016466f4c6e66135bd3e8d505", + "content-hash": "0bcf16196f2dc3921a3762ed173e56d3", "packages": [ { "name": "allure-framework/allure-codeception", @@ -7540,28 +7540,28 @@ }, { "name": "codeception/aspect-mock", - "version": "4.0.0", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/Codeception/AspectMock.git", - "reference": "b8658c620400dce1d06b6cc1d5c9c19e6d2509c2" + "reference": "eef5e5e9ebd66c89d6184416e83851c354963e9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/AspectMock/zipball/b8658c620400dce1d06b6cc1d5c9c19e6d2509c2", - "reference": "b8658c620400dce1d06b6cc1d5c9c19e6d2509c2", + "url": "https://api.github.com/repos/Codeception/AspectMock/zipball/eef5e5e9ebd66c89d6184416e83851c354963e9c", + "reference": "eef5e5e9ebd66c89d6184416e83851c354963e9c", "shasum": "" }, "require": { - "goaop/framework": "^3.0", - "php": "^7.4", - "phpunit/phpunit": "^9.5", - "symfony/finder": ">=4.4 <6.0" + "goaop/framework": "^2.2.0", + "php": "^7.0", + "phpunit/phpunit": "> 6.0.0", + "symfony/finder": ">=2.4 <6.0" }, "require-dev": { - "codeception/codeception": "^4.1", - "codeception/specify": "^1.4", - "codeception/verify": "^2.1" + "codeception/codeception": "^4.0", + "codeception/specify": "^1.0", + "codeception/verify": "^1.2" }, "type": "library", "autoload": { @@ -7582,9 +7582,9 @@ "description": "Experimental Mocking Framework powered by Aspects", "support": { "issues": "https://github.com/Codeception/AspectMock/issues", - "source": "https://github.com/Codeception/AspectMock/tree/4.0.0" + "source": "https://github.com/Codeception/AspectMock/tree/3.1.1" }, - "time": "2021-04-16T19:07:56+00:00" + "time": "2021-04-10T19:47:51+00:00" }, { "name": "doctrine/cache", @@ -7757,35 +7757,33 @@ }, { "name": "goaop/framework", - "version": "3.0.0", + "version": "2.3.5", "source": { "type": "git", "url": "https://github.com/goaop/framework.git", - "reference": "596fcaefc18dfc4e3982b3ee552b0a3ceca9a8b1" + "reference": "19a6f2110c71aed99081ca23c359436b723a6cdf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/goaop/framework/zipball/596fcaefc18dfc4e3982b3ee552b0a3ceca9a8b1", - "reference": "596fcaefc18dfc4e3982b3ee552b0a3ceca9a8b1", + "url": "https://api.github.com/repos/goaop/framework/zipball/19a6f2110c71aed99081ca23c359436b723a6cdf", + "reference": "19a6f2110c71aed99081ca23c359436b723a6cdf", "shasum": "" }, "require": { - "doctrine/annotations": "^1.11.1", - "doctrine/cache": "^1.10", - "goaop/parser-reflection": "^3.0.1", + "doctrine/annotations": "^1.2.3", + "doctrine/cache": "^1.5", + "goaop/parser-reflection": "~2.0", "jakubledl/dissect": "~1.0", - "laminas/laminas-code": "^4.0", - "php": "^7.4.0", - "symfony/finder": "^4.4|^5.1" + "php": "~7.0", + "symfony/finder": "^3.4|^4.2|^5.0" }, "require-dev": { - "adlawson/vfs": "^0.12.1", + "adlawson/vfs": "^0.12", "doctrine/orm": "^2.5", - "phpstan/phpstan": "^0.12.64", - "phpunit/phpunit": "^9.5", - "symfony/console": "^4.4|^5.1", - "symfony/filesystem": "^4.4|^5.1", - "symfony/process": "^4.4|^5.1", + "phpunit/phpunit": "^5.7", + "symfony/console": "^2.7|^3.0", + "symfony/filesystem": "^3.3", + "symfony/process": "^3.3", "webmozart/glob": "^4.1" }, "suggest": { @@ -7797,7 +7795,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -7825,7 +7823,7 @@ ], "support": { "issues": "https://github.com/goaop/framework/issues", - "source": "https://github.com/goaop/framework/tree/3.0.0" + "source": "https://github.com/goaop/framework/tree/2.3.5" }, "funding": [ { @@ -7833,28 +7831,28 @@ "type": "github" } ], - "time": "2021-01-08T13:54:33+00:00" + "time": "2021-06-11T16:17:30+00:00" }, { "name": "goaop/parser-reflection", - "version": "3.0.1", + "version": "2.1.2", "source": { "type": "git", "url": "https://github.com/goaop/parser-reflection.git", - "reference": "c06ae32c4f5664dbd5829ab417485929eded0657" + "reference": "d4257ee557484ac886bee46bd41ebecb7c4bfa16" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/goaop/parser-reflection/zipball/c06ae32c4f5664dbd5829ab417485929eded0657", - "reference": "c06ae32c4f5664dbd5829ab417485929eded0657", + "url": "https://api.github.com/repos/goaop/parser-reflection/zipball/d4257ee557484ac886bee46bd41ebecb7c4bfa16", + "reference": "d4257ee557484ac886bee46bd41ebecb7c4bfa16", "shasum": "" }, "require": { "nikic/php-parser": "^4.0", - "php": ">=7.3" + "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "^7.0" + "phpunit/phpunit": "~4.0" }, "type": "library", "extra": { @@ -7886,9 +7884,9 @@ "description": "Provides reflection information, based on raw source", "support": { "issues": "https://github.com/goaop/parser-reflection/issues", - "source": "https://github.com/goaop/parser-reflection/tree/3.0.1" + "source": "https://github.com/goaop/parser-reflection/tree/2.x" }, - "time": "2021-01-03T18:16:54+00:00" + "time": "2020-08-13T00:19:00+00:00" }, { "name": "jakubledl/dissect", @@ -7949,205 +7947,6 @@ }, "time": "2013-01-29T21:29:14+00:00" }, - { - "name": "laminas/laminas-code", - "version": "4.3.0", - "source": { - "type": "git", - "url": "https://github.com/laminas/laminas-code.git", - "reference": "1beb4447f9efd26041eba7eff50614e798c353fd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-code/zipball/1beb4447f9efd26041eba7eff50614e798c353fd", - "reference": "1beb4447f9efd26041eba7eff50614e798c353fd", - "shasum": "" - }, - "require": { - "laminas/laminas-eventmanager": "^3.3", - "php": "^7.4 || ~8.0.0" - }, - "conflict": { - "phpspec/prophecy": "<1.9.0" - }, - "replace": { - "zendframework/zend-code": "self.version" - }, - "require-dev": { - "doctrine/annotations": "^1.10.4", - "ext-phar": "*", - "laminas/laminas-coding-standard": "^2.1.4", - "laminas/laminas-stdlib": "^3.3.0", - "phpunit/phpunit": "^9.4.2", - "psalm/plugin-phpunit": "^0.14.0", - "vimeo/psalm": "^4.3.1" - }, - "suggest": { - "doctrine/annotations": "Doctrine\\Common\\Annotations >=1.0 for annotation features", - "laminas/laminas-stdlib": "Laminas\\Stdlib component", - "laminas/laminas-zendframework-bridge": "A bridge with Zend Framework" - }, - "type": "library", - "autoload": { - "psr-4": { - "Laminas\\Code\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Extensions to the PHP Reflection API, static code scanning, and code generation", - "homepage": "https://laminas.dev", - "keywords": [ - "code", - "laminas", - "laminasframework" - ], - "support": { - "chat": "https://laminas.dev/chat", - "docs": "https://docs.laminas.dev/laminas-code/", - "forum": "https://discourse.laminas.dev", - "issues": "https://github.com/laminas/laminas-code/issues", - "rss": "https://github.com/laminas/laminas-code/releases.atom", - "source": "https://github.com/laminas/laminas-code" - }, - "funding": [ - { - "url": "https://funding.communitybridge.org/projects/laminas-project", - "type": "community_bridge" - } - ], - "time": "2021-05-12T12:41:03+00:00" - }, - { - "name": "laminas/laminas-eventmanager", - "version": "3.3.1", - "source": { - "type": "git", - "url": "https://github.com/laminas/laminas-eventmanager.git", - "reference": "966c859b67867b179fde1eff0cd38df51472ce4a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-eventmanager/zipball/966c859b67867b179fde1eff0cd38df51472ce4a", - "reference": "966c859b67867b179fde1eff0cd38df51472ce4a", - "shasum": "" - }, - "require": { - "laminas/laminas-zendframework-bridge": "^1.0", - "php": "^7.3 || ^8.0" - }, - "replace": { - "zendframework/zend-eventmanager": "^3.2.1" - }, - "require-dev": { - "container-interop/container-interop": "^1.1", - "laminas/laminas-coding-standard": "~1.0.0", - "laminas/laminas-stdlib": "^2.7.3 || ^3.0", - "phpbench/phpbench": "^0.17.1", - "phpunit/phpunit": "^8.5.8" - }, - "suggest": { - "container-interop/container-interop": "^1.1, to use the lazy listeners feature", - "laminas/laminas-stdlib": "^2.7.3 || ^3.0, to use the FilterChain feature" - }, - "type": "library", - "autoload": { - "psr-4": { - "Laminas\\EventManager\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Trigger and listen to events within a PHP application", - "homepage": "https://laminas.dev", - "keywords": [ - "event", - "eventmanager", - "events", - "laminas" - ], - "support": { - "chat": "https://laminas.dev/chat", - "docs": "https://docs.laminas.dev/laminas-eventmanager/", - "forum": "https://discourse.laminas.dev", - "issues": "https://github.com/laminas/laminas-eventmanager/issues", - "rss": "https://github.com/laminas/laminas-eventmanager/releases.atom", - "source": "https://github.com/laminas/laminas-eventmanager" - }, - "funding": [ - { - "url": "https://funding.communitybridge.org/projects/laminas-project", - "type": "community_bridge" - } - ], - "time": "2021-03-08T15:24:29+00:00" - }, - { - "name": "laminas/laminas-zendframework-bridge", - "version": "1.2.0", - "source": { - "type": "git", - "url": "https://github.com/laminas/laminas-zendframework-bridge.git", - "reference": "6cccbddfcfc742eb02158d6137ca5687d92cee32" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/6cccbddfcfc742eb02158d6137ca5687d92cee32", - "reference": "6cccbddfcfc742eb02158d6137ca5687d92cee32", - "shasum": "" - }, - "require": { - "php": "^7.3 || ^8.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.1 || ^9.3", - "psalm/plugin-phpunit": "^0.15.1", - "squizlabs/php_codesniffer": "^3.5", - "vimeo/psalm": "^4.6" - }, - "type": "library", - "extra": { - "laminas": { - "module": "Laminas\\ZendFrameworkBridge" - } - }, - "autoload": { - "files": [ - "src/autoload.php" - ], - "psr-4": { - "Laminas\\ZendFrameworkBridge\\": "src//" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Alias legacy ZF class names to Laminas Project equivalents.", - "keywords": [ - "ZendFramework", - "autoloading", - "laminas", - "zf" - ], - "support": { - "forum": "https://discourse.laminas.dev/", - "issues": "https://github.com/laminas/laminas-zendframework-bridge/issues", - "rss": "https://github.com/laminas/laminas-zendframework-bridge/releases.atom", - "source": "https://github.com/laminas/laminas-zendframework-bridge" - }, - "funding": [ - { - "url": "https://funding.communitybridge.org/projects/laminas-project", - "type": "community_bridge" - } - ], - "time": "2021-02-25T21:54:58+00:00" - }, { "name": "pdepend/pdepend", "version": "2.9.1", From 7693a14d6db4d59ee6eda2dce07240763a5a5b2e Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 14 Jun 2021 16:55:21 -0500 Subject: [PATCH 624/888] MQE-2750: Update composer dependencies to be PHP 8 compatible --- composer.json | 16 +- composer.lock | 937 +++++++++++++++++++++----------------------------- 2 files changed, 400 insertions(+), 553 deletions(-) diff --git a/composer.json b/composer.json index 1df037098..4927abb43 100755 --- a/composer.json +++ b/composer.json @@ -22,12 +22,12 @@ "codeception/module-sequence": "^1.0", "codeception/module-webdriver": "^1.0", "composer/composer": "^1.9||^2.0", - "csharpru/vault-php": "^4.1.0", + "csharpru/vault-php": "^4.2.1", "csharpru/vault-php-guzzle6-transport": "^2.0", - "hoa/console": "^3.0", + "hoa/console": "~3.0", "monolog/monolog": "^1.17", - "mustache/mustache": "^2.5", - "php-webdriver/webdriver": "^1.11.0", + "mustache/mustache": "~2.5", + "php-webdriver/webdriver": "^1.9.0", "spomky-labs/otphp": "^10.0", "symfony/console": "^4.4", "symfony/finder": "^5.0", @@ -42,13 +42,13 @@ "brainmaestro/composer-git-hooks": "^2.3.1", "codacy/coverage": "^1.4", "codeception/aspect-mock": "^3.0", - "php-coveralls/php-coveralls": "^2.2", + "php-coveralls/php-coveralls": "^1.0||^2.2", "phpmd/phpmd": "^2.8.0", "phpunit/phpunit": "^9.0", "rregeer/phpunit-coverage-check": "^0.1.4", - "sebastian/phpcpd": "^6.0", - "squizlabs/php_codesniffer": "^3.5", - "symfony/stopwatch": "^3.4" + "sebastian/phpcpd": "~6.0.0", + "squizlabs/php_codesniffer": "~3.5.4", + "symfony/stopwatch": "~3.4.6" }, "autoload": { "files": ["src/Magento/FunctionalTestingFramework/_bootstrap.php"], diff --git a/composer.lock b/composer.lock index 3972b78a0..1b0846fcc 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "0bcf16196f2dc3921a3762ed173e56d3", + "content-hash": "465713023b0749c53f630e64d2413880", "packages": [ { "name": "allure-framework/allure-codeception", @@ -127,16 +127,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.184.2", + "version": "3.180.1", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "78fe691ab466fecf195209672f6c00c5d4ed219a" + "reference": "7801112fd8be227954a6ecfbfd85b01ee4a7cae4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/78fe691ab466fecf195209672f6c00c5d4ed219a", - "reference": "78fe691ab466fecf195209672f6c00c5d4ed219a", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/7801112fd8be227954a6ecfbfd85b01ee4a7cae4", + "reference": "7801112fd8be227954a6ecfbfd85b01ee4a7cae4", "shasum": "" }, "require": { @@ -211,9 +211,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.184.2" + "source": "https://github.com/aws/aws-sdk-php/tree/3.180.1" }, - "time": "2021-06-11T18:20:15+00:00" + "time": "2021-05-04T18:14:38+00:00" }, { "name": "beberlei/assert", @@ -793,16 +793,16 @@ }, { "name": "composer/ca-bundle", - "version": "1.2.10", + "version": "1.2.9", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "9fdb22c2e97a614657716178093cd1da90a64aa8" + "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/9fdb22c2e97a614657716178093cd1da90a64aa8", - "reference": "9fdb22c2e97a614657716178093cd1da90a64aa8", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/78a0e288fdcebf92aa2318a8d3656168da6ac1a5", + "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5", "shasum": "" }, "require": { @@ -849,7 +849,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.2.10" + "source": "https://github.com/composer/ca-bundle/tree/1.2.9" }, "funding": [ { @@ -865,20 +865,20 @@ "type": "tidelift" } ], - "time": "2021-06-07T13:58:28+00:00" + "time": "2021-01-12T12:10:35+00:00" }, { "name": "composer/composer", - "version": "2.1.3", + "version": "2.0.13", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "fc5c4573aafce3a018eb7f1f8f91cea423970f2e" + "reference": "986e8b86b7b570632ad0a905c3726c33dd4c0efb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/fc5c4573aafce3a018eb7f1f8f91cea423970f2e", - "reference": "fc5c4573aafce3a018eb7f1f8f91cea423970f2e", + "url": "https://api.github.com/repos/composer/composer/zipball/986e8b86b7b570632ad0a905c3726c33dd4c0efb", + "reference": "986e8b86b7b570632ad0a905c3726c33dd4c0efb", "shasum": "" }, "require": { @@ -886,21 +886,21 @@ "composer/metadata-minifier": "^1.0", "composer/semver": "^3.0", "composer/spdx-licenses": "^1.2", - "composer/xdebug-handler": "^2.0", + "composer/xdebug-handler": "^1.1", "justinrainbow/json-schema": "^5.2.10", "php": "^5.3.2 || ^7.0 || ^8.0", "psr/log": "^1.0", "react/promise": "^1.2 || ^2.7", "seld/jsonlint": "^1.4", "seld/phar-utils": "^1.0", - "symfony/console": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0", - "symfony/filesystem": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0", - "symfony/finder": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0", - "symfony/process": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0" + "symfony/console": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0", + "symfony/filesystem": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0", + "symfony/finder": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0", + "symfony/process": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0" }, "require-dev": { "phpspec/prophecy": "^1.10", - "symfony/phpunit-bridge": "^4.2 || ^5.0 || ^6.0" + "symfony/phpunit-bridge": "^4.2 || ^5.0" }, "suggest": { "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages", @@ -913,7 +913,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -947,7 +947,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/composer/issues", - "source": "https://github.com/composer/composer/tree/2.1.3" + "source": "https://github.com/composer/composer/tree/2.0.13" }, "funding": [ { @@ -963,7 +963,7 @@ "type": "tidelift" } ], - "time": "2021-06-09T14:31:20+00:00" + "time": "2021-04-27T11:11:08+00:00" }, { "name": "composer/metadata-minifier", @@ -1036,16 +1036,16 @@ }, { "name": "composer/semver", - "version": "3.2.5", + "version": "3.2.4", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "31f3ea725711245195f62e54ffa402d8ef2fdba9" + "reference": "a02fdf930a3c1c3ed3a49b5f63859c0c20e10464" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/31f3ea725711245195f62e54ffa402d8ef2fdba9", - "reference": "31f3ea725711245195f62e54ffa402d8ef2fdba9", + "url": "https://api.github.com/repos/composer/semver/zipball/a02fdf930a3c1c3ed3a49b5f63859c0c20e10464", + "reference": "a02fdf930a3c1c3ed3a49b5f63859c0c20e10464", "shasum": "" }, "require": { @@ -1097,7 +1097,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.2.5" + "source": "https://github.com/composer/semver/tree/3.2.4" }, "funding": [ { @@ -1113,7 +1113,7 @@ "type": "tidelift" } ], - "time": "2021-05-24T12:41:47+00:00" + "time": "2020-11-13T08:59:24+00:00" }, { "name": "composer/spdx-licenses", @@ -1196,16 +1196,16 @@ }, { "name": "composer/xdebug-handler", - "version": "2.0.1", + "version": "1.4.6", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "964adcdd3a28bf9ed5d9ac6450064e0d71ed7496" + "reference": "f27e06cd9675801df441b3656569b328e04aa37c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/964adcdd3a28bf9ed5d9ac6450064e0d71ed7496", - "reference": "964adcdd3a28bf9ed5d9ac6450064e0d71ed7496", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/f27e06cd9675801df441b3656569b328e04aa37c", + "reference": "f27e06cd9675801df441b3656569b328e04aa37c", "shasum": "" }, "require": { @@ -1240,7 +1240,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/2.0.1" + "source": "https://github.com/composer/xdebug-handler/tree/1.4.6" }, "funding": [ { @@ -1256,7 +1256,7 @@ "type": "tidelift" } ], - "time": "2021-05-05T19:37:51+00:00" + "time": "2021-03-25T17:01:18+00:00" }, { "name": "csharpru/vault-php", @@ -2635,16 +2635,16 @@ }, { "name": "monolog/monolog", - "version": "1.26.1", + "version": "1.26.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "c6b00f05152ae2c9b04a448f99c7590beb6042f5" + "reference": "2209ddd84e7ef1256b7af205d0717fb62cfc9c33" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/c6b00f05152ae2c9b04a448f99c7590beb6042f5", - "reference": "c6b00f05152ae2c9b04a448f99c7590beb6042f5", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/2209ddd84e7ef1256b7af205d0717fb62cfc9c33", + "reference": "2209ddd84e7ef1256b7af205d0717fb62cfc9c33", "shasum": "" }, "require": { @@ -2705,7 +2705,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/1.26.1" + "source": "https://github.com/Seldaek/monolog/tree/1.26.0" }, "funding": [ { @@ -2717,7 +2717,7 @@ "type": "tidelift" } ], - "time": "2021-05-28T08:32:12+00:00" + "time": "2020-12-14T12:56:38+00:00" }, { "name": "mtdowling/jmespath.php", @@ -2890,16 +2890,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.10.5", + "version": "v4.6.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "4432ba399e47c66624bc73c8c0f811e5c109576f" + "reference": "c346bbfafe2ff60680258b631afb730d186ed864" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4432ba399e47c66624bc73c8c0f811e5c109576f", - "reference": "4432ba399e47c66624bc73c8c0f811e5c109576f", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/c346bbfafe2ff60680258b631afb730d186ed864", + "reference": "c346bbfafe2ff60680258b631afb730d186ed864", "shasum": "" }, "require": { @@ -2907,8 +2907,8 @@ "php": ">=7.0" }, "require-dev": { - "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + "ircmaxell/php-yacc": "0.0.5", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0" }, "bin": [ "bin/php-parse" @@ -2916,7 +2916,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.9-dev" + "dev-master": "4.3-dev" } }, "autoload": { @@ -2940,9 +2940,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.10.5" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.6.0" }, - "time": "2021-05-03T19:11:20+00:00" + "time": "2020-07-02T17:12:47+00:00" }, { "name": "paragonie/constant_time_encoding", @@ -3013,29 +3013,28 @@ }, { "name": "phar-io/manifest", - "version": "2.0.1", + "version": "1.0.3", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133" + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/85265efd3af7ba3ca4b2a2c34dbfc5788dd29133", - "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", "shasum": "" }, "require": { "ext-dom": "*", "ext-phar": "*", - "ext-xmlwriter": "*", - "phar-io/version": "^3.0.1", - "php": "^7.2 || ^8.0" + "phar-io/version": "^2.0", + "php": "^5.6 || ^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { @@ -3069,24 +3068,24 @@ "issues": "https://github.com/phar-io/manifest/issues", "source": "https://github.com/phar-io/manifest/tree/master" }, - "time": "2020-06-27T14:33:11+00:00" + "time": "2018-07-08T19:23:20+00:00" }, { "name": "phar-io/version", - "version": "3.1.0", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/phar-io/version.git", - "reference": "bae7c545bef187884426f042434e561ab1ddb182" + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/bae7c545bef187884426f042434e561ab1ddb182", - "reference": "bae7c545bef187884426f042434e561ab1ddb182", + "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0" + "php": "^5.6 || ^7.0" }, "type": "library", "autoload": { @@ -3118,9 +3117,9 @@ "description": "Library for handling version information and constraints", "support": { "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/3.1.0" + "source": "https://github.com/phar-io/version/tree/master" }, - "time": "2021-02-23T14:00:09+00:00" + "time": "2018-07-08T19:19:57+00:00" }, { "name": "php-webdriver/webdriver", @@ -3415,27 +3414,28 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "0.5.5", + "version": "0.5.4", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "ea0b17460ec38e20d7eb64e7ec49b5d44af5d28c" + "reference": "e352d065af1ae9b41c12d1dfd309e90f7b1f55c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/ea0b17460ec38e20d7eb64e7ec49b5d44af5d28c", - "reference": "ea0b17460ec38e20d7eb64e7ec49b5d44af5d28c", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/e352d065af1ae9b41c12d1dfd309e90f7b1f55c9", + "reference": "e352d065af1ae9b41c12d1dfd309e90f7b1f55c9", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "require-dev": { + "phing/phing": "^2.16.3", "php-parallel-lint/php-parallel-lint": "^1.2", "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^0.12.87", + "phpstan/phpstan": "^0.12.60", "phpstan/phpstan-strict-rules": "^0.12.5", - "phpunit/phpunit": "^9.5", + "phpunit/phpunit": "^7.5.20", "symfony/process": "^5.2" }, "type": "library", @@ -3458,41 +3458,38 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/0.5.5" + "source": "https://github.com/phpstan/phpdoc-parser/tree/0.5.4" }, - "time": "2021-06-11T13:24:46+00:00" + "time": "2021-04-03T14:46:19+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.6", + "version": "8.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "f6293e1b30a2354e8428e004689671b83871edde" + "reference": "ca6647ffddd2add025ab3f21644a441d7c146cdc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f6293e1b30a2354e8428e004689671b83871edde", - "reference": "f6293e1b30a2354e8428e004689671b83871edde", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca6647ffddd2add025ab3f21644a441d7c146cdc", + "reference": "ca6647ffddd2add025ab3f21644a441d7c146cdc", "shasum": "" }, "require": { "ext-dom": "*", - "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.10.2", - "php": ">=7.3", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-text-template": "^2.0.2", - "sebastian/code-unit-reverse-lookup": "^2.0.2", - "sebastian/complexity": "^2.0", - "sebastian/environment": "^5.1.2", - "sebastian/lines-of-code": "^1.0.3", - "sebastian/version": "^3.0.1", - "theseer/tokenizer": "^1.2.0" + "php": "^7.3", + "phpunit/php-file-iterator": "^3.0", + "phpunit/php-text-template": "^2.0", + "phpunit/php-token-stream": "^4.0", + "sebastian/code-unit-reverse-lookup": "^2.0", + "sebastian/environment": "^5.0", + "sebastian/version": "^3.0", + "theseer/tokenizer": "^1.1.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^9.0" }, "suggest": { "ext-pcov": "*", @@ -3501,7 +3498,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.2-dev" + "dev-master": "8.0-dev" } }, "autoload": { @@ -3529,7 +3526,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.6" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/8.0.2" }, "funding": [ { @@ -3537,7 +3534,7 @@ "type": "github" } ], - "time": "2021-03-28T07:26:59+00:00" + "time": "2020-05-23T08:02:54+00:00" }, { "name": "phpunit/php-file-iterator", @@ -3780,18 +3777,78 @@ ], "time": "2020-10-26T13:16:10+00:00" }, + { + "name": "phpunit/php-token-stream", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/a853a0e183b9db7eed023d7933a858fa1c8d25a3", + "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-token-stream/issues", + "source": "https://github.com/sebastianbergmann/php-token-stream/tree/master" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "abandoned": true, + "time": "2020-08-04T08:28:15+00:00" + }, { "name": "phpunit/phpunit", - "version": "9.5.5", + "version": "9.2.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "89ff45ea9d70e35522fb6654a2ebc221158de276" + "reference": "1c6a9e4312e209e659f1fce3ce88dd197c2448f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/89ff45ea9d70e35522fb6654a2ebc221158de276", - "reference": "89ff45ea9d70e35522fb6654a2ebc221158de276", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1c6a9e4312e209e659f1fce3ce88dd197c2448f6", + "reference": "1c6a9e4312e209e659f1fce3ce88dd197c2448f6", "shasum": "" }, "require": { @@ -3802,31 +3859,30 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.10.1", - "phar-io/manifest": "^2.0.1", - "phar-io/version": "^3.0.2", - "php": ">=7.3", - "phpspec/prophecy": "^1.12.1", - "phpunit/php-code-coverage": "^9.2.3", - "phpunit/php-file-iterator": "^3.0.5", - "phpunit/php-invoker": "^3.1.1", - "phpunit/php-text-template": "^2.0.3", - "phpunit/php-timer": "^5.0.2", - "sebastian/cli-parser": "^1.0.1", - "sebastian/code-unit": "^1.0.6", - "sebastian/comparator": "^4.0.5", - "sebastian/diff": "^4.0.3", - "sebastian/environment": "^5.1.3", - "sebastian/exporter": "^4.0.3", - "sebastian/global-state": "^5.0.1", - "sebastian/object-enumerator": "^4.0.3", - "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^2.3.2", - "sebastian/version": "^3.0.2" + "myclabs/deep-copy": "^1.9.5", + "phar-io/manifest": "^1.0.3", + "phar-io/version": "^2.0.1", + "php": "^7.3", + "phpspec/prophecy": "^1.10.3", + "phpunit/php-code-coverage": "^8.0.2", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-invoker": "^3.0.2", + "phpunit/php-text-template": "^2.0.2", + "phpunit/php-timer": "^5.0.1", + "sebastian/code-unit": "^1.0.5", + "sebastian/comparator": "^4.0.3", + "sebastian/diff": "^4.0.1", + "sebastian/environment": "^5.1.2", + "sebastian/exporter": "^4.0.2", + "sebastian/global-state": "^4.0", + "sebastian/object-enumerator": "^4.0.2", + "sebastian/resource-operations": "^3.0.2", + "sebastian/type": "^2.1.1", + "sebastian/version": "^3.0.1" }, "require-dev": { "ext-pdo": "*", - "phpspec/prophecy-phpunit": "^2.0.1" + "phpspec/prophecy-phpunit": "^2.0" }, "suggest": { "ext-soap": "*", @@ -3838,7 +3894,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.5-dev" + "dev-master": "9.2-dev" } }, "autoload": { @@ -3869,7 +3925,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.5" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.2.6" }, "funding": [ { @@ -3881,7 +3937,7 @@ "type": "github" } ], - "time": "2021-06-05T04:49:07+00:00" + "time": "2020-07-13T17:55:55+00:00" }, { "name": "psr/cache", @@ -4453,62 +4509,6 @@ }, "time": "2020-05-12T15:16:56+00:00" }, - { - "name": "sebastian/cli-parser", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for parsing CLI options", - "homepage": "https://github.com/sebastianbergmann/cli-parser", - "support": { - "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T06:08:49+00:00" - }, { "name": "sebastian/code-unit", "version": "1.0.8", @@ -4694,63 +4694,6 @@ ], "time": "2020-10-26T15:49:45+00:00" }, - { - "name": "sebastian/complexity", - "version": "2.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.7", - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for calculating the complexity of PHP code units", - "homepage": "https://github.com/sebastianbergmann/complexity", - "support": { - "issues": "https://github.com/sebastianbergmann/complexity/issues", - "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T15:52:27+00:00" - }, { "name": "sebastian/diff", "version": "4.0.4", @@ -4959,26 +4902,26 @@ }, { "name": "sebastian/global-state", - "version": "5.0.3", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49" + "reference": "bdb1e7c79e592b8c82cb1699be3c8743119b8a72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/23bd5951f7ff26f12d4e3242864df3e08dec4e49", - "reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bdb1e7c79e592b8c82cb1699be3c8743119b8a72", + "reference": "bdb1e7c79e592b8c82cb1699be3c8743119b8a72", "shasum": "" }, "require": { - "php": ">=7.3", + "php": "^7.3", "sebastian/object-reflector": "^2.0", "sebastian/recursion-context": "^4.0" }, "require-dev": { "ext-dom": "*", - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^9.0" }, "suggest": { "ext-uopz": "*" @@ -4986,7 +4929,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -5011,72 +4954,9 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.3" + "source": "https://github.com/sebastianbergmann/global-state/tree/master" }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2021-06-11T13:31:12+00:00" - }, - { - "name": "sebastian/lines-of-code", - "version": "1.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.6", - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for counting the lines of code in PHP source code", - "homepage": "https://github.com/sebastianbergmann/lines-of-code", - "support": { - "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-11-28T06:42:11+00:00" + "time": "2020-02-07T06:11:37+00:00" }, { "name": "sebastian/object-enumerator", @@ -5310,16 +5190,16 @@ }, { "name": "sebastian/type", - "version": "2.3.2", + "version": "2.3.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "0d1c587401514d17e8f9258a27e23527cb1b06c1" + "reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/0d1c587401514d17e8f9258a27e23527cb1b06c1", - "reference": "0d1c587401514d17e8f9258a27e23527cb1b06c1", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/81cd61ab7bbf2de744aba0ea61fae32f721df3d2", + "reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2", "shasum": "" }, "require": { @@ -5354,7 +5234,7 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/2.3.2" + "source": "https://github.com/sebastianbergmann/type/tree/2.3.1" }, "funding": [ { @@ -5362,7 +5242,7 @@ "type": "github" } ], - "time": "2021-06-04T13:02:07+00:00" + "time": "2020-10-26T13:18:59+00:00" }, { "name": "sebastian/version", @@ -5605,16 +5485,16 @@ }, { "name": "symfony/console", - "version": "v4.4.25", + "version": "v4.4.22", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "a62acecdf5b50e314a4f305cd01b5282126f3095" + "reference": "36bbd079b69b94bcc9c9c9e1e37ca3b1e7971625" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/a62acecdf5b50e314a4f305cd01b5282126f3095", - "reference": "a62acecdf5b50e314a4f305cd01b5282126f3095", + "url": "https://api.github.com/repos/symfony/console/zipball/36bbd079b69b94bcc9c9c9e1e37ca3b1e7971625", + "reference": "36bbd079b69b94bcc9c9c9e1e37ca3b1e7971625", "shasum": "" }, "require": { @@ -5674,7 +5554,7 @@ "description": "Eases the creation of beautiful and testable command line interfaces", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/console/tree/v4.4.25" + "source": "https://github.com/symfony/console/tree/v4.4.22" }, "funding": [ { @@ -5690,20 +5570,20 @@ "type": "tidelift" } ], - "time": "2021-05-26T11:20:16+00:00" + "time": "2021-04-16T17:32:19+00:00" }, { "name": "symfony/css-selector", - "version": "v5.3.0", + "version": "v5.2.7", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "fcd0b29a7a0b1bb5bfbedc6231583d77fea04814" + "reference": "59a684f5ac454f066ecbe6daecce6719aed283fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/fcd0b29a7a0b1bb5bfbedc6231583d77fea04814", - "reference": "fcd0b29a7a0b1bb5bfbedc6231583d77fea04814", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/59a684f5ac454f066ecbe6daecce6719aed283fb", + "reference": "59a684f5ac454f066ecbe6daecce6719aed283fb", "shasum": "" }, "require": { @@ -5739,7 +5619,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v5.3.0" + "source": "https://github.com/symfony/css-selector/tree/v5.3.0-BETA1" }, "funding": [ { @@ -5755,7 +5635,7 @@ "type": "tidelift" } ], - "time": "2021-05-26T17:40:38+00:00" + "time": "2021-04-07T16:07:52+00:00" }, { "name": "symfony/deprecation-contracts", @@ -5826,16 +5706,16 @@ }, { "name": "symfony/event-dispatcher", - "version": "v4.4.25", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "047773e7016e4fd45102cedf4bd2558ae0d0c32f" + "reference": "c352647244bd376bf7d31efbd5401f13f50dad0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/047773e7016e4fd45102cedf4bd2558ae0d0c32f", - "reference": "047773e7016e4fd45102cedf4bd2558ae0d0c32f", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/c352647244bd376bf7d31efbd5401f13f50dad0c", + "reference": "c352647244bd376bf7d31efbd5401f13f50dad0c", "shasum": "" }, "require": { @@ -5889,7 +5769,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.25" + "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.20" }, "funding": [ { @@ -5905,7 +5785,7 @@ "type": "tidelift" } ], - "time": "2021-05-26T17:39:37+00:00" + "time": "2021-01-27T09:09:26+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -5988,16 +5868,16 @@ }, { "name": "symfony/filesystem", - "version": "v5.3.0", + "version": "v5.2.7", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "348116319d7fb7d1faa781d26a48922428013eb2" + "reference": "056e92acc21d977c37e6ea8e97374b2a6c8551b0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/348116319d7fb7d1faa781d26a48922428013eb2", - "reference": "348116319d7fb7d1faa781d26a48922428013eb2", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/056e92acc21d977c37e6ea8e97374b2a6c8551b0", + "reference": "056e92acc21d977c37e6ea8e97374b2a6c8551b0", "shasum": "" }, "require": { @@ -6030,7 +5910,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.3.0" + "source": "https://github.com/symfony/filesystem/tree/v5.2.7" }, "funding": [ { @@ -6046,20 +5926,20 @@ "type": "tidelift" } ], - "time": "2021-05-26T17:43:10+00:00" + "time": "2021-04-01T10:42:13+00:00" }, { "name": "symfony/finder", - "version": "v5.3.0", + "version": "v5.2.4", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "0ae3f047bed4edff6fd35b26a9a6bfdc92c953c6" + "reference": "0d639a0943822626290d169965804f79400e6a04" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/0ae3f047bed4edff6fd35b26a9a6bfdc92c953c6", - "reference": "0ae3f047bed4edff6fd35b26a9a6bfdc92c953c6", + "url": "https://api.github.com/repos/symfony/finder/zipball/0d639a0943822626290d169965804f79400e6a04", + "reference": "0d639a0943822626290d169965804f79400e6a04", "shasum": "" }, "require": { @@ -6091,7 +5971,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.3.0" + "source": "https://github.com/symfony/finder/tree/v5.2.4" }, "funding": [ { @@ -6107,20 +5987,20 @@ "type": "tidelift" } ], - "time": "2021-05-26T12:52:38+00:00" + "time": "2021-02-15T18:55:04+00:00" }, { "name": "symfony/http-foundation", - "version": "v5.3.1", + "version": "v5.2.7", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "8827b90cf8806e467124ad476acd15216c2fceb6" + "reference": "a416487a73bb9c9d120e9ba3a60547f4a3fb7a1f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/8827b90cf8806e467124ad476acd15216c2fceb6", - "reference": "8827b90cf8806e467124ad476acd15216c2fceb6", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/a416487a73bb9c9d120e9ba3a60547f4a3fb7a1f", + "reference": "a416487a73bb9c9d120e9ba3a60547f4a3fb7a1f", "shasum": "" }, "require": { @@ -6164,7 +6044,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v5.3.1" + "source": "https://github.com/symfony/http-foundation/tree/v5.2.7" }, "funding": [ { @@ -6180,20 +6060,20 @@ "type": "tidelift" } ], - "time": "2021-06-02T09:32:00+00:00" + "time": "2021-05-01T13:46:24+00:00" }, { "name": "symfony/mime", - "version": "v5.3.0", + "version": "v5.2.7", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "ed710d297b181f6a7194d8172c9c2423d58e4852" + "reference": "7af452bf51c46f18da00feb32e1ad36db9426515" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/ed710d297b181f6a7194d8172c9c2423d58e4852", - "reference": "ed710d297b181f6a7194d8172c9c2423d58e4852", + "url": "https://api.github.com/repos/symfony/mime/zipball/7af452bf51c46f18da00feb32e1ad36db9426515", + "reference": "7af452bf51c46f18da00feb32e1ad36db9426515", "shasum": "" }, "require": { @@ -6247,7 +6127,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v5.3.0" + "source": "https://github.com/symfony/mime/tree/v5.2.7" }, "funding": [ { @@ -6263,20 +6143,20 @@ "type": "tidelift" } ], - "time": "2021-05-26T17:43:10+00:00" + "time": "2021-04-29T20:47:09+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.23.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce" + "reference": "c6c942b1ac76c82448322025e084cadc56048b4e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce", - "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/c6c942b1ac76c82448322025e084cadc56048b4e", + "reference": "c6c942b1ac76c82448322025e084cadc56048b4e", "shasum": "" }, "require": { @@ -6288,7 +6168,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -6326,7 +6206,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.1" }, "funding": [ { @@ -6342,20 +6222,20 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.23.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "65bd267525e82759e7d8c4e8ceea44f398838e65" + "reference": "2d63434d922daf7da8dd863e7907e67ee3031483" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/65bd267525e82759e7d8c4e8ceea44f398838e65", - "reference": "65bd267525e82759e7d8c4e8ceea44f398838e65", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/2d63434d922daf7da8dd863e7907e67ee3031483", + "reference": "2d63434d922daf7da8dd863e7907e67ee3031483", "shasum": "" }, "require": { @@ -6369,7 +6249,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -6413,7 +6293,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.22.1" }, "funding": [ { @@ -6429,20 +6309,20 @@ "type": "tidelift" } ], - "time": "2021-05-27T09:27:20+00:00" + "time": "2021-01-22T09:19:47+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.23.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8" + "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/43a0283138253ed1d48d352ab6d0bdb3f809f248", + "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248", "shasum": "" }, "require": { @@ -6454,7 +6334,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -6497,7 +6377,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.22.1" }, "funding": [ { @@ -6513,7 +6393,7 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2021-01-22T09:19:47+00:00" }, { "name": "symfony/polyfill-mbstring", @@ -6597,16 +6477,16 @@ }, { "name": "symfony/polyfill-php72", - "version": "v1.23.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "9a142215a36a3888e30d0a9eeea9766764e96976" + "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9a142215a36a3888e30d0a9eeea9766764e96976", - "reference": "9a142215a36a3888e30d0a9eeea9766764e96976", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", + "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", "shasum": "" }, "require": { @@ -6615,7 +6495,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -6653,7 +6533,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-php72/tree/v1.22.1" }, "funding": [ { @@ -6669,20 +6549,20 @@ "type": "tidelift" } ], - "time": "2021-05-27T09:17:38+00:00" + "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.23.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010" + "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fba8933c384d6476ab14fb7b8526e5287ca7e010", - "reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", + "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", "shasum": "" }, "require": { @@ -6691,7 +6571,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -6732,7 +6612,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.22.1" }, "funding": [ { @@ -6748,20 +6628,20 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.23.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0" + "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/eca0bf41ed421bed1b57c4958bab16aa86b757d0", - "reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dc3063ba22c2a1fd2f45ed856374d79114998f91", + "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91", "shasum": "" }, "require": { @@ -6770,7 +6650,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -6815,7 +6695,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.22.1" }, "funding": [ { @@ -6831,7 +6711,7 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/process", @@ -6975,35 +6855,31 @@ }, { "name": "symfony/yaml", - "version": "v5.3.0", + "version": "v4.4.22", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "3bbcf262fceb3d8f48175302e6ba0ac96e3a5a11" + "reference": "1c2fd24147961525eaefb65b11987cab75adab59" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/3bbcf262fceb3d8f48175302e6ba0ac96e3a5a11", - "reference": "3bbcf262fceb3d8f48175302e6ba0ac96e3a5a11", + "url": "https://api.github.com/repos/symfony/yaml/zipball/1c2fd24147961525eaefb65b11987cab75adab59", + "reference": "1c2fd24147961525eaefb65b11987cab75adab59", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1", + "php": ">=7.1.3", "symfony/polyfill-ctype": "~1.8" }, "conflict": { - "symfony/console": "<4.4" + "symfony/console": "<3.4" }, "require-dev": { - "symfony/console": "^4.4|^5.0" + "symfony/console": "^3.4|^4.0|^5.0" }, "suggest": { "symfony/console": "For validating YAML files using the lint command" }, - "bin": [ - "Resources/bin/yaml-lint" - ], "type": "library", "autoload": { "psr-4": { @@ -7030,7 +6906,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v5.3.0" + "source": "https://github.com/symfony/yaml/tree/v4.4.22" }, "funding": [ { @@ -7046,7 +6922,7 @@ "type": "tidelift" } ], - "time": "2021-05-26T17:43:10+00:00" + "time": "2021-04-23T12:09:37+00:00" }, { "name": "thecodingmachine/safe", @@ -7835,20 +7711,20 @@ }, { "name": "goaop/parser-reflection", - "version": "2.1.2", + "version": "2.1.3", "source": { "type": "git", "url": "https://github.com/goaop/parser-reflection.git", - "reference": "d4257ee557484ac886bee46bd41ebecb7c4bfa16" + "reference": "2e837e150e15d38f7004b0dbcd0af4abe034c9e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/goaop/parser-reflection/zipball/d4257ee557484ac886bee46bd41ebecb7c4bfa16", - "reference": "d4257ee557484ac886bee46bd41ebecb7c4bfa16", + "url": "https://api.github.com/repos/goaop/parser-reflection/zipball/2e837e150e15d38f7004b0dbcd0af4abe034c9e2", + "reference": "2e837e150e15d38f7004b0dbcd0af4abe034c9e2", "shasum": "" }, "require": { - "nikic/php-parser": "^4.0", + "nikic/php-parser": "^4.0 <4.7.0", "php": ">=7.1" }, "require-dev": { @@ -7886,7 +7762,7 @@ "issues": "https://github.com/goaop/parser-reflection/issues", "source": "https://github.com/goaop/parser-reflection/tree/2.x" }, - "time": "2020-08-13T00:19:00+00:00" + "time": "2020-08-13T21:02:42+00:00" }, { "name": "jakubledl/dissect", @@ -8089,20 +7965,20 @@ }, { "name": "phpmd/phpmd", - "version": "2.10.1", + "version": "2.10.0", "source": { "type": "git", "url": "https://github.com/phpmd/phpmd.git", - "reference": "bd5ef43d1dcaf7272605027c959c1c5ff3761f7a" + "reference": "58ef9e746a1ab50ad3360d5d301e1229ed2612cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpmd/phpmd/zipball/bd5ef43d1dcaf7272605027c959c1c5ff3761f7a", - "reference": "bd5ef43d1dcaf7272605027c959c1c5ff3761f7a", + "url": "https://api.github.com/repos/phpmd/phpmd/zipball/58ef9e746a1ab50ad3360d5d301e1229ed2612cb", + "reference": "58ef9e746a1ab50ad3360d5d301e1229ed2612cb", "shasum": "" }, "require": { - "composer/xdebug-handler": "^1.0 || ^2.0", + "composer/xdebug-handler": "^1.0", "ext-xml": "*", "pdepend/pdepend": "^2.9.1", "php": ">=5.3.9" @@ -8160,7 +8036,7 @@ "support": { "irc": "irc://irc.freenode.org/phpmd", "issues": "https://github.com/phpmd/phpmd/issues", - "source": "https://github.com/phpmd/phpmd/tree/2.10.1" + "source": "https://github.com/phpmd/phpmd/tree/2.10.0" }, "funding": [ { @@ -8168,7 +8044,7 @@ "type": "tidelift" } ], - "time": "2021-05-11T17:16:16+00:00" + "time": "2021-04-26T18:44:44+00:00" }, { "name": "rregeer/phpunit-coverage-check", @@ -8216,6 +8092,62 @@ }, "time": "2018-07-29T13:27:58+00:00" }, + { + "name": "sebastian/cli-parser", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:08:49+00:00" + }, { "name": "sebastian/phpcpd", "version": "6.0.3", @@ -8279,16 +8211,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.6.0", + "version": "3.5.8", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "ffced0d2c8fa8e6cdc4d695a743271fab6c38625" + "reference": "9d583721a7157ee997f235f327de038e7ea6dac4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ffced0d2c8fa8e6cdc4d695a743271fab6c38625", - "reference": "ffced0d2c8fa8e6cdc4d695a743271fab6c38625", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/9d583721a7157ee997f235f327de038e7ea6dac4", + "reference": "9d583721a7157ee997f235f327de038e7ea6dac4", "shasum": "" }, "require": { @@ -8331,39 +8263,36 @@ "source": "https://github.com/squizlabs/PHP_CodeSniffer", "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" }, - "time": "2021-04-09T00:54:41+00:00" + "time": "2020-10-23T02:01:07+00:00" }, { "name": "symfony/config", - "version": "v5.3.0", + "version": "v4.4.22", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "9f4a448c2d7fd2c90882dfff930b627ddbe16810" + "reference": "f6d8318c14e4be81525ae47b30e618f0bed4c7b3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/9f4a448c2d7fd2c90882dfff930b627ddbe16810", - "reference": "9f4a448c2d7fd2c90882dfff930b627ddbe16810", + "url": "https://api.github.com/repos/symfony/config/zipball/f6d8318c14e4be81525ae47b30e618f0bed4c7b3", + "reference": "f6d8318c14e4be81525ae47b30e618f0bed4c7b3", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1", - "symfony/filesystem": "^4.4|^5.0", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-php80": "^1.15", - "symfony/polyfill-php81": "^1.22" + "php": ">=7.1.3", + "symfony/filesystem": "^3.4|^4.0|^5.0", + "symfony/polyfill-ctype": "~1.8" }, "conflict": { - "symfony/finder": "<4.4" + "symfony/finder": "<3.4" }, "require-dev": { - "symfony/event-dispatcher": "^4.4|^5.0", - "symfony/finder": "^4.4|^5.0", - "symfony/messenger": "^4.4|^5.0", + "symfony/event-dispatcher": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/messenger": "^4.1|^5.0", "symfony/service-contracts": "^1.1|^2", - "symfony/yaml": "^4.4|^5.0" + "symfony/yaml": "^3.4|^4.0|^5.0" }, "suggest": { "symfony/yaml": "To use the yaml reference dumper" @@ -8394,7 +8323,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v5.3.0" + "source": "https://github.com/symfony/config/tree/v4.4.22" }, "funding": [ { @@ -8410,44 +8339,41 @@ "type": "tidelift" } ], - "time": "2021-05-26T17:43:10+00:00" + "time": "2021-04-07T15:47:03+00:00" }, { "name": "symfony/dependency-injection", - "version": "v5.3.0", + "version": "v4.4.22", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "94d973cb742d8c5c5dcf9534220e6b73b09af1d4" + "reference": "778b140b3e8f6890f43dc2c978e58e69f188909a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/94d973cb742d8c5c5dcf9534220e6b73b09af1d4", - "reference": "94d973cb742d8c5c5dcf9534220e6b73b09af1d4", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/778b140b3e8f6890f43dc2c978e58e69f188909a", + "reference": "778b140b3e8f6890f43dc2c978e58e69f188909a", "shasum": "" }, "require": { - "php": ">=7.2.5", - "psr/container": "^1.1.1", - "symfony/deprecation-contracts": "^2.1", - "symfony/polyfill-php80": "^1.15", + "php": ">=7.1.3", + "psr/container": "^1.0", "symfony/service-contracts": "^1.1.6|^2" }, "conflict": { - "ext-psr": "<1.1|>=2", - "symfony/config": "<5.3", - "symfony/finder": "<4.4", - "symfony/proxy-manager-bridge": "<4.4", - "symfony/yaml": "<4.4" + "symfony/config": "<4.3|>=5.0", + "symfony/finder": "<3.4", + "symfony/proxy-manager-bridge": "<3.4", + "symfony/yaml": "<3.4" }, "provide": { "psr/container-implementation": "1.0", "symfony/service-implementation": "1.0|2.0" }, "require-dev": { - "symfony/config": "^5.3", - "symfony/expression-language": "^4.4|^5.0", - "symfony/yaml": "^4.4|^5.0" + "symfony/config": "^4.3", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0" }, "suggest": { "symfony/config": "", @@ -8482,86 +8408,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v5.3.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-05-26T17:57:12+00:00" - }, - { - "name": "symfony/polyfill-php81", - "version": "v1.23.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "e66119f3de95efc359483f810c4c3e6436279436" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/e66119f3de95efc359483f810c4c3e6436279436", - "reference": "e66119f3de95efc359483f810c4c3e6436279436", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.23-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php81\\": "" - }, - "files": [ - "bootstrap.php" - ], - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.23.0" + "source": "https://github.com/symfony/dependency-injection/tree/v4.4.22" }, "funding": [ { @@ -8577,7 +8424,7 @@ "type": "tidelift" } ], - "time": "2021-05-21T13:25:03+00:00" + "time": "2021-04-07T15:47:03+00:00" }, { "name": "symfony/stopwatch", From 4b70461d144d22869c0fc93745c4fc77be883268 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 14 Jun 2021 22:36:45 -0500 Subject: [PATCH 625/888] MQE-2750: Update composer dependencies to be PHP 8 compatible --- composer.json | 4 +--- composer.lock | 65 ++++++++------------------------------------------- 2 files changed, 11 insertions(+), 58 deletions(-) diff --git a/composer.json b/composer.json index 4927abb43..a7393fc6d 100755 --- a/composer.json +++ b/composer.json @@ -45,10 +45,8 @@ "php-coveralls/php-coveralls": "^1.0||^2.2", "phpmd/phpmd": "^2.8.0", "phpunit/phpunit": "^9.0", - "rregeer/phpunit-coverage-check": "^0.1.4", "sebastian/phpcpd": "~6.0.0", - "squizlabs/php_codesniffer": "~3.5.4", - "symfony/stopwatch": "~3.4.6" + "squizlabs/php_codesniffer": "~3.5.4" }, "autoload": { "files": ["src/Magento/FunctionalTestingFramework/_bootstrap.php"], diff --git a/composer.lock b/composer.lock index 1b0846fcc..01a5ff77f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "465713023b0749c53f630e64d2413880", + "content-hash": "6703d4aff2c0f30efb681b320a9a2d2f", "packages": [ { "name": "allure-framework/allure-codeception", @@ -8046,52 +8046,6 @@ ], "time": "2021-04-26T18:44:44+00:00" }, - { - "name": "rregeer/phpunit-coverage-check", - "version": "0.1.6", - "source": { - "type": "git", - "url": "https://github.com/richardregeer/phpunit-coverage-check.git", - "reference": "330ae9318e0e60960cfb97c4a0459e3e4a3080e0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/richardregeer/phpunit-coverage-check/zipball/330ae9318e0e60960cfb97c4a0459e3e4a3080e0", - "reference": "330ae9318e0e60960cfb97c4a0459e3e4a3080e0", - "shasum": "" - }, - "require": { - "php": ">=5.5.0" - }, - "bin": [ - "bin/coverage-check" - ], - "type": "library", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Richard Regeer", - "email": "rich2309@gmail.com" - } - ], - "description": "Check the code coverage using the clover report of phpunit", - "keywords": [ - "ci", - "code coverage", - "php", - "phpunit", - "testing", - "unittest" - ], - "support": { - "issues": "https://github.com/richardregeer/phpunit-coverage-check/issues", - "source": "https://github.com/richardregeer/phpunit-coverage-check/tree/master" - }, - "time": "2018-07-29T13:27:58+00:00" - }, { "name": "sebastian/cli-parser", "version": "1.0.1", @@ -8428,20 +8382,21 @@ }, { "name": "symfony/stopwatch", - "version": "v3.4.47", + "version": "v5.3.0", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "298b81faad4ce60e94466226b2abbb8c9bca7462" + "reference": "313d02f59d6543311865007e5ff4ace05b35ee65" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/298b81faad4ce60e94466226b2abbb8c9bca7462", - "reference": "298b81faad4ce60e94466226b2abbb8c9bca7462", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/313d02f59d6543311865007e5ff4ace05b35ee65", + "reference": "313d02f59d6543311865007e5ff4ace05b35ee65", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" + "php": ">=7.2.5", + "symfony/service-contracts": "^1.0|^2" }, "type": "library", "autoload": { @@ -8466,10 +8421,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Stopwatch Component", + "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v3.4.47" + "source": "https://github.com/symfony/stopwatch/tree/v5.3.0" }, "funding": [ { @@ -8485,7 +8440,7 @@ "type": "tidelift" } ], - "time": "2020-10-24T10:57:07+00:00" + "time": "2021-05-26T17:43:10+00:00" } ], "aliases": [], From cc270c9a1b3c108f6c989e15840c6463f0498d05 Mon Sep 17 00:00:00 2001 From: Adarsh Manickam <adarsh.apple@icloud.com> Date: Sun, 20 Jun 2021 14:54:11 +0530 Subject: [PATCH 626/888] Updated monolog/monolog to ^2.2 --- composer.json | 2 +- composer.lock | 48 +++++++++++++++++++++++++++++------------------- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/composer.json b/composer.json index 26dd6b06a..9ecaeb2be 100755 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ "csharpru/vault-php": "^4.1.0", "csharpru/vault-php-guzzle6-transport": "^2.0", "hoa/console": "~3.0", - "monolog/monolog": "^1.17", + "monolog/monolog": "^2.2", "mustache/mustache": "~2.5", "php-webdriver/webdriver": "^1.8.0", "spomky-labs/otphp": "^10.0", diff --git a/composer.lock b/composer.lock index 8711d6d8e..e74a7fe67 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ec8d82a1a84dbf04502a26273da1cb0f", + "content-hash": "e37470453c311fc07a216b38b43e9e50", "packages": [ { "name": "allure-framework/allure-codeception", @@ -2626,21 +2626,21 @@ }, { "name": "monolog/monolog", - "version": "1.26.0", + "version": "2.2.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "2209ddd84e7ef1256b7af205d0717fb62cfc9c33" + "reference": "1cb1cde8e8dd0f70cc0fe51354a59acad9302084" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/2209ddd84e7ef1256b7af205d0717fb62cfc9c33", - "reference": "2209ddd84e7ef1256b7af205d0717fb62cfc9c33", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/1cb1cde8e8dd0f70cc0fe51354a59acad9302084", + "reference": "1cb1cde8e8dd0f70cc0fe51354a59acad9302084", "shasum": "" }, "require": { - "php": ">=5.3.0", - "psr/log": "~1.0" + "php": ">=7.2", + "psr/log": "^1.0.1" }, "provide": { "psr/log-implementation": "1.0.0" @@ -2648,29 +2648,39 @@ "require-dev": { "aws/aws-sdk-php": "^2.4.9 || ^3.0", "doctrine/couchdb": "~1.0@dev", - "graylog2/gelf-php": "~1.0", + "elasticsearch/elasticsearch": "^7", + "graylog2/gelf-php": "^1.4.2", + "mongodb/mongodb": "^1.8", "php-amqplib/php-amqplib": "~2.4", "php-console/php-console": "^3.1.3", + "phpspec/prophecy": "^1.6.1", "phpstan/phpstan": "^0.12.59", - "phpunit/phpunit": "~4.5", - "ruflin/elastica": ">=0.90 <3.0", - "sentry/sentry": "^0.13", + "phpunit/phpunit": "^8.5", + "predis/predis": "^1.1", + "rollbar/rollbar": "^1.3", + "ruflin/elastica": ">=0.90 <7.0.1", "swiftmailer/swiftmailer": "^5.3|^6.0" }, "suggest": { "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", - "ext-mongo": "Allow sending log messages to a MongoDB server", + "ext-mbstring": "Allow to work properly with unicode symbols", + "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", - "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", "php-console/php-console": "Allow sending log messages to Google Chrome", "rollbar/rollbar": "Allow sending log messages to Rollbar", - "ruflin/elastica": "Allow sending log messages to an Elastic Search server", - "sentry/sentry": "Allow sending log messages to a Sentry server" + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" }, "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.x-dev" + } + }, "autoload": { "psr-4": { "Monolog\\": "src/Monolog" @@ -2684,11 +2694,11 @@ { "name": "Jordi Boggiano", "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" + "homepage": "https://seld.be" } ], "description": "Sends your logs to files, sockets, inboxes, databases and various web services", - "homepage": "http://github.com/Seldaek/monolog", + "homepage": "https://github.com/Seldaek/monolog", "keywords": [ "log", "logging", @@ -2696,7 +2706,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/1.26.0" + "source": "https://github.com/Seldaek/monolog/tree/2.2.0" }, "funding": [ { @@ -2708,7 +2718,7 @@ "type": "tidelift" } ], - "time": "2020-12-14T12:56:38+00:00" + "time": "2020-12-14T13:15:25+00:00" }, { "name": "mtdowling/jmespath.php", From 9e039c4b3f22e67fd60df9ab50a53ec13b5a2749 Mon Sep 17 00:00:00 2001 From: Adarsh Manickam <adarsh.apple@icloud.com> Date: Sun, 20 Jun 2021 14:54:50 +0530 Subject: [PATCH 627/888] Fixed monolog warning method usage in PHPUnit tests --- .../FunctionalTestingFramework/Config/Reader/Filesystem.php | 2 +- .../DataGenerator/Handlers/PersistedObjectHandler.php | 2 +- .../Test/Util/ActionObjectExtractor.php | 2 +- src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php | 2 +- src/Magento/FunctionalTestingFramework/Util/TestGenerator.php | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Config/Reader/Filesystem.php b/src/Magento/FunctionalTestingFramework/Config/Reader/Filesystem.php index 8f3fd5200..494c62908 100644 --- a/src/Magento/FunctionalTestingFramework/Config/Reader/Filesystem.php +++ b/src/Magento/FunctionalTestingFramework/Config/Reader/Filesystem.php @@ -210,7 +210,7 @@ protected function verifyFileEmpty($content, $fileName) { if (empty($content)) { if (MftfApplicationConfig::getConfig()->verboseEnabled()) { - LoggingUtil::getInstance()->getLogger(Filesystem::class)->warn( + LoggingUtil::getInstance()->getLogger(Filesystem::class)->warning( "XML File is empty.", ["File" => $fileName] ); diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php index 60fdf0212..c1f5d8d85 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php @@ -193,7 +193,7 @@ public function retrieveEntityField($stepKey, $field, $scope) $warnMsg = "Undefined field {$field} in entity object with a stepKey of {$stepKey}\n"; $warnMsg .= "Please fix the invalid reference. This will result in fatal error in next major release."; //TODO: change this to throw an exception in next major release - LoggingUtil::getInstance()->getLogger(PersistedObjectHandler::class)->warn($warnMsg); + LoggingUtil::getInstance()->getLogger(PersistedObjectHandler::class)->warning($warnMsg); if (MftfApplicationConfig::getConfig()->verboseEnabled() && MftfApplicationConfig::getConfig()->getPhase() !== MftfApplicationConfig::UNIT_TEST_PHASE) { print("\n$warnMsg\n"); diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/ActionObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/ActionObjectExtractor.php index 03813315f..8fdcf82f6 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/ActionObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/ActionObjectExtractor.php @@ -305,7 +305,7 @@ private function auditMergeSteps($stepKeyRefs, $testName) }); foreach ($atRiskStepRef as $stepKey => $stepRefs) { - LoggingUtil::getInstance()->getLogger(ActionObjectExtractor::class)->warn( + LoggingUtil::getInstance()->getLogger(ActionObjectExtractor::class)->warning( 'multiple actions referencing step key', ['test' => $testName, 'stepKey' => $stepKey, 'ref' => $stepRefs] ); diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index 1a10e3029..b9a74de84 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -585,7 +585,7 @@ private function setArrayValueWithLogging($inArray, $index, $value) } else { $warnMsg = 'Path: ' . $value . ' is ignored by ModuleResolver. ' . PHP_EOL . 'Path: '; $warnMsg .= $inArray[$index] . ' is set for Module: ' . $index . PHP_EOL; - LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->warn($warnMsg); + LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->warning($warnMsg); } return $outArray; } diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 31035c8f6..9d2d097f4 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -362,7 +362,7 @@ private function assembleAllTestPhp($testManifest, array $testsToIgnore) if (MftfApplicationConfig::getConfig()->verboseEnabled()) { print("NOTICE: {$errMessage}"); } - LoggingUtil::getInstance()->getLogger(self::class)->warn($errMessage); + LoggingUtil::getInstance()->getLogger(self::class)->warning($errMessage); continue; } } From ca55c2f36d16663d980781ddcc48e27c92f4af6c Mon Sep 17 00:00:00 2001 From: Sergii Ivashchenko <serg.ivashchenko@gmail.com> Date: Sun, 20 Jun 2021 11:55:13 +0100 Subject: [PATCH 628/888] Eliminated Aspect Mock usage from FilesystemTest --- .../Config/Reader/FilesystemTest.php | 94 ++++++++++--------- .../Config/Reader/Filesystem.php | 2 +- 2 files changed, 50 insertions(+), 46 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Config/Reader/FilesystemTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Config/Reader/FilesystemTest.php index f91f071f0..1fe5bb6b5 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Config/Reader/FilesystemTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Config/Reader/FilesystemTest.php @@ -3,20 +3,23 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace tests\unit\Magento\FunctionalTestFramework\Config\Reader; +use Magento\FunctionalTestingFramework\Config\ConverterInterface; use Magento\FunctionalTestingFramework\Config\FileResolver\Module; use Magento\FunctionalTestingFramework\Config\Reader\Filesystem; +use Magento\FunctionalTestingFramework\Config\SchemaLocatorInterface; use Magento\FunctionalTestingFramework\Config\ValidationState; use Magento\FunctionalTestingFramework\Util\Iterator\File; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use AspectMock\Test as AspectMock; use tests\unit\Util\TestLoggingUtil; class FilesystemTest extends TestCase { /** - * Before test functionality * @return void */ public function setUp(): void @@ -25,79 +28,80 @@ public function setUp(): void } /** - * Test Reading Empty Files * @throws \Exception */ public function testEmptyXmlFile() { - // create mocked items and read the file - $someFile = $this->setMockFile("somepath.xml", ""); - $filesystem = $this->createPseudoFileSystem($someFile); - $filesystem->read(); + $filesystem = $this->getFilesystem($this->getFileIterator('somepath.xml', '')); + $this->assertEquals([], $filesystem->read()); - // validate log statement TestLoggingUtil::getInstance()->validateMockLogStatement( - "warning", - "XML File is empty.", - ["File" => "somepath.xml"] + 'warning', + 'XML File is empty.', + ['File' => 'somepath.xml'] ); } /** - * Function used to set mock for File created in test + * Retrieve mocked file iterator * * @param string $fileName * @param string $content - * @return object + * @return File|MockObject * @throws \Exception */ - public function setMockFile($fileName, $content) + public function getFileIterator(string $fileName, string $content): File { - $file = AspectMock::double( - File::class, - [ - 'current' => "", - 'count' => 1, - 'getFilename' => $fileName - ] - )->make(); + $iterator = new \ArrayIterator([$content]); + + $file = $this->createMock(File::class); + + $file->method('current') + ->willReturn($content); + $file->method('getFilename') + ->willReturn($fileName); + $file->method('count') + ->willReturn(1); + + $file->method('next') + ->willReturnCallback(function () use ($iterator): void { + $iterator->next(); + }); - //set mocked data property for File - $property = new \ReflectionProperty(File::class, 'data'); - $property->setAccessible(true); - $property->setValue($file, [$fileName => $content]); + $file->method('valid') + ->willReturnCallback(function () use ($iterator): bool { + return $iterator->valid(); + }); return $file; } /** - * Function used to set mock for filesystem class during test + * Get real instance of Filesystem class with mocked dependencies * - * @param string $fileList - * @return object - * @throws \Exception + * @param File $fileIterator + * @return Filesystem */ - public function createPseudoFileSystem($fileList) + public function getFilesystem(File $fileIterator): Filesystem { - $filesystem = AspectMock::double(Filesystem::class)->make(); - - //set resolver to use mocked resolver - $mockFileResolver = AspectMock::double(Module::class, ['get' => $fileList])->make(); - $property = new \ReflectionProperty(Filesystem::class, 'fileResolver'); - $property->setAccessible(true); - $property->setValue($filesystem, $mockFileResolver); - - //set validator to use mocked validator - $mockValidation = AspectMock::double(ValidationState::class, ['isValidationRequired' => false])->make(); - $property = new \ReflectionProperty(Filesystem::class, 'validationState'); - $property->setAccessible(true); - $property->setValue($filesystem, $mockValidation); + $fileResolver = $this->createMock(Module::class); + $fileResolver->method('get') + ->willReturn($fileIterator); + $validationState = $this->createMock(ValidationState::class); + $validationState->method('isValidationRequired') + ->willReturn(false); + $filesystem = new Filesystem( + $fileResolver, + $this->createMock(ConverterInterface::class), + $this->createMock(SchemaLocatorInterface::class), + $validationState, + '' + ); return $filesystem; } /** - * After class functionality * @return void */ public static function tearDownAfterClass(): void diff --git a/src/Magento/FunctionalTestingFramework/Config/Reader/Filesystem.php b/src/Magento/FunctionalTestingFramework/Config/Reader/Filesystem.php index 8f3fd5200..b6b323fb1 100644 --- a/src/Magento/FunctionalTestingFramework/Config/Reader/Filesystem.php +++ b/src/Magento/FunctionalTestingFramework/Config/Reader/Filesystem.php @@ -148,7 +148,7 @@ protected function readFiles($fileList) /** @var \Magento\FunctionalTestingFramework\Config\Dom $configMerger */ $configMerger = null; $debugLevel = MftfApplicationConfig::getConfig()->getDebugLevel(); - foreach ($fileList as $key => $content) { + foreach ($fileList as $content) { //check if file is empty and continue to next if it is if (!$this->verifyFileEmpty($content, $fileList->getFilename())) { continue; From d0e1304340a53abd5cfeb6dc43752e9078e6fd3c Mon Sep 17 00:00:00 2001 From: Adarsh Manickam <adarsh.apple@icloud.com> Date: Sun, 20 Jun 2021 16:52:32 +0530 Subject: [PATCH 629/888] Removed usage of AspectMock in AnnotationsCheckTest.php --- .../StaticCheck/AnnotationsCheckTest.php | 48 ++++++++----------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/StaticCheck/AnnotationsCheckTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/StaticCheck/AnnotationsCheckTest.php index 010a9e357..004955998 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/StaticCheck/AnnotationsCheckTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/StaticCheck/AnnotationsCheckTest.php @@ -3,32 +3,27 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace tests\unit\Magento\FunctionalTestFramework\StaticCheck; -use AspectMock\Test as AspectMock; use Magento\FunctionalTestingFramework\StaticCheck\AnnotationsCheck; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; -use tests\unit\Util\MagentoTestCase; use ReflectionClass; +use tests\unit\Util\MagentoTestCase; class AnnotationsCheckTest extends MagentoTestCase { /** @var AnnotationsCheck */ private $staticCheck; - /** @var ReflectionClass*/ + /** @var ReflectionClass */ private $staticCheckClass; public function setUp(): void { $this->staticCheck = new AnnotationsCheck(); - $this->staticCheckClass = new \ReflectionClass($this->staticCheck); - } - - public function tearDown(): void - { - AspectMock::clean(); + $this->staticCheckClass = new ReflectionClass($this->staticCheck); } public function testValidateRequiredAnnotationsNoError() @@ -56,11 +51,9 @@ public function testValidateRequiredAnnotationsNoError() ]; $expected = []; - // mock test object - $test = AspectMock::double( - TestObject::class, - ['getAnnotations' => $annotations, 'getName' => 'AnnotationsCheckTest'] - )->make(); + $test = $this->createMock(TestObject::class); + + $test->expects($this->once())->method('getAnnotations')->willReturn($annotations); $validateRequiredAnnotations = $this->staticCheckClass->getMethod('validateRequiredAnnotations'); $validateRequiredAnnotations->setAccessible(true); @@ -99,11 +92,10 @@ public function testValidateRequiredAnnotationsMissing() ] ]; - // mock test object - $test = AspectMock::double( - TestObject::class, - ['getAnnotations' => $annotations, 'getName' => 'AnnotationsCheckTest'] - )->make(); + $test = $this->createMock(TestObject::class); + + $test->expects($this->once())->method('getAnnotations')->willReturn($annotations); + $test->expects($this->once())->method('getName')->willReturn('AnnotationsCheckTest'); $validateRequiredAnnotations = $this->staticCheckClass->getMethod('validateRequiredAnnotations'); $validateRequiredAnnotations->setAccessible(true); @@ -137,11 +129,10 @@ public function testValidateRequiredAnnotationsMissingNoTestCaseId() ] ]; - // mock test object - $test = AspectMock::double( - TestObject::class, - ['getAnnotations' => $annotations, 'getName' => 'AnnotationsCheckTest'] - )->make(); + $test = $this->createMock(TestObject::class); + + $test->expects($this->once())->method('getAnnotations')->willReturn($annotations); + $test->expects($this->once())->method('getName')->willReturn('AnnotationsCheckTest'); $validateRequiredAnnotations = $this->staticCheckClass->getMethod('validateRequiredAnnotations'); $validateRequiredAnnotations->setAccessible(true); @@ -179,11 +170,10 @@ public function testValidateRequiredAnnotationsEmpty() ] ]; - // mock test object - $test = AspectMock::double( - TestObject::class, - ['getAnnotations' => $annotations, 'getName' => 'AnnotationsCheckTest'] - )->make(); + $test = $this->createMock(TestObject::class); + + $test->expects($this->once())->method('getAnnotations')->willReturn($annotations); + $test->expects($this->once())->method('getName')->willReturn('AnnotationsCheckTest'); $validateRequiredAnnotations = $this->staticCheckClass->getMethod('validateRequiredAnnotations'); $validateRequiredAnnotations->setAccessible(true); From 135fdf977d75e9912fe0125749667570a87f12a3 Mon Sep 17 00:00:00 2001 From: Medvediev <v.medvediev@atwix.com> Date: Wed, 23 Jun 2021 16:03:27 +0300 Subject: [PATCH 630/888] Eliminated Aspect Mock usage from ActionMergeUtilTest --- .../Test/Util/ActionMergeUtilTest.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php index 8c55210a4..099d8ef81 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php @@ -5,7 +5,6 @@ */ namespace tests\unit\Magento\FunctionalTestFramework\Test\Util; -use AspectMock\Test as AspectMock; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; @@ -110,8 +109,13 @@ public function testResolveActionStepEntityData() $mockDataObject = new EntityDataObject($dataObjectName, $dataObjectType, $mockData, null, null, null); // Set up mock DataObject Handler - $mockDOHInstance = AspectMock::double(DataObjectHandler::class, ['getObject' => $mockDataObject])->make(); - AspectMock::double(DataObjectHandler::class, ['getInstance' => $mockDOHInstance]); + $mockDOHInstance = $this->createMock(DataObjectHandler::class); + $mockDOHInstance->expects($this->any()) + ->method('getObject') + ->willReturn($mockDataObject); + $property = new \ReflectionProperty(DataObjectHandler::class, 'INSTANCE'); + $property->setAccessible(true); + $property->setValue($mockDOHInstance); // Create test object and action object $actionAttributes = [$userInputKey => $userInputValue]; From 64b0e5fe66f4ab9de1e26813f08f4427dd768983 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 23 Jun 2021 11:08:10 -0500 Subject: [PATCH 631/888] MQE-2750: Update composer dependencies to be PHP 8 compatible --- composer.json | 2 +- composer.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index a7393fc6d..5bdf4d580 100755 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ "sort-packages": true }, "require": { - "php": "^7.3||^8.0", + "php": "^7.3", "ext-curl": "*", "ext-dom": "*", "ext-intl": "*", diff --git a/composer.lock b/composer.lock index 01a5ff77f..501bd0f56 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "6703d4aff2c0f30efb681b320a9a2d2f", + "content-hash": "5628d42629fa152086085a4548ffc636", "packages": [ { "name": "allure-framework/allure-codeception", @@ -8449,7 +8449,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^7.3||^8.0", + "php": "^7.3", "ext-curl": "*", "ext-dom": "*", "ext-intl": "*", From b2eae3fabe95756d53b34ee1dd0c853dd651dc9c Mon Sep 17 00:00:00 2001 From: Adarsh Manickam <adarsh.apple@icloud.com> Date: Wed, 23 Jun 2021 21:52:09 +0530 Subject: [PATCH 632/888] Removed usage of AspectMock in DeprecatedEntityUsageCheckTest --- .../StaticCheck/DeprecatedEntityUsageCheckTest.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/StaticCheck/DeprecatedEntityUsageCheckTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/StaticCheck/DeprecatedEntityUsageCheckTest.php index dc339c8a3..bb4c96e89 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/StaticCheck/DeprecatedEntityUsageCheckTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/StaticCheck/DeprecatedEntityUsageCheckTest.php @@ -6,7 +6,6 @@ namespace tests\unit\Magento\FunctionalTestFramework\StaticCheck; -use AspectMock\Test as AspectMock; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\OperationDefinitionObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; use Magento\FunctionalTestingFramework\Page\Objects\ElementObject; @@ -34,11 +33,6 @@ public function setUp(): void $this->staticCheckClass = new \ReflectionClass($this->staticCheck); } - public function tearDown(): void - { - AspectMock::clean(); - } - public function testInvalidPathOption() { $input = $this->getMockBuilder(InputInterface::class) From 4b89a0301665b55129459f1b9c0749cab0aa5bd2 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 23 Jun 2021 14:05:31 -0500 Subject: [PATCH 633/888] MQE-2772: Updated monolog/monolog to ^2.2 --- composer.lock | 48 +++++++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/composer.lock b/composer.lock index 501bd0f56..cfc6e4f9e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "5628d42629fa152086085a4548ffc636", + "content-hash": "6e848e638ba77ff322a62b24136fb06a", "packages": [ { "name": "allure-framework/allure-codeception", @@ -2635,21 +2635,21 @@ }, { "name": "monolog/monolog", - "version": "1.26.0", + "version": "2.2.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "2209ddd84e7ef1256b7af205d0717fb62cfc9c33" + "reference": "1cb1cde8e8dd0f70cc0fe51354a59acad9302084" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/2209ddd84e7ef1256b7af205d0717fb62cfc9c33", - "reference": "2209ddd84e7ef1256b7af205d0717fb62cfc9c33", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/1cb1cde8e8dd0f70cc0fe51354a59acad9302084", + "reference": "1cb1cde8e8dd0f70cc0fe51354a59acad9302084", "shasum": "" }, "require": { - "php": ">=5.3.0", - "psr/log": "~1.0" + "php": ">=7.2", + "psr/log": "^1.0.1" }, "provide": { "psr/log-implementation": "1.0.0" @@ -2657,29 +2657,39 @@ "require-dev": { "aws/aws-sdk-php": "^2.4.9 || ^3.0", "doctrine/couchdb": "~1.0@dev", - "graylog2/gelf-php": "~1.0", + "elasticsearch/elasticsearch": "^7", + "graylog2/gelf-php": "^1.4.2", + "mongodb/mongodb": "^1.8", "php-amqplib/php-amqplib": "~2.4", "php-console/php-console": "^3.1.3", + "phpspec/prophecy": "^1.6.1", "phpstan/phpstan": "^0.12.59", - "phpunit/phpunit": "~4.5", - "ruflin/elastica": ">=0.90 <3.0", - "sentry/sentry": "^0.13", + "phpunit/phpunit": "^8.5", + "predis/predis": "^1.1", + "rollbar/rollbar": "^1.3", + "ruflin/elastica": ">=0.90 <7.0.1", "swiftmailer/swiftmailer": "^5.3|^6.0" }, "suggest": { "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", - "ext-mongo": "Allow sending log messages to a MongoDB server", + "ext-mbstring": "Allow to work properly with unicode symbols", + "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", - "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", "php-console/php-console": "Allow sending log messages to Google Chrome", "rollbar/rollbar": "Allow sending log messages to Rollbar", - "ruflin/elastica": "Allow sending log messages to an Elastic Search server", - "sentry/sentry": "Allow sending log messages to a Sentry server" + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" }, "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.x-dev" + } + }, "autoload": { "psr-4": { "Monolog\\": "src/Monolog" @@ -2693,11 +2703,11 @@ { "name": "Jordi Boggiano", "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" + "homepage": "https://seld.be" } ], "description": "Sends your logs to files, sockets, inboxes, databases and various web services", - "homepage": "http://github.com/Seldaek/monolog", + "homepage": "https://github.com/Seldaek/monolog", "keywords": [ "log", "logging", @@ -2705,7 +2715,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/1.26.0" + "source": "https://github.com/Seldaek/monolog/tree/2.2.0" }, "funding": [ { @@ -2717,7 +2727,7 @@ "type": "tidelift" } ], - "time": "2020-12-14T12:56:38+00:00" + "time": "2020-12-14T13:15:25+00:00" }, { "name": "mtdowling/jmespath.php", From 9484d8584d0b4593af50c7a9071963aedbcb258b Mon Sep 17 00:00:00 2001 From: silinmykola <m.silin@atwix.com> Date: Sun, 27 Jun 2021 18:19:48 +0300 Subject: [PATCH 634/888] 33294 eliminate aspectMock from allureHelperTest --- .../Allure/AllureHelperTest.php | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php index b009af5ff..9e0e8ca93 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php @@ -7,13 +7,12 @@ use Magento\FunctionalTestingFramework\Allure\AllureHelper; use Magento\FunctionalTestingFramework\Allure\Event\AddUniqueAttachmentEvent; +use PHPUnit\Framework\TestCase; use Yandex\Allure\Adapter\Allure; -use Yandex\Allure\Adapter\Event\AddAttachmentEvent; +use Yandex\Allure\Adapter\AllureException; use Yandex\Allure\Adapter\Event\StepFinishedEvent; use Yandex\Allure\Adapter\Event\StepStartedEvent; use Yandex\Allure\Adapter\Model\Attachment; -use AspectMock\Test as AspectMock; -use PHPUnit\Framework\TestCase; class AllureHelperTest extends TestCase { @@ -25,12 +24,11 @@ class AllureHelperTest extends TestCase public function tearDown(): void { Allure::setDefaultLifecycle(); - AspectMock::clean(); } /** - * AddAtachmentToStep should add an attachment to the current step - * @throws \Yandex\Allure\Adapter\AllureException + * AddAttachmentToStep should add an attachment to the current step + * @throws AllureException */ public function testAddAttachmentToStep() { @@ -52,7 +50,7 @@ public function testAddAttachmentToStep() /** * AddAttachmentToLastStep should add an attachment only to the last step - * @throws \Yandex\Allure\Adapter\AllureException + * @throws AllureException */ public function testAddAttachmentToLastStep() { @@ -88,14 +86,15 @@ public function testAddAttachmentToLastStep() /** * AddAttachment actions should have files with different attachment names - * @throws \Yandex\Allure\Adapter\AllureException + * @throws AllureException */ public function testAddAttachementUniqueName() { - $this->mockCopyFile(); $expectedData = "string"; $expectedCaption = "caption"; + $this->mockCopyFile($expectedData, $expectedCaption); + //Prepare Allure lifecycle Allure::lifecycle()->fire(new StepStartedEvent('firstStep')); @@ -112,23 +111,26 @@ public function testAddAttachementUniqueName() /** * Mock entire attachment writing mechanisms - * @throws \Exception */ public function mockAttachmentWriteEvent() { - AspectMock::double(AddUniqueAttachmentEvent::class, [ - "getAttachmentFileName" => self::MOCK_FILENAME - ]); + $this->createMock(AddUniqueAttachmentEvent::class) + ->expects($this->any()) + ->method('getAttachmentFileName') + ->willReturn(self::MOCK_FILENAME); } /** * Mock only file writing mechanism - * @throws \Exception + * @throws \ReflectionException */ - public function mockCopyFile() + public function mockCopyFile(string $expectedData, string $expectedCaption) { - AspectMock::double(AddUniqueAttachmentEvent::class, [ - "copyFile" => true - ]); + $addUniqueAttachmentEvent = new AddUniqueAttachmentEvent($expectedData, $expectedCaption); + $reflection = new \ReflectionClass(AddUniqueAttachmentEvent::class); + $reflectionMethod = $reflection->getMethod('copyFile'); + $reflectionMethod->setAccessible(true); + $output = $reflectionMethod->invoke($addUniqueAttachmentEvent); + $this->assertEquals(true, $output); } } From 3396029a043c714b07653317d0019c98b9284d3e Mon Sep 17 00:00:00 2001 From: silinmykola <m.silin@atwix.com> Date: Mon, 28 Jun 2021 13:20:18 +0300 Subject: [PATCH 635/888] 33292 replace AspectMock from BaseGenerateCommandTest --- .../Console/BaseGenerateCommandTest.php | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php index d2a58c0ff..ce43cde78 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php @@ -5,7 +5,6 @@ */ namespace tests\unit\Magento\FunctionalTestFramework\Console; -use AspectMock\Test as AspectMock; use PHPUnit\Framework\TestCase; use Magento\FunctionalTestingFramework\Console\BaseGenerateCommand; use Magento\FunctionalTestingFramework\Suite\Objects\SuiteObject; @@ -15,11 +14,6 @@ class BaseGenerateCommandTest extends TestCase { - public function tearDown(): void - { - AspectMock::clean(); - } - public function testOneTestOneSuiteConfig() { $testOne = new TestObject('Test1', [], [], []); @@ -182,13 +176,25 @@ public function testSuiteToTestSyntax() */ public function mockHandlers($testArray, $suiteArray) { - AspectMock::double(TestObjectHandler::class, ['initTestData' => ''])->make(); + $testObjectHandler = TestObjectHandler::getInstance(); + $reflection = new \ReflectionClass(TestObjectHandler::class); + $reflectionMethod = $reflection->getMethod('initTestData'); + $reflectionMethod->setAccessible(true); + $output = $reflectionMethod->invoke($testObjectHandler); + $this->assertEquals('', $output); + $handler = TestObjectHandler::getInstance(); $property = new \ReflectionProperty(TestObjectHandler::class, 'tests'); $property->setAccessible(true); $property->setValue($handler, $testArray); - AspectMock::double(SuiteObjectHandler::class, ['initSuiteData' => ''])->make(); + $suiteObjectHandler = SuiteObjectHandler::getInstance(); + $reflection = new \ReflectionClass(SuiteObjectHandler::class); + $reflectionMethod = $reflection->getMethod('initSuiteData'); + $reflectionMethod->setAccessible(true); + $output = $reflectionMethod->invoke($suiteObjectHandler); + $this->assertEquals('', $output); + $handler = SuiteObjectHandler::getInstance(); $property = new \ReflectionProperty(SuiteObjectHandler::class, 'suiteObjects'); $property->setAccessible(true); From 7550d4a80d8443fef2f27e7cafc05c93727a4b6f Mon Sep 17 00:00:00 2001 From: "andrii.zinkevych" <a.zinkevych@atwix.com> Date: Wed, 30 Jun 2021 23:59:13 +0300 Subject: [PATCH 636/888] 33307: Eliminated AspectMock usage from GenerationErrorHandlerTest.php --- .../Util/GenerationErrorHandlerTest.php | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/GenerationErrorHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/GenerationErrorHandlerTest.php index 70b354687..8d84dac7a 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/GenerationErrorHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/GenerationErrorHandlerTest.php @@ -3,10 +3,11 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace tests\unit\Magento\FunctionalTestFramework\Util; -use AspectMock\Test as AspectMock; +use ReflectionProperty; use tests\unit\Util\MagentoTestCase; use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; @@ -21,10 +22,10 @@ class GenerationErrorHandlerTest extends MagentoTestCase */ public function testGetDistinctErrors() { - AspectMock::double( - MftfApplicationConfig::class, - ['getPhase' => MftfApplicationConfig::GENERATION_PHASE] - ); + $this->createMock(MftfApplicationConfig::class) + ->expects($this->once()) + ->method('getPhase') + ->willReturn(MftfApplicationConfig::GENERATION_PHASE); $expectedAllErrors = [ 'test' => [ @@ -79,10 +80,10 @@ public function testGetDistinctErrors() */ public function testGetErrorsWithSameKey() { - AspectMock::double( - MftfApplicationConfig::class, - ['getPhase' => MftfApplicationConfig::GENERATION_PHASE] - ); + $this->createMock(MftfApplicationConfig::class) + ->expects($this->once()) + ->method('getPhase') + ->willReturn(MftfApplicationConfig::GENERATION_PHASE); $expectedAllErrors = [ 'test' => [ @@ -163,10 +164,10 @@ public function testGetErrorsWithSameKey() */ public function testGetAllErrorsDuplicate() { - AspectMock::double( - MftfApplicationConfig::class, - ['getPhase' => MftfApplicationConfig::GENERATION_PHASE] - ); + $this->createMock(MftfApplicationConfig::class) + ->expects($this->once()) + ->method('getPhase') + ->willReturn(MftfApplicationConfig::GENERATION_PHASE); $expectedAllErrors = [ 'test' => [ @@ -254,7 +255,7 @@ public function testGetAllErrorMessages($expectedErrMessages, $errors) $handler = GenerationErrorHandler::getInstance(); $handler->reset(); - $property = new \ReflectionProperty(GenerationErrorHandler::class, 'errors'); + $property = new ReflectionProperty(GenerationErrorHandler::class, 'errors'); $property->setAccessible(true); $property->setValue($handler, $errors); @@ -334,10 +335,10 @@ public function getAllErrorMessagesDataProvider() */ public function testResetError() { - AspectMock::double( - MftfApplicationConfig::class, - ['getPhase' => MftfApplicationConfig::GENERATION_PHASE] - ); + $this->createMock(MftfApplicationConfig::class) + ->expects($this->once()) + ->method('getPhase') + ->willReturn(MftfApplicationConfig::GENERATION_PHASE); GenerationErrorHandler::getInstance()->addError('something', 'some', 'error'); GenerationErrorHandler::getInstance()->addError('otherthing', 'other', 'error'); @@ -353,7 +354,7 @@ public function testResetError() public function tearDown(): void { - $property = new \ReflectionProperty(GenerationErrorHandler::class, 'instance'); + $property = new ReflectionProperty(GenerationErrorHandler::class, 'instance'); $property->setAccessible(true); $property->setValue(null); } From 8afc71a8dacb78adb0b69cbe71df4c1cb041596e Mon Sep 17 00:00:00 2001 From: "andrii.zinkevych" <a.zinkevych@atwix.com> Date: Thu, 1 Jul 2021 11:27:06 +0300 Subject: [PATCH 637/888] 33307: Fixed expects for method --- .../Util/GenerationErrorHandlerTest.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/GenerationErrorHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/GenerationErrorHandlerTest.php index 8d84dac7a..470d84041 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/GenerationErrorHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/GenerationErrorHandlerTest.php @@ -23,7 +23,6 @@ class GenerationErrorHandlerTest extends MagentoTestCase public function testGetDistinctErrors() { $this->createMock(MftfApplicationConfig::class) - ->expects($this->once()) ->method('getPhase') ->willReturn(MftfApplicationConfig::GENERATION_PHASE); @@ -81,7 +80,6 @@ public function testGetDistinctErrors() public function testGetErrorsWithSameKey() { $this->createMock(MftfApplicationConfig::class) - ->expects($this->once()) ->method('getPhase') ->willReturn(MftfApplicationConfig::GENERATION_PHASE); @@ -165,7 +163,6 @@ public function testGetErrorsWithSameKey() public function testGetAllErrorsDuplicate() { $this->createMock(MftfApplicationConfig::class) - ->expects($this->once()) ->method('getPhase') ->willReturn(MftfApplicationConfig::GENERATION_PHASE); @@ -336,7 +333,6 @@ public function getAllErrorMessagesDataProvider() public function testResetError() { $this->createMock(MftfApplicationConfig::class) - ->expects($this->once()) ->method('getPhase') ->willReturn(MftfApplicationConfig::GENERATION_PHASE); From e8bbf77f2b1639604560507c7733df21deee904c Mon Sep 17 00:00:00 2001 From: Karyna <k.tsymbal@atwix.com> Date: Thu, 1 Jul 2021 14:04:37 +0300 Subject: [PATCH 638/888] Eliminate AspectMock from FileStorageTest --- .../SecretStorage/FileStorageTest.php | 23 +++++++++++++------ .../Handlers/SecretStorage/FileStorage.php | 19 +++++++++------ 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/FileStorageTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/FileStorageTest.php index 62cb9798e..be97e04ab 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/FileStorageTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/FileStorageTest.php @@ -3,29 +3,38 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace tests\unit\Magento\FunctionalTestFramework\DataGenerator\Handlers\SecretStorage; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\SecretStorage\FileStorage; +use ReflectionClass; use tests\unit\Util\MagentoTestCase; -use AspectMock\Test as AspectMock; class FileStorageTest extends MagentoTestCase { - /** * Test basic encryption/decryption functionality in FileStorage class. */ - public function testBasicEncryptDecrypt() + public function testBasicEncryptDecrypt(): void { $testKey = 'magento/myKey'; $testValue = 'myValue'; - - AspectMock::double(FileStorage::class, [ - 'readInCredentialsFile' => ["$testKey=$testValue"] - ]); + $creds = ["$testKey=$testValue"]; $fileStorage = new FileStorage(); + $reflection = new ReflectionClass(FileStorage::class); + + // Emulate initialize() function result with the test credentials + $reflectionMethod = $reflection->getMethod('encryptCredFileContents'); + $reflectionMethod->setAccessible(true); + $secretData = $reflectionMethod->invokeArgs($fileStorage, [$creds]); + + // Set encrypted test credentials to the private 'secretData' property + $reflectionProperty = $reflection->getProperty('secretData'); + $reflectionProperty->setAccessible(true); + $reflectionProperty->setValue($fileStorage, $secretData); + $encryptedCred = $fileStorage->getEncryptedValue($testKey); // assert the value we've gotten is in fact not identical to our test value diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/FileStorage.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/FileStorage.php index be77a6de2..62ecfbedc 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/FileStorage.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/FileStorage.php @@ -21,14 +21,17 @@ class FileStorage extends BaseStorage private $secretData = []; /** - * FileStorage constructor + * Initialize secret data value which represents encrypted credentials + * + * @return void * @throws TestFrameworkException */ - public function __construct() + private function initialize(): void { - parent::__construct(); - $creds = $this->readInCredentialsFile(); - $this->secretData = $this->encryptCredFileContents($creds); + if (!$this->secretData) { + $creds = $this->readInCredentialsFile(); + $this->secretData = $this->encryptCredFileContents($creds); + } } /** @@ -36,10 +39,12 @@ public function __construct() * * @param string $key * @return string|null + * @throws TestFrameworkException */ - public function getEncryptedValue($key) + public function getEncryptedValue($key): ?string { - $value = null; + $this->initialize(); + // Check if secret is in cached array if (null !== ($value = parent::getEncryptedValue($key))) { return $value; From 888d7cde0f1e3ab1a7a85a18ce26963918e76cc7 Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Sun, 4 Jul 2021 19:01:53 +0300 Subject: [PATCH 639/888] MFTF-33305: Eliminate AspectMock from ObjectExtensionUtilTest --- .../Test/Util/ObjectExtensionUtilTest.php | 153 ++++++++++-------- .../unit/Util/MockModuleResolverBuilder.php | 33 ++-- 2 files changed, 112 insertions(+), 74 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ObjectExtensionUtilTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ObjectExtensionUtilTest.php index 6bf2da577..fc1893e0b 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ObjectExtensionUtilTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ObjectExtensionUtilTest.php @@ -3,32 +3,31 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace tests\unit\Magento\FunctionalTestFramework\Test\Util; -use AspectMock\Proxy\Verifier; -use AspectMock\Test as AspectMock; -use Magento\FunctionalTestingFramework\ObjectManager\ObjectManager; -use Magento\FunctionalTestingFramework\ObjectManagerFactory; +use Exception; +use Magento\FunctionalTestingFramework\ObjectManager; use Magento\FunctionalTestingFramework\Test\Handlers\ActionGroupObjectHandler; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; use Magento\FunctionalTestingFramework\Test\Parsers\ActionGroupDataParser; use Magento\FunctionalTestingFramework\Test\Parsers\TestDataParser; -use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; -use Monolog\Handler\TestHandler; -use Monolog\Logger; use PHPUnit\Framework\TestCase; +use ReflectionProperty; +use tests\unit\Util\MockModuleResolverBuilder; use tests\unit\Util\TestDataArrayBuilder; use tests\unit\Util\TestLoggingUtil; -use tests\unit\Util\MockModuleResolverBuilder; class ObjectExtensionUtilTest extends TestCase { /** - * Before test functionality + * Before test functionality. + * * @return void + * @throws Exception */ - public function setUp(): void + protected function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); $resolverMock = new MockModuleResolverBuilder(); @@ -36,7 +35,8 @@ public function setUp(): void } /** - * After class functionality + * After class functionality. + * * @return void */ public static function tearDownAfterClass(): void @@ -45,10 +45,12 @@ public static function tearDownAfterClass(): void } /** - * Tests generating a test that extends another test - * @throws \Exception + * Tests generating a test that extends another test. + * + * @return void + * @throws Exception */ - public function testGenerateExtendedTest() + public function testGenerateExtendedTest(): void { $mockActions = [ "mockStep" => ["nodeName" => "mockNode", "stepKey" => "mockStep"] @@ -86,10 +88,12 @@ public function testGenerateExtendedTest() } /** - * Tests generating a test that extends another test - * @throws \Exception + * Tests generating a test that extends another test. + * + * @return void + * @throws Exception */ - public function testGenerateExtendedWithHooks() + public function testGenerateExtendedWithHooks(): void { $mockBeforeHooks = [ "beforeHookAction" => ["nodeName" => "mockNodeBefore", "stepKey" => "mockStepBefore"] @@ -132,10 +136,12 @@ public function testGenerateExtendedWithHooks() } /** - * Tests generating a test that extends another test - * @throws \Exception + * Tests generating a test that extends another test. + * + * @return void + * @throws Exception */ - public function testExtendedTestNoParent() + public function testExtendedTestNoParent(): void { $testDataArrayBuilder = new TestDataArrayBuilder(); $mockExtendedTest = $testDataArrayBuilder @@ -158,10 +164,12 @@ public function testExtendedTestNoParent() } /** - * Tests generating a test that extends another test - * @throws \Exception + * Tests generating a test that extends another test. + * + * @return void + * @throws Exception */ - public function testExtendingExtendedTest() + public function testExtendingExtendedTest(): void { $testDataArrayBuilder = new TestDataArrayBuilder(); $mockParentTest = $testDataArrayBuilder @@ -200,10 +208,12 @@ public function testExtendingExtendedTest() } /** - * Tests generating an action group that extends another action group - * @throws \Exception + * Tests generating an action group that extends another action group. + * + * @return void + * @throws Exception */ - public function testGenerateExtendedActionGroup() + public function testGenerateExtendedActionGroup(): void { $mockSimpleActionGroup = [ "nodeName" => "actionGroup", @@ -259,10 +269,12 @@ public function testGenerateExtendedActionGroup() } /** - * Tests generating an action group that extends an action group that does not exist - * @throws \Exception + * Tests generating an action group that extends an action group that does not exist. + * + * @return void + * @throws Exception */ - public function testGenerateExtendedActionGroupNoParent() + public function testGenerateExtendedActionGroupNoParent(): void { $mockExtendedActionGroup = [ "nodeName" => "actionGroup", @@ -292,10 +304,12 @@ public function testGenerateExtendedActionGroupNoParent() } /** - * Tests generating an action group that extends another action group that is already extended - * @throws \Exception + * Tests generating an action group that extends another action group that is already extended. + * + * @return void + * @throws Exception */ - public function testExtendingExtendedActionGroup() + public function testExtendingExtendedActionGroup(): void { $mockParentActionGroup = [ "nodeName" => "actionGroup", @@ -333,7 +347,7 @@ public function testExtendingExtendedActionGroup() // parse and generate test object with mocked data try { ActionGroupObjectHandler::getInstance()->getObject('mockExtendedActionGroup'); - } catch (\Exception $e) { + } catch (Exception $e) { // validate log statement TestLoggingUtil::getInstance()->validateMockLogStatement( 'error', @@ -347,11 +361,12 @@ public function testExtendingExtendedActionGroup() } /** - * Tests generating a test that extends a skipped parent test + * Tests generating a test that extends a skipped parent test. * - * @throws \Exception + * @return void + * @throws Exception */ - public function testExtendedTestSkippedParent() + public function testExtendedTestSkippedParent(): void { $testDataArrayBuilder = new TestDataArrayBuilder(); $mockParentTest = $testDataArrayBuilder @@ -384,43 +399,55 @@ public function testExtendedTestSkippedParent() /** * Function used to set mock for parser return and force init method to run between tests. * - * @param array $testData - * @throws \Exception + * @param array|null $testData + * @param array|null $actionGroupData + * + * @return void + * @throws Exception */ - private function setMockTestOutput($testData = null, $actionGroupData = null) + private function setMockTestOutput(array $testData = null, array $actionGroupData = null): void { // clear test object handler value to inject parsed content - $property = new \ReflectionProperty(TestObjectHandler::class, 'testObjectHandler'); + $property = new ReflectionProperty(TestObjectHandler::class, 'testObjectHandler'); $property->setAccessible(true); $property->setValue(null); // clear test object handler value to inject parsed content - $property = new \ReflectionProperty(ActionGroupObjectHandler::class, 'instance'); + $property = new ReflectionProperty(ActionGroupObjectHandler::class, 'instance'); $property->setAccessible(true); $property->setValue(null); - $mockDataParser = AspectMock::double(TestDataParser::class, ['readTestData' => $testData])->make(); - $mockActionGroupParser = AspectMock::double( - ActionGroupDataParser::class, - ['readActionGroupData' => $actionGroupData] - )->make(); - $instance = AspectMock::double( - ObjectManager::class, - [ - 'create' => function ($className) use ( - $mockDataParser, - $mockActionGroupParser - ) { - if ($className == TestDataParser::class) { - return $mockDataParser; - } - if ($className == ActionGroupDataParser::class) { - return $mockActionGroupParser; + $mockDataParser = $this->createMock(TestDataParser::class); + $mockDataParser + ->method('readTestData') + ->willReturn($testData); + + $mockActionGroupParser = $this->createMock(ActionGroupDataParser::class); + $mockActionGroupParser + ->method('readActionGroupData') + ->willReturn($actionGroupData); + + $instance = $this->createMock(ObjectManager::class); + $instance + ->method('create') + ->will( + $this->returnCallback( + function ($className) use ($mockDataParser, $mockActionGroupParser) { + if ($className === TestDataParser::class) { + return $mockDataParser; + } + + if ($className === ActionGroupDataParser::class) { + return $mockActionGroupParser; + } + + return null; } - } - ] - )->make(); - // bypass the private constructor - AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); + ) + ); + // clear object manager value to inject expected instance + $property = new ReflectionProperty(ObjectManager::class, 'instance'); + $property->setAccessible(true); + $property->setValue($instance); } } diff --git a/dev/tests/unit/Util/MockModuleResolverBuilder.php b/dev/tests/unit/Util/MockModuleResolverBuilder.php index 0e1b6fc31..8bf30aa00 100644 --- a/dev/tests/unit/Util/MockModuleResolverBuilder.php +++ b/dev/tests/unit/Util/MockModuleResolverBuilder.php @@ -3,31 +3,35 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace tests\unit\Util; use AspectMock\Test as AspectMock; +use Exception; +use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\ObjectManager; -use Magento\FunctionalTestingFramework\ObjectManagerFactory; use Magento\FunctionalTestingFramework\Util\ModuleResolver; -use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use ReflectionProperty; class MockModuleResolverBuilder { /** - * Default paths for mock ModuleResolver + * Default paths for mock ModuleResolver. * * @var array */ private $defaultPaths = ['Magento_Module' => '/base/path/some/other/path/Magento/Module']; /** - * Mock ModuleResolver builder + * Mock ModuleResolver builder. + * + * @param array|null $paths * - * @param array $paths * @return void - * @throws \Exception + * @throws Exception */ - public function setup($paths = null) + public function setup(array $paths = null): void { if (empty($paths)) { $paths = $this->defaultPaths; @@ -35,9 +39,12 @@ public function setup($paths = null) $mockConfig = AspectMock::double(MftfApplicationConfig::class, ['forceGenerateEnabled' => false]); $instance = AspectMock::double(ObjectManager::class, ['create' => $mockConfig->make(), 'get' => null])->make(); - AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); + // clear object manager value to inject expected instance + $property = new ReflectionProperty(ObjectManager::class, 'instance'); + $property->setAccessible(true); + $property->setValue($instance); - $property = new \ReflectionProperty(ModuleResolver::class, 'instance'); + $property = new ReflectionProperty(ModuleResolver::class, 'instance'); $property->setAccessible(true); $property->setValue(null); @@ -51,10 +58,14 @@ public function setup($paths = null) ); $instance = AspectMock::double(ObjectManager::class, ['create' => $mockResolver->make(), 'get' => null]) ->make(); - AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); + + // clear object manager value to inject expected instance + $property = new ReflectionProperty(ObjectManager::class, 'instance'); + $property->setAccessible(true); + $property->setValue($instance); $resolver = ModuleResolver::getInstance(); - $property = new \ReflectionProperty(ModuleResolver::class, 'enabledModuleNameAndPaths'); + $property = new ReflectionProperty(ModuleResolver::class, 'enabledModuleNameAndPaths'); $property->setAccessible(true); $property->setValue($resolver, $paths); } From a016b291c60b62f064182db72de7ad0519b451ea Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Sun, 4 Jul 2021 20:19:47 +0300 Subject: [PATCH 640/888] MFTF-33301: Eliminated AspectMock usage for TestObjectHandlerTest --- .../Test/Handlers/TestObjectHandlerTest.php | 70 +++++++++++-------- 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php index 6d259cca2..b5d461db9 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php @@ -3,29 +3,32 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace tests\unit\Magento\FunctionalTestFramework\Test\Handlers; -use AspectMock\Test as AspectMock; - -use Magento\FunctionalTestingFramework\ObjectManager; -use Magento\FunctionalTestingFramework\ObjectManagerFactory; +use Exception; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Magento\FunctionalTestingFramework\Test\Objects\TestHookObject; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; -use Magento\FunctionalTestingFramework\Test\Parsers\TestDataParser; use Magento\FunctionalTestingFramework\Test\Util\TestObjectExtractor; +use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; use tests\unit\Util\MagentoTestCase; +use tests\unit\Util\MockModuleResolverBuilder; use tests\unit\Util\ObjectHandlerUtil; use tests\unit\Util\TestDataArrayBuilder; -use tests\unit\Util\MockModuleResolverBuilder; use tests\unit\Util\TestLoggingUtil; -use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; class TestObjectHandlerTest extends MagentoTestCase { - public function setUp(): void + /** + * Before test functionality. + * + * @return void + * @throws Exception + */ + protected function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); } @@ -33,9 +36,10 @@ public function setUp(): void /** * Basic test to validate array => test object conversion. * - * @throws \Exception + * @return void + * @throws Exception */ - public function testGetTestObject() + public function testGetTestObject(): void { // set up mock data $testDataArrayBuilder = new TestDataArrayBuilder(); @@ -53,7 +57,6 @@ public function testGetTestObject() // run object handler method $toh = TestObjectHandler::getInstance(); - $mockConfig = AspectMock::double(TestObjectHandler::class, ['initTestData' => false]); $actualTestObject = $toh->getObject($testDataArrayBuilder->testName); // perform asserts @@ -114,9 +117,11 @@ public function testGetTestObject() } /** - * Tests basic getting of a test that has a fileName + * Tests basic getting of a test that has a fileName. + * + * @return void */ - public function testGetTestWithFileName() + public function testGetTestWithFileName(): void { $this->markTestIncomplete('TODO'); } @@ -124,9 +129,10 @@ public function testGetTestWithFileName() /** * Tests the function used to get a series of relevant tests by group. * - * @throws \Exception + * @return void + * @throws Exception */ - public function testGetTestsByGroup() + public function testGetTestsByGroup(): void { // set up mock data with Exclude Test $includeTest = (new TestDataArrayBuilder()) @@ -155,11 +161,12 @@ public function testGetTestsByGroup() } /** - * Tests the function used to parse and determine a test's Module (used in allure Features annotation) + * Tests the function used to parse and determine a test's Module (used in allure Features annotation). * - * @throws \Exception + * @return void + * @throws Exception */ - public function testGetTestWithModuleName() + public function testGetTestWithModuleName(): void { // set up Test Data $moduleExpected = "SomeModuleName"; @@ -201,11 +208,12 @@ public function testGetTestWithModuleName() } /** - * getObject should throw exception if test extends from itself + * getObject should throw exception if test extends from itself. * - * @throws \Exception + * @return void + * @throws Exception */ - public function testGetTestObjectWithInvalidExtends() + public function testGetTestObjectWithInvalidExtends(): void { // set up Test Data $testOne = (new TestDataArrayBuilder()) @@ -230,11 +238,12 @@ public function testGetTestObjectWithInvalidExtends() } /** - * getAllObjects should throw exception if test extends from itself + * getAllObjects should throw exception if test extends from itself. * - * @throws \Exception + * @return void + * @throws Exception */ - public function testGetAllTestObjectsWithInvalidExtends() + public function testGetAllTestObjectsWithInvalidExtends(): void { // set up Test Data $testOne = (new TestDataArrayBuilder()) @@ -270,11 +279,12 @@ public function testGetAllTestObjectsWithInvalidExtends() } /** - * Validate test object when ENABLE_PAUSE is set to true + * Validate test object when ENABLE_PAUSE is set to true. * - * @throws \Exception + * @return void + * @throws Exception */ - public function testGetTestObjectWhenEnablePause() + public function testGetTestObjectWhenEnablePause(): void { // set up mock data putenv('ENABLE_PAUSE=true'); @@ -293,7 +303,6 @@ public function testGetTestObjectWhenEnablePause() // run object handler method $toh = TestObjectHandler::getInstance(); - $mockConfig = AspectMock::double(TestObjectHandler::class, ['initTestData' => false]); $actualTestObject = $toh->getObject($testDataArrayBuilder->testName); // perform asserts @@ -363,14 +372,13 @@ public function testGetTestObjectWhenEnablePause() } /** - * After method functionality + * After method functionality. * * @return void */ - public function tearDown(): void + protected function tearDown(): void { TestLoggingUtil::getInstance()->clearMockLoggingUtil(); - AspectMock::clean(); parent::tearDownAfterClass(); } } From e63c603700ac004e2f585218dcca3a6f1a7c21c8 Mon Sep 17 00:00:00 2001 From: "andrii.zinkevych" <a.zinkevych@atwix.com> Date: Sun, 4 Jul 2021 20:42:56 +0300 Subject: [PATCH 641/888] 33300: Eliminated AspectMock usage from SuiteObjectHandlerTest.php --- .../Suite/Handlers/SuiteObjectHandlerTest.php | 79 +++++++++++-------- 1 file changed, 47 insertions(+), 32 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/Handlers/SuiteObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/Handlers/SuiteObjectHandlerTest.php index 6f337b05c..f8f8d6b48 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/Handlers/SuiteObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/Handlers/SuiteObjectHandlerTest.php @@ -3,32 +3,29 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace tests\unit\Magento\FunctionalTestFramework\Suite\Handlers; -use AspectMock\Test as AspectMock; -use Magento\FunctionalTestingFramework\ObjectManager\ObjectManager; -use Magento\FunctionalTestingFramework\ObjectManagerFactory; +use Exception; +use Magento\FunctionalTestingFramework\ObjectManager; use Magento\FunctionalTestingFramework\Suite\Handlers\SuiteObjectHandler; use Magento\FunctionalTestingFramework\Suite\Parsers\SuiteDataParser; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; use Magento\FunctionalTestingFramework\Test\Parsers\TestDataParser; +use ReflectionProperty; use tests\unit\Util\MagentoTestCase; use tests\unit\Util\SuiteDataArrayBuilder; use tests\unit\Util\TestDataArrayBuilder; -use tests\unit\Util\MockModuleResolverBuilder; class SuiteObjectHandlerTest extends MagentoTestCase { - public function setUp(): void - { - $resolverMock = new MockModuleResolverBuilder(); - $resolverMock->setup(); - } - /** - * Tests basic parsing and accesors of suite object and suite object supporting classes + * Tests basic parsing and accessors of suite object and suite object supporting classes. + * + * @throws Exception */ - public function testGetSuiteObject() + public function testGetSuiteObject(): void { $suiteDataArrayBuilder = new SuiteDataArrayBuilder(); $mockData = $suiteDataArrayBuilder @@ -82,35 +79,53 @@ public function testGetSuiteObject() * Function used to set mock for parser return and force init method to run between tests. * * @param array $testData - * @throws \Exception + * @param array $suiteData + * + * @throws Exception */ - private function setMockTestAndSuiteParserOutput($testData, $suiteData) + private function setMockTestAndSuiteParserOutput(array $testData, array $suiteData): void { // clear test object handler value to inject parsed content - $property = new \ReflectionProperty(TestObjectHandler::class, 'testObjectHandler'); + $property = new ReflectionProperty(TestObjectHandler::class, 'testObjectHandler'); $property->setAccessible(true); $property->setValue(null); // clear suite object handler value to inject parsed content - $property = new \ReflectionProperty(SuiteObjectHandler::class, 'instance'); + $property = new ReflectionProperty(SuiteObjectHandler::class, 'instance'); $property->setAccessible(true); $property->setValue(null); - $mockDataParser = AspectMock::double(TestDataParser::class, ['readTestData' => $testData])->make(); - $mockSuiteDataParser = AspectMock::double(SuiteDataParser::class, ['readSuiteData' => $suiteData])->make(); - $instance = AspectMock::double( - ObjectManager::class, - ['create' => function ($clazz) use ($mockDataParser, $mockSuiteDataParser) { - if ($clazz == TestDataParser::class) { - return $mockDataParser; - } - - if ($clazz == SuiteDataParser::class) { - return $mockSuiteDataParser; - } - }] - )->make(); - // bypass the private constructor - AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); + $mockDataParser = $this->createMock(TestDataParser::class); + $mockDataParser + ->method('readTestData') + ->willReturn($testData); + + $mockSuiteDataParser = $this->createMock(SuiteDataParser::class); + $mockSuiteDataParser + ->method('readSuiteData') + ->willReturn($suiteData); + + $instance = $this->createMock(ObjectManager::class); + $instance + ->method('create') + ->will( + $this->returnCallback( + function ($clazz) use ($mockDataParser, $mockSuiteDataParser) { + if ($clazz == TestDataParser::class) { + return $mockDataParser; + } + + if ($clazz == SuiteDataParser::class) { + return $mockSuiteDataParser; + } + + return null; + } + ) + ); + + $property = new ReflectionProperty(ObjectManager::class, 'instance'); + $property->setAccessible(true); + $property->setValue($instance); } } From a45647689037e269484caa2a0457c03722d8bb18 Mon Sep 17 00:00:00 2001 From: "andrii.zinkevych" <a.zinkevych@atwix.com> Date: Sun, 4 Jul 2021 20:57:21 +0300 Subject: [PATCH 642/888] 33300: Added return type for methods --- .../Suite/Handlers/SuiteObjectHandlerTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/Handlers/SuiteObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/Handlers/SuiteObjectHandlerTest.php index f8f8d6b48..c672d20b7 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/Handlers/SuiteObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/Handlers/SuiteObjectHandlerTest.php @@ -23,6 +23,7 @@ class SuiteObjectHandlerTest extends MagentoTestCase /** * Tests basic parsing and accessors of suite object and suite object supporting classes. * + * @return void * @throws Exception */ public function testGetSuiteObject(): void @@ -81,6 +82,7 @@ public function testGetSuiteObject(): void * @param array $testData * @param array $suiteData * + * @return void * @throws Exception */ private function setMockTestAndSuiteParserOutput(array $testData, array $suiteData): void From 55709f004b9e7c2e979b3178e193a487d6aeb8cd Mon Sep 17 00:00:00 2001 From: "andrii.zinkevych" <a.zinkevych@atwix.com> Date: Sun, 4 Jul 2021 21:25:51 +0300 Subject: [PATCH 643/888] 33307: Removed not used mocked object --- .../Util/GenerationErrorHandlerTest.php | 34 ++++++------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/GenerationErrorHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/GenerationErrorHandlerTest.php index 470d84041..35ffd6d3b 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/GenerationErrorHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/GenerationErrorHandlerTest.php @@ -10,7 +10,6 @@ use ReflectionProperty; use tests\unit\Util\MagentoTestCase; use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; -use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; /** * Class GenerationErrorHandlerTest @@ -20,12 +19,8 @@ class GenerationErrorHandlerTest extends MagentoTestCase /** * Test get errors when all errors are distinct */ - public function testGetDistinctErrors() + public function testGetDistinctErrors():void { - $this->createMock(MftfApplicationConfig::class) - ->method('getPhase') - ->willReturn(MftfApplicationConfig::GENERATION_PHASE); - $expectedAllErrors = [ 'test' => [ 'Sameple1Test' => [ @@ -77,12 +72,8 @@ public function testGetDistinctErrors() /** * Test get errors when some errors have the same key */ - public function testGetErrorsWithSameKey() + public function testGetErrorsWithSameKey(): void { - $this->createMock(MftfApplicationConfig::class) - ->method('getPhase') - ->willReturn(MftfApplicationConfig::GENERATION_PHASE); - $expectedAllErrors = [ 'test' => [ 'Sameple1Test' => [ @@ -160,12 +151,8 @@ public function testGetErrorsWithSameKey() /** * Test get errors when some errors are duplicate */ - public function testGetAllErrorsDuplicate() + public function testGetAllErrorsDuplicate(): void { - $this->createMock(MftfApplicationConfig::class) - ->method('getPhase') - ->willReturn(MftfApplicationConfig::GENERATION_PHASE); - $expectedAllErrors = [ 'test' => [ 'Sameple1Test' => [ @@ -245,9 +232,11 @@ public function testGetAllErrorsDuplicate() * * @param string $expectedErrMessages * @param array $errors + * + * @return void * @dataProvider getAllErrorMessagesDataProvider */ - public function testGetAllErrorMessages($expectedErrMessages, $errors) + public function testGetAllErrorMessages(string $expectedErrMessages, array $errors): void { $handler = GenerationErrorHandler::getInstance(); $handler->reset(); @@ -265,7 +254,7 @@ public function testGetAllErrorMessages($expectedErrMessages, $errors) * * @return array */ - public function getAllErrorMessagesDataProvider() + public function getAllErrorMessagesDataProvider(): array { return [ ['', []], @@ -330,12 +319,8 @@ public function getAllErrorMessagesDataProvider() /** * Test reset */ - public function testResetError() + public function testResetError(): void { - $this->createMock(MftfApplicationConfig::class) - ->method('getPhase') - ->willReturn(MftfApplicationConfig::GENERATION_PHASE); - GenerationErrorHandler::getInstance()->addError('something', 'some', 'error'); GenerationErrorHandler::getInstance()->addError('otherthing', 'other', 'error'); GenerationErrorHandler::getInstance()->reset(); @@ -348,6 +333,9 @@ public function testResetError() $this->assertEquals([], GenerationErrorHandler::getInstance()->getErrorsByType('nothing')); } + /** + * @inheritdoc + */ public function tearDown(): void { $property = new ReflectionProperty(GenerationErrorHandler::class, 'instance'); From 648f8b2b8a9c5fcc81508fa1ebd64b2540f94226 Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Sun, 4 Jul 2021 21:34:17 +0300 Subject: [PATCH 644/888] MFTF-33302: Eliminated AspectMock from ActionGroupObjectTest --- .../Test/Objects/ActionGroupObjectTest.php | 131 +++++++++++++----- 1 file changed, 97 insertions(+), 34 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionGroupObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionGroupObjectTest.php index 4424989f8..60e97e79c 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionGroupObjectTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionGroupObjectTest.php @@ -3,10 +3,10 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace tests\unit\Magento\FunctionalTestFramework\Test\Objects; -use AspectMock\Test as AspectMock; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Page\Handlers\SectionObjectHandler; @@ -15,9 +15,10 @@ use Magento\FunctionalTestingFramework\Test\Objects\ActionGroupObject; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Magento\FunctionalTestingFramework\Test\Objects\ArgumentObject; -use tests\unit\Util\MagentoTestCase; +use ReflectionProperty; use tests\unit\Util\ActionGroupObjectBuilder; use tests\unit\Util\EntityDataObjectBuilder; +use tests\unit\Util\MagentoTestCase; use tests\unit\Util\TestLoggingUtil; class ActionGroupObjectTest extends MagentoTestCase @@ -25,18 +26,22 @@ class ActionGroupObjectTest extends MagentoTestCase const ACTION_GROUP_MERGE_KEY = 'TestKey'; /** - * Before test functionality + * Before test functionality. + * * @return void */ - public function setUp(): void + protected function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); } /** - * Tests a string literal in an action group + * Tests a string literal in an action group. + * + * @return void + * @throws TestReferenceException */ - public function testGetStepsWithDefaultCase() + public function testGetStepsWithDefaultCase(): void { $entity = (new EntityDataObjectBuilder()) ->withDataFields(['field1' => 'testValue']) @@ -48,9 +53,12 @@ public function testGetStepsWithDefaultCase() } /** - * Tests a data reference in an action group, replaced by the user + * Tests a data reference in an action group, replaced by the user. + * + * @return void + * @throws TestReferenceException */ - public function testGetStepsWithCustomArgs() + public function testGetStepsWithCustomArgs(): void { $this->setEntityObjectHandlerReturn(function ($entityName) { if ($entityName == "data2") { @@ -87,8 +95,11 @@ public function testGetStepsWithCustomArgs() /** * Tests a data reference in an action group replaced with a persisted reference. + * + * @return void + * @throws TestReferenceException */ - public function testGetStepsWithPersistedArgs() + public function testGetStepsWithPersistedArgs(): void { $actionGroupUnderTest = (new ActionGroupObjectBuilder()) ->withActionObjects([new ActionObject('action1', 'testAction', ['userInput' => '{{arg1.field2}}'])]) @@ -110,8 +121,11 @@ public function testGetStepsWithPersistedArgs() /** * Tests a data reference in an action group replaced with a data.field reference. + * + * @return void + * @throws TestReferenceException */ - public function testGetStepsWithNoFieldArg() + public function testGetStepsWithNoFieldArg(): void { $this->setEntityObjectHandlerReturn(function ($entityName) { if ($entityName == "data2") { @@ -130,8 +144,11 @@ public function testGetStepsWithNoFieldArg() /** * Tests a data reference in an action group resolved with its default state. + * + * @return void + * @throws TestReferenceException */ - public function testGetStepsWithNoArgs() + public function testGetStepsWithNoArgs(): void { $this->setEntityObjectHandlerReturn(function ($entityName) { if ($entityName == "data1") { @@ -149,8 +166,11 @@ public function testGetStepsWithNoArgs() /** * Tests a parameterized section reference in an action group resolved with user args. + * + * @return void + * @throws TestReferenceException */ - public function testGetStepsWithParameterizedArg() + public function testGetStepsWithParameterizedArg(): void { // Mock Entity Object Handler $this->setEntityObjectHandlerReturn(function ($entityName) { @@ -161,9 +181,14 @@ public function testGetStepsWithParameterizedArg() // mock the section object handler response $element = new ElementObject("element1", "textArea", ".selector {{var1}}", null, null, true); $section = new SectionObject("testSection", ["element1" => $element]); + $sectionInstance = $this->createMock(SectionObjectHandler::class); + $sectionInstance + ->method('getObject') + ->willReturn($section); // bypass the private constructor - $sectionInstance = AspectMock::double(SectionObjectHandler::class, ['getObject' => $section])->make(); - AspectMock::double(SectionObjectHandler::class, ['getInstance' => $sectionInstance]); + $property = new ReflectionProperty(SectionObjectHandler::class, 'INSTANCE'); + $property->setAccessible(true); + $property->setValue($sectionInstance); $actionGroupUnderTest = (new ActionGroupObjectBuilder()) ->withActionObjects( @@ -183,8 +208,11 @@ public function testGetStepsWithParameterizedArg() /** * Tests a parameterized section reference in an action group resolved with user simpleArgs. + * + * @return void + * @throws TestReferenceException */ - public function testGetStepsWithParameterizedSimpleArg() + public function testGetStepsWithParameterizedSimpleArg(): void { // Mock Entity Object Handler $this->setEntityObjectHandlerReturn(function ($entityName) { @@ -195,9 +223,15 @@ public function testGetStepsWithParameterizedSimpleArg() // mock the section object handler response $element = new ElementObject("element1", "textArea", ".selector {{var1}}", null, null, true); $section = new SectionObject("testSection", ["element1" => $element]); + + $sectionInstance = $this->createMock(SectionObjectHandler::class); + $sectionInstance + ->method('getObject') + ->willReturn($section); // bypass the private constructor - $sectionInstance = AspectMock::double(SectionObjectHandler::class, ['getObject' => $section])->make(); - AspectMock::double(SectionObjectHandler::class, ['getInstance' => $sectionInstance]); + $property = new ReflectionProperty(SectionObjectHandler::class, 'INSTANCE'); + $property->setAccessible(true); + $property->setValue($sectionInstance); $actionGroupUnderTest = (new ActionGroupObjectBuilder()) ->withActionObjects( @@ -221,8 +255,11 @@ public function testGetStepsWithParameterizedSimpleArg() /** * Tests a data reference in an action group resolved with a persisted reference used in another function. + * + * @return void + * @throws TestReferenceException */ - public function testGetStepsWithOuterScopePersistence() + public function testGetStepsWithOuterScopePersistence(): void { $actionGroupUnderTest = (new ActionGroupObjectBuilder()) ->withActionObjects([new ActionObject('action1', 'testAction', ['userInput' => '{{arg1.field1}}'])]) @@ -235,8 +272,10 @@ public function testGetStepsWithOuterScopePersistence() /** * Tests an action group with mismatching args. + * + * @return void */ - public function testExceptionOnMissingActions() + public function testExceptionOnMissingActions(): void { $actionGroupUnderTest = (new ActionGroupObjectBuilder()) ->withArguments([new ArgumentObject('arg1', null, 'entity')]) @@ -249,8 +288,10 @@ public function testExceptionOnMissingActions() /** * Tests an action group with missing args. + * + * @return void */ - public function testExceptionOnMissingArguments() + public function testExceptionOnMissingArguments(): void { $actionGroupUnderTest = (new ActionGroupObjectBuilder()) ->withArguments([new ArgumentObject('arg1', null, 'entity')]) @@ -262,10 +303,12 @@ public function testExceptionOnMissingArguments() } /** - * Tests the stepKey replacement with "stepKey + invocationKey" process filter - * Specific to actions that make it past a "require stepKey replacement" filter + * Tests the stepKey replacement with "stepKey + invocationKey" process filter. + * Specific to actions that make it past a "require stepKey replacement" filter. + * + * @return void */ - public function testStepKeyReplacementFilteredIn() + public function testStepKeyReplacementFilteredIn(): void { $createStepKey = "createDataStepKey"; $updateStepKey = "updateDataStepKey"; @@ -293,10 +336,12 @@ public function testStepKeyReplacementFilteredIn() } /** - * Tests the stepKey replacement with "stepKey + invocationKey" process filter - * Specific to actions that make are removed by a "require stepKey replacement" filter + * Tests the stepKey replacement with "stepKey + invocationKey" process filter. + * Specific to actions that make are removed by a "require stepKey replacement" filter. + * + * @return void */ - public function testStepKeyReplacementFilteredOut() + public function testStepKeyReplacementFilteredOut(): void { $clickStepKey = "clickStepKey"; $fillFieldStepKey = "fillFieldStepKey"; @@ -322,13 +367,26 @@ public function testStepKeyReplacementFilteredOut() * duration of a single test case. * * @param mixed $return + * * @return void */ - private function setEntityObjectHandlerReturn($return) + private function setEntityObjectHandlerReturn($return): void { - $instance = AspectMock::double(DataObjectHandler::class, ['getObject' => $return]) - ->make(); // bypass the private constructor - AspectMock::double(DataObjectHandler::class, ['getInstance' => $instance]); + $instance = $this->createMock(DataObjectHandler::class); + + if (is_callable($return)) { + $instance + ->method('getObject') + ->will($this->returnCallback($return)); + } else { + $instance + ->method('getObject') + ->willReturn($return); + } + // bypass the private constructor + $property = new ReflectionProperty(DataObjectHandler::class, 'INSTANCE'); + $property->setAccessible(true); + $property->setValue($instance); } /** @@ -337,11 +395,15 @@ private function setEntityObjectHandlerReturn($return) * * @param array $actions * @param array $expectedValue - * @param string $expectedMergeKey + * @param string|null $expectedMergeKey + * * @return void */ - private function assertOnMergeKeyAndActionValue($actions, $expectedValue, $expectedMergeKey = null) - { + private function assertOnMergeKeyAndActionValue( + array $actions, + array $expectedValue, + ?string $expectedMergeKey = null + ): void { $expectedMergeKey = $expectedMergeKey ?? ActionGroupObjectBuilder::DEFAULT_ACTION_OBJECT_NAME . self::ACTION_GROUP_MERGE_KEY; $this->assertArrayHasKey($expectedMergeKey, $actions); @@ -352,7 +414,8 @@ private function assertOnMergeKeyAndActionValue($actions, $expectedValue, $expec } /** - * After class functionality + * After class functionality. + * * @return void */ public static function tearDownAfterClass(): void From 6b12ed005adffb750d4a0fd74366769f75b13e53 Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Mon, 5 Jul 2021 11:24:47 +0300 Subject: [PATCH 645/888] MFTF-33303: Eliminated AspectMock usage from ActionObjectTest --- .../Test/Objects/ActionObjectTest.php | 210 +++++++++++++----- 1 file changed, 154 insertions(+), 56 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php index 8bf71d542..f3c75a073 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php @@ -3,21 +3,24 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace tests\unit\Magento\FunctionalTestFramework\Test\Objects; -use AspectMock\Test as AspectMock; +use Exception; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; +use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; +use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Page\Handlers\PageObjectHandler; +use Magento\FunctionalTestingFramework\Page\Handlers\SectionObjectHandler; use Magento\FunctionalTestingFramework\Page\Objects\ElementObject; use Magento\FunctionalTestingFramework\Page\Objects\PageObject; -use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; -use Magento\FunctionalTestingFramework\Page\Handlers\SectionObjectHandler; use Magento\FunctionalTestingFramework\Page\Objects\SectionObject; -use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; -use tests\unit\Util\TestLoggingUtil; +use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; +use ReflectionProperty; use tests\unit\Util\MagentoTestCase; +use tests\unit\Util\TestLoggingUtil; /** * Class ActionObjectTest @@ -25,36 +28,45 @@ class ActionObjectTest extends MagentoTestCase { /** - * Before test functionality + * Before test functionality. + * * @return void */ - public function setUp(): void + protected function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); } /** - * The order offset should be 0 when the action is instantiated with 'before' + * The order offset should be 0 when the action is instantiated with 'before'. + * + * @return void */ - public function testConstructOrderBefore() + public function testConstructOrderBefore(): void { $actionObject = new ActionObject('stepKey', 'type', [], null, 'before'); $this->assertEquals(0, $actionObject->getOrderOffset()); } /** - * The order offset should be 1 when the action is instantiated with 'after' + * The order offset should be 1 when the action is instantiated with 'after'. + * + * @return void */ - public function testConstructOrderAfter() + public function testConstructOrderAfter(): void { $actionObject = new ActionObject('stepKey', 'type', [], null, 'after'); $this->assertEquals(1, $actionObject->getOrderOffset()); } /** - * {{Section.element}} should be replaced with #theElementSelector + * {{Section.element}} should be replaced with #theElementSelector. + * + * @return void + * @throws TestReferenceException + * @throws XmlException */ - public function testResolveElementInSelector() + public function testResolveElementInSelector(): void { // Set up mocks $actionObject = new ActionObject('merge123', 'fillField', [ @@ -76,9 +88,13 @@ public function testResolveElementInSelector() } /** - * {{Section.element(param)}} should replace correctly with 'stringLiterals' + * {{Section.element(param)}} should replace correctly with 'stringLiterals'. + * + * @return void + * @throws TestReferenceException + * @throws XmlException */ - public function testResolveSelectorWithOneStringLiteral() + public function testResolveSelectorWithOneStringLiteral(): void { $actionObject = new ActionObject('key123', 'fillField', [ 'selector' => "{{SectionObject.elementObject('stringliteral')}}", @@ -99,9 +115,13 @@ public function testResolveSelectorWithOneStringLiteral() } /** - * {{Section.element(param)}} should replace correctly with {{data.key}} references + * {{Section.element(param)}} should replace correctly with {{data.key}} references. + * + * @return void + * @throws TestReferenceException + * @throws XmlException */ - public function testResolveSelectorWithOneDataReference() + public function testResolveSelectorWithOneDataReference(): void { $actionObject = new ActionObject('key123', 'fillField', [ 'selector' => "{{SectionObject.elementObject(dataObject.key)}}", @@ -128,9 +148,13 @@ public function testResolveSelectorWithOneDataReference() } /** - * {{Section.element(param)}} should replace correctly with $data.key$ references + * {{Section.element(param)}} should replace correctly with $data.key$ references. + * + * @return void + * @throws TestReferenceException + * @throws XmlException */ - public function testResolveSelectorWithOnePersistedReference() + public function testResolveSelectorWithOnePersistedReference(): void { $actionObject = new ActionObject('key123', 'fillField', [ 'selector' => '{{SectionObject.elementObject($data.key$)}}', @@ -154,8 +178,12 @@ public function testResolveSelectorWithOnePersistedReference() /** * {{Section.element(param1,param2,param3)}} should replace correctly with all 3 data types. + * + * @return void + * @throws TestReferenceException + * @throws XmlException */ - public function testResolveSelectorWithManyParams() + public function testResolveSelectorWithManyParams(): void { $actionObject = new ActionObject('key123', 'fillField', [ 'selector' => "{{SectionObject.elementObject('stringLiteral', data.key, \$data.key\$)}}", @@ -182,9 +210,13 @@ public function testResolveSelectorWithManyParams() } /** - * Timeout property on the ActionObject should be set if the ElementObject has a timeout + * Timeout property on the ActionObject should be set if the ElementObject has a timeout. + * + * @return void + * @throws TestReferenceException + * @throws XmlException */ - public function testTimeoutFromElement() + public function testTimeoutFromElement(): void { // Set up mocks $actionObject = new ActionObject('merge123', 'click', [ @@ -201,20 +233,27 @@ public function testTimeoutFromElement() } /** - * {{PageObject.url}} should be replaced with someUrl.html + * {{PageObject.url}} should be replaced with someUrl.html. * - * @throws /Exception + * @return void + * @throws Exception */ - public function testResolveUrl() + public function testResolveUrl(): void { // Set up mocks $actionObject = new ActionObject('merge123', 'amOnPage', [ 'url' => '{{PageObject.url}}' ]); $pageObject = new PageObject('PageObject', '/replacement/url.html', 'Test', [], false, "test"); - $instance = AspectMock::double(PageObjectHandler::class, ['getObject' => $pageObject]) - ->make(); // bypass the private constructor - AspectMock::double(PageObjectHandler::class, ['getInstance' => $instance]); + + $instance = $this->createMock(PageObjectHandler::class); + $instance + ->method('getObject') + ->willReturn($pageObject); + // bypass the private constructor + $property = new ReflectionProperty(PageObjectHandler::class, 'INSTANCE'); + $property->setAccessible(true); + $property->setValue($instance); // Call the method under test $actionObject->resolveReferences(); @@ -227,11 +266,12 @@ public function testResolveUrl() } /** - * {{PageObject}} should not be replaced and should elicit a warning in console + * {{PageObject}} should not be replaced and should elicit a warning in console. * - * @throws /Exception + * @return void + * @throws Exception */ - public function testResolveUrlWithNoAttribute() + public function testResolveUrlWithNoAttribute(): void { $this->expectException(TestReferenceException::class); @@ -241,36 +281,51 @@ public function testResolveUrlWithNoAttribute() ]); $pageObject = new PageObject('PageObject', '/replacement/url.html', 'Test', [], false, "test"); $pageObjectList = ["PageObject" => $pageObject]; - $instance = AspectMock::double( - PageObjectHandler::class, - ['getObject' => $pageObject, 'getAllObjects' => $pageObjectList] - )->make(); // bypass the private constructor - AspectMock::double(PageObjectHandler::class, ['getInstance' => $instance]); + + $instance = $this->createMock(PageObjectHandler::class); + $instance + ->method('getObject') + ->willReturn($pageObject); + $instance + ->method('getAllObjects') + ->willReturn($pageObjectList); + // bypass the private constructor + $property = new ReflectionProperty(PageObjectHandler::class, 'INSTANCE'); + $property->setAccessible(true); + $property->setValue($instance); // Call the method under test $actionObject->resolveReferences(); } /** - * {{PageObject.url(param)}} should be replaced + * {{PageObject.url(param)}} should be replaced. + * + * @return void */ - public function testResolveUrlWithOneParam() + public function testResolveUrlWithOneParam(): void { $this->markTestIncomplete('TODO'); } /** - * {{PageObject.url(param1,param2,param3)}} should be replaced + * {{PageObject.url(param1,param2,param3)}} should be replaced. + * + * @return void */ - public function testResolveUrlWithManyParams() + public function testResolveUrlWithManyParams(): void { $this->markTestIncomplete('TODO'); } /** - * {{EntityDataObject.key}} should be replaced with someDataValue + * {{EntityDataObject.key}} should be replaced with someDataValue. + * + * @return void + * @throws TestReferenceException + * @throws XmlException */ - public function testResolveDataInUserInput() + public function testResolveDataInUserInput(): void { // Set up mocks $actionObject = new ActionObject('merge123', 'fillField', [ @@ -294,9 +349,13 @@ public function testResolveDataInUserInput() } /** - * {{EntityDataObject.values}} should be replaced with ["value1","value2"] + * {{EntityDataObject.values}} should be replaced with ["value1","value2"]. + * + * @return void + * @throws TestReferenceException + * @throws XmlException */ - public function testResolveArrayData() + public function testResolveArrayData(): void { // Set up mocks $actionObject = new ActionObject('merge123', 'fillField', [ @@ -325,8 +384,12 @@ public function testResolveArrayData() /** * Action object should throw an exception if a reference to a parameterized selector has too few given args. + * + * @return void + * @throws TestReferenceException + * @throws XmlException */ - public function testTooFewArgumentException() + public function testTooFewArgumentException(): void { $this->expectException(TestReferenceException::class); @@ -343,8 +406,12 @@ public function testTooFewArgumentException() /** * Action object should throw an exception if a reference to a parameterized selector has too many given args. + * + * @return void + * @throws TestReferenceException + * @throws XmlException */ - public function testTooManyArgumentException() + public function testTooManyArgumentException(): void { $this->expectException(TestReferenceException::class); @@ -361,8 +428,12 @@ public function testTooManyArgumentException() /** * Action object should throw an exception if the timezone provided is not valid. + * + * @return void + * @throws TestReferenceException + * @throws XmlException */ - public function testInvalidTimezoneException() + public function testInvalidTimezoneException(): void { $this->expectException(TestReferenceException::class); @@ -374,23 +445,50 @@ public function testInvalidTimezoneException() $actionObject->resolveReferences(); } - private function mockSectionHandlerWithElement($elementObject) + /** + * Mock section handler with the specified ElementObject. + * + * @param ElementObject $elementObject + * + * @return void + * @throws Exception + */ + private function mockSectionHandlerWithElement(ElementObject $elementObject): void { $sectionObject = new SectionObject('SectionObject', ['elementObject' => $elementObject]); - $instance = AspectMock::double(SectionObjectHandler::class, ['getObject' => $sectionObject]) - ->make(); // bypass the private constructor - AspectMock::double(SectionObjectHandler::class, ['getInstance' => $instance]); + $instance = $this->createMock(SectionObjectHandler::class); + $instance + ->method('getObject') + ->willReturn($sectionObject); + // bypass the private constructor + $property = new ReflectionProperty(SectionObjectHandler::class, 'INSTANCE'); + $property->setAccessible(true); + $property->setValue($instance); } - private function mockDataHandlerWithData($dataObject) + /** + * Mock data handler with the specified EntityDataObject. + * + * @param EntityDataObject $dataObject + * + * @return void + * @throws Exception + */ + private function mockDataHandlerWithData(EntityDataObject $dataObject): void { - $dataInstance = AspectMock::double(DataObjectHandler::class, ['getObject' => $dataObject]) - ->make(); - AspectMock::double(DataObjectHandler::class, ['getInstance' => $dataInstance]); + $dataInstance = $this->createMock(DataObjectHandler::class); + $dataInstance + ->method('getObject') + ->willReturn($dataObject); + // bypass the private constructor + $property = new ReflectionProperty(DataObjectHandler::class, 'INSTANCE'); + $property->setAccessible(true); + $property->setValue($dataInstance); } /** - * After class functionality + * After class functionality. + * * @return void */ public static function tearDownAfterClass(): void From 73b6a91c20a9a67593e5be04083cd6348ba9d6a2 Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Mon, 5 Jul 2021 11:38:29 +0300 Subject: [PATCH 646/888] MFTF-33303: Clearing AspectMock mocking before each test --- dev/tests/unit/Util/MagentoTestCase.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dev/tests/unit/Util/MagentoTestCase.php b/dev/tests/unit/Util/MagentoTestCase.php index 7760acfc6..bb38a0b5c 100644 --- a/dev/tests/unit/Util/MagentoTestCase.php +++ b/dev/tests/unit/Util/MagentoTestCase.php @@ -19,6 +19,8 @@ public static function setUpBeforeClass(): void if (!self::fileExists(DOCS_OUTPUT_DIR)) { mkdir(DOCS_OUTPUT_DIR, 0755, true); } + // Should be used to clean AspectMock mocking before using PHPUnit mocking and Reflection. + AspectMock::clean(); parent::setUpBeforeClass(); } From ef4f9ea708446c2baff77304df1a0549b1ccaedf Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Mon, 5 Jul 2021 11:41:38 +0300 Subject: [PATCH 647/888] MFTF-33305: Clearing AspectMock mocking before each test --- dev/tests/unit/Util/MagentoTestCase.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dev/tests/unit/Util/MagentoTestCase.php b/dev/tests/unit/Util/MagentoTestCase.php index 7760acfc6..c34236fc1 100644 --- a/dev/tests/unit/Util/MagentoTestCase.php +++ b/dev/tests/unit/Util/MagentoTestCase.php @@ -19,6 +19,9 @@ public static function setUpBeforeClass(): void if (!self::fileExists(DOCS_OUTPUT_DIR)) { mkdir(DOCS_OUTPUT_DIR, 0755, true); } + // Should be used to clean AspectMock mocking before using PHPUnit mocking and Reflection. + AspectMock::clean(); + parent::setUpBeforeClass(); parent::setUpBeforeClass(); } From 172a1efc1b3e0c911be11c25c438f5f46c26c476 Mon Sep 17 00:00:00 2001 From: "andrii.zinkevych" <a.zinkevych@atwix.com> Date: Tue, 6 Jul 2021 12:05:40 +0300 Subject: [PATCH 648/888] 33309: Eliminated AspectMock usage from TestGeneratorTest.php --- .../Util/TestGeneratorTest.php | 86 +++++++++++-------- .../Util/Filesystem/CestFileCreatorUtil.php | 66 ++++++++++++++ .../Util/TestGenerator.php | 13 +-- 3 files changed, 121 insertions(+), 44 deletions(-) create mode 100644 src/Magento/FunctionalTestingFramework/Util/Filesystem/CestFileCreatorUtil.php diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php index 8817d89c7..3bc06de59 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php @@ -3,16 +3,18 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace tests\unit\Magento\FunctionalTestFramework\Util; -use AspectMock\Test as AspectMock; - +use Exception; +use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Filter\FilterList; -use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Magento\FunctionalTestingFramework\Test\Objects\TestHookObject; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; +use Magento\FunctionalTestingFramework\Util\Filesystem\CestFileCreatorUtil; +use ReflectionProperty; use tests\unit\Util\MagentoTestCase; use Magento\FunctionalTestingFramework\Util\TestGenerator; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; @@ -22,7 +24,7 @@ class TestGeneratorTest extends MagentoTestCase { /** - * Before method functionality + * Before method functionality. */ public function setUp(): void { @@ -30,35 +32,29 @@ public function setUp(): void } /** - * After method functionality + * After method functionality. * * @return void */ public function tearDown(): void { - AspectMock::clean(); GenerationErrorHandler::getInstance()->reset(); } /** * Basic test to check exceptions for incorrect entities. * - * @throws \Exception + * @return void + * @throws Exception */ - public function testEntityException() + public function testEntityException(): void { $actionObject = new ActionObject('fakeAction', 'comment', [ 'userInput' => '{{someEntity.entity}}' ]); $testObject = new TestObject("sampleTest", ["merge123" => $actionObject], [], [], "filename"); - - AspectMock::double(TestObjectHandler::class, ['initTestData' => '']); - $testGeneratorObject = TestGenerator::getInstance("", ["sampleTest" => $testObject]); - - AspectMock::double(TestGenerator::class, ['loadAllTestObjects' => ["sampleTest" => $testObject]]); - $testGeneratorObject->createAllTestFiles(null, []); // assert that no exception for createAllTestFiles and generation error is stored in GenerationErrorHandler @@ -69,11 +65,12 @@ public function testEntityException() } /** - * Tests that skipped tests do not have a fully generated body + * Tests that skipped tests do not have a fully generated body. * - * @throws \Magento\FunctionalTestingFramework\Exceptions\TestReferenceException + * @return void + * @throws TestReferenceException */ - public function testSkippedNoGeneration() + public function testSkippedNoGeneration(): void { $actionInput = 'fakeInput'; $actionObject = new ActionObject('fakeAction', 'comment', [ @@ -91,14 +88,22 @@ public function testSkippedNoGeneration() } /** - * Tests that skipped tests have a fully generated body when --allowSkipped is passed in + * Tests that skipped tests have a fully generated body when --allowSkipped is passed in. * - * @throws \Magento\FunctionalTestingFramework\Exceptions\TestReferenceException + * @return void + * @throws TestReferenceException */ - public function testAllowSkipped() + public function testAllowSkipped(): void { // Mock allowSkipped for TestGenerator - AspectMock::double(MftfApplicationConfig::class, ['allowSkipped' => true]); + $mockConfig = $this->createMock(MftfApplicationConfig::class); + $mockConfig->expects($this->any()) + ->method('allowSkipped') + ->willReturn(true); + + $property = new ReflectionProperty(MftfApplicationConfig::class, 'MFTF_APPLICATION_CONTEXT'); + $property->setAccessible(true); + $property->setValue($mockConfig); $actionInput = 'fakeInput'; $actionObject = new ActionObject('fakeAction', 'comment', [ @@ -128,17 +133,20 @@ public function testAllowSkipped() } /** - * Tests that TestGenerator createAllTestFiles correctly filters based on severity + * Tests that TestGenerator createAllTestFiles correctly filters based on severity. * - * @throws \Magento\FunctionalTestingFramework\Exceptions\TestReferenceException + * @return void + * @throws TestReferenceException */ - public function testFilter() + public function testFilter(): void { - // Mock filters for TestGenerator - AspectMock::double( - MftfApplicationConfig::class, - ['getFilterList' => new FilterList(['severity' => ["CRITICAL"]])] - ); + $mockConfig = $this->createMock(MftfApplicationConfig::class); + $fileList = new FilterList(['severity' => ["CRITICAL"]]); + $mockConfig->expects($this->once())->method('getFilterList')->willReturn($fileList); + + $property = new ReflectionProperty(MftfApplicationConfig::class, 'MFTF_APPLICATION_CONTEXT'); + $property->setAccessible(true); + $property->setValue($mockConfig); $actionInput = 'fakeInput'; $actionObject = new ActionObject('fakeAction', 'comment', [ @@ -161,16 +169,26 @@ public function testFilter() [], "filename" ); - AspectMock::double(TestGenerator::class, ['loadAllTestObjects' => ["sampleTest" => $test1, "test2" => $test2]]); // Mock createCestFile to return name of tests that testGenerator tried to create $generatedTests = []; - AspectMock::double(TestGenerator::class, ['createCestFile' => function ($arg1, $arg2) use (&$generatedTests) { - $generatedTests[$arg2] = true; - }]); + $cestFileCreatorUtil = $this->createMock(CestFileCreatorUtil::class); + $cestFileCreatorUtil->expects($this->once()) + ->method('create') + ->will( + $this->returnCallback( + function ($filename) use (&$generatedTests) { + $generatedTests[$filename] = true; + } + ) + ); + + $property = new ReflectionProperty(CestFileCreatorUtil::class, 'INSTANCE'); + $property->setAccessible(true); + $property->setValue($cestFileCreatorUtil); $testGeneratorObject = TestGenerator::getInstance("", ["sampleTest" => $test1, "test2" => $test2]); - $testGeneratorObject->createAllTestFiles(null, []); + $testGeneratorObject->createAllTestFiles(); // Ensure Test1 was Generated but not Test 2 $this->assertArrayHasKey('test1Cest', $generatedTests); diff --git a/src/Magento/FunctionalTestingFramework/Util/Filesystem/CestFileCreatorUtil.php b/src/Magento/FunctionalTestingFramework/Util/Filesystem/CestFileCreatorUtil.php new file mode 100644 index 000000000..a1c408359 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/Filesystem/CestFileCreatorUtil.php @@ -0,0 +1,66 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\FunctionalTestingFramework\Util\Filesystem; + +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; + +class CestFileCreatorUtil +{ + /** + * Singleton CestFileCreatorUtil Instance. + * + * @var CestFileCreatorUtil + */ + private static $INSTANCE; + + /** + * CestFileCreatorUtil constructor. + */ + private function __construct(){} + + /** + * Get CestFileCreatorUtil instance. + * + * @return CestFileCreatorUtil + */ + public static function getInstance() + { + if (self::$INSTANCE === null) { + return new self(); + } + + return self::$INSTANCE; + } + + /** + * Create a single PHP file containing the $cestPhp using the $filename. + * If the _generated directory doesn't exist it will be created. + * + * @param string $exportDirectory + * @param string $testPhp + * @param string $filename + * + * @return void + * @throws TestFrameworkException + */ + public function create(string $filename, string $exportDirectory, string $testPhp): void + { + DirSetupUtil::createGroupDir($exportDirectory); + $exportFilePath = $exportDirectory . DIRECTORY_SEPARATOR . $filename . '.php'; + $file = fopen($exportFilePath, 'w'); + + if (!$file) { + throw new TestFrameworkException( + sprintf('Could not open test file: "%s"', $exportFilePath) + ); + } + + fwrite($file, $testPhp); + fclose($file); + } +} diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index b019d5f2a..917b40809 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -22,6 +22,7 @@ use Magento\FunctionalTestingFramework\Test\Objects\TestHookObject; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; use Magento\FunctionalTestingFramework\Test\Util\BaseObjectExtractor; +use Magento\FunctionalTestingFramework\Util\Filesystem\CestFileCreatorUtil; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; use Magento\FunctionalTestingFramework\Util\Manifest\BaseTestManifest; use Magento\FunctionalTestingFramework\Test\Util\ActionObjectExtractor; @@ -207,21 +208,13 @@ private function loadAllTestObjects($testsToIgnore) * * @param string $testPhp * @param string $filename + * * @return void * @throws TestFrameworkException */ private function createCestFile(string $testPhp, string $filename) { - DirSetupUtil::createGroupDir($this->exportDirectory); - $exportFilePath = $this->exportDirectory . DIRECTORY_SEPARATOR . $filename . ".php"; - $file = fopen($exportFilePath, 'w'); - - if (!$file) { - throw new TestFrameworkException(sprintf('Could not open test file: "%s"', $exportFilePath)); - } - - fwrite($file, $testPhp); - fclose($file); + CestFileCreatorUtil::getInstance()->create($filename, $this->exportDirectory, $testPhp); } /** From ea1b727d52373f0b514cea3c352e4119127c4d88 Mon Sep 17 00:00:00 2001 From: "andrii.zinkevych" <a.zinkevych@atwix.com> Date: Tue, 6 Jul 2021 12:17:45 +0300 Subject: [PATCH 649/888] 33309: Fixed static-tests --- .../Util/Filesystem/CestFileCreatorUtil.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/Filesystem/CestFileCreatorUtil.php b/src/Magento/FunctionalTestingFramework/Util/Filesystem/CestFileCreatorUtil.php index a1c408359..b3c896ccb 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Filesystem/CestFileCreatorUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/Filesystem/CestFileCreatorUtil.php @@ -21,7 +21,9 @@ class CestFileCreatorUtil /** * CestFileCreatorUtil constructor. */ - private function __construct(){} + private function __construct() + { + } /** * Get CestFileCreatorUtil instance. @@ -41,9 +43,9 @@ public static function getInstance() * Create a single PHP file containing the $cestPhp using the $filename. * If the _generated directory doesn't exist it will be created. * + * @param string $filename * @param string $exportDirectory * @param string $testPhp - * @param string $filename * * @return void * @throws TestFrameworkException From d2182190782879c8c0322e24a10893322859f039 Mon Sep 17 00:00:00 2001 From: "andrii.zinkevych" <a.zinkevych@atwix.com> Date: Wed, 7 Jul 2021 17:57:37 +0300 Subject: [PATCH 650/888] 33308: Eliminated AspectMock usage from ModuleResolverTest.php --- .../Util/ModuleResolverTest.php | 1024 ++++++----------- .../Util/ModuleResolver.php | 186 +-- .../ModuleResolver/ModuleResolverService.php | 322 ++++++ 3 files changed, 682 insertions(+), 850 deletions(-) create mode 100644 src/Magento/FunctionalTestingFramework/Util/ModuleResolver/ModuleResolverService.php diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php index f43f82fe2..286044d8a 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php @@ -3,36 +3,35 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace tests\unit\Magento\FunctionalTestFramework\Util; -use AspectMock\Proxy\Verifier; -use AspectMock\Test as AspectMock; - +use Exception; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\Exceptions\FastFailException; -use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; -use Magento\FunctionalTestingFramework\ObjectManager; -use Magento\FunctionalTestingFramework\ObjectManagerFactory; -use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; +use Magento\FunctionalTestingFramework\Util\ModuleResolver\ModuleResolverService; use Magento\FunctionalTestingFramework\Util\ModuleResolver; +use PHPUnit\Framework\MockObject\MockObject; +use ReflectionProperty; use tests\unit\Util\MagentoTestCase; -use PHPUnit\Runner\Exception; use tests\unit\Util\TestLoggingUtil; class ModuleResolverTest extends MagentoTestCase { /** - * Before test functionality + * Before test functionality. + * * @return void */ - public function setUp(): void + protected function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); } /** - * After class functionality + * After class functionality. + * * @return void */ public static function tearDownAfterClass(): void @@ -41,43 +40,47 @@ public static function tearDownAfterClass(): void } /** - * Validate that Paths that are already set are returned - * @throws \Exception + * Validate that Paths that are already set are returned. + * + * @return void + * @throws Exception */ - public function testGetModulePathsAlreadySet() + public function testGetModulePathsAlreadySet(): void { - $this->setMockResolverClass(); $resolver = ModuleResolver::getInstance(); $this->setMockResolverProperties($resolver, ["example" . DIRECTORY_SEPARATOR . "paths"]); $this->assertEquals(["example" . DIRECTORY_SEPARATOR . "paths"], $resolver->getModulesPath()); } /** - * Validate paths are aggregated correctly - * @throws \Exception + * Validate paths are aggregated correctly. + * + * @return void + * @throws Exception */ - public function testGetModulePathsAggregate() + public function testGetModulePathsAggregate(): void { $this->mockForceGenerate(false); - $this->setMockResolverClass( - false, - null, - null, - null, - [ - 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'example' => ['example'], - 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'sample' => ['sample'], - ], - null, - [ - 'Magento_example' => 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'example', - 'Magento_sample' => 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'sample', - ], - null, - null, - [], - [] - ); + + $moduleResolverService = $this->createMock(ModuleResolverService::class); + $moduleResolverService->expects($this->any()) + ->method('getRegisteredModuleList') + ->willReturn( + [ + 'Magento_example' => 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'example', + 'Magento_sample' => 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'sample', + ] + ); + $moduleResolverService->expects($this->any()) + ->method('aggregateTestModulePaths') + ->willReturn( + [ + 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'example' => ['example'], + 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'sample' => ['sample'], + ] + ); + + $this->setMockResolverCreatorProperties($moduleResolverService); $resolver = ModuleResolver::getInstance(); $this->setMockResolverProperties($resolver, null, [0 => 'Magento_example', 1 => 'Magento_sample']); $this->assertEquals( @@ -90,141 +93,34 @@ public function testGetModulePathsAggregate() } /** - * Validate aggregateTestModulePaths() when module path part of DEV_TESTS - * - * @throws \Exception - */ - public function testAggregateTestModulePathsDevTests() - { - $origin = TESTS_MODULE_PATH; - $modulePath = ModuleResolver::DEV_TESTS . DIRECTORY_SEPARATOR . "Magento"; - putenv("TESTS_MODULE_PATH=$modulePath"); - - $this->mockForceGenerate(false); - $mockResolver = $this->setMockResolverClass( - true, - [], - null, - null, - [], - [], - [], - null, - null, - [], - [], - null, - function ($arg) { - return $arg; - }, - function ($arg) { - return $arg; - } - ); - $resolver = ModuleResolver::getInstance(); - $this->setMockResolverProperties($resolver, null, null); - $this->assertEquals( - [], - $resolver->getModulesPath() - ); - - $mockResolver->verifyNeverInvoked('globRelevantPaths', [$modulePath, '']); - - putenv("TESTS_MODULE_PATH=$origin"); - } - - /** - * Validate correct path locations are fed into globRelevantPaths - * @throws \Exception - */ - public function testGetModulePathsLocations() - { - // clear test object handler value to inject parsed content - $property = new \ReflectionProperty(ModuleResolver::class, 'instance'); - $property->setAccessible(true); - $property->setValue(null); - - $this->mockForceGenerate(false); - $mockResolver = $this->setMockResolverClass( - true, - [], - null, - null, - [], - [], - [], - null, - null, - [], - [], - null, - function ($arg) { - return $arg; - }, - function ($arg) { - return $arg; - } - ); - $resolver = ModuleResolver::getInstance(); - $this->setMockResolverProperties($resolver, null, null); - $this->assertEquals( - [], - $resolver->getModulesPath() - ); - - // Define the Module paths from app/code - $magentoBaseCodePath = MAGENTO_BP; - - // Define the Module paths from default TESTS_MODULE_PATH - $modulePath = defined('TESTS_MODULE_PATH') ? TESTS_MODULE_PATH : TESTS_BP; - - $mockResolver->verifyInvoked('globRelevantPaths', [$modulePath, '']); - $mockResolver->verifyInvoked( - 'globRelevantPaths', - [$magentoBaseCodePath . DIRECTORY_SEPARATOR . "vendor" , 'Test' . DIRECTORY_SEPARATOR .'Mftf'] - ); - $mockResolver->verifyInvoked( - 'globRelevantPaths', - [ - $magentoBaseCodePath . DIRECTORY_SEPARATOR . "app" . DIRECTORY_SEPARATOR . "code", - 'Test' . DIRECTORY_SEPARATOR .'Mftf' - ] - ); - } - - /** - * Validate aggregateTestModulePathsFromComposerJson + * Validate aggregateTestModulePathsFromComposerJson. * - * @throws \Exception + * @return void + * @throws Exception */ - public function testAggregateTestModulePathsFromComposerJson() + public function testAggregateTestModulePathsFromComposerJson(): void { $this->mockForceGenerate(false); - $this->setMockResolverClass( - false, - null, // getEnabledModules - null, // applyCustomMethods - null, // globRelevantWrapper - [], // relevantPath - null, // getCustomModulePaths - null, // getRegisteredModuleList - null, // aggregateTestModulePathsFromComposerJson - [], // aggregateTestModulePathsFromComposerInstaller - [ - 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathA' => - [ - 'Magento_ModuleA', - 'Magento_ModuleB' - ], - 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathB' => - [ - 'Magento_ModuleB', - 'Magento_ModuleC' - ], - ], // getComposerJsonTestModulePaths - [] // getComposerInstalledTestModulePaths - ); + $moduleResolverService = $this->createMock(ModuleResolverService::class); + $moduleResolverService->expects($this->any()) + ->method('getComposerJsonTestModulePaths') + ->willReturn( + [ + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathA' => + [ + 'Magento_ModuleA', + 'Magento_ModuleB' + ], + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathB' => + [ + 'Magento_ModuleB', + 'Magento_ModuleC' + ], + ] + ); + + $this->setMockResolverCreatorProperties($moduleResolverService); $resolver = ModuleResolver::getInstance(); $this->setMockResolverProperties($resolver, null, [0 => 'Magento_ModuleB', 1 => 'Magento_ModuleC']); $this->assertEquals( @@ -236,90 +132,33 @@ public function testAggregateTestModulePathsFromComposerJson() } /** - * Validate getComposerJsonTestModulePaths with paths invocation - * - * @throws \Exception - */ - public function testGetComposerJsonTestModulePathsForPathInvocation() - { - $this->mockForceGenerate(false); - $mockResolver = $this->setMockResolverClass( - false, - [], - null, - null, - [], - null, - null, - null, - null, - [], - [] - ); - - $resolver = ModuleResolver::getInstance(); - $this->setMockResolverProperties($resolver, null, null); - $this->assertEquals( - [], - $resolver->getModulesPath() - ); - - // Expected dev tests path - $expectedSearchPaths[] = MAGENTO_BP - . DIRECTORY_SEPARATOR - . 'dev' - . DIRECTORY_SEPARATOR - . 'tests' - . DIRECTORY_SEPARATOR - . 'acceptance' - . DIRECTORY_SEPARATOR - . 'tests' - . DIRECTORY_SEPARATOR - . 'functional'; - - // Expected test module path - $testModulePath = defined('TESTS_MODULE_PATH') ? TESTS_MODULE_PATH : TESTS_BP; - - if (array_search($testModulePath, $expectedSearchPaths) === false) { - $expectedSearchPaths[] = $testModulePath; - } - - $mockResolver->verifyInvoked('getComposerJsonTestModulePaths', [$expectedSearchPaths]); - } - - /** - * Validate aggregateTestModulePathsFromComposerInstaller + * Validate aggregateTestModulePathsFromComposerInstaller. * - * @throws \Exception + * @return void + * @throws Exception */ - public function testAggregateTestModulePathsFromComposerInstaller() + public function testAggregateTestModulePathsFromComposerInstaller(): void { $this->mockForceGenerate(false); - $this->setMockResolverClass( - false, - null, - null, - null, - [], - null, - null, - null, - null, - [], - [ - 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathA' => - [ - 'Magento_ModuleA', - 'Magento_ModuleB' - ], - 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathB' => - [ - 'Magento_ModuleB', - 'Magento_ModuleC' - ], - ] - ); - + $moduleResolverService = $this->createMock(ModuleResolverService::class); + $moduleResolverService->expects($this->any()) + ->method('getComposerInstalledTestModulePaths') + ->willReturn( + [ + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathA' => + [ + 'Magento_ModuleA', + 'Magento_ModuleB' + ], + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathB' => + [ + 'Magento_ModuleB', + 'Magento_ModuleC' + ], + ] + ); + + $this->setMockResolverCreatorProperties($moduleResolverService); $resolver = ModuleResolver::getInstance(); $this->setMockResolverProperties( $resolver, @@ -336,93 +175,62 @@ public function testAggregateTestModulePathsFromComposerInstaller() } /** - * Validate getComposerInstalledTestModulePaths with paths invocation - * - * @throws \Exception - */ - public function testGetComposerInstalledTestModulePathsForPathInvocation() - { - $this->mockForceGenerate(false); - $mockResolver = $this->setMockResolverClass( - false, - [], - null, - null, - [], - null, - null, - null, - null, - [], - [] - ); - - $resolver = ModuleResolver::getInstance(); - $this->setMockResolverProperties($resolver, null, null); - $this->assertEquals( - [], - $resolver->getModulesPath() - ); - - // Expected file path - $expectedSearchPath = MAGENTO_BP . DIRECTORY_SEPARATOR . 'composer.json'; - - $mockResolver->verifyInvoked('getComposerInstalledTestModulePaths', [$expectedSearchPath]); - } - - /** - * Validate mergeModulePaths() and flipAndFilterModulePathsArray() + * Validate mergeModulePaths() and flipAndFilterModulePathsArray(). * - * @throws \Exception + * @return void + * @throws Exception */ - public function testMergeFlipAndFilterModulePathsNoForceGenerate() + public function testMergeFlipAndFilterModulePathsNoForceGenerate(): void { $this->mockForceGenerate(false); - $this->setMockResolverClass( - false, - null, - null, - null, - null, - null, - null, - null, - null, - [ - 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathA' => - [ - 'Magento_ModuleA' - ], - 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathB' => - [ - 'Magento_ModuleB' - ], - ], - [ - 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathD' => - [ - 'Magento_ModuleD' - ], - 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathE' => - [ - 'Magento_ModuleE' - ], - 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathC' => - [ - 'Magento_ModuleC', - 'Magento_ModuleB', - ], - ], - [ - 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'example' => ['Magento_Example'], - 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'sample' => ['Magento_Sample'], - 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'path1' => ['Magento_Path1'], - 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'path2' => ['Magento_Path2'], - 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'path3' => ['Magento_Path3'], - 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'path4' => ['Magento_Path4'], - ] - ); - + $moduleResolverService = $this->createMock(ModuleResolverService::class); + $moduleResolverService->expects($this->any()) + ->method('getComposerJsonTestModulePaths') + ->willReturn( + [ + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathA' => + [ + 'Magento_ModuleA' + ], + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathB' => + [ + 'Magento_ModuleB' + ] + ] + ); + $moduleResolverService->expects($this->any()) + ->method('getComposerInstalledTestModulePaths') + ->willReturn( + [ + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathD' => + [ + 'Magento_ModuleD' + ], + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathE' => + [ + 'Magento_ModuleE' + ], + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathC' => + [ + 'Magento_ModuleC', + 'Magento_ModuleB', + ] + ] + ); + $moduleResolverService->expects($this->any()) + ->method('aggregateTestModulePaths') + ->willReturn( + [ + 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'example' => ['Magento_Example'], + 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'sample' => ['Magento_Sample'], + 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'path1' => ['Magento_Path1'], + 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'path2' => ['Magento_Path2'], + 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'path3' => ['Magento_Path3'], + 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'path4' => ['Magento_Path4'] + ] + ); + + $this->setMockResolverCreatorProperties($moduleResolverService); $resolver = ModuleResolver::getInstance(); $this->setMockResolverProperties( $resolver, @@ -454,55 +262,59 @@ public function testMergeFlipAndFilterModulePathsNoForceGenerate() } /** - * Validate mergeModulePaths() and flipAndSortModulePathsArray() + * Validate mergeModulePaths() and flipAndSortModulePathsArray(). * - * @throws \Exception + * @return void + * @throws Exception */ - public function testMergeFlipNoSortModulePathsNoForceGenerate() + public function testMergeFlipNoSortModulePathsNoForceGenerate(): void { $this->mockForceGenerate(false); - $this->setMockResolverClass( - false, - null, - null, - null, - null, - null, - null, - null, - null, - [ - 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR - . 'Magento' . DIRECTORY_SEPARATOR . 'ModuleA' => - [ - 'Magento_ModuleA' - ], - 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR - . 'Magento' . DIRECTORY_SEPARATOR . 'ModuleBC' => - [ - 'Magento_ModuleB', - 'Magento_ModuleC', - ], - ], - [ - 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR - . 'Magento' . DIRECTORY_SEPARATOR . 'ModuleCD' => - [ - 'Magento_ModuleC', - 'Magento_ModuleD' - ], - 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR - . 'Magento' . DIRECTORY_SEPARATOR . 'ModuleE' => - [ - 'Magento_ModuleE' - ], - ], - [ - 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'example' => ['Magento_Example'], - 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'sample' => ['Magento_Sample'], - ] - ); - + $moduleResolverService = $this->createMock(ModuleResolverService::class); + $moduleResolverService->expects($this->any()) + ->method('getComposerJsonTestModulePaths') + ->willReturn( + [ + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR + . 'Magento' . DIRECTORY_SEPARATOR . 'ModuleA' => + [ + 'Magento_ModuleA' + ], + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR + . 'Magento' . DIRECTORY_SEPARATOR . 'ModuleBC' => + [ + 'Magento_ModuleB', + 'Magento_ModuleC', + ] + ] + ); + $moduleResolverService->expects($this->any()) + ->method('getComposerInstalledTestModulePaths') + ->willReturn( + [ + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR + . 'Magento' . DIRECTORY_SEPARATOR . 'ModuleCD' => + [ + 'Magento_ModuleC', + 'Magento_ModuleD' + ], + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR + . 'Magento' . DIRECTORY_SEPARATOR . 'ModuleE' => + [ + 'Magento_ModuleE' + ] + ] + ); + $moduleResolverService->expects($this->any()) + ->method('aggregateTestModulePaths') + ->willReturn( + [ + 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'example' => ['Magento_Example'], + 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'sample' => ['Magento_Sample'] + ] + ); + + $this->setMockResolverCreatorProperties($moduleResolverService); $resolver = ModuleResolver::getInstance(); $this->setMockResolverProperties( $resolver, @@ -529,55 +341,59 @@ public function testMergeFlipNoSortModulePathsNoForceGenerate() } /** - * Validate mergeModulePaths() and flipAndSortModulePathsArray() + * Validate mergeModulePaths() and flipAndSortModulePathsArray(). * - * @throws \Exception + * @return void + * @throws Exception */ - public function testMergeFlipAndSortModulePathsForceGenerate() + public function testMergeFlipAndSortModulePathsForceGenerate(): void { $this->mockForceGenerate(true); - $this->setMockResolverClass( - false, - null, - null, - null, - null, - null, - null, - null, - null, - [ - 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR + $moduleResolverService = $this->createMock(ModuleResolverService::class); + $moduleResolverService->expects($this->any()) + ->method('getComposerJsonTestModulePaths') + ->willReturn( + [ + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'Magento' . DIRECTORY_SEPARATOR . 'ModuleA' => - [ - 'Magento_ModuleA' - ], - 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR + [ + 'Magento_ModuleA' + ], + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'Magento' . DIRECTORY_SEPARATOR . 'ModuleBC' => - [ - 'Magento_ModuleB', - 'Magento_ModuleC', - ], - ], - [ - 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR + [ + 'Magento_ModuleB', + 'Magento_ModuleC', + ] + ] + ); + $moduleResolverService->expects($this->any()) + ->method('getComposerInstalledTestModulePaths') + ->willReturn( + [ + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'Magento' . DIRECTORY_SEPARATOR . 'ModuleCD' => - [ - 'Magento_ModuleC', - 'Magento_ModuleD' - ], - 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR + [ + 'Magento_ModuleC', + 'Magento_ModuleD' + ], + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'Magento' . DIRECTORY_SEPARATOR . 'ModuleD' => - [ - 'Magento_ModuleD' - ], - ], - [ - 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'example' => ['Magento_Example'], - 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'sample' => ['Magento_Sample'], - ] - ); - + [ + 'Magento_ModuleD' + ] + ] + ); + $moduleResolverService->expects($this->any()) + ->method('aggregateTestModulePaths') + ->willReturn( + [ + 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'example' => ['Magento_Example'], + 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'sample' => ['Magento_Sample'] + ] + ); + + $this->setMockResolverCreatorProperties($moduleResolverService); $resolver = ModuleResolver::getInstance(); $this->setMockResolverProperties( $resolver, @@ -609,45 +425,45 @@ public function testMergeFlipAndSortModulePathsForceGenerate() } /** - * Validate logging warning in flipAndFilterModulePathsArray() + * Validate logging warning in flipAndFilterModulePathsArray(). * - * @throws \Exception + * @return void + * @throws Exception */ - public function testMergeFlipAndFilterModulePathsWithLogging() + public function testMergeFlipAndFilterModulePathsWithLogging(): void { $this->mockForceGenerate(false); - $this->setMockResolverClass( - false, - null, - null, - null, - [], - null, - null, - null, - null, - [ - 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathA' => - [ - 'Magento_ModuleA' - ], - 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathB' => - [ - 'Magento_ModuleB' - ], - ], - [ - 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathA' => - [ - 'Magento_ModuleA' - ], - 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathB' => - [ - 'Magento_ModuleC' - ], - ] - ); - + $moduleResolverService = $this->createMock(ModuleResolverService::class); + $moduleResolverService->expects($this->any()) + ->method('getComposerJsonTestModulePaths') + ->willReturn( + [ + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathA' => + [ + 'Magento_ModuleA' + ], + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathB' => + [ + 'Magento_ModuleB' + ] + ] + ); + $moduleResolverService->expects($this->any()) + ->method('getComposerInstalledTestModulePaths') + ->willReturn( + [ + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathA' => + [ + 'Magento_ModuleA' + ], + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathB' => + [ + 'Magento_ModuleC' + ] + ] + ); + + $this->setMockResolverCreatorProperties($moduleResolverService); $resolver = ModuleResolver::getInstance(); $this->setMockResolverProperties( $resolver, @@ -666,37 +482,30 @@ public function testMergeFlipAndFilterModulePathsWithLogging() ], $resolver->getModulesPath() ); + $warnMsg = 'Path: composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR; $warnMsg .= 'pathA is ignored by ModuleResolver. ' . PHP_EOL . 'Path: composer' . DIRECTORY_SEPARATOR; $warnMsg .= 'json' . DIRECTORY_SEPARATOR . 'pathA is set for Module: Magento_ModuleA' . PHP_EOL; - TestLoggingUtil::getInstance()->validateMockLogStatement( - 'warning', - $warnMsg, - [] - ); + TestLoggingUtil::getInstance()->validateMockLogStatement('warning', $warnMsg, []); } /** - * Validate custom modules are added - * @throws \Exception + * Validate custom modules are added. + * + * @return void + * @throws Exception */ - public function testApplyCustomModuleMethods() + public function testApplyCustomModuleMethods(): void { - $this->setMockResolverClass( - false, - null, - null, - null, - [], - [ 'Magento_Module' => 'otherPath'], - null, - null, - null, - [], - [] - ); + $this->mockForceGenerate(true); + $moduleResolverService = $this->createMock(ModuleResolverService::class); + $moduleResolverService->expects($this->any()) + ->method('getCustomModulePaths') + ->willReturn(['Magento_Module' => 'otherPath']); + + $this->setMockResolverCreatorProperties($moduleResolverService); $resolver = ModuleResolver::getInstance(); - $this->setMockResolverProperties($resolver, null, null, null); + $this->setMockResolverProperties($resolver); $this->assertEquals(['otherPath'], $resolver->getModulesPath()); TestLoggingUtil::getInstance()->validateMockLogStatement( 'info', @@ -709,35 +518,24 @@ public function testApplyCustomModuleMethods() * Validate blocklisted modules are removed * Module paths are sorted according to module name in alphabetically ascending order * - * @throws \Exception + * @throws Exception */ - public function testGetModulePathsBlocklist() + public function testGetModulePathsBlocklist(): void { - $this->setMockResolverClass( - false, - null, - null, - null, - [], - null, - null, - null, - null, - [], - [], - [ - 'thisPath/some/path4' => ['Some_Module4'], - 'devTests/Magento/path3' => ['Magento_Module3'], - 'appCode/Magento/path2' => ['Magento_Module2'], - 'vendor/amazon/path1' => ['Amazon_Module1'], - ], - function ($arg) { - return $arg; - }, - function ($arg) { - return $arg; - } - ); + $this->mockForceGenerate(true); + $moduleResolverService = $this->createMock(ModuleResolverService::class); + $moduleResolverService->expects($this->any()) + ->method('aggregateTestModulePaths') + ->willReturn( + [ + 'thisPath/some/path4' => ['Some_Module4'], + 'devTests/Magento/path3' => ['Magento_Module3'], + 'appCode/Magento/path2' => ['Magento_Module2'], + 'vendor/amazon/path1' => ['Amazon_Module1'] + ] + ); + + $this->setMockResolverCreatorProperties($moduleResolverService); $resolver = ModuleResolver::getInstance(); $this->setMockResolverProperties($resolver, null, null, ['Magento_Module3']); $this->assertEquals( @@ -752,68 +550,33 @@ function ($arg) { } /** - * Validate that getEnabledModules errors out when no Admin Token is returned and --force is false - * @throws \Exception + * Validate that getEnabledModules errors out when no Admin Token is returned and --force is false. + * + * @return void + * @throws Exception */ - public function testGetModulePathsNoAdminToken() + public function testGetModulePathsNoAdminToken(): void { // Set --force to false $this->mockForceGenerate(false); - - // Mock ModuleResolver and $enabledModulesPath - $this->setMockResolverClass( - false, - null, - ["example" . DIRECTORY_SEPARATOR . "paths"], - [], - null, - null, - null, - null, - null, - [], - [] - ); $resolver = ModuleResolver::getInstance(); - $this->setMockResolverProperties($resolver, null, null); + $this->setMockResolverProperties($resolver); - // Cannot Generate if no --force was passed in and no Admin Token is returned succesfully + // Cannot Generate if no --force was passed in and no Admin Token is returned successfully $this->expectException(FastFailException::class); $resolver->getModulesPath(); } - /** - * Validates that getAdminToken is not called when --force is enabled - */ - public function testGetAdminTokenNotCalledWhenForce() - { - // Set --force to true - $this->mockForceGenerate(true); - - // Mock ModuleResolver and applyCustomModuleMethods() - $mockResolver = $this->setMockResolverClass(); - $resolver = ModuleResolver::getInstance(); - $this->setMockResolverProperties($resolver, null, null); - $resolver->getModulesPath(); - $mockResolver->verifyNeverInvoked("getAdminToken"); - - // verifyNeverInvoked does not add to assertion count - $this->addToAssertionCount(1); - } - /** * Verify the getAdminToken method returns throws an exception if ENV is not fully loaded. */ - public function testGetAdminTokenWithMissingEnv() + public function testGetAdminTokenWithMissingEnv(): void { - // Set --force to true + // Set --force to false $this->mockForceGenerate(false); // Unset env unset($_ENV['MAGENTO_ADMIN_USERNAME']); - - // Mock ModuleResolver and applyCustomModuleMethods() - $mockResolver = $this->setMockResolverClass(); $resolver = ModuleResolver::getInstance(); // Expect exception @@ -824,13 +587,10 @@ public function testGetAdminTokenWithMissingEnv() /** * Verify the getAdminToken method returns throws an exception if Token was bad. */ - public function testGetAdminTokenWithBadResponse() + public function testGetAdminTokenWithBadResponse(): void { - // Set --force to true + // Set --force to false $this->mockForceGenerate(false); - - // Mock ModuleResolver and applyCustomModuleMethods() - $mockResolver = $this->setMockResolverClass(); $resolver = ModuleResolver::getInstance(); // Expect exception @@ -839,153 +599,71 @@ public function testGetAdminTokenWithBadResponse() } /** - * Function used to set mock for parser return and force init method to run between tests. - * - * @param string $mockToken - * @param array $mockGetEnabledModules - * @param string[] $mockApplyCustomMethods - * @param string[] $mockGlobRelevantWrapper - * @param string[] $mockRelevantPaths - * @param string[] $mockGetCustomModulePaths - * @param string[] $mockGetRegisteredModuleList - * @param string[] $mockAggregateTestModulePathsFromComposerJson - * @param string[] $mockAggregateTestModulePathsFromComposerInstaller - * @param string[] $mockGetComposerJsonTestModulePaths - * @param string[] $mockGetComposerInstalledTestModulePaths - * @param string[] $mockAggregateTestModulePaths - * @param string[] $mockNormalizeModuleNames - * @param string[] $mockFlipAndFilterModulePathsArray - * @param string[] $mockFlipAndSortModulePathsArray - * @throws \Exception - * @return Verifier ModuleResolver double - */ - private function setMockResolverClass( - $mockToken = null, - $mockGetEnabledModules = null, - $mockApplyCustomMethods = null, - $mockGlobRelevantWrapper = null, - $mockRelevantPaths = null, - $mockGetCustomModulePaths = null, - $mockGetRegisteredModuleList = null, - $mockAggregateTestModulePathsFromComposerJson = null, - $mockAggregateTestModulePathsFromComposerInstaller = null, - $mockGetComposerJsonTestModulePaths = null, - $mockGetComposerInstalledTestModulePaths = null, - $mockAggregateTestModulePaths = null, - $mockNormalizeModuleNames = null, - $mockFlipAndFilterModulePathsArray = null, - $mockFlipAndSortModulePathsArray = null - ) { - $property = new \ReflectionProperty(ModuleResolver::class, 'instance'); - $property->setAccessible(true); - $property->setValue(null); - - $mockMethods = []; - if (isset($mockToken)) { - $mockMethods['getAdminToken'] = $mockToken; - } - if (isset($mockGetEnabledModules)) { - $mockMethods['getEnabledModules'] = $mockGetEnabledModules; - } - if (isset($mockApplyCustomMethods)) { - $mockMethods['applyCustomModuleMethods'] = $mockApplyCustomMethods; - } - if (isset($mockGlobRelevantWrapper)) { - $mockMethods['globRelevantWrapper'] = $mockGlobRelevantWrapper; - } - if (isset($mockRelevantPaths)) { - $mockMethods['globRelevantPaths'] = $mockRelevantPaths; - } - if (isset($mockGetCustomModulePaths)) { - $mockMethods['getCustomModulePaths'] = $mockGetCustomModulePaths; - } - if (isset($mockGetRegisteredModuleList)) { - $mockMethods['getRegisteredModuleList'] = $mockGetRegisteredModuleList; - } - if (isset($mockAggregateTestModulePathsFromComposerJson)) { - $mockMethods['aggregateTestModulePathsFromComposerJson'] = $mockAggregateTestModulePathsFromComposerJson; - } - if (isset($mockAggregateTestModulePathsFromComposerInstaller)) { - $mockMethods['aggregateTestModulePathsFromComposerInstaller'] = - $mockAggregateTestModulePathsFromComposerInstaller; - } - if (isset($mockGetComposerJsonTestModulePaths)) { - $mockMethods['getComposerJsonTestModulePaths'] = $mockGetComposerJsonTestModulePaths; - } - if (isset($mockGetComposerInstalledTestModulePaths)) { - $mockMethods['getComposerInstalledTestModulePaths'] = $mockGetComposerInstalledTestModulePaths; - } - if (isset($mockAggregateTestModulePaths)) { - $mockMethods['aggregateTestModulePaths'] = $mockAggregateTestModulePaths; - } - if (isset($mockNormalizeModuleNames)) { - $mockMethods['normalizeModuleNames'] = $mockNormalizeModuleNames; - } - if (isset($mockFlipAndFilterModulePathsArray)) { - $mockMethods['flipAndFilterModulePathsArray'] = $mockFlipAndFilterModulePathsArray; - } - if (isset($mockFlipAndSortModulePathsArray)) { - $mockMethods['flipAndSortModulePathsArray'] = $mockFlipAndSortModulePathsArray; - } - $mockResolver = AspectMock::double( - ModuleResolver::class, - $mockMethods - ); - $instance = AspectMock::double( - ObjectManager::class, - ['create' => $mockResolver->make(), 'get' => null] - )->make(); - // bypass the private constructor - AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); - - return $mockResolver; - } - - /** - * Function used to set mock for Resolver properties + * Function used to set mock for Resolver properties. * * @param ModuleResolver $instance * @param array $mockPaths * @param array $mockModules * @param array $mockBlocklist - * @throws \Exception + * + * @return void + * @throws Exception */ - private function setMockResolverProperties($instance, $mockPaths = null, $mockModules = null, $mockBlocklist = []) - { - $property = new \ReflectionProperty(ModuleResolver::class, 'enabledModulePaths'); + private function setMockResolverProperties( + ModuleResolver $instance, + $mockPaths = null, + $mockModules = null, + $mockBlocklist = [] + ): void { + $property = new ReflectionProperty(ModuleResolver::class, 'enabledModulePaths'); $property->setAccessible(true); $property->setValue($instance, $mockPaths); - $property = new \ReflectionProperty(ModuleResolver::class, 'enabledModules'); + $property = new ReflectionProperty(ModuleResolver::class, 'enabledModules'); $property->setAccessible(true); $property->setValue($instance, $mockModules); - $property = new \ReflectionProperty(ModuleResolver::class, 'moduleBlocklist'); + $property = new ReflectionProperty(ModuleResolver::class, 'moduleBlocklist'); $property->setAccessible(true); $property->setValue($instance, $mockBlocklist); } + /** + * Function used to set mock for ResolverCreator properties. + * + * @param MockObject $moduleResolverService + * + * @return void + */ + private function setMockResolverCreatorProperties(MockObject $moduleResolverService): void + { + $property = new ReflectionProperty(ModuleResolverService::class, 'INSTANCE'); + $property->setAccessible(true); + $property->setValue($moduleResolverService); + } + /** * Mocks MftfApplicationConfig->forceGenerateEnabled() - * @param $forceGenerate - * @throws \Exception + * @param bool $forceGenerate + * * @return void + * @throws Exception */ - private function mockForceGenerate($forceGenerate) + private function mockForceGenerate(bool $forceGenerate): void { - $mockConfig = AspectMock::double( - MftfApplicationConfig::class, - ['forceGenerateEnabled' => $forceGenerate] - ); - $instance = AspectMock::double( - ObjectManager::class, - ['create' => $mockConfig->make(), 'get' => null] - )->make(); - AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); + $mockConfig = $this->createMock(MftfApplicationConfig::class); + $mockConfig->expects($this->once()) + ->method('forceGenerateEnabled') + ->willReturn($forceGenerate); + + $property = new ReflectionProperty(MftfApplicationConfig::class, 'MFTF_APPLICATION_CONTEXT'); + $property->setAccessible(true); + $property->setValue($mockConfig); } /** - * After method functionality + * After method functionality. + * * @return void */ protected function tearDown(): void @@ -994,7 +672,5 @@ protected function tearDown(): void if (!isset($_ENV['MAGENTO_ADMIN_USERNAME'])) { $_ENV['MAGENTO_ADMIN_USERNAME'] = "admin"; } - - AspectMock::clean(); } } diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index b9a74de84..09ff90dfc 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -8,6 +8,7 @@ use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\ModuleResolver\ModuleResolverService; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; @@ -136,27 +137,6 @@ class ModuleResolver 'SampleTests', 'SampleTemplates' ]; - /** - * Registered module list in magento system under test - * - * @var array - */ - private $registeredModuleList = []; - - /** - * Composer json based test module paths - * - * @var array - */ - private $composerJsonModulePaths = null; - - /** - * Composer installed test module paths - * - * @var array - */ - private $composerInstalledModulePaths = null; - /** * Get ModuleResolver instance. * @@ -311,90 +291,7 @@ protected function getModuleAllowlist() */ private function aggregateTestModulePaths() { - $allModulePaths = []; - - // Define the Module paths from magento bp - $magentoBaseCodePath = FilePathFormatter::format(MAGENTO_BP, false); - - // Define the Module paths from default TESTS_MODULE_PATH - $modulePath = defined('TESTS_MODULE_PATH') ? TESTS_MODULE_PATH : TESTS_BP; - $modulePath = FilePathFormatter::format($modulePath, false); - - // If $modulePath is DEV_TESTS path, we don't need to search by pattern - if (strpos($modulePath, self::DEV_TESTS) === false) { - $codePathsToPattern[$modulePath] = ''; - } - - $vendorCodePath = DIRECTORY_SEPARATOR . self::VENDOR; - $codePathsToPattern[$magentoBaseCodePath . $vendorCodePath] = self::TEST_MFTF_PATTERN; - - $appCodePath = DIRECTORY_SEPARATOR . self::APP_CODE; - $codePathsToPattern[$magentoBaseCodePath . $appCodePath] = self::TEST_MFTF_PATTERN; - - foreach ($codePathsToPattern as $codePath => $pattern) { - $allModulePaths = array_merge_recursive($allModulePaths, $this->globRelevantPaths($codePath, $pattern)); - } - - return $allModulePaths; - } - - /** - * Function which takes a code path and a pattern and determines if there are any matching subdir paths. Matches - * are returned as an associative array keyed by basename (the last dir excluding pattern) to an array containing - * the matching path. - * - * @param string $testPath - * @param string $pattern - * @return array - */ - private function globRelevantPaths($testPath, $pattern) - { - $modulePaths = []; - $relevantPaths = []; - - if (file_exists($testPath)) { - $relevantPaths = $this->globRelevantWrapper($testPath, $pattern); - } - - foreach ($relevantPaths as $codePath) { - // Reduce magento/app/code/Magento/AdminGws/<pattern> to magento/app/code/Magento/AdminGws to read symlink - // Symlinks must be resolved otherwise they will not match Magento's filepath to the module - $potentialSymlink = str_replace(DIRECTORY_SEPARATOR . $pattern, "", $codePath); - if (is_link($potentialSymlink)) { - $codePath = realpath($potentialSymlink) . DIRECTORY_SEPARATOR . $pattern; - } - $mainModName = basename(str_replace($pattern, '', $codePath)); - $modulePaths[$codePath] = [$mainModName]; - - if (MftfApplicationConfig::getConfig()->verboseEnabled()) { - LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->debug( - "including module", - ['module' => $mainModName, 'path' => $codePath] - ); - } - } - - return $modulePaths; - } - - /** - * Glob wrapper for globRelevantPaths function - * - * @param string $testPath - * @param string $pattern - * @return array - */ - private static function globRelevantWrapper($testPath, $pattern) - { - if ($pattern == "") { - return glob($testPath . '*' . DIRECTORY_SEPARATOR . '*' . $pattern); - } - $subDirectory = "*" . DIRECTORY_SEPARATOR; - $directories = glob($testPath . $subDirectory . $pattern, GLOB_ONLYDIR); - foreach (glob($testPath . $subDirectory, GLOB_ONLYDIR) as $dir) { - $directories = array_merge_recursive($directories, self::globRelevantWrapper($dir, $pattern)); - } - return $directories; + return ModuleResolverService::getInstance()->aggregateTestModulePaths(); } /** @@ -428,23 +325,14 @@ private function aggregateTestModulePathsFromComposerJson() * Retrieve all module code paths that have test module composer json files * * @param array $codePaths + * * @return array */ private function getComposerJsonTestModulePaths($codePaths) { - if (null !== $this->composerJsonModulePaths) { - return $this->composerJsonModulePaths; - } - try { - $this->composerJsonModulePaths = []; - $resolver = new ComposerModuleResolver(); - $this->composerJsonModulePaths = $resolver->getTestModulesFromPaths($codePaths); - } catch (TestFrameworkException $e) { - } - - return $this->composerJsonModulePaths; + return ModuleResolverService::getInstance()->getComposerJsonTestModulePaths($codePaths); } - + /** * Aggregate all code paths with composer installed test modules * @@ -462,22 +350,13 @@ private function aggregateTestModulePathsFromComposerInstaller() /** * Retrieve composer installed test module code paths * - * @params string $composerFile + * @param string $composerFile + * * @return array */ private function getComposerInstalledTestModulePaths($composerFile) { - if (null !== $this->composerInstalledModulePaths) { - return $this->composerInstalledModulePaths; - } - try { - $this->composerInstalledModulePaths = []; - $resolver = new ComposerModuleResolver(); - $this->composerInstalledModulePaths = $resolver->getComposerInstalledTestModules($composerFile); - } catch (TestFrameworkException $e) { - } - - return $this->composerInstalledModulePaths; + return ModuleResolverService::getInstance()->getComposerInstalledTestModulePaths($composerFile); } /** @@ -739,18 +618,7 @@ private function removeBlocklistModules($modulePaths) */ private function getCustomModulePaths() { - $customModulePaths = []; - $paths = getenv(self::CUSTOM_MODULE_PATHS); - - if (!$paths) { - return $customModulePaths; - } - - foreach (explode(',', $paths) as $path) { - $customModulePaths[$this->findVendorAndModuleNameFromPath(trim($path))] = $path; - } - - return $customModulePaths; + return ModuleResolverService::getInstance()->getCustomModulePaths(); } /** @@ -770,41 +638,7 @@ private function getModuleBlocklist() */ private function getRegisteredModuleList() { - if (!empty($this->registeredModuleList)) { - return $this->registeredModuleList; - } - - if (array_key_exists('MAGENTO_BP', $_ENV)) { - $autoloadPath = realpath(MAGENTO_BP . "/app/autoload.php"); - if ($autoloadPath) { - require_once($autoloadPath); - } else { - throw new TestFrameworkException("Magento app/autoload.php not found with given MAGENTO_BP:" - . MAGENTO_BP); - } - } - - try { - $allComponents = []; - if (!class_exists(self::REGISTRAR_CLASS)) { - throw new TestFrameworkException("Magento Installation not found when loading registered modules.\n"); - } - $components = new \Magento\Framework\Component\ComponentRegistrar(); - foreach (self::PATHS as $componentType) { - $allComponents = array_merge($allComponents, $components->getPaths($componentType)); - } - array_walk($allComponents, function (&$value) { - // Magento stores component paths with unix DIRECTORY_SEPARATOR, need to stay uniform and convert - $value = realpath($value); - $value .= DIRECTORY_SEPARATOR . self::TEST_MFTF_PATTERN; - }); - return $allComponents; - } catch (TestFrameworkException $e) { - LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->warning( - "$e" - ); - } - return []; + return ModuleResolverService::getInstance()->getRegisteredModuleList(); } /** diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver/ModuleResolverService.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver/ModuleResolverService.php new file mode 100644 index 000000000..0f6513436 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver/ModuleResolverService.php @@ -0,0 +1,322 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\FunctionalTestingFramework\Util\ModuleResolver; + +use Magento\Framework\Component\ComponentRegistrar; +use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\ComposerModuleResolver; +use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; +use Magento\FunctionalTestingFramework\Util\ModuleResolver; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; + +class ModuleResolverService +{ + /** + * Singleton ModuleResolverCreator Instance. + * + * @var ModuleResolverService + */ + private static $INSTANCE; + + /** + * Composer json based test module paths. + * + * @var array + */ + private $composerJsonModulePaths = null; + + /** + * Composer installed test module paths. + * + * @var array + */ + private $composerInstalledModulePaths = null; + + /** + * ModuleResolverService constructor. + */ + private function __construct() + { + } + + /** + * Get ModuleResolverCreator instance. + * + * @return ModuleResolverService + */ + public static function getInstance() + { + if (self::$INSTANCE === null) { + return new self(); + } + + return self::$INSTANCE; + } + + /** + * Calls Magento method for determining registered modules. + * + * @return string[] + * @throws TestFrameworkException + */ + public function getRegisteredModuleList(): array + { + if (!empty($this->registeredModuleList)) { + return $this->registeredModuleList; + } + + if (array_key_exists('MAGENTO_BP', $_ENV)) { + $autoloadPath = realpath(MAGENTO_BP . "/app/autoload.php"); + + if ($autoloadPath) { + require_once($autoloadPath); + } else { + throw new TestFrameworkException( + "Magento app/autoload.php not found with given MAGENTO_BP:" . MAGENTO_BP + ); + } + } + + try { + $allComponents = []; + + if (!class_exists(ModuleResolver::REGISTRAR_CLASS)) { + throw new TestFrameworkException("Magento Installation not found when loading registered modules.\n"); + } + + $components = new ComponentRegistrar(); + + foreach (ModuleResolver::PATHS as $componentType) { + $allComponents = array_merge($allComponents, $components->getPaths($componentType)); + } + + array_walk($allComponents, function (&$value) { + // Magento stores component paths with unix DIRECTORY_SEPARATOR, need to stay uniform and convert + $value = realpath($value); + $value .= DIRECTORY_SEPARATOR . ModuleResolver::TEST_MFTF_PATTERN; + }); + + return $allComponents; + } catch (TestFrameworkException $exception) { + LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->warning("$exception"); + } + return []; + } + + /** + * Function which takes a code path and a pattern and determines if there are any matching subdir paths. Matches + * are returned as an associative array keyed by basename (the last dir excluding pattern) to an array containing + * the matching path. + * + * @param string $testPath + * @param string $pattern + * + * @return array + * @throws TestFrameworkException + */ + public function globRelevantPaths(string $testPath, string $pattern): array + { + $modulePaths = []; + $relevantPaths = []; + + if (file_exists($testPath)) { + $relevantPaths = $this->globRelevantWrapper($testPath, $pattern); + } + + foreach ($relevantPaths as $codePath) { + $potentialSymlink = str_replace(DIRECTORY_SEPARATOR . $pattern, "", $codePath); + + if (is_link($potentialSymlink)) { + $codePath = realpath($potentialSymlink) . DIRECTORY_SEPARATOR . $pattern; + } + + $mainModName = basename(str_replace($pattern, '', $codePath)); + $modulePaths[$codePath] = [$mainModName]; + + if (MftfApplicationConfig::getConfig()->verboseEnabled()) { + LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->debug( + "including module", + ['module' => $mainModName, 'path' => $codePath] + ); + } + } + + return $modulePaths; + } + + /** + * Glob wrapper for globRelevantPaths function. + * + * @param string $testPath + * @param string $pattern + * + * @return array + */ + private static function globRelevantWrapper(string $testPath, string $pattern): array + { + if ($pattern == "") { + return glob($testPath . '*' . DIRECTORY_SEPARATOR . '*' . $pattern); + } + + $subDirectory = "*" . DIRECTORY_SEPARATOR; + $directories = glob($testPath . $subDirectory . $pattern, GLOB_ONLYDIR); + + foreach (glob($testPath . $subDirectory, GLOB_ONLYDIR) as $dir) { + $directories = array_merge_recursive($directories, self::globRelevantWrapper($dir, $pattern)); + } + + return $directories; + } + + /** + * Retrieve all module code paths that have test module composer json files. + * + * @param array $codePaths + * + * @return array + */ + public function getComposerJsonTestModulePaths(array $codePaths): array + { + if (null !== $this->composerJsonModulePaths) { + return $this->composerJsonModulePaths; + } + + try { + $this->composerJsonModulePaths = []; + $resolver = new ComposerModuleResolver(); + $this->composerJsonModulePaths = $resolver->getTestModulesFromPaths($codePaths); + } catch (TestFrameworkException $e) { + } + + return $this->composerJsonModulePaths; + } + + /** + * Retrieve composer installed test module code paths. + * + * @param string $composerFile + * + * @return array + */ + public function getComposerInstalledTestModulePaths(string $composerFile): array + { + if (null !== $this->composerInstalledModulePaths) { + return $this->composerInstalledModulePaths; + } + + try { + $this->composerInstalledModulePaths = []; + $resolver = new ComposerModuleResolver(); + $this->composerInstalledModulePaths = $resolver->getComposerInstalledTestModules($composerFile); + } catch (TestFrameworkException $e) { + } + + return $this->composerInstalledModulePaths; + } + + /** + * Retrieves all module directories which might contain pertinent test code. + * + * @return array + * @throws TestFrameworkException + */ + public function aggregateTestModulePaths(): array + { + $allModulePaths = []; + + // Define the Module paths from magento bp + $magentoBaseCodePath = FilePathFormatter::format(MAGENTO_BP, false); + + // Define the Module paths from default TESTS_MODULE_PATH + $modulePath = defined('TESTS_MODULE_PATH') ? TESTS_MODULE_PATH : TESTS_BP; + $modulePath = FilePathFormatter::format($modulePath, false); + + // If $modulePath is DEV_TESTS path, we don't need to search by pattern + if (strpos($modulePath, ModuleResolver::DEV_TESTS) === false) { + $codePathsToPattern[$modulePath] = ''; + } + + $vendorCodePath = DIRECTORY_SEPARATOR . ModuleResolver::VENDOR; + $codePathsToPattern[$magentoBaseCodePath . $vendorCodePath] = ModuleResolver::TEST_MFTF_PATTERN; + + $appCodePath = DIRECTORY_SEPARATOR . ModuleResolver::APP_CODE; + $codePathsToPattern[$magentoBaseCodePath . $appCodePath] = ModuleResolver::TEST_MFTF_PATTERN; + + foreach ($codePathsToPattern as $codePath => $pattern) { + $allModulePaths = array_merge_recursive($allModulePaths, $this->globRelevantPaths($codePath, $pattern)); + } + + return $allModulePaths; + } + + /** + * Returns an array of custom module paths defined by the user. + * + * @return string[] + */ + public function getCustomModulePaths(): array + { + $customModulePaths = []; + $paths = getenv(ModuleResolver::CUSTOM_MODULE_PATHS); + + if (!$paths) { + return $customModulePaths; + } + + foreach (explode(',', $paths) as $path) { + $customModulePaths[$this->findVendorAndModuleNameFromPath(trim($path))] = $path; + } + + return $customModulePaths; + } + + /** + * Find vendor and module name from path. + * + * @param string $path + * + * @return string + */ + private function findVendorAndModuleNameFromPath(string $path): string + { + $path = str_replace(DIRECTORY_SEPARATOR . ModuleResolver::TEST_MFTF_PATTERN, '', $path); + + return $this->findVendorNameFromPath($path) . '_' . basename($path); + } + + /** + * Find vendor name from path. + * + * @param string $path + * + * @return string + */ + private function findVendorNameFromPath(string $path): string + { + $possibleVendorName = 'UnknownVendor'; + $dirPaths = [ + ModuleResolver::VENDOR, + ModuleResolver::APP_CODE, + ModuleResolver::DEV_TESTS + ]; + + foreach ($dirPaths as $dirPath) { + $regex = "~.+\\/" . $dirPath . "\/(?<" . ModuleResolver::VENDOR . ">[^\/]+)\/.+~"; + $match = []; + preg_match($regex, $path, $match); + + if (isset($match[ModuleResolver::VENDOR])) { + $possibleVendorName = ucfirst($match[ModuleResolver::VENDOR]); + return $possibleVendorName; + } + } + + return $possibleVendorName; + } +} From d50f5b983173e61e39a707304e6a1dcfa2481449 Mon Sep 17 00:00:00 2001 From: "andrii.zinkevych" <a.zinkevych@atwix.com> Date: Thu, 15 Jul 2021 11:08:40 +0300 Subject: [PATCH 651/888] 33293: Eliminated AspectMock usage from PersistedObjectHandlerTest.php --- .../Handlers/PersistedObjectHandlerTest.php | 210 ++++++++++++------ .../DataGenerator/Persist/CurlHandler.php | 30 ++- .../Persist/DataPersistenceHandler.php | 8 +- 3 files changed, 172 insertions(+), 76 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php index 7e39fe216..4d70444b6 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php @@ -3,18 +3,15 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace tests\unit\Magento\FunctionalTestFramework\DataGenerator\Handlers; -use AspectMock\Test as AspectMock; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; +use Exception; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; -use Magento\FunctionalTestingFramework\DataGenerator\Parsers\DataProfileSchemaParser; use Magento\FunctionalTestingFramework\DataGenerator\Persist\CurlHandler; -use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; -use Magento\FunctionalTestingFramework\ObjectManager; -use Magento\FunctionalTestingFramework\ObjectManagerFactory; +use ReflectionProperty; use tests\unit\Util\MagentoTestCase; use tests\unit\Util\ObjectHandlerUtil; use tests\unit\Util\TestLoggingUtil; @@ -25,28 +22,31 @@ class PersistedObjectHandlerTest extends MagentoTestCase { /** - * Before test functionality - * @return void + * @inheritDoc */ public function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); } - public function testCreateEntityWithNonExistingName() + /** + * Validate testCreateEntityWithNonExistingName. + * + * @return void + * @throws TestReferenceException + */ + public function testCreateEntityWithNonExistingName(): void { // Test Data and Variables - $entityName = "InvalidEntity"; - $entityStepKey = "StepKey"; + $entityName = 'InvalidEntity'; + $entityStepKey = 'StepKey'; $scope = PersistedObjectHandler::TEST_SCOPE; $exceptionMessage = "Entity \"" . $entityName . "\" does not exist." . "\nException occurred executing action at StepKey \"" . $entityStepKey . "\""; $this->expectException(TestReferenceException::class); - $this->expectExceptionMessage($exceptionMessage); - $handler = PersistedObjectHandler::getInstance(); // Call method @@ -57,13 +57,19 @@ public function testCreateEntityWithNonExistingName() ); } - public function testCreateSimpleEntity() + /** + * Validate testCreateSimpleEntity. + * + * @return void + * @throws TestReferenceException + */ + public function testCreateSimpleEntity(): void { // Test Data and Variables - $entityName = "EntityOne"; - $entityStepKey = "StepKey"; - $dataKey = "testKey"; - $dataValue = "testValue"; + $entityName = 'EntityOne'; + $entityStepKey = 'StepKey'; + $dataKey = 'testKey'; + $dataValue = 'testValue'; $scope = PersistedObjectHandler::TEST_SCOPE; $parserOutput = [ 'entity' => [ @@ -78,7 +84,7 @@ public function testCreateSimpleEntity() ] ] ]; - $jsonResponse = " + $jsonResponse = " { \"" . strtolower($dataKey) . "\" : \"{$dataValue}\" } @@ -100,13 +106,19 @@ public function testCreateSimpleEntity() $this->assertEquals($dataValue, $persistedValue); } - public function testDeleteSimpleEntity() + /** + * Validate testDeleteSimpleEntity. + * + * @return void + * @throws TestReferenceException + */ + public function testDeleteSimpleEntity(): void { // Test Data and Variables - $entityName = "EntityOne"; - $entityStepKey = "StepKey"; - $dataKey = "testKey"; - $dataValue = "testValue"; + $entityName = 'EntityOne'; + $entityStepKey = 'StepKey'; + $dataKey = 'testKey'; + $dataValue = 'testValue'; $scope = PersistedObjectHandler::TEST_SCOPE; $parserOutput = [ 'entity' => [ @@ -121,7 +133,7 @@ public function testDeleteSimpleEntity() ] ] ]; - $jsonResponse = " + $jsonResponse = " { \"" . strtolower($dataKey) . "\" : \"{$dataValue}\" } @@ -148,13 +160,19 @@ public function testDeleteSimpleEntity() $this->addToAssertionCount(1); } - public function testGetSimpleEntity() + /** + * Validate testGetSimpleEntity. + * + * @return void + * @throws Exception + */ + public function testGetSimpleEntity(): void { // Test Data and Variables - $entityName = "EntityOne"; - $entityStepKey = "StepKey"; - $dataKey = "testKey"; - $dataValue = "testValue"; + $entityName = 'EntityOne'; + $entityStepKey = 'StepKey'; + $dataKey = 'testKey'; + $dataValue = 'testValue'; $scope = PersistedObjectHandler::TEST_SCOPE; $parserOutput = [ 'entity' => [ @@ -169,7 +187,7 @@ public function testGetSimpleEntity() ] ] ]; - $jsonResponse = " + $jsonResponse = " { \"" . strtolower($dataKey) . "\" : \"{$dataValue}\" } @@ -191,16 +209,22 @@ public function testGetSimpleEntity() $this->assertEquals($dataValue, $persistedValue); } - public function testUpdateSimpleEntity() + /** + * Validate testUpdateSimpleEntity. + * + * @return void + * @throws TestReferenceException + */ + public function testUpdateSimpleEntity(): void { - $this->markTestSkipped("Potential Bug in DataPersistenceHandler class"); + $this->markTestSkipped('Potential Bug in DataPersistenceHandler class'); // Test Data and Variables - $entityName = "EntityOne"; - $entityStepKey = "StepKey"; - $dataKey = "testKey"; - $dataValue = "testValue"; - $updateName = "EntityTwo"; - $updateValue = "newValue"; + $entityName = 'EntityOne'; + $entityStepKey = 'StepKey'; + $dataKey = 'testKey'; + $dataValue = 'testValue'; + $updateName = 'EntityTwo'; + $updateValue = 'newValue'; $scope = PersistedObjectHandler::TEST_SCOPE; $parserOutput = [ 'entity' => [ @@ -224,7 +248,7 @@ public function testUpdateSimpleEntity() ] ] ]; - $jsonResponse = " + $jsonResponse = " { \"" . strtolower($dataKey) . "\" : \"{$dataValue}\" } @@ -257,21 +281,27 @@ public function testUpdateSimpleEntity() $this->assertEquals($updateValue, $persistedValue); } - public function testRetrieveEntityAcrossScopes() + /** + * Validate testRetrieveEntityAcrossScopes. + * + * @return void + * @throws TestReferenceException + */ + public function testRetrieveEntityAcrossScopes(): void { // Test Data and Variables - $entityNameOne = "EntityOne"; - $entityStepKeyOne = "StepKeyOne"; - $dataKeyOne = "testKeyOne"; - $dataValueOne = "testValueOne"; - $entityNameTwo = "EntityTwo"; - $entityStepKeyTwo = "StepKeyTwo"; - $dataKeyTwo = "testKeyTwo"; - $dataValueTwo = "testValueTwo"; - $entityNameThree = "EntityThree"; - $entityStepKeyThree = "StepKeyThree"; - $dataKeyThree = "testKeyThree"; - $dataValueThree = "testValueThree"; + $entityNameOne = 'EntityOne'; + $entityStepKeyOne = 'StepKeyOne'; + $dataKeyOne = 'testKeyOne'; + $dataValueOne = 'testValueOne'; + $entityNameTwo = 'EntityTwo'; + $entityStepKeyTwo = 'StepKeyTwo'; + $dataKeyTwo = 'testKeyTwo'; + $dataValueTwo = 'testValueTwo'; + $entityNameThree = 'EntityThree'; + $entityStepKeyThree = 'StepKeyThree'; + $dataKeyThree = 'testKeyThree'; + $dataValueThree = 'testValueThree'; $parserOutputOne = [ 'entity' => [ @@ -368,6 +398,8 @@ public function testRetrieveEntityAcrossScopes() } /** + * Validate testRetrieveEntityValidField. + * * @param string $name * @param string $key * @param string $value @@ -375,9 +407,18 @@ public function testRetrieveEntityAcrossScopes() * @param string $scope * @param string $stepKey * @dataProvider entityDataProvider + * + * @return void + * @throws TestReferenceException */ - public function testRetrieveEntityValidField($name, $key, $value, $type, $scope, $stepKey) - { + public function testRetrieveEntityValidField( + string $name, + string $key, + string $value, + string $type, + string $scope, + string $stepKey + ): void { $parserOutputOne = [ 'entity' => [ $name => [ @@ -411,6 +452,8 @@ public function testRetrieveEntityValidField($name, $key, $value, $type, $scope, } /** + * Validate testRetrieveEntityInValidField. + * * @param string $name * @param string $key * @param string $value @@ -418,14 +461,21 @@ public function testRetrieveEntityValidField($name, $key, $value, $type, $scope, * @param string $scope * @param string $stepKey * @dataProvider entityDataProvider + * + * @return void * @throws TestReferenceException - * @throws TestFrameworkException */ - public function testRetrieveEntityInValidField($name, $key, $value, $type, $scope, $stepKey) - { - $invalidDataKey = "invalidDataKey"; + public function testRetrieveEntityInValidField( + string $name, + string $key, + string $value, + string $type, + string $scope, + string $stepKey + ): void { + $invalidDataKey = 'invalidDataKey'; $warnMsg = "Undefined field {$invalidDataKey} in entity object with a stepKey of {$stepKey}\n"; - $warnMsg .= "Please fix the invalid reference. This will result in fatal error in next major release."; + $warnMsg .= 'Please fix the invalid reference. This will result in fatal error in next major release.'; $parserOutputOne = [ 'entity' => [ @@ -465,8 +515,10 @@ public function testRetrieveEntityInValidField($name, $key, $value, $type, $scop /** * Data provider for testRetrieveEntityField + * + * @return array */ - public static function entityDataProvider() + public static function entityDataProvider(): array { return [ ['Entity1', 'testKey1', 'testValue1', 'testType', PersistedObjectHandler::HOOK_SCOPE, 'StepKey1'], @@ -475,20 +527,37 @@ public static function entityDataProvider() ]; } - public function mockCurlHandler($response) + /** + * Create mock curl handler. + * + * @param string $response + * @throws Exception + */ + public function mockCurlHandler(string $response): void { - AspectMock::double(CurlHandler::class, [ - "__construct" => null, - "executeRequest" => $response, - "getRequestDataArray" => [], - "isContentTypeJson" => true - ]); + $mockCurlHandler = $this->createMock(CurlHandler::class); + $mockCurlHandler->expects($this->any()) + ->method('executeRequest') + ->willReturn($response); + $mockCurlHandler->expects($this->once()) + ->method('getRequestDataArray') + ->willReturn([]); + $mockCurlHandler->expects($this->once()) + ->method('isContentTypeJson') + ->willReturn(true); + + $property = new ReflectionProperty(CurlHandler::class, "INSTANCE"); + $property->setAccessible(true); + $property->setValue($mockCurlHandler); } + /** + * @inheritDoc + */ public function tearDown(): void { // Clear out Singleton between tests - $property = new \ReflectionProperty(PersistedObjectHandler::class, "INSTANCE"); + $property = new ReflectionProperty(PersistedObjectHandler::class, 'INSTANCE'); $property->setAccessible(true); $property->setValue(null); @@ -496,8 +565,7 @@ public function tearDown(): void } /** - * After class functionality - * @return void + * @inheritDoc */ public static function tearDownAfterClass(): void { diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php index 89055b83f..9931cc470 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php @@ -63,6 +63,13 @@ class CurlHandler */ private $isJson; + /** + * Singleton CurlHandler Instance. + * + * @var CurlHandler + */ + private static $INSTANCE; + /** * Operation to Curl method mapping. * @@ -82,7 +89,7 @@ class CurlHandler * @param EntityDataObject $entityObject * @param string $storeCode */ - public function __construct($operation, $entityObject, $storeCode = null) + private function __construct($operation, $entityObject, $storeCode = null) { $this->operation = $operation; $this->entityObject = $entityObject; @@ -95,6 +102,27 @@ public function __construct($operation, $entityObject, $storeCode = null) $this->isJson = false; } + /** + * Get CurlHandler instance. + * + * @param string $operation + * @param EntityDataObject $entityObject + * @param string|null $storeCode + * + * @return CurlHandler + */ + public static function getInstance( + string $operation, + EntityDataObject $entityObject, + ?string $storeCode = null + ) { + if (self::$INSTANCE === null) { + return new self($operation, $entityObject, $storeCode); + } + + return self::$INSTANCE; + } + /** * Executes an api request based on parameters given by constructor. * diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/DataPersistenceHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/DataPersistenceHandler.php index 73ee2be19..0be6cc24e 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/DataPersistenceHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/DataPersistenceHandler.php @@ -86,7 +86,7 @@ public function createEntity($storeCode = null) if (!empty($storeCode)) { $this->storeCode = $storeCode; } - $curlHandler = new CurlHandler('create', $this->entityObject, $this->storeCode); + $curlHandler = CurlHandler::getInstance('create', $this->entityObject, $this->storeCode); $result = $curlHandler->executeRequest($this->dependentObjects); $this->setCreatedObject( $result, @@ -111,7 +111,7 @@ public function updateEntity($updateDataName, $updateDependentObjects = []) $this->dependentObjects[] = $dependentObject->getCreatedObject(); } $updateEntityObject = DataObjectHandler::getInstance()->getObject($updateDataName); - $curlHandler = new CurlHandler('update', $updateEntityObject, $this->storeCode); + $curlHandler = CurlHandler::getInstance('update', $updateEntityObject, $this->storeCode); $result = $curlHandler->executeRequest(array_merge($this->dependentObjects, [$this->createdObject])); $this->setCreatedObject( $result, @@ -134,7 +134,7 @@ public function getEntity($index = null, $storeCode = null) if (!empty($storeCode)) { $this->storeCode = $storeCode; } - $curlHandler = new CurlHandler('get', $this->entityObject, $this->storeCode); + $curlHandler = CurlHandler::getInstance('get', $this->entityObject, $this->storeCode); $result = $curlHandler->executeRequest($this->dependentObjects); $this->setCreatedObject( $result, @@ -152,7 +152,7 @@ public function getEntity($index = null, $storeCode = null) */ public function deleteEntity() { - $curlHandler = new CurlHandler('delete', $this->createdObject, $this->storeCode); + $curlHandler = CurlHandler::getInstance('delete', $this->createdObject, $this->storeCode); $curlHandler->executeRequest($this->dependentObjects); } From d46a66d439cff45c47b65f320a94418138ccb173 Mon Sep 17 00:00:00 2001 From: "andrii.zinkevych" <a.zinkevych@atwix.com> Date: Thu, 15 Jul 2021 11:45:39 +0300 Subject: [PATCH 652/888] 33293: Fixed static-test --- .../DataGenerator/Persist/CurlHandler.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php index 9931cc470..d5250c890 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php @@ -105,9 +105,9 @@ private function __construct($operation, $entityObject, $storeCode = null) /** * Get CurlHandler instance. * - * @param string $operation + * @param string $operation * @param EntityDataObject $entityObject - * @param string|null $storeCode + * @param string|null $storeCode * * @return CurlHandler */ From a449f0709bbe60e98882e2facd5dc284aebbf0d7 Mon Sep 17 00:00:00 2001 From: silinmykola <m.silin@atwix.com> Date: Fri, 16 Jul 2021 13:40:15 +0300 Subject: [PATCH 653/888] 33292 change tearDown method --- .../Console/BaseGenerateCommandTest.php | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php index ce43cde78..e0e1c7233 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php @@ -14,6 +14,18 @@ class BaseGenerateCommandTest extends TestCase { + public function tearDown(): void + { + $handler = TestObjectHandler::getInstance(); + $property = new \ReflectionProperty(TestObjectHandler::class, 'tests'); + $property->setAccessible(true); + $property->setValue($handler, []); + + $handler = SuiteObjectHandler::getInstance(); + $property = new \ReflectionProperty(SuiteObjectHandler::class, 'suiteObjects'); + $property->setAccessible(true); + $property->setValue($handler, []); + } public function testOneTestOneSuiteConfig() { $testOne = new TestObject('Test1', [], [], []); @@ -176,25 +188,11 @@ public function testSuiteToTestSyntax() */ public function mockHandlers($testArray, $suiteArray) { - $testObjectHandler = TestObjectHandler::getInstance(); - $reflection = new \ReflectionClass(TestObjectHandler::class); - $reflectionMethod = $reflection->getMethod('initTestData'); - $reflectionMethod->setAccessible(true); - $output = $reflectionMethod->invoke($testObjectHandler); - $this->assertEquals('', $output); - $handler = TestObjectHandler::getInstance(); $property = new \ReflectionProperty(TestObjectHandler::class, 'tests'); $property->setAccessible(true); $property->setValue($handler, $testArray); - $suiteObjectHandler = SuiteObjectHandler::getInstance(); - $reflection = new \ReflectionClass(SuiteObjectHandler::class); - $reflectionMethod = $reflection->getMethod('initSuiteData'); - $reflectionMethod->setAccessible(true); - $output = $reflectionMethod->invoke($suiteObjectHandler); - $this->assertEquals('', $output); - $handler = SuiteObjectHandler::getInstance(); $property = new \ReflectionProperty(SuiteObjectHandler::class, 'suiteObjects'); $property->setAccessible(true); From bbec23ac32d455607a696bbb20ede41386a68ce4 Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Mon, 19 Jul 2021 15:26:02 +0300 Subject: [PATCH 654/888] 33292: aspect mock replacement, unit test refactoring --- .../Console/BaseGenerateCommandTest.php | 115 +++++++++++++----- 1 file changed, 83 insertions(+), 32 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php index e0e1c7233..fe486b615 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Console/BaseGenerateCommandTest.php @@ -3,30 +3,46 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace tests\unit\Magento\FunctionalTestFramework\Console; -use PHPUnit\Framework\TestCase; +use Exception; use Magento\FunctionalTestingFramework\Console\BaseGenerateCommand; -use Magento\FunctionalTestingFramework\Suite\Objects\SuiteObject; use Magento\FunctionalTestingFramework\Suite\Handlers\SuiteObjectHandler; -use Magento\FunctionalTestingFramework\Test\Objects\TestObject; +use Magento\FunctionalTestingFramework\Suite\Objects\SuiteObject; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; +use Magento\FunctionalTestingFramework\Test\Objects\TestObject; +use PHPUnit\Framework\TestCase; +use ReflectionClass; +use ReflectionException; +use ReflectionProperty; class BaseGenerateCommandTest extends TestCase { - public function tearDown(): void + /** + * @inheritDoc + */ + protected function tearDown(): void { $handler = TestObjectHandler::getInstance(); - $property = new \ReflectionProperty(TestObjectHandler::class, 'tests'); - $property->setAccessible(true); - $property->setValue($handler, []); + $testsProperty = new ReflectionProperty(TestObjectHandler::class, 'tests'); + $testsProperty->setAccessible(true); + $testsProperty->setValue($handler, []); + $testObjectHandlerProperty = new ReflectionProperty(TestObjectHandler::class, 'testObjectHandler'); + $testObjectHandlerProperty->setAccessible(true); + $testObjectHandlerProperty->setValue($handler); $handler = SuiteObjectHandler::getInstance(); - $property = new \ReflectionProperty(SuiteObjectHandler::class, 'suiteObjects'); - $property->setAccessible(true); - $property->setValue($handler, []); + $suiteObjectsProperty = new ReflectionProperty(SuiteObjectHandler::class, 'suiteObjects'); + $suiteObjectsProperty->setAccessible(true); + $suiteObjectsProperty->setValue($handler, []); + $suiteObjectHandlerProperty = new ReflectionProperty(SuiteObjectHandler::class, 'instance'); + $suiteObjectHandlerProperty->setAccessible(true); + $suiteObjectHandlerProperty->setValue($handler); } - public function testOneTestOneSuiteConfig() + + public function testOneTestOneSuiteConfig(): void { $testOne = new TestObject('Test1', [], [], []); $suiteOne = new SuiteObject('Suite1', ['Test1' => $testOne], [], []); @@ -41,7 +57,7 @@ public function testOneTestOneSuiteConfig() $this->assertEquals($expected, $actual); } - public function testOneTestTwoSuitesConfig() + public function testOneTestTwoSuitesConfig(): void { $testOne = new TestObject('Test1', [], [], []); $suiteOne = new SuiteObject('Suite1', ['Test1' => $testOne], [], []); @@ -57,7 +73,7 @@ public function testOneTestTwoSuitesConfig() $this->assertEquals($expected, $actual); } - public function testOneTestOneGroup() + public function testOneTestOneGroup(): void { $testOne = new TestObject('Test1', [], ['group' => ['Group1']], []); @@ -71,7 +87,7 @@ public function testOneTestOneGroup() $this->assertEquals($expected, $actual); } - public function testThreeTestsTwoGroup() + public function testThreeTestsTwoGroup(): void { $testOne = new TestObject('Test1', [], ['group' => ['Group1']], []); $testTwo = new TestObject('Test2', [], ['group' => ['Group1']], []); @@ -87,7 +103,7 @@ public function testThreeTestsTwoGroup() $this->assertEquals($expected, $actual); } - public function testOneTestOneSuiteOneGroupConfig() + public function testOneTestOneSuiteOneGroupConfig(): void { $testOne = new TestObject('Test1', [], ['group' => ['Group1']], []); $suiteOne = new SuiteObject('Suite1', ['Test1' => $testOne], [], []); @@ -102,7 +118,7 @@ public function testOneTestOneSuiteOneGroupConfig() $this->assertEquals($expected, $actual); } - public function testTwoTestOneSuiteTwoGroupConfig() + public function testTwoTestOneSuiteTwoGroupConfig(): void { $testOne = new TestObject('Test1', [], ['group' => ['Group1']], []); $testTwo = new TestObject('Test2', [], ['group' => ['Group2']], []); @@ -118,7 +134,7 @@ public function testTwoTestOneSuiteTwoGroupConfig() $this->assertEquals($expected, $actual); } - public function testTwoTestTwoSuiteOneGroupConfig() + public function testTwoTestTwoSuiteOneGroupConfig(): void { $testOne = new TestObject('Test1', [], ['group' => ['Group1']], []); $testTwo = new TestObject('Test2', [], ['group' => ['Group1']], []); @@ -137,10 +153,12 @@ public function testTwoTestTwoSuiteOneGroupConfig() /** * Test specific usecase of a test that is in a group with the group being called along with the suite - * i.e. run:group Group1 Suite1 - * @throws \Exception + * i.e. run:group Group1 Suite1. + * + * @return void + * @throws Exception */ - public function testThreeTestOneSuiteOneGroupMix() + public function testThreeTestOneSuiteOneGroupMix(): void { $testOne = new TestObject('Test1', [], [], []); $testTwo = new TestObject('Test2', [], [], []); @@ -162,7 +180,7 @@ public function testThreeTestOneSuiteOneGroupMix() $this->assertEquals($expected, $actual); } - public function testSuiteToTestSyntax() + public function testSuiteToTestSyntax(): void { $testOne = new TestObject('Test1', [], [], []); $suiteOne = new SuiteObject( @@ -181,49 +199,82 @@ public function testSuiteToTestSyntax() } /** - * Mock handlers to skip parsing + * Mock handlers to skip parsing. + * * @param array $testArray * @param array $suiteArray - * @throws \Exception + * + * @return void + * @throws Exception */ - public function mockHandlers($testArray, $suiteArray) + public function mockHandlers(array $testArray, array $suiteArray): void { + // bypass the initTestData method + $testObjectHandlerClass = new ReflectionClass(TestObjectHandler::class); + $constructor = $testObjectHandlerClass->getConstructor(); + $constructor->setAccessible(true); + $testObjectHandlerObject = $testObjectHandlerClass->newInstanceWithoutConstructor(); + $constructor->invoke($testObjectHandlerObject); + + $testObjectHandlerProperty = new ReflectionProperty(TestObjectHandler::class, 'testObjectHandler'); + $testObjectHandlerProperty->setAccessible(true); + $testObjectHandlerProperty->setValue($testObjectHandlerObject); + $handler = TestObjectHandler::getInstance(); - $property = new \ReflectionProperty(TestObjectHandler::class, 'tests'); + $property = new ReflectionProperty(TestObjectHandler::class, 'tests'); $property->setAccessible(true); $property->setValue($handler, $testArray); + // bypass the initTestData method + $suiteObjectHandlerClass = new ReflectionClass(SuiteObjectHandler::class); + $constructor = $suiteObjectHandlerClass->getConstructor(); + $constructor->setAccessible(true); + $suiteObjectHandlerObject = $suiteObjectHandlerClass->newInstanceWithoutConstructor(); + $constructor->invoke($suiteObjectHandlerObject); + + $suiteObjectHandlerProperty = new ReflectionProperty(SuiteObjectHandler::class, 'instance'); + $suiteObjectHandlerProperty->setAccessible(true); + $suiteObjectHandlerProperty->setValue($suiteObjectHandlerObject); + $handler = SuiteObjectHandler::getInstance(); - $property = new \ReflectionProperty(SuiteObjectHandler::class, 'suiteObjects'); + $property = new ReflectionProperty(SuiteObjectHandler::class, 'suiteObjects'); $property->setAccessible(true); $property->setValue($handler, $suiteArray); } /** - * Changes visibility and runs getTestAndSuiteConfiguration + * Changes visibility and runs getTestAndSuiteConfiguration. + * * @param array $testArray + * * @return string + * @throws ReflectionException */ - public function callTestConfig($testArray) + public function callTestConfig(array $testArray): string { $command = new BaseGenerateCommand(); - $class = new \ReflectionClass($command); + $class = new ReflectionClass($command); $method = $class->getMethod('getTestAndSuiteConfiguration'); $method->setAccessible(true); + return $method->invokeArgs($command, [$testArray]); } /** - * Changes visibility and runs getGroupAndSuiteConfiguration + * Changes visibility and runs getGroupAndSuiteConfiguration. + * * @param array $groupArray + * * @return string + * @throws ReflectionException */ - public function callGroupConfig($groupArray) + public function callGroupConfig(array $groupArray): string { $command = new BaseGenerateCommand(); - $class = new \ReflectionClass($command); + $class = new ReflectionClass($command); $method = $class->getMethod('getGroupAndSuiteConfiguration'); $method->setAccessible(true); + return $method->invokeArgs($command, [$groupArray]); } } From 93a3a5bfd6135473a4b3af62446530ca97005b82 Mon Sep 17 00:00:00 2001 From: Andrii Beziazychnyi <a.beziazychnyi@atwix.com> Date: Fri, 16 Jul 2021 15:39:38 +0300 Subject: [PATCH 655/888] CE-32868: Updated "monolog" to the latest version 2.3.1 --- composer.json | 6 +++--- composer.lock | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/composer.json b/composer.json index 15a28c947..94ff6a35f 100755 --- a/composer.json +++ b/composer.json @@ -25,8 +25,9 @@ "csharpru/vault-php": "^4.2.1", "csharpru/vault-php-guzzle6-transport": "^2.0", "hoa/console": "~3.0", - "monolog/monolog": "^2.2", + "monolog/monolog": "^2.3", "mustache/mustache": "~2.5", + "nikic/php-parser": "^4.4", "php-webdriver/webdriver": "^1.9.0", "spomky-labs/otphp": "^10.0", "symfony/console": "^4.4", @@ -35,8 +36,7 @@ "symfony/mime": "^5.0", "symfony/process": "^4.4", "vlucas/phpdotenv": "^2.4", - "weew/helpers-array": "^1.3", - "nikic/php-parser": "^4.4" + "weew/helpers-array": "^1.3" }, "require-dev": { "brainmaestro/composer-git-hooks": "^2.3.1", diff --git a/composer.lock b/composer.lock index cfc6e4f9e..e2110d79b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "6e848e638ba77ff322a62b24136fb06a", + "content-hash": "dcd4540cf1aed5a943189676f90f43cb", "packages": [ { "name": "allure-framework/allure-codeception", @@ -2635,16 +2635,16 @@ }, { "name": "monolog/monolog", - "version": "2.2.0", + "version": "2.3.1", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "1cb1cde8e8dd0f70cc0fe51354a59acad9302084" + "reference": "9738e495f288eec0b187e310b7cdbbb285777dbe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/1cb1cde8e8dd0f70cc0fe51354a59acad9302084", - "reference": "1cb1cde8e8dd0f70cc0fe51354a59acad9302084", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/9738e495f288eec0b187e310b7cdbbb285777dbe", + "reference": "9738e495f288eec0b187e310b7cdbbb285777dbe", "shasum": "" }, "require": { @@ -2663,7 +2663,7 @@ "php-amqplib/php-amqplib": "~2.4", "php-console/php-console": "^3.1.3", "phpspec/prophecy": "^1.6.1", - "phpstan/phpstan": "^0.12.59", + "phpstan/phpstan": "^0.12.91", "phpunit/phpunit": "^8.5", "predis/predis": "^1.1", "rollbar/rollbar": "^1.3", @@ -2715,7 +2715,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/2.2.0" + "source": "https://github.com/Seldaek/monolog/tree/2.3.1" }, "funding": [ { @@ -2727,7 +2727,7 @@ "type": "tidelift" } ], - "time": "2020-12-14T13:15:25+00:00" + "time": "2021-07-14T11:56:39+00:00" }, { "name": "mtdowling/jmespath.php", From 1a71fe7cd5581e099ef39f3a6a853af8865bc323 Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Tue, 20 Jul 2021 11:52:09 +0300 Subject: [PATCH 656/888] 33294: Eliminated aspect mock from AllureHelperTest --- .../Allure/AllureHelperTest.php | 100 ++++++++++++------ .../Allure/AllureHelper.php | 20 ++-- .../Allure/Event/AddUniqueAttachmentEvent.php | 83 +++++++++------ 3 files changed, 135 insertions(+), 68 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php index 9e0e8ca93..638db3702 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php @@ -3,11 +3,14 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace tests\unit\Magento\FunctionalTestFramework\Allure; use Magento\FunctionalTestingFramework\Allure\AllureHelper; use Magento\FunctionalTestingFramework\Allure\Event\AddUniqueAttachmentEvent; use PHPUnit\Framework\TestCase; +use ReflectionProperty; use Yandex\Allure\Adapter\Allure; use Yandex\Allure\Adapter\AllureException; use Yandex\Allure\Adapter\Event\StepFinishedEvent; @@ -16,25 +19,32 @@ class AllureHelperTest extends TestCase { - const MOCK_FILENAME = 'filename'; + private const MOCK_FILENAME = 'filename'; /** - * Clear Allure Lifecycle + * Clear Allure Lifecycle. + * + * @return void */ - public function tearDown(): void + protected function tearDown(): void { Allure::setDefaultLifecycle(); + $instanceProperty = new ReflectionProperty(AddUniqueAttachmentEvent::class, 'instance'); + $instanceProperty->setAccessible(true); + $instanceProperty->setValue(null); } /** - * AddAttachmentToStep should add an attachment to the current step + * The AddAttachmentToStep should add an attachment to the current step. + * + * @return void * @throws AllureException */ - public function testAddAttachmentToStep() + public function testAddAttachmentToStep(): void { - $this->mockAttachmentWriteEvent(); - $expectedData = "string"; - $expectedCaption = "caption"; + $expectedData = 'string'; + $expectedCaption = 'caption'; + $this->mockAttachmentWriteEvent($expectedData, $expectedCaption); //Prepare Allure lifecycle Allure::lifecycle()->fire(new StepStartedEvent('firstStep')); @@ -49,14 +59,16 @@ public function testAddAttachmentToStep() } /** - * AddAttachmentToLastStep should add an attachment only to the last step + * The AddAttachmentToLastStep should add an attachment only to the last step. + * + * @return void * @throws AllureException */ - public function testAddAttachmentToLastStep() + public function testAddAttachmentToLastStep(): void { - $this->mockAttachmentWriteEvent(); - $expectedData = "string"; - $expectedCaption = "caption"; + $expectedData = 'string'; + $expectedCaption = 'caption'; + $this->mockAttachmentWriteEvent($expectedData, $expectedCaption); //Prepare Allure lifecycle Allure::lifecycle()->fire(new StepStartedEvent('firstStep')); @@ -85,14 +97,15 @@ public function testAddAttachmentToLastStep() } /** - * AddAttachment actions should have files with different attachment names + * The AddAttachment actions should have files with different attachment names. + * + * @return void * @throws AllureException */ - public function testAddAttachementUniqueName() + public function testAddAttachmentUniqueName(): void { - $expectedData = "string"; - $expectedCaption = "caption"; - + $expectedData = 'string'; + $expectedCaption = 'caption'; $this->mockCopyFile($expectedData, $expectedCaption); //Prepare Allure lifecycle @@ -110,27 +123,52 @@ public function testAddAttachementUniqueName() } /** - * Mock entire attachment writing mechanisms + * Mock entire attachment writing mechanisms. + * + * @param string $filePathOrContents + * @param string $caption + * + * @return void */ - public function mockAttachmentWriteEvent() + private function mockAttachmentWriteEvent(string $filePathOrContents, string $caption): void { - $this->createMock(AddUniqueAttachmentEvent::class) - ->expects($this->any()) + $mockInstance = $this->getMockBuilder(AddUniqueAttachmentEvent::class) + ->setConstructorArgs([$filePathOrContents, $caption]) + ->disallowMockingUnknownTypes() + ->onlyMethods(['getAttachmentFileName']) + ->getMock(); + + $mockInstance ->method('getAttachmentFileName') ->willReturn(self::MOCK_FILENAME); + + $instanceProperty = new ReflectionProperty(AddUniqueAttachmentEvent::class, 'instance'); + $instanceProperty->setAccessible(true); + $instanceProperty->setValue($mockInstance, $mockInstance); } /** - * Mock only file writing mechanism - * @throws \ReflectionException + * Mock only file writing mechanism. + * + * @param string $filePathOrContents + * @param string $caption + * + * @return void */ - public function mockCopyFile(string $expectedData, string $expectedCaption) + private function mockCopyFile(string $filePathOrContents, string $caption): void { - $addUniqueAttachmentEvent = new AddUniqueAttachmentEvent($expectedData, $expectedCaption); - $reflection = new \ReflectionClass(AddUniqueAttachmentEvent::class); - $reflectionMethod = $reflection->getMethod('copyFile'); - $reflectionMethod->setAccessible(true); - $output = $reflectionMethod->invoke($addUniqueAttachmentEvent); - $this->assertEquals(true, $output); + $mockInstance = $this->getMockBuilder(AddUniqueAttachmentEvent::class) + ->setConstructorArgs([$filePathOrContents, $caption]) + ->disallowMockingUnknownTypes() + ->onlyMethods(['copyFile']) + ->getMock(); + + $mockInstance + ->method('copyFile') + ->willReturn(true); + + $instanceProperty = new ReflectionProperty(AddUniqueAttachmentEvent::class, 'instance'); + $instanceProperty->setAccessible(true); + $instanceProperty->setValue($mockInstance, $mockInstance); } } diff --git a/src/Magento/FunctionalTestingFramework/Allure/AllureHelper.php b/src/Magento/FunctionalTestingFramework/Allure/AllureHelper.php index 58bbc55b8..6263908bc 100644 --- a/src/Magento/FunctionalTestingFramework/Allure/AllureHelper.php +++ b/src/Magento/FunctionalTestingFramework/Allure/AllureHelper.php @@ -3,34 +3,40 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\FunctionalTestingFramework\Allure; use Magento\FunctionalTestingFramework\Allure\Event\AddUniqueAttachmentEvent; use Yandex\Allure\Adapter\Allure; -use Yandex\Allure\Adapter\Event\AddAttachmentEvent; +use Yandex\Allure\Adapter\AllureException; class AllureHelper { /** - * Adds attachment to the current step + * Adds attachment to the current step. + * * @param mixed $data * @param string $caption - * @throws \Yandex\Allure\Adapter\AllureException + * * @return void + * @throws AllureException */ - public static function addAttachmentToCurrentStep($data, $caption) + public static function addAttachmentToCurrentStep($data, $caption): void { - Allure::lifecycle()->fire(new AddUniqueAttachmentEvent($data, $caption)); + Allure::lifecycle()->fire(AddUniqueAttachmentEvent::getInstance($data, $caption)); } /** * Adds Attachment to the last executed step. * Use this when adding attachments outside of an $I->doSomething() step/context. + * * @param mixed $data * @param string $caption + * * @return void */ - public static function addAttachmentToLastStep($data, $caption) + public static function addAttachmentToLastStep($data, $caption): void { $rootStep = Allure::lifecycle()->getStepStorage()->getLast(); $trueLastStep = array_last($rootStep->getSteps()); @@ -40,7 +46,7 @@ public static function addAttachmentToLastStep($data, $caption) return; } - $attachmentEvent = new AddUniqueAttachmentEvent($data, $caption); + $attachmentEvent = AddUniqueAttachmentEvent::getInstance($data, $caption); $attachmentEvent->process($trueLastStep); } } diff --git a/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php b/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php index bf16e5b49..c5e7c0d31 100644 --- a/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php +++ b/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php @@ -1,35 +1,63 @@ <?php - /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\FunctionalTestingFramework\Allure\Event; use Symfony\Component\Mime\MimeTypes; use Yandex\Allure\Adapter\AllureException; use Yandex\Allure\Adapter\Event\AddAttachmentEvent; -const DEFAULT_FILE_EXTENSION = 'txt'; -const DEFAULT_MIME_TYPE = 'text/plain'; - class AddUniqueAttachmentEvent extends AddAttachmentEvent { + private const DEFAULT_FILE_EXTENSION = 'txt'; + private const DEFAULT_MIME_TYPE = 'text/plain'; + /** - * @var string + * @var AddUniqueAttachmentEvent|null */ - private $type; + private static $instance; /** - * Near copy of parent function, added uniqid call for filename to prevent buggy allure behavior - * @param string $filePathOrContents + * An alternative way to instantiate an instance of this class. Used to mock this class object in unit tests. + * + * @param mixed $filePathOrContents + * @param string $caption + * @param string|null $type + * + * @return AddUniqueAttachmentEvent + */ + public static function getInstance( + $filePathOrContents, + string $caption, + ?string $type = null + ): AddUniqueAttachmentEvent { + if (!self::$instance) { + self::$instance = new AddUniqueAttachmentEvent( + $filePathOrContents, + $caption, + $type + ); + } + return self::$instance; + } + + /** + * Near copy of parent function, added uniqid call for filename to prevent buggy allure behavior. + * + * @param mixed $filePathOrContents * @param string $type + * * @return string * @throws AllureException */ - public function getAttachmentFileName($filePathOrContents, $type) + public function getAttachmentFileName($filePathOrContents, $type): string { $filePath = $filePathOrContents; + if (!file_exists($filePath) || !is_file($filePath)) { //Save contents to temporary file $filePath = tempnam(sys_get_temp_dir(), 'allure-attachment'); @@ -40,13 +68,11 @@ public function getAttachmentFileName($filePathOrContents, $type) if (!isset($type)) { $type = $this->guessFileMimeType($filePath); - $this->type = $type; } - $fileExtension = $this->guessFileExtension($type); - $fileSha1 = uniqid(sha1_file($filePath)); $outputPath = parent::getOutputPath($fileSha1, $fileExtension); + if (!$this->copyFile($filePath, $outputPath)) { throw new AllureException("Failed to copy attachment from $filePath to $outputPath."); } @@ -56,51 +82,48 @@ public function getAttachmentFileName($filePathOrContents, $type) /** * Copies file from one path to another. Wrapper for mocking in unit test. + * * @param string $filePath * @param string $outputPath + * * @return boolean */ - private function copyFile($filePath, $outputPath) + public function copyFile(string $filePath, string $outputPath): bool { return copy($filePath, $outputPath); } /** - * Copy of parent private function + * Copy of parent private function. + * * @param string $filePath + * * @return string */ - private function guessFileMimeType($filePath) + private function guessFileMimeType(string $filePath): string { $type = MimeTypes::getDefault()->guessMimeType($filePath); + if (!isset($type)) { - return DEFAULT_MIME_TYPE; + return self::DEFAULT_MIME_TYPE; } return $type; } /** - * Copy of parent private function + * Copy of parent private function. + * * @param string $mimeType + * * @return string */ - private function guessFileExtension($mimeType) + private function guessFileExtension(string $mimeType): string { $candidate = MimeTypes::getDefault()->getExtensions($mimeType); + if (empty($candidate)) { - return DEFAULT_FILE_EXTENSION; + return self::DEFAULT_FILE_EXTENSION; } return reset($candidate); } - - /** - * Copy of parent private function - * @param string $sha1 - * @param string $extension - * @return string - */ - public function getOutputFileName($sha1, $extension) - { - return $sha1 . '-attachment.' . $extension; - } } From 15a240ec7a5875846088e2d534dd47cbab42bb5d Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Wed, 21 Jul 2021 08:35:19 +0300 Subject: [PATCH 657/888] 33305: Removed an extra line --- dev/tests/unit/Util/MagentoTestCase.php | 1 - 1 file changed, 1 deletion(-) diff --git a/dev/tests/unit/Util/MagentoTestCase.php b/dev/tests/unit/Util/MagentoTestCase.php index c34236fc1..bb38a0b5c 100644 --- a/dev/tests/unit/Util/MagentoTestCase.php +++ b/dev/tests/unit/Util/MagentoTestCase.php @@ -22,7 +22,6 @@ public static function setUpBeforeClass(): void // Should be used to clean AspectMock mocking before using PHPUnit mocking and Reflection. AspectMock::clean(); parent::setUpBeforeClass(); - parent::setUpBeforeClass(); } /** From 7cc350ae7fe22a74b13475a3fd787ef5f7135d4a Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Wed, 21 Jul 2021 17:24:32 +0300 Subject: [PATCH 658/888] 33304: code refactoring, fixing test failed for all test cases --- .../Test/Util/ActionMergeUtilTest.php | 58 ++++++++++--------- dev/tests/unit/Util/MagentoTestCase.php | 2 + 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php index 099d8ef81..56bb0f0c5 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php @@ -3,6 +3,8 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace tests\unit\Magento\FunctionalTestFramework\Test\Util; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; @@ -12,16 +14,18 @@ use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Magento\FunctionalTestingFramework\Test\Util\ActionMergeUtil; use Magento\FunctionalTestingFramework\Test\Util\ActionObjectExtractor; +use ReflectionProperty; use tests\unit\Util\MagentoTestCase; use tests\unit\Util\TestLoggingUtil; class ActionMergeUtilTest extends MagentoTestCase { /** - * Before test functionality + * Before test functionality. + * * @return void */ - public function setUp(): void + protected function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); } @@ -30,8 +34,10 @@ public function setUp(): void * Test to validate actions are properly ordered during a merge. * * @return void + * @throws TestReferenceException + * @throws XmlException */ - public function testResolveActionStepOrdering() + public function testResolveActionStepOrdering(): void { $actions = []; $actionsLength = 11; @@ -45,7 +51,6 @@ public function testResolveActionStepOrdering() $stepKey = 'stepKey'. $i; $type = 'testType'; $actionAttributes = []; - $actions[] = new ActionObject($stepKey, $type, $actionAttributes); } @@ -92,8 +97,10 @@ public function testResolveActionStepOrdering() * Test to validate action steps properly resolve entity data references. * * @return void + * @throws TestReferenceException + * @throws XmlException */ - public function testResolveActionStepEntityData() + public function testResolveActionStepEntityData(): void { $dataObjectName = 'myObject'; $dataObjectType = 'testObject'; @@ -110,40 +117,34 @@ public function testResolveActionStepEntityData() // Set up mock DataObject Handler $mockDOHInstance = $this->createMock(DataObjectHandler::class); - $mockDOHInstance->expects($this->any()) + $mockDOHInstance + ->expects($this->any()) ->method('getObject') ->willReturn($mockDataObject); - $property = new \ReflectionProperty(DataObjectHandler::class, 'INSTANCE'); + $property = new ReflectionProperty(DataObjectHandler::class, 'INSTANCE'); $property->setAccessible(true); - $property->setValue($mockDOHInstance); + $property->setValue($mockDOHInstance, $mockDOHInstance); // Create test object and action object $actionAttributes = [$userInputKey => $userInputValue]; $actions[$actionName] = new ActionObject($actionName, $actionType, $actionAttributes); - $this->assertEquals($userInputValue, $actions[$actionName]->getCustomActionAttributes()[$userInputKey]); $mergeUtil = new ActionMergeUtil("test", "TestCase"); $resolvedActions = $mergeUtil->resolveActionSteps($actions); - $this->assertEquals($dataFieldValue, $resolvedActions[$actionName]->getCustomActionAttributes()[$userInputKey]); } /** * Verify that an XmlException is thrown when an action references a non-existant action. * - * @throws TestReferenceException - * @throws XmlException * @return void - */ - /** * @throws TestReferenceException * @throws XmlException */ - public function testNoActionException() + public function testNoActionException(): void { $actionObjects = []; - $actionObjects[] = new ActionObject('actionKey1', 'bogusType', []); $actionObjects[] = new ActionObject( 'actionKey2', @@ -153,8 +154,7 @@ public function testNoActionException() ActionObject::MERGE_ACTION_ORDER_BEFORE ); - $this->expectException(\Magento\FunctionalTestingFramework\Exceptions\XmlException::class); - + $this->expectException(XmlException::class); $actionMergeUtil = new ActionMergeUtil("actionMergeUtilTest", "TestCase"); $actionMergeUtil->resolveActionSteps($actionObjects); } @@ -162,11 +162,11 @@ public function testNoActionException() /** * Verify that a <waitForPageLoad> action is added after actions that have a wait (timeout property). * + * @return void * @throws TestReferenceException * @throws XmlException - * @return void */ - public function testInsertWait() + public function testInsertWait(): void { $actionObjectOne = new ActionObject('actionKey1', 'bogusType', []); $actionObjectOne->setTimeout(42); @@ -189,10 +189,11 @@ public function testInsertWait() /** * Verify that a <fillField> action is replaced by <fillSecretField> when secret _CREDS are referenced. * + * @return void * @throws TestReferenceException * @throws XmlException */ - public function testValidFillFieldSecretFunction() + public function testValidFillFieldSecretFunction(): void { $actionObjectOne = new ActionObject( 'actionKey1', @@ -202,7 +203,6 @@ public function testValidFillFieldSecretFunction() $actionObject = [$actionObjectOne]; $actionMergeUtil = new ActionMergeUtil('actionMergeUtilTest', 'TestCase'); - $result = $actionMergeUtil->resolveActionSteps($actionObject); $expectedValue = new ActionObject( @@ -216,10 +216,11 @@ public function testValidFillFieldSecretFunction() /** * Verify that a <magentoCLI> action uses <magentoCLI> when secret _CREDS are referenced. * + * @return void * @throws TestReferenceException * @throws XmlException */ - public function testValidMagentoCLISecretFunction() + public function testValidMagentoCLISecretFunction(): void { $actionObjectOne = new ActionObject( 'actionKey1', @@ -229,7 +230,6 @@ public function testValidMagentoCLISecretFunction() $actionObject = [$actionObjectOne]; $actionMergeUtil = new ActionMergeUtil('actionMergeUtilTest', 'TestCase'); - $result = $actionMergeUtil->resolveActionSteps($actionObject); $expectedValue = new ActionObject( @@ -243,10 +243,11 @@ public function testValidMagentoCLISecretFunction() /** * Verify that a <field> override in a <createData> action uses <field> when secret _CREDS are referenced. * + * @return void * @throws TestReferenceException * @throws XmlException */ - public function testValidCreateDataSecretFunction() + public function testValidCreateDataSecretFunction(): void { $actionObjectOne = new ActionObject( 'actionKey1', @@ -256,7 +257,6 @@ public function testValidCreateDataSecretFunction() $actionObject = [$actionObjectOne]; $actionMergeUtil = new ActionMergeUtil('actionMergeUtilTest', 'TestCase'); - $result = $actionMergeUtil->resolveActionSteps($actionObject); $expectedValue = new ActionObject( @@ -270,10 +270,11 @@ public function testValidCreateDataSecretFunction() /** * Verify that a <click> action throws an exception when secret _CREDS are referenced. * + * @return void * @throws TestReferenceException * @throws XmlException */ - public function testInvalidSecretFunctions() + public function testInvalidSecretFunctions(): void { $this->expectException(TestReferenceException::class); $this->expectExceptionMessage( @@ -292,7 +293,8 @@ public function testInvalidSecretFunctions() } /** - * After class functionality + * After class functionality. + * * @return void */ public static function tearDownAfterClass(): void diff --git a/dev/tests/unit/Util/MagentoTestCase.php b/dev/tests/unit/Util/MagentoTestCase.php index 7760acfc6..bb38a0b5c 100644 --- a/dev/tests/unit/Util/MagentoTestCase.php +++ b/dev/tests/unit/Util/MagentoTestCase.php @@ -19,6 +19,8 @@ public static function setUpBeforeClass(): void if (!self::fileExists(DOCS_OUTPUT_DIR)) { mkdir(DOCS_OUTPUT_DIR, 0755, true); } + // Should be used to clean AspectMock mocking before using PHPUnit mocking and Reflection. + AspectMock::clean(); parent::setUpBeforeClass(); } From 4bcfac1046f355dc612089b3dd1a4de3a557b5dd Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Wed, 21 Jul 2021 18:03:29 +0300 Subject: [PATCH 659/888] 33294: Code refactoring after code review --- .../Allure/Event/AddUniqueAttachmentEvent.php | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php b/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php index c5e7c0d31..ccf95eb37 100644 --- a/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php +++ b/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php @@ -21,30 +21,6 @@ class AddUniqueAttachmentEvent extends AddAttachmentEvent */ private static $instance; - /** - * An alternative way to instantiate an instance of this class. Used to mock this class object in unit tests. - * - * @param mixed $filePathOrContents - * @param string $caption - * @param string|null $type - * - * @return AddUniqueAttachmentEvent - */ - public static function getInstance( - $filePathOrContents, - string $caption, - ?string $type = null - ): AddUniqueAttachmentEvent { - if (!self::$instance) { - self::$instance = new AddUniqueAttachmentEvent( - $filePathOrContents, - $caption, - $type - ); - } - return self::$instance; - } - /** * Near copy of parent function, added uniqid call for filename to prevent buggy allure behavior. * @@ -93,6 +69,30 @@ public function copyFile(string $filePath, string $outputPath): bool return copy($filePath, $outputPath); } + /** + * Unit test helper function. + * + * @param mixed $filePathOrContents + * @param string $caption + * @param string|null $type + * + * @return AddUniqueAttachmentEvent + */ + public static function getInstance( + $filePathOrContents, + string $caption, + ?string $type = null + ): AddUniqueAttachmentEvent { + if (!self::$instance) { + self::$instance = new AddUniqueAttachmentEvent( + $filePathOrContents, + $caption, + $type + ); + } + return self::$instance; + } + /** * Copy of parent private function. * From c858eb1a0d82691913e13ba85f353023ab80b33a Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 21 Jul 2021 18:28:26 -0500 Subject: [PATCH 660/888] MQE-2806: changelog and version bump for release 3.6.0 --- CHANGELOG.md | 19 ++++++++++++++++++- composer.json | 2 +- composer.lock | 2 +- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 328824514..741a15260 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ Magento Functional Testing Framework Changelog ================================================ +3.6.0 +--------- + +### Enhancements + +* Maintainability + * Updated composer dependencies to be PHP 8 compatible with the except of codeception/aspect-mock. + +### GitHub Pull Requests: + +* [#830](https://github.com/magento/magento2-functional-testing-framework/pull/830) -- Add ability to configure multiple OTPs +* [#832](https://github.com/magento/magento2-functional-testing-framework/pull/832) -- Updated monolog/monolog to ^2.2 +* [#833](https://github.com/magento/magento2-functional-testing-framework/pull/833) -- Removed usage of AspectMock in FilesystemTest +* [#834](https://github.com/magento/magento2-functional-testing-framework/pull/834) -- Removed usage of AspectMock in AnnotationsCheckTest +* [#838](https://github.com/magento/magento2-functional-testing-framework/pull/838) -- Removed usage of AspectMock in DeprecatedEntityUsageCheckTest +* [#841](https://github.com/magento/magento2-functional-testing-framework/pull/841) -- Removed usage of AspectMock in GenerationErrorHandlerTest +* [#854](https://github.com/magento/magento2-functional-testing-framework/pull/854) -- Updated "monolog" to the latest version 2.3.1 + 3.5.1 --------- @@ -7,7 +25,6 @@ Magento Functional Testing Framework Changelog * [#825](https://github.com/magento/magento2-functional-testing-framework/pull/825) -- Update allure-codeception in order to support php8 - 3.5.0 --------- diff --git a/composer.json b/composer.json index 94ff6a35f..bdf92ca3d 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "3.5.1", + "version": "3.6.0", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index e2110d79b..226426ef8 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "dcd4540cf1aed5a943189676f90f43cb", + "content-hash": "9bec96d8a169a4286803657bbf61004c", "packages": [ { "name": "allure-framework/allure-codeception", From 3bf364839d6df276abd6ee775371d178b811a244 Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Thu, 22 Jul 2021 12:02:06 +0300 Subject: [PATCH 661/888] 33294: Code refactoring after code review --- .../Allure/AllureHelperTest.php | 26 --------------- .../Allure/Event/AddUniqueAttachmentEvent.php | 32 +++++++++++-------- 2 files changed, 19 insertions(+), 39 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php index 638db3702..1e17b780d 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php @@ -106,7 +106,6 @@ public function testAddAttachmentUniqueName(): void { $expectedData = 'string'; $expectedCaption = 'caption'; - $this->mockCopyFile($expectedData, $expectedCaption); //Prepare Allure lifecycle Allure::lifecycle()->fire(new StepStartedEvent('firstStep')); @@ -146,29 +145,4 @@ private function mockAttachmentWriteEvent(string $filePathOrContents, string $ca $instanceProperty->setAccessible(true); $instanceProperty->setValue($mockInstance, $mockInstance); } - - /** - * Mock only file writing mechanism. - * - * @param string $filePathOrContents - * @param string $caption - * - * @return void - */ - private function mockCopyFile(string $filePathOrContents, string $caption): void - { - $mockInstance = $this->getMockBuilder(AddUniqueAttachmentEvent::class) - ->setConstructorArgs([$filePathOrContents, $caption]) - ->disallowMockingUnknownTypes() - ->onlyMethods(['copyFile']) - ->getMock(); - - $mockInstance - ->method('copyFile') - ->willReturn(true); - - $instanceProperty = new ReflectionProperty(AddUniqueAttachmentEvent::class, 'instance'); - $instanceProperty->setAccessible(true); - $instanceProperty->setValue($mockInstance, $mockInstance); - } } diff --git a/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php b/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php index ccf95eb37..990cd5f10 100644 --- a/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php +++ b/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php @@ -7,6 +7,8 @@ namespace Magento\FunctionalTestingFramework\Allure\Event; +use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Symfony\Component\Mime\MimeTypes; use Yandex\Allure\Adapter\AllureException; use Yandex\Allure\Adapter\Event\AddAttachmentEvent; @@ -56,19 +58,6 @@ public function getAttachmentFileName($filePathOrContents, $type): string return $this->getOutputFileName($fileSha1, $fileExtension); } - /** - * Copies file from one path to another. Wrapper for mocking in unit test. - * - * @param string $filePath - * @param string $outputPath - * - * @return boolean - */ - public function copyFile(string $filePath, string $outputPath): bool - { - return copy($filePath, $outputPath); - } - /** * Unit test helper function. * @@ -93,6 +82,23 @@ public static function getInstance( return self::$instance; } + /** + * Copies file from one path to another. Wrapper for mocking in unit test. + * + * @param string $filePath + * @param string $outputPath + * + * @return boolean + * @throws TestFrameworkException + */ + private function copyFile(string $filePath, string $outputPath): bool + { + if (MftfApplicationConfig::getConfig()->getPhase() === MftfApplicationConfig::UNIT_TEST_PHASE) { + return true; + } + return copy($filePath, $outputPath); + } + /** * Copy of parent private function. * From 1fdb5b9b96dd7cd0c668c2f30b06a7bd2e50bb95 Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Thu, 22 Jul 2021 12:36:17 +0300 Subject: [PATCH 662/888] 33305: Code refactoring after code review --- .../Test/Util/ObjectExtensionUtilTest.php | 133 +++++++++--------- .../unit/Util/MockModuleResolverBuilder.php | 33 ++--- 2 files changed, 76 insertions(+), 90 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ObjectExtensionUtilTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ObjectExtensionUtilTest.php index fc1893e0b..b30e4b50e 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ObjectExtensionUtilTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ObjectExtensionUtilTest.php @@ -15,7 +15,6 @@ use Magento\FunctionalTestingFramework\Test\Parsers\TestDataParser; use PHPUnit\Framework\TestCase; use ReflectionProperty; -use tests\unit\Util\MockModuleResolverBuilder; use tests\unit\Util\TestDataArrayBuilder; use tests\unit\Util\TestLoggingUtil; @@ -30,8 +29,6 @@ class ObjectExtensionUtilTest extends TestCase protected function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); - $resolverMock = new MockModuleResolverBuilder(); - $resolverMock->setup(); } /** @@ -53,7 +50,7 @@ public static function tearDownAfterClass(): void public function testGenerateExtendedTest(): void { $mockActions = [ - "mockStep" => ["nodeName" => "mockNode", "stepKey" => "mockStep"] + 'mockStep' => ['nodeName' => 'mockNode', 'stepKey' => 'mockStep'] ]; $testDataArrayBuilder = new TestDataArrayBuilder(); @@ -66,7 +63,7 @@ public function testGenerateExtendedTest(): void $mockExtendedTest = $testDataArrayBuilder ->withName('extendedTest') ->withAnnotations(['title' => [['value' => 'extendedTest']]]) - ->withTestReference("simpleTest") + ->withTestReference('simpleTest') ->build(); $mockTestData = array_merge($mockSimpleTest, $mockExtendedTest); @@ -83,8 +80,8 @@ public function testGenerateExtendedTest(): void ); // assert that expected test is generated - $this->assertEquals($testObject->getParentName(), "simpleTest"); - $this->assertArrayHasKey("mockStep", $testObject->getOrderedActions()); + $this->assertEquals($testObject->getParentName(), 'simpleTest'); + $this->assertArrayHasKey('mockStep', $testObject->getOrderedActions()); } /** @@ -96,10 +93,10 @@ public function testGenerateExtendedTest(): void public function testGenerateExtendedWithHooks(): void { $mockBeforeHooks = [ - "beforeHookAction" => ["nodeName" => "mockNodeBefore", "stepKey" => "mockStepBefore"] + 'beforeHookAction' => ['nodeName' => 'mockNodeBefore', 'stepKey' => 'mockStepBefore'] ]; $mockAfterHooks = [ - "afterHookAction" => ["nodeName" => "mockNodeAfter", "stepKey" => "mockStepAfter"] + 'afterHookAction' => ['nodeName' => 'mockNodeAfter', 'stepKey' => 'mockStepAfter'] ]; $testDataArrayBuilder = new TestDataArrayBuilder(); @@ -113,7 +110,7 @@ public function testGenerateExtendedWithHooks(): void $mockExtendedTest = $testDataArrayBuilder ->withName('extendedTest') ->withAnnotations(['title' => [['value' => 'extendedTest']]]) - ->withTestReference("simpleTest") + ->withTestReference('simpleTest') ->build(); $mockTestData = array_merge($mockSimpleTest, $mockExtendedTest); @@ -130,9 +127,9 @@ public function testGenerateExtendedWithHooks(): void ); // assert that expected test is generated - $this->assertEquals($testObject->getParentName(), "simpleTest"); - $this->assertArrayHasKey("mockStepBefore", $testObject->getHooks()['before']->getActions()); - $this->assertArrayHasKey("mockStepAfter", $testObject->getHooks()['after']->getActions()); + $this->assertEquals($testObject->getParentName(), 'simpleTest'); + $this->assertArrayHasKey('mockStepBefore', $testObject->getHooks()['before']->getActions()); + $this->assertArrayHasKey('mockStepAfter', $testObject->getHooks()['after']->getActions()); } /** @@ -146,7 +143,7 @@ public function testExtendedTestNoParent(): void $testDataArrayBuilder = new TestDataArrayBuilder(); $mockExtendedTest = $testDataArrayBuilder ->withName('extendedTest') - ->withTestReference("simpleTest") + ->withTestReference('simpleTest') ->build(); $mockTestData = array_merge($mockExtendedTest); @@ -158,7 +155,7 @@ public function testExtendedTestNoParent(): void // validate log statement TestLoggingUtil::getInstance()->validateMockLogStatement( 'debug', - "parent test not defined. test will be skipped", + 'parent test not defined. test will be skipped', ['parent' => 'simpleTest', 'test' => 'extendedTest'] ); } @@ -181,19 +178,19 @@ public function testExtendingExtendedTest(): void ->withName('simpleTest') ->withAnnotations(['title' => [['value' => 'simpleTest']]]) ->withTestActions() - ->withTestReference("anotherTest") + ->withTestReference('anotherTest') ->build(); $mockExtendedTest = $testDataArrayBuilder ->withName('extendedTest') ->withAnnotations(['title' => [['value' => 'extendedTest']]]) - ->withTestReference("simpleTest") + ->withTestReference('simpleTest') ->build(); $mockTestData = array_merge($mockParentTest, $mockSimpleTest, $mockExtendedTest); $this->setMockTestOutput($mockTestData); - $this->expectExceptionMessage("Cannot extend a test that already extends another test. Test: simpleTest"); + $this->expectExceptionMessage('Cannot extend a test that already extends another test. Test: simpleTest'); // parse and generate test object with mocked data TestObjectHandler::getInstance()->getObject('extendedTest'); @@ -201,10 +198,10 @@ public function testExtendingExtendedTest(): void // validate log statement TestLoggingUtil::getInstance()->validateMockLogStatement( 'debug', - "parent test not defined. test will be skipped", + 'parent test not defined. test will be skipped', ['parent' => 'simpleTest', 'test' => 'extendedTest'] ); - $this->expectOutputString("Extending Test: anotherTest => simpleTest" . PHP_EOL); + $this->expectOutputString('Extending Test: anotherTest => simpleTest' . PHP_EOL); } /** @@ -216,30 +213,30 @@ public function testExtendingExtendedTest(): void public function testGenerateExtendedActionGroup(): void { $mockSimpleActionGroup = [ - "nodeName" => "actionGroup", - "name" => "mockSimpleActionGroup", - "filename" => "someFile", - "commentHere" => [ - "nodeName" => "comment", - "selector" => "selector", - "stepKey" => "commentHere" + 'nodeName' => 'actionGroup', + 'name' => 'mockSimpleActionGroup', + 'filename' => 'someFile', + 'commentHere' => [ + 'nodeName' => 'comment', + 'selector' => 'selector', + 'stepKey' => 'commentHere' ], - "parentComment" => [ - "nodeName" => "comment", - "selector" => "parentSelector", - "stepKey" => "parentComment" + 'parentComment' => [ + 'nodeName' => 'comment', + 'selector' => 'parentSelector', + 'stepKey' => 'parentComment' ], ]; $mockExtendedActionGroup = [ - "nodeName" => "actionGroup", - "name" => "mockExtendedActionGroup", - "filename" => "someFile", - "extends" => "mockSimpleActionGroup", - "commentHere" => [ - "nodeName" => "comment", - "selector" => "otherSelector", - "stepKey" => "commentHere" + 'nodeName' => 'actionGroup', + 'name' => 'mockExtendedActionGroup', + 'filename' => 'someFile', + 'extends' => 'mockSimpleActionGroup', + 'commentHere' => [ + 'nodeName' => 'comment', + 'selector' => 'otherSelector', + 'stepKey' => 'commentHere' ], ]; @@ -262,10 +259,10 @@ public function testGenerateExtendedActionGroup(): void ); // assert that expected test is generated - $this->assertEquals("mockSimpleActionGroup", $actionGroupObject->getParentName()); + $this->assertEquals('mockSimpleActionGroup', $actionGroupObject->getParentName()); $actions = $actionGroupObject->getActions(); - $this->assertEquals("otherSelector", $actions["commentHere"]->getCustomActionAttributes()["selector"]); - $this->assertEquals("parentSelector", $actions["parentComment"]->getCustomActionAttributes()["selector"]); + $this->assertEquals('otherSelector', $actions['commentHere']->getCustomActionAttributes()['selector']); + $this->assertEquals('parentSelector', $actions['parentComment']->getCustomActionAttributes()['selector']); } /** @@ -277,14 +274,14 @@ public function testGenerateExtendedActionGroup(): void public function testGenerateExtendedActionGroupNoParent(): void { $mockExtendedActionGroup = [ - "nodeName" => "actionGroup", - "name" => "mockExtendedActionGroup", - "filename" => "someFile", - "extends" => "mockSimpleActionGroup", - "commentHere" => [ - "nodeName" => "comment", - "selector" => "otherSelector", - "stepKey" => "commentHere" + 'nodeName' => 'actionGroup', + 'name' => 'mockExtendedActionGroup', + 'filename' => 'someFile', + 'extends' => 'mockSimpleActionGroup', + 'commentHere' => [ + 'nodeName' => 'comment', + 'selector' => 'otherSelector', + 'stepKey' => 'commentHere' ], ]; @@ -296,7 +293,7 @@ public function testGenerateExtendedActionGroupNoParent(): void $this->setMockTestOutput(null, $mockActionGroupData); $this->expectExceptionMessage( - "Parent Action Group mockSimpleActionGroup not defined for Test " . $mockExtendedActionGroup['name'] + 'Parent Action Group mockSimpleActionGroup not defined for Test ' . $mockExtendedActionGroup['name'] ); // parse and generate test object with mocked data @@ -312,23 +309,23 @@ public function testGenerateExtendedActionGroupNoParent(): void public function testExtendingExtendedActionGroup(): void { $mockParentActionGroup = [ - "nodeName" => "actionGroup", - "name" => "mockParentActionGroup", - "filename" => "someFile" + 'nodeName' => 'actionGroup', + 'name' => 'mockParentActionGroup', + 'filename' => 'someFile' ]; $mockSimpleActionGroup = [ - "nodeName" => "actionGroup", - "name" => "mockSimpleActionGroup", - "filename" => "someFile", - "extends" => "mockParentActionGroup", + 'nodeName' => 'actionGroup', + 'name' => 'mockSimpleActionGroup', + 'filename' => 'someFile', + 'extends' => 'mockParentActionGroup' ]; $mockExtendedActionGroup = [ - "nodeName" => "actionGroup", - "name" => "mockExtendedActionGroup", - "filename" => "someFile", - "extends" => "mockSimpleActionGroup", + 'nodeName' => 'actionGroup', + 'name' => 'mockExtendedActionGroup', + 'filename' => 'someFile', + 'extends' => 'mockSimpleActionGroup' ]; $mockActionGroupData = [ @@ -341,22 +338,22 @@ public function testExtendingExtendedActionGroup(): void $this->setMockTestOutput(null, $mockActionGroupData); $this->expectExceptionMessage( - "Cannot extend an action group that already extends another action group. " . $mockSimpleActionGroup['name'] + 'Cannot extend an action group that already extends another action group. ' . $mockSimpleActionGroup['name'] ); // parse and generate test object with mocked data try { ActionGroupObjectHandler::getInstance()->getObject('mockExtendedActionGroup'); - } catch (Exception $e) { + } catch (Exception $exception) { // validate log statement TestLoggingUtil::getInstance()->validateMockLogStatement( 'error', - "Cannot extend an action group that already extends another action group. " . + 'Cannot extend an action group that already extends another action group. ' . $mockSimpleActionGroup['name'], ['parent' => $mockSimpleActionGroup['name'], 'actionGroup' => $mockExtendedActionGroup['name']] ); - throw $e; + throw $exception; } } @@ -379,7 +376,7 @@ public function testExtendedTestSkippedParent(): void $testDataArrayBuilder->reset(); $mockExtendedTest = $testDataArrayBuilder ->withName('extendTest') - ->withTestReference("baseTest") + ->withTestReference('baseTest') ->build(); $mockTestData = array_merge($mockParentTest, $mockExtendedTest); @@ -391,7 +388,7 @@ public function testExtendedTestSkippedParent(): void // validate log statement TestLoggingUtil::getInstance()->validateMockLogStatement( 'debug', - "extendTest is skipped due to ParentTestIsSkipped", + 'extendTest is skipped due to ParentTestIsSkipped', [] ); } diff --git a/dev/tests/unit/Util/MockModuleResolverBuilder.php b/dev/tests/unit/Util/MockModuleResolverBuilder.php index 8bf30aa00..0e1b6fc31 100644 --- a/dev/tests/unit/Util/MockModuleResolverBuilder.php +++ b/dev/tests/unit/Util/MockModuleResolverBuilder.php @@ -3,35 +3,31 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -declare(strict_types=1); - namespace tests\unit\Util; use AspectMock\Test as AspectMock; -use Exception; -use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\ObjectManager; +use Magento\FunctionalTestingFramework\ObjectManagerFactory; use Magento\FunctionalTestingFramework\Util\ModuleResolver; -use ReflectionProperty; +use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; class MockModuleResolverBuilder { /** - * Default paths for mock ModuleResolver. + * Default paths for mock ModuleResolver * * @var array */ private $defaultPaths = ['Magento_Module' => '/base/path/some/other/path/Magento/Module']; /** - * Mock ModuleResolver builder. - * - * @param array|null $paths + * Mock ModuleResolver builder * + * @param array $paths * @return void - * @throws Exception + * @throws \Exception */ - public function setup(array $paths = null): void + public function setup($paths = null) { if (empty($paths)) { $paths = $this->defaultPaths; @@ -39,12 +35,9 @@ public function setup(array $paths = null): void $mockConfig = AspectMock::double(MftfApplicationConfig::class, ['forceGenerateEnabled' => false]); $instance = AspectMock::double(ObjectManager::class, ['create' => $mockConfig->make(), 'get' => null])->make(); - // clear object manager value to inject expected instance - $property = new ReflectionProperty(ObjectManager::class, 'instance'); - $property->setAccessible(true); - $property->setValue($instance); + AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); - $property = new ReflectionProperty(ModuleResolver::class, 'instance'); + $property = new \ReflectionProperty(ModuleResolver::class, 'instance'); $property->setAccessible(true); $property->setValue(null); @@ -58,14 +51,10 @@ public function setup(array $paths = null): void ); $instance = AspectMock::double(ObjectManager::class, ['create' => $mockResolver->make(), 'get' => null]) ->make(); - - // clear object manager value to inject expected instance - $property = new ReflectionProperty(ObjectManager::class, 'instance'); - $property->setAccessible(true); - $property->setValue($instance); + AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); $resolver = ModuleResolver::getInstance(); - $property = new ReflectionProperty(ModuleResolver::class, 'enabledModuleNameAndPaths'); + $property = new \ReflectionProperty(ModuleResolver::class, 'enabledModuleNameAndPaths'); $property->setAccessible(true); $property->setValue($resolver, $paths); } From 9f0135500a80c10f46092e146517f119e3ae3ccd Mon Sep 17 00:00:00 2001 From: Karyna <k.tsymbal@atwix.com> Date: Thu, 22 Jul 2021 14:32:00 +0300 Subject: [PATCH 663/888] Issue 33296: Eliminate AspectMock from OperationDataArrayResolverTest --- .../OperationDataArrayResolverTest.php | 395 ++++++++++-------- 1 file changed, 218 insertions(+), 177 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php index 2721bd266..db043f860 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php @@ -3,13 +3,15 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace tests\unit\Magento\FunctionalTestFramework\DataGenerator\Persist; -use AspectMock\Test as AspectMock; +use Exception; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\OperationDefinitionObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Persist\OperationDataArrayResolver; -use Magento\FunctionalTestingFramework\Util\Iterator\AbstractIterator; +use ReflectionProperty; use tests\unit\Util\MagentoTestCase; use tests\unit\Util\EntityDataObjectBuilder; use tests\unit\Util\OperationDefinitionBuilder; @@ -18,27 +20,28 @@ class OperationDataArrayResolverTest extends MagentoTestCase { - const NESTED_METADATA_EXPECTED_RESULT = ["parentType" => [ - "name" => "Hopper", - "address" => ["city" => "Hawkins", "state" => "Indiana", "zip" => 78758], - "isPrimary" => true, - "gpa" => 3.5678, - "phone" => 5555555 + const NESTED_METADATA_EXPECTED_RESULT = ['parentType' => [ + 'name' => 'Hopper', + 'address' => ['city' => 'Hawkins', 'state' => 'Indiana', 'zip' => 78758], + 'isPrimary' => true, + 'gpa' => 3.5678, + 'phone' => 5555555 ]]; - const NESTED_METADATA_ARRAY_RESULT = ["parentType" => [ - "name" => "Hopper", - "isPrimary" => true, - "gpa" => 3.5678, - "phone" => 5555555, - "address" => [ - ["city" => "Hawkins", "state" => "Indiana", "zip" => 78758], - ["city" => "Austin", "state" => "Texas", "zip" => 78701], + const NESTED_METADATA_ARRAY_RESULT = ['parentType' => [ + 'name' => 'Hopper', + 'isPrimary' => true, + 'gpa' => 3.5678, + 'phone' => 5555555, + 'address' => [ + ['city' => 'Hawkins', 'state' => 'Indiana', 'zip' => 78758], + ['city' => 'Austin', 'state' => 'Texas', 'zip' => 78701], ] ]]; /** * Before test functionality + * * @return void */ public function setUp(): void @@ -54,8 +57,11 @@ public function setUp(): void * <field>boolField</field> * <field>doubleField</field> * </object> + * + * @return void + * @throws Exception */ - public function testBasicPrimitiveMetadataResolve() + public function testBasicPrimitiveMetadataResolve(): void { // set up data object $entityObjectBuilder = new EntityDataObjectBuilder(); @@ -74,11 +80,11 @@ public function testBasicPrimitiveMetadataResolve() ); // assert on result - $expectedResult = ["testType" => [ - "name" => "Hopper", - "gpa" => 3.5678, - "phone" => 5555555, - "isPrimary" => true + $expectedResult = ['testType' => [ + 'name' => 'Hopper', + 'gpa' => 3.5678, + 'phone' => 5555555, + 'isPrimary' => true ]]; $this->assertEquals($expectedResult, $result); @@ -90,56 +96,54 @@ public function testBasicPrimitiveMetadataResolve() * <field>someField</field> * <field>objectRef</field> * </object> + * + * @return void + * @throws Exception */ - public function testNestedMetadataResolve() + public function testNestedMetadataResolve(): void { // set up data objects $entityDataObjBuilder = new EntityDataObjectBuilder(); $parentDataObject = $entityDataObjBuilder - ->withName("parentObject") - ->withType("parentType") + ->withName('parentObject') + ->withType('parentType') ->withLinkedEntities(['childObject' => 'childType']) ->build(); $childDataObject = $entityDataObjBuilder - ->withName("childObject") - ->withType("childType") - ->withDataFields(["city" => "Hawkins", "state" => "Indiana", "zip" => "78758"]) + ->withName('childObject') + ->withType('childType') + ->withDataFields(['city' => 'Hawkins', 'state' => 'Indiana', 'zip' => '78758']) ->build(); // mock data object handler - $mockDOHInstance = AspectMock::double(DataObjectHandler::class, ['getObject' => $childDataObject])->make(); - AspectMock::double(DataObjectHandler::class, ['getInstance' => $mockDOHInstance]); + $this->mockDataObjectHandler($childDataObject); // set up metadata objects $parentOpElementBuilder = new OperationElementBuilder(); $parentElement = $parentOpElementBuilder - ->withKey("parentType") - ->withType("parentType") - ->addFields(["address" => "childType"]) + ->withKey('parentType') + ->withType('parentType') + ->addFields(['address' => 'childType']) ->build(); $operationDefinitionBuilder = new OperationDefinitionBuilder(); $childOperationDefinition = $operationDefinitionBuilder - ->withName("createChildType") - ->withOperation("create") - ->withType("childType") + ->withName('createChildType') + ->withOperation('create') + ->withType('childType') ->withMetadata([ - "city" => "string", - "state" => "string", - "zip" => "integer" + 'city' => 'string', + 'state' => 'string', + 'zip' => 'integer' ])->build(); // mock meta data object handler - $mockDOHInstance = AspectMock::double( - OperationDefinitionObjectHandler::class, - ['getObject' => $childOperationDefinition] - )->make(); - AspectMock::double(OperationDefinitionObjectHandler::class, ['getInstance' => $mockDOHInstance]); + $this->mockOperationDefinitionObjectHandler($childOperationDefinition); // resolve data object and metadata array $operationResolver = new OperationDataArrayResolver(); - $result = $operationResolver->resolveOperationDataArray($parentDataObject, [$parentElement], "create", false); + $result = $operationResolver->resolveOperationDataArray($parentDataObject, [$parentElement], 'create', false); // assert on the result $this->assertEquals(self::NESTED_METADATA_EXPECTED_RESULT, $result); @@ -153,45 +157,47 @@ public function testNestedMetadataResolve() * <field>anotherField</field> * </object> * </object> + * + * @return void + * @throws Exception */ - public function testNestedMetadata() + public function testNestedMetadata(): void { // set up data objects $entityDataObjectBuilder = new EntityDataObjectBuilder(); $parentDataObject = $entityDataObjectBuilder - ->withName("parentObject") - ->withType("parentType") + ->withName('parentObject') + ->withType('parentType') ->withLinkedEntities(['childObject' => 'childType']) ->build(); $childDataObject = $entityDataObjectBuilder - ->withName("childObject") - ->withType("childType") - ->withDataFields(["city" => "Hawkins", "state" => "Indiana", "zip" => "78758"]) + ->withName('childObject') + ->withType('childType') + ->withDataFields(['city' => 'Hawkins', 'state' => 'Indiana', 'zip' => '78758']) ->build(); // mock data object handler - $mockDOHInstance = AspectMock::double(DataObjectHandler::class, ['getObject' => $childDataObject])->make(); - AspectMock::double(DataObjectHandler::class, ['getInstance' => $mockDOHInstance]); + $this->mockDataObjectHandler($childDataObject); // set up metadata objects $childOpElementBuilder = new OperationElementBuilder(); $childElement = $childOpElementBuilder - ->withKey("address") - ->withType("childType") - ->withFields(["city" => "string", "state" => "string", "zip" => "integer"]) + ->withKey('address') + ->withType('childType') + ->withFields(['city' => 'string', 'state' => 'string', 'zip' => 'integer']) ->build(); $parentOpElementBuilder = new OperationElementBuilder(); $parentElement = $parentOpElementBuilder - ->withKey("parentType") - ->withType("parentType") - ->addElements(["address" => $childElement]) + ->withKey('parentType') + ->withType('parentType') + ->addElements(['address' => $childElement]) ->build(); // resolve data object and metadata array $operationResolver = new OperationDataArrayResolver(); - $result = $operationResolver->resolveOperationDataArray($parentDataObject, [$parentElement], "create", false); + $result = $operationResolver->resolveOperationDataArray($parentDataObject, [$parentElement], 'create', false); // assert on the result $this->assertEquals(self::NESTED_METADATA_EXPECTED_RESULT, $result); @@ -207,66 +213,69 @@ public function testNestedMetadata() * </object> * </array * </object> + * + * @return void + * @throws Exception */ - public function testNestedMetadataArrayOfObjects() + public function testNestedMetadataArrayOfObjects(): void { // set up data objects $entityDataObjectBuilder = new EntityDataObjectBuilder(); $parentDataObject = $entityDataObjectBuilder - ->withName("parentObject") - ->withType("parentType") + ->withName('parentObject') + ->withType('parentType') ->withLinkedEntities(['childObject1' => 'childType', 'childObject2' => 'childType']) ->build(); // mock data object handler - $mockDOHInstance = AspectMock::double(DataObjectHandler::class, ["getObject" => function ($name) { + $callback = function ($name) { $entityDataObjectBuilder = new EntityDataObjectBuilder(); - if ($name == "childObject1") { + if ($name === 'childObject1') { return $entityDataObjectBuilder - ->withName("childObject1") - ->withType("childType") - ->withDataFields(["city" => "Hawkins", "state" => "Indiana", "zip" => "78758"]) + ->withName('childObject1') + ->withType('childType') + ->withDataFields(['city' => 'Hawkins', 'state' => 'Indiana', 'zip' => '78758']) ->build(); } - if ($name == "childObject2") { + if ($name === 'childObject2') { return $entityDataObjectBuilder - ->withName("childObject2") - ->withType("childType") - ->withDataFields(["city" => "Austin", "state" => "Texas", "zip" => "78701"]) + ->withName('childObject2') + ->withType('childType') + ->withDataFields(['city' => 'Austin', 'state' => 'Texas', 'zip' => '78701']) ->build(); } - }])->make(); - AspectMock::double(DataObjectHandler::class, ['getInstance' => $mockDOHInstance]); + }; + $this->mockDataObjectHandler($callback); // set up metadata objects $childOpElementBuilder = new OperationElementBuilder(); $childElement = $childOpElementBuilder - ->withKey("childType") - ->withType("childType") - ->withFields(["city" => "string", "state" => "string", "zip" => "integer"]) + ->withKey('childType') + ->withType('childType') + ->withFields(['city' => 'string', 'state' => 'string', 'zip' => 'integer']) ->build(); $arrayOpElementBuilder = new OperationElementBuilder(); $arrayElement = $arrayOpElementBuilder - ->withKey("address") - ->withType("childType") + ->withKey('address') + ->withType('childType') ->withFields([]) ->withElementType(OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY) - ->withNestedElements(["childType" => $childElement]) + ->withNestedElements(['childType' => $childElement]) ->build(); $parentOpElementBuilder = new OperationElementBuilder(); $parentElement = $parentOpElementBuilder - ->withKey("parentType") - ->withType("parentType") - ->addElements(["address" => $arrayElement]) + ->withKey('parentType') + ->withType('parentType') + ->addElements(['address' => $arrayElement]) ->build(); // resolve data object and metadata array $operationResolver = new OperationDataArrayResolver(); - $result = $operationResolver->resolveOperationDataArray($parentDataObject, [$parentElement], "create", false); + $result = $operationResolver->resolveOperationDataArray($parentDataObject, [$parentElement], 'create', false); // Do assert on result here $this->assertEquals(self::NESTED_METADATA_ARRAY_RESULT, $result); @@ -280,44 +289,47 @@ public function testNestedMetadataArrayOfObjects() * <value>object</value> * </array * </object> + * + * @return void + * @throws Exception */ - public function testNestedMetadataArrayOfValue() + public function testNestedMetadataArrayOfValue(): void { // set up data objects $entityDataObjectBuilder = new EntityDataObjectBuilder(); $parentDataObject = $entityDataObjectBuilder - ->withName("parentObject") - ->withType("parentType") + ->withName('parentObject') + ->withType('parentType') ->withLinkedEntities(['childObject1' => 'childType', 'childObject2' => 'childType']) ->build(); - // mock data object handler - $mockDOHInstance = AspectMock::double(DataObjectHandler::class, ["getObject" => function ($name) { + $callback = function ($name) { $entityDataObjectBuilder = new EntityDataObjectBuilder(); - if ($name == "childObject1") { + if ($name == 'childObject1') { return $entityDataObjectBuilder - ->withName("childObject1") - ->withType("childType") - ->withDataFields(["city" => "Hawkins", "state" => "Indiana", "zip" => "78758"]) + ->withName('childObject1') + ->withType('childType') + ->withDataFields(['city' => 'Hawkins', 'state' => 'Indiana', 'zip' => '78758']) ->build(); }; - if ($name == "childObject2") { + if ($name == 'childObject2') { return $entityDataObjectBuilder - ->withName("childObject2") - ->withType("childType") - ->withDataFields(["city" => "Austin", "state" => "Texas", "zip" => "78701"]) + ->withName('childObject2') + ->withType('childType') + ->withDataFields(['city' => 'Austin', 'state' => 'Texas', 'zip' => '78701']) ->build(); } - }])->make(); - AspectMock::double(DataObjectHandler::class, ['getInstance' => $mockDOHInstance]); + }; + // mock data object handler + $this->mockDataObjectHandler($callback); // set up metadata objects $arrayOpElementBuilder = new OperationElementBuilder(); $arrayElement = $arrayOpElementBuilder - ->withKey("address") - ->withType("childType") + ->withKey('address') + ->withType('childType') ->withElementType(OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY) ->withNestedElements([]) ->withFields([]) @@ -325,44 +337,39 @@ public function testNestedMetadataArrayOfValue() $parentOpElementBuilder = new OperationElementBuilder(); $parentElement = $parentOpElementBuilder - ->withKey("parentType") - ->withType("parentType") - ->addElements(["address" => $arrayElement]) + ->withKey('parentType') + ->withType('parentType') + ->addElements(['address' => $arrayElement]) ->build(); $operationDefinitionBuilder = new OperationDefinitionBuilder(); $childOperationDefinition = $operationDefinitionBuilder - ->withName("createChildType") - ->withOperation("create") - ->withType("childType") + ->withName('createChildType') + ->withOperation('create') + ->withType('childType') ->withMetadata([ - "city" => "string", - "state" => "string", - "zip" => "integer" + 'city' => 'string', + 'state' => 'string', + 'zip' => 'integer' ])->build(); // mock meta data object handler - $mockDOHInstance = AspectMock::double( - OperationDefinitionObjectHandler::class, - ['getObject' => $childOperationDefinition] - )->make(); - AspectMock::double(OperationDefinitionObjectHandler::class, ['getInstance' => $mockDOHInstance]); + $this->mockOperationDefinitionObjectHandler($childOperationDefinition); // resolve data object and metadata array $operationResolver = new OperationDataArrayResolver(); - $result = $operationResolver->resolveOperationDataArray($parentDataObject, [$parentElement], "create", false); + $result = $operationResolver->resolveOperationDataArray($parentDataObject, [$parentElement], 'create', false); // Do assert on result here $this->assertEquals(self::NESTED_METADATA_ARRAY_RESULT, $result); } - public function testNestedMetadataArrayOfDiverseObjects() + public function testNestedMetadataArrayOfDiverseObjects(): void { - $entityDataObjBuilder = new EntityDataObjectBuilder(); $parentDataObject = $entityDataObjBuilder - ->withName("parentObject") - ->withType("parentType") + ->withName('parentObject') + ->withType('parentType') ->withLinkedEntities(['child1Object' => 'childType1','child2Object' => 'childType2']) ->build(); @@ -378,22 +385,15 @@ public function testNestedMetadataArrayOfDiverseObjects() ->withDataFields(['city' => 'Testcity 2','zip' => 54321,'state' => 'Teststate']) ->build(); - $mockDOHInstance = AspectMock::double( - DataObjectHandler::class, - [ - 'getObject' => function ($name) use ($child1DataObject, $child2DataObject) { - switch ($name) { - case 'child1Object': - return $child1DataObject; - case 'child2Object': - return $child2DataObject; - } - } - ] - )->make(); - AspectMock::double(DataObjectHandler::class, [ - 'getInstance' => $mockDOHInstance - ]); + $dataObjectCallback = function ($name) use ($child1DataObject, $child2DataObject) { + switch ($name) { + case 'child1Object': + return $child1DataObject; + case 'child2Object': + return $child2DataObject; + } + }; + $this->mockDataObjectHandler($dataObjectCallback); $operationDefinitionBuilder = new OperationDefinitionBuilder(); $child1OperationDefinition = $operationDefinitionBuilder @@ -415,25 +415,15 @@ public function testNestedMetadataArrayOfDiverseObjects() 'state' => 'string' ])->build(); - $mockODOHInstance = AspectMock::double( - OperationDefinitionObjectHandler::class, - [ - 'getObject' => function ($name) use ($child1OperationDefinition, $child2OperationDefinition) { - switch ($name) { - case 'createchildType1': - return $child1OperationDefinition; - case 'createchildType2': - return $child2OperationDefinition; - } - } - ] - )->make(); - AspectMock::double( - OperationDefinitionObjectHandler::class, - [ - 'getInstance' => $mockODOHInstance - ] - ); + $operationObjectCallback = function ($name) use ($child1OperationDefinition, $child2OperationDefinition) { + switch ($name) { + case 'createchildType1': + return $child1OperationDefinition; + case 'createchildType2': + return $child2OperationDefinition; + } + }; + $this->mockOperationDefinitionObjectHandler($operationObjectCallback); $arrayObElementBuilder = new OperationElementBuilder(); $arrayElement = $arrayObElementBuilder @@ -477,55 +467,55 @@ public function testNestedMetadataArrayOfDiverseObjects() $this->assertEquals($expectedResult, $result); } - public function testExtendedWithRequiredEntity() + public function testExtendedWithRequiredEntity(): void { $entityDataObjectBuilder = new EntityDataObjectBuilder(); $extEntityDataObject = $entityDataObjectBuilder - ->withName("extEntity") - ->withType("entity") - ->withLinkedEntities(["baseSubentity" => "subentity","extSubentity" => "subentity"]) + ->withName('extEntity') + ->withType('entity') + ->withLinkedEntities(['baseSubentity' => 'subentity','extSubentity' => 'subentity']) ->build(); - $mockDOHInstance = AspectMock::double(DataObjectHandler::class, ["getObject" => function ($name) { + $callback = function ($name) { $entityDataObjectBuilder = new EntityDataObjectBuilder(); - if ($name == "baseSubentity") { + if ($name === 'baseSubentity') { return $entityDataObjectBuilder - ->withName("baseSubentity") - ->withType("subentity") - ->withDataFields(["subtest" => "BaseSubtest"]) + ->withName('baseSubentity') + ->withType('subentity') + ->withDataFields(['subtest' => 'BaseSubtest']) ->build(); } - if ($name == "extSubentity") { + if ($name === 'extSubentity') { return $entityDataObjectBuilder - ->withName("extSubentity") - ->withType("subentity") - ->withDataFields(["subtest" => "ExtSubtest"]) + ->withName('extSubentity') + ->withType('subentity') + ->withDataFields(['subtest' => 'ExtSubtest']) ->build(); } - }])->make(); - AspectMock::double(DataObjectHandler::class, ['getInstance' => $mockDOHInstance]); + }; + $this->mockDataObjectHandler($callback); $subentityOpElementBuilder = new OperationElementBuilder(); $subentityOpElement = $subentityOpElementBuilder - ->withKey("sub") - ->withType("subentity") - ->withElementType("object") - ->withFields(["subtest" => "string"]) + ->withKey('sub') + ->withType('subentity') + ->withElementType('object') + ->withFields(['subtest' => 'string']) ->build(); $operationResolver = new OperationDataArrayResolver(); $result = $operationResolver->resolveOperationDataArray( $extEntityDataObject, [$subentityOpElement], - "create", + 'create', false ); $expected = [ - "sub" => [ - "subtest" => "ExtSubtest" + 'sub' => [ + 'subtest' => 'ExtSubtest' ] ]; @@ -533,10 +523,61 @@ public function testExtendedWithRequiredEntity() } /** * After class functionality + * * @return void */ public static function tearDownAfterClass(): void { TestLoggingUtil::getInstance()->clearMockLoggingUtil(); } + + /** + * Set up mock DataObjectHandler + * + * @param $childDataObject + * + * @return void + */ + private function mockDataObjectHandler($childDataObject): void + { + $instance = $this->createMock(DataObjectHandler::class); + if (is_callable($childDataObject)) { + $instance->expects($this->any()) + ->method('getObject') + ->willReturnCallback($childDataObject); + } else { + $instance->expects($this->any()) + ->method('getObject') + ->willReturn($childDataObject); + } + + $property = new ReflectionProperty(DataObjectHandler::class, 'INSTANCE'); + $property->setAccessible(true); + $property->setValue($instance); + } + + /** + * Set up mock OperationDefinitionObjectHandler + * + * @param $childOperationDefinition + * + * @return void + */ + private function mockOperationDefinitionObjectHandler($childOperationDefinition): void + { + $instance = $this->createPartialMock(OperationDefinitionObjectHandler::class, ['getObject']); + if (is_callable($childOperationDefinition)) { + $instance->expects($this->any()) + ->method('getObject') + ->willReturnCallback($childOperationDefinition); + } else { + $instance->expects($this->any()) + ->method('getObject') + ->willReturn($childOperationDefinition); + } + + $property = new ReflectionProperty(OperationDefinitionObjectHandler::class, 'INSTANCE'); + $property->setAccessible(true); + $property->setValue($instance); + } } From 2c6f9ecb7e24dc110199e18de7a0752422cababe Mon Sep 17 00:00:00 2001 From: Karyna <k.tsymbal@atwix.com> Date: Thu, 22 Jul 2021 14:52:23 +0300 Subject: [PATCH 664/888] Issue 33297: Eliminate AspectMock from DataExtensionUtilTest --- .../Util/DataExtensionUtilTest.php | 82 +++++++++---------- dev/tests/unit/Util/MagentoTestCase.php | 2 + 2 files changed, 43 insertions(+), 41 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Util/DataExtensionUtilTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Util/DataExtensionUtilTest.php index 3b79ffec3..513715cc1 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Util/DataExtensionUtilTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Util/DataExtensionUtilTest.php @@ -3,37 +3,28 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace tests\unit\Magento\FunctionalTestFramework\DataGenerator\Util; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Parsers\DataProfileSchemaParser; -use Magento\FunctionalTestingFramework\ObjectManager\ObjectManager; -use Magento\FunctionalTestingFramework\ObjectManagerFactory; +use Magento\FunctionalTestingFramework\ObjectManager; +use ReflectionProperty; use tests\unit\Util\MagentoTestCase; -use AspectMock\Test as AspectMock; /** * Class DataExtensionUtilTest */ class DataExtensionUtilTest extends MagentoTestCase { - /** - * Before method functionality - * @return void - */ - protected function setUp(): void - { - AspectMock::clean(); - } - - public function testNoParentData() + public function testNoParentData(): void { $extendedDataObject = [ 'entity' => [ 'extended' => [ 'type' => 'testType', - 'extends' => "parent", + 'extends' => 'parent', 'data' => [ 0 => [ 'key' => 'testKey', @@ -46,21 +37,21 @@ public function testNoParentData() $this->setMockEntities($extendedDataObject); - $this->expectExceptionMessage("Parent Entity parent not defined for Entity extended."); - DataObjectHandler::getInstance()->getObject("extended"); + $this->expectExceptionMessage('Parent Entity parent not defined for Entity extended.'); + DataObjectHandler::getInstance()->getObject('extended'); } - public function testAlreadyExtendedParentData() + public function testAlreadyExtendedParentData(): void { $extendedDataObjects = [ 'entity' => [ 'extended' => [ 'type' => 'testType', - 'extends' => "parent" + 'extends' => 'parent' ], 'parent' => [ 'type' => 'type', - 'extends' => "grandparent" + 'extends' => 'grandparent' ], 'grandparent' => [ 'type' => 'grand' @@ -71,18 +62,18 @@ public function testAlreadyExtendedParentData() $this->setMockEntities($extendedDataObjects); $this->expectExceptionMessage( - "Cannot extend an entity that already extends another entity. Entity: parent." . PHP_EOL + 'Cannot extend an entity that already extends another entity. Entity: parent.' . PHP_EOL ); - DataObjectHandler::getInstance()->getObject("extended"); + DataObjectHandler::getInstance()->getObject('extended'); } - public function testExtendedVarGetter() + public function testExtendedVarGetter(): void { $extendedDataObjects = [ 'entity' => [ 'extended' => [ 'type' => 'testType', - 'extends' => "parent" + 'extends' => 'parent' ], 'parent' => [ 'type' => 'type', @@ -98,18 +89,18 @@ public function testExtendedVarGetter() ]; $this->setMockEntities($extendedDataObjects); - $resultextendedDataObject = DataObjectHandler::getInstance()->getObject("extended"); + $resultextendedDataObject = DataObjectHandler::getInstance()->getObject('extended'); // Perform Asserts - $this->assertEquals("someOtherEntity->id", $resultextendedDataObject->getVarReference("someOtherEntity")); + $this->assertEquals('someOtherEntity->id', $resultextendedDataObject->getVarReference('someOtherEntity')); } - public function testGetLinkedEntities() + public function testGetLinkedEntities(): void { $extendedDataObjects = [ 'entity' => [ 'extended' => [ 'type' => 'testType', - 'extends' => "parent" + 'extends' => 'parent' ], 'parent' => [ 'type' => 'type', @@ -129,27 +120,36 @@ public function testGetLinkedEntities() $this->setMockEntities($extendedDataObjects); // Perform Asserts - $resultextendedDataObject = DataObjectHandler::getInstance()->getObject("extended"); - $this->assertEquals("linkedEntity1", $resultextendedDataObject->getLinkedEntitiesOfType("linkedEntityType")[0]); - $this->assertEquals("linkedEntity2", $resultextendedDataObject->getLinkedEntitiesOfType("otherEntityType")[0]); + $resultextendedDataObject = DataObjectHandler::getInstance()->getObject('extended'); + $this->assertEquals('linkedEntity1', $resultextendedDataObject->getLinkedEntitiesOfType('linkedEntityType')[0]); + $this->assertEquals('linkedEntity2', $resultextendedDataObject->getLinkedEntitiesOfType('otherEntityType')[0]); } - private function setMockEntities($mockEntityData) + /** + * Prepare mock entites. + * + * @param $mockEntityData + * + * @return void + */ + private function setMockEntities($mockEntityData): void { - $property = new \ReflectionProperty(DataObjectHandler::class, 'INSTANCE'); + $property = new ReflectionProperty(DataObjectHandler::class, 'INSTANCE'); $property->setAccessible(true); $property->setValue(null); - $mockDataProfileSchemaParser = AspectMock::double(DataProfileSchemaParser::class, [ - 'readDataProfiles' => $mockEntityData - ])->make(); + $mockDataProfileSchemaParser = $this->createMock(DataProfileSchemaParser::class); + $mockDataProfileSchemaParser->expects($this->any()) + ->method('readDataProfiles') + ->willReturn($mockEntityData); - $mockObjectManager = AspectMock::double(ObjectManager::class, [ - 'create' => $mockDataProfileSchemaParser - ])->make(); + $mockObjectManager = $this->createMock(ObjectManager::class); + $mockObjectManager + ->method('create') + ->willReturn($mockDataProfileSchemaParser); - AspectMock::double(ObjectManagerFactory::class, [ - 'getObjectManager' => $mockObjectManager - ]); + $property = new ReflectionProperty(ObjectManager::class, 'instance'); + $property->setAccessible(true); + $property->setValue($mockObjectManager); } } diff --git a/dev/tests/unit/Util/MagentoTestCase.php b/dev/tests/unit/Util/MagentoTestCase.php index 7760acfc6..bb38a0b5c 100644 --- a/dev/tests/unit/Util/MagentoTestCase.php +++ b/dev/tests/unit/Util/MagentoTestCase.php @@ -19,6 +19,8 @@ public static function setUpBeforeClass(): void if (!self::fileExists(DOCS_OUTPUT_DIR)) { mkdir(DOCS_OUTPUT_DIR, 0755, true); } + // Should be used to clean AspectMock mocking before using PHPUnit mocking and Reflection. + AspectMock::clean(); parent::setUpBeforeClass(); } From e8aad70f0df5b8bc69f80753a4aa1aa73c66bb44 Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Thu, 22 Jul 2021 15:53:50 +0300 Subject: [PATCH 665/888] 33306: Eliminated AspectMock from the ParallelGroupSorterTest class --- .../Util/Sorter/ParallelGroupSorterTest.php | 239 ++++++++---------- 1 file changed, 102 insertions(+), 137 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Sorter/ParallelGroupSorterTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Sorter/ParallelGroupSorterTest.php index 6b25a837a..e289532b5 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Sorter/ParallelGroupSorterTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Sorter/ParallelGroupSorterTest.php @@ -3,23 +3,26 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace tests\unit\Magento\FunctionalTestFramework\Util\Sorter; -use AspectMock\Test as AspectMock; use Magento\FunctionalTestingFramework\Exceptions\FastFailException; -use Magento\FunctionalTestingFramework\Suite\Handlers\SuiteObjectHandler; -use Magento\FunctionalTestingFramework\Suite\Objects\SuiteObject; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; use Magento\FunctionalTestingFramework\Util\Sorter\ParallelGroupSorter; +use ReflectionProperty; use tests\unit\Util\MagentoTestCase; class ParallelGroupSorterTest extends MagentoTestCase { /** - * Test a basic sort of available tests based on size + * Test a basic sort of available tests based on size. + * + * @return void + * @throws FastFailException */ - public function testBasicTestsSplitByTime() + public function testBasicTestsSplitByTime(): void { $sampleTestArray = [ 'test1' => 100, @@ -44,7 +47,6 @@ public function testBasicTestsSplitByTime() $testSorter = new ParallelGroupSorter(); $actualResult = $testSorter->getTestsGroupedBySize([], $sampleTestArray, 200); - $this->assertCount(5, $actualResult); foreach ($actualResult as $gropuNumber => $actualTests) { @@ -54,31 +56,15 @@ public function testBasicTestsSplitByTime() } /** - * Test a sort of both tests and a suite which is larger than the given line limitation + * Test a sort of both tests and a suite which is larger than the given line limitation. + * + * @return void + * @throws FastFailException */ - public function testTestsAndSuitesSplitByTime() + public function testTestsAndSuitesSplitByTime(): void { // mock tests for test object handler. - $numberOfCalls = 0; - $mockTest1 = AspectMock::double( - TestObject::class, - ['getEstimatedDuration' => function () use (&$numberOfCalls) { - $actionCount = [300, 275]; - $result = $actionCount[$numberOfCalls]; - $numberOfCalls++; - - return $result; - }] - )->make(); - - $mockHandler = AspectMock::double( - TestObjectHandler::class, - ['getObject' => function () use ($mockTest1) { - return $mockTest1; - }] - )->make(); - - AspectMock::double(TestObjectHandler::class, ['getInstance' => $mockHandler])->make(); + $this->createMockForTest(0); // create test to size array $sampleTestArray = [ @@ -115,9 +101,12 @@ public function testTestsAndSuitesSplitByTime() } /** - * Test splitting tests based on a fixed group number + * Test splitting tests based on a fixed group number. + * + * @return void + * @throws FastFailException */ - public function testBasicTestsSplitByGroup() + public function testBasicTestsSplitByGroup(): void { $sampleTestArray = [ 'test1' => 100, @@ -140,7 +129,7 @@ public function testBasicTestsSplitByGroup() 'test18' => 34, 'test19' => 45, 'test20' => 58, - 'test21' => 9, + 'test21' => 9 ]; $expectedResult = [ @@ -153,7 +142,6 @@ public function testBasicTestsSplitByGroup() $testSorter = new ParallelGroupSorter(); $actualResult = $testSorter->getTestsGroupedByFixedGroupCount([], $sampleTestArray, 5); - $this->assertCount(5, $actualResult); foreach ($actualResult as $gropuNumber => $actualTests) { @@ -163,16 +151,19 @@ public function testBasicTestsSplitByGroup() } /** - * Test splitting tests based a group number bigger than ever needed + * Test splitting tests based a group number bigger than ever needed. + * + * @return void + * @throws FastFailException */ - public function testBasicTestsSplitByBigGroupNumber() + public function testBasicTestsSplitByBigGroupNumber(): void { $sampleTestArray = [ 'test1' => 100, 'test2' => 300, 'test3' => 50, 'test4' => 60, - 'test5' => 25, + 'test5' => 25 ]; $expectedResult = [ @@ -185,7 +176,6 @@ public function testBasicTestsSplitByBigGroupNumber() $testSorter = new ParallelGroupSorter(); $actualResult = $testSorter->getTestsGroupedByFixedGroupCount([], $sampleTestArray, 10); - $this->assertCount(5, $actualResult); foreach ($actualResult as $gropuNumber => $actualTests) { @@ -195,9 +185,12 @@ public function testBasicTestsSplitByBigGroupNumber() } /** - * Test splitting tests based a minimum group number + * Test splitting tests based a minimum group number. + * + * @return void + * @throws FastFailException */ - public function testBasicTestsSplitByMinGroupNumber() + public function testBasicTestsSplitByMinGroupNumber(): void { $sampleTestArray = [ 'test1' => 100, @@ -213,7 +206,6 @@ public function testBasicTestsSplitByMinGroupNumber() $testSorter = new ParallelGroupSorter(); $actualResult = $testSorter->getTestsGroupedByFixedGroupCount([], $sampleTestArray, 1); - $this->assertCount(1, $actualResult); foreach ($actualResult as $gropuNumber => $actualTests) { @@ -223,31 +215,15 @@ public function testBasicTestsSplitByMinGroupNumber() } /** - * Test splitting tests and suites based on a fixed group number + * Test splitting tests and suites based on a fixed group number. + * + * @return void + * @throws FastFailException */ - public function testTestsAndSuitesSplitByGroup() + public function testTestsAndSuitesSplitByGroup(): void { // mock tests for test object handler. - $numberOfCalls = 0; - $mockTest1 = AspectMock::double( - TestObject::class, - ['getEstimatedDuration' => function () use (&$numberOfCalls) { - $actionCount = [300, 275, 300, 275]; - $result = $actionCount[$numberOfCalls]; - $numberOfCalls++; - - return $result; - }] - )->make(); - - $mockHandler = AspectMock::double( - TestObjectHandler::class, - ['getObject' => function () use ($mockTest1) { - return $mockTest1; - }] - )->make(); - - AspectMock::double(TestObjectHandler::class, ['getInstance' => $mockHandler])->make(); + $this->createMockForTest(0); // create test to size array $sampleTestArray = [ @@ -283,7 +259,7 @@ public function testTestsAndSuitesSplitByGroup() 'test30' => 93, 'test31' => 330, 'test32' => 85, - 'test33' => 291, + 'test33' => 291 ]; // create mock suite references @@ -294,7 +270,6 @@ public function testTestsAndSuitesSplitByGroup() // perform sort $testSorter = new ParallelGroupSorter(); $actualResult = $testSorter->getTestsGroupedByFixedGroupCount($sampleSuiteArray, $sampleTestArray, 15); - // verify the resulting groups $this->assertCount(15, $actualResult); @@ -313,7 +288,7 @@ public function testTestsAndSuitesSplitByGroup() 12 => ['test28', 'test2', 'test15'], 13 => ['test19', 'test16', 'test20'], 14 => ['mockSuite1_0_G'], - 15 => ['mockSuite1_1_G'], + 15 => ['mockSuite1_1_G'] ]; foreach ($actualResult as $groupNum => $group) { @@ -322,37 +297,21 @@ public function testTestsAndSuitesSplitByGroup() } /** - * Test splitting tests and suites based a group number bigger than ever needed + * Test splitting tests and suites based a group number bigger than ever needed. + * + * @return void + * @throws FastFailException */ - public function testTestsAndSuitesSplitByBigGroupNumber() + public function testTestsAndSuitesSplitByBigGroupNumber(): void { // mock tests for test object handler. - $numberOfCalls = 0; - $mockTest1 = AspectMock::double( - TestObject::class, - ['getEstimatedDuration' => function () use (&$numberOfCalls) { - $actionCount = [300, 275, 300, 275]; - $result = $actionCount[$numberOfCalls]; - $numberOfCalls++; - - return $result; - }] - )->make(); - - $mockHandler = AspectMock::double( - TestObjectHandler::class, - ['getObject' => function () use ($mockTest1) { - return $mockTest1; - }] - )->make(); - - AspectMock::double(TestObjectHandler::class, ['getInstance' => $mockHandler])->make(); + $this->createMockForTest(0); // create test to size array $sampleTestArray = [ 'test1' => 275, 'test2' => 190, - 'test3' => 200, + 'test3' => 200 ]; // create mock suite references @@ -363,7 +322,6 @@ public function testTestsAndSuitesSplitByBigGroupNumber() // perform sort $testSorter = new ParallelGroupSorter(); $actualResult = $testSorter->getTestsGroupedByFixedGroupCount($sampleSuiteArray, $sampleTestArray, 10); - // verify the resulting groups $this->assertCount(5, $actualResult); @@ -381,37 +339,21 @@ public function testTestsAndSuitesSplitByBigGroupNumber() } /** - * Test splitting tests and suites based a minimum group number + * Test splitting tests and suites based a minimum group number. + * + * @return void + * @throws FastFailException */ - public function testTestsAndSuitesSplitByMinGroupNumber() + public function testTestsAndSuitesSplitByMinGroupNumber(): void { // mock tests for test object handler. - $numberOfCalls = 0; - $mockTest1 = AspectMock::double( - TestObject::class, - ['getEstimatedDuration' => function () use (&$numberOfCalls) { - $actionCount = [300, 275, 300, 275]; - $result = $actionCount[$numberOfCalls]; - $numberOfCalls++; - - return $result; - }] - )->make(); - - $mockHandler = AspectMock::double( - TestObjectHandler::class, - ['getObject' => function () use ($mockTest1) { - return $mockTest1; - }] - )->make(); - - AspectMock::double(TestObjectHandler::class, ['getInstance' => $mockHandler])->make(); + $this->createMockForTest(0); // create test to size array $sampleTestArray = [ 'test1' => 1, 'test2' => 125, - 'test3' => 35, + 'test3' => 35 ]; // create mock suite references @@ -422,14 +364,13 @@ public function testTestsAndSuitesSplitByMinGroupNumber() // perform sort $testSorter = new ParallelGroupSorter(); $actualResult = $testSorter->getTestsGroupedByFixedGroupCount($sampleSuiteArray, $sampleTestArray, 3); - // verify the resulting groups $this->assertCount(3, $actualResult); $expectedResults = [ 1 => ['test2', 'test3', 'test1'], 2 => ['mockSuite1_0_G'], - 3 => ['mockSuite1_1_G'], + 3 => ['mockSuite1_1_G'] ]; foreach ($actualResult as $groupNum => $group) { @@ -438,39 +379,21 @@ public function testTestsAndSuitesSplitByMinGroupNumber() } /** - * Test splitting tests and suites with invalid group number + * Test splitting tests and suites with invalid group number. + * + * @return void */ - public function testTestsAndSuitesSplitByInvalidGroupNumber() + public function testTestsAndSuitesSplitByInvalidGroupNumber(): void { // mock tests for test object handler. - $numberOfCalls = 0; - $mockTest1 = AspectMock::double( - TestObject::class, - ['getEstimatedDuration' => function () use (&$numberOfCalls) { - $actionCount = [300, 275, 300, 275]; - $result = $actionCount[$numberOfCalls]; - $numberOfCalls++; - - return $result; - }] - )->make(); - - $mockHandler = AspectMock::double( - TestObjectHandler::class, - ['getObject' => function () use ($mockTest1) { - return $mockTest1; - }] - )->make(); - - AspectMock::double(TestObjectHandler::class, ['getInstance' => $mockHandler])->make(); + $this->createMockForTest(0); // create test to size array $sampleTestArray = [ 'test1' => 1, 'test2' => 125, - 'test3' => 35, + 'test3' => 35 ]; - // create mock suite references $sampleSuiteArray = [ 'mockSuite1' => ['mockTest1', 'mockTest2'] @@ -483,4 +406,46 @@ public function testTestsAndSuitesSplitByInvalidGroupNumber() $testSorter = new ParallelGroupSorter(); $testSorter->getTestsGroupedByFixedGroupCount($sampleSuiteArray, $sampleTestArray, 1); } + + /** + * @inheritDoc + */ + public static function tearDownAfterClass(): void + { + $instanceProperty = new ReflectionProperty(TestObjectHandler::class, 'testObjectHandler'); + $instanceProperty->setAccessible(true); + $instanceProperty->setValue(null); + } + + /** + * Mock test object and test object handler. + * + * @param int $numberOfCalls + * + * @return void + */ + private function createMockForTest(int $numberOfCalls): void + { + $mockTest1 = $this->createMock(TestObject::class); + $mockTest1 + ->method('getEstimatedDuration') + ->willReturnCallback( + function () use (&$numberOfCalls) { + $actionCount = [300, 275, 300, 275]; + $result = $actionCount[$numberOfCalls]; + $numberOfCalls++; + + return $result; + } + ); + + $mockHandler = $this->createMock(TestObjectHandler::class); + $mockHandler + ->method('getObject') + ->willReturn($mockTest1); + + $instanceProperty = new ReflectionProperty(TestObjectHandler::class, 'testObjectHandler'); + $instanceProperty->setAccessible(true); + $instanceProperty->setValue($mockHandler, $mockHandler); + } } From c929d3c68bb7c6b4e20ea56aeab5c5b9c180ccae Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Thu, 22 Jul 2021 18:00:37 +0300 Subject: [PATCH 666/888] 33308: Code refactoring --- .../Util/ModuleResolverTest.php | 30 ++++++++++++------- .../ModuleResolver/ModuleResolverService.php | 2 +- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php index 286044d8a..cec3b9461 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php @@ -37,6 +37,14 @@ protected function setUp(): void public static function tearDownAfterClass(): void { TestLoggingUtil::getInstance()->clearMockLoggingUtil(); + + $moduleResolverServiceInstance = new ReflectionProperty(ModuleResolverService::class, 'INSTANCE'); + $moduleResolverServiceInstance->setAccessible(true); + $moduleResolverServiceInstance->setValue(null); + + $mftfAppConfigInstance = new ReflectionProperty(MftfApplicationConfig::class, 'MFTF_APPLICATION_CONTEXT'); + $mftfAppConfigInstance->setAccessible(true); + $mftfAppConfigInstance->setValue(null); } /** @@ -48,8 +56,8 @@ public static function tearDownAfterClass(): void public function testGetModulePathsAlreadySet(): void { $resolver = ModuleResolver::getInstance(); - $this->setMockResolverProperties($resolver, ["example" . DIRECTORY_SEPARATOR . "paths"]); - $this->assertEquals(["example" . DIRECTORY_SEPARATOR . "paths"], $resolver->getModulesPath()); + $this->setMockResolverProperties($resolver, ['example' . DIRECTORY_SEPARATOR . 'paths']); + $this->assertEquals(['example' . DIRECTORY_SEPARATOR . 'paths'], $resolver->getModulesPath()); } /** @@ -68,7 +76,7 @@ public function testGetModulePathsAggregate(): void ->willReturn( [ 'Magento_example' => 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'example', - 'Magento_sample' => 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'sample', + 'Magento_sample' => 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'sample' ] ); $moduleResolverService->expects($this->any()) @@ -76,7 +84,7 @@ public function testGetModulePathsAggregate(): void ->willReturn( [ 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'example' => ['example'], - 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'sample' => ['sample'], + 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'sample' => ['sample'] ] ); @@ -116,7 +124,7 @@ public function testAggregateTestModulePathsFromComposerJson(): void [ 'Magento_ModuleB', 'Magento_ModuleC' - ], + ] ] ); @@ -154,7 +162,7 @@ public function testAggregateTestModulePathsFromComposerInstaller(): void [ 'Magento_ModuleB', 'Magento_ModuleC' - ], + ] ] ); @@ -243,7 +251,7 @@ public function testMergeFlipAndFilterModulePathsNoForceGenerate(): void 4 => 'Magento_ModuleB', 5 => 'Magento_ModuleD', 6 => 'Magento_Otherexample', - 7 => 'Magento_ModuleC', + 7 => 'Magento_ModuleC' ] ); $this->assertEquals( @@ -254,7 +262,7 @@ public function testMergeFlipAndFilterModulePathsNoForceGenerate(): void 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'example', 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathB', 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathD', - 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathC', + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathC' ], $resolver->getModulesPath() @@ -284,7 +292,7 @@ public function testMergeFlipNoSortModulePathsNoForceGenerate(): void . 'Magento' . DIRECTORY_SEPARATOR . 'ModuleBC' => [ 'Magento_ModuleB', - 'Magento_ModuleC', + 'Magento_ModuleC' ] ] ); @@ -363,7 +371,7 @@ public function testMergeFlipAndSortModulePathsForceGenerate(): void . 'Magento' . DIRECTORY_SEPARATOR . 'ModuleBC' => [ 'Magento_ModuleB', - 'Magento_ModuleC', + 'Magento_ModuleC' ] ] ); @@ -670,7 +678,7 @@ protected function tearDown(): void { // re set env if (!isset($_ENV['MAGENTO_ADMIN_USERNAME'])) { - $_ENV['MAGENTO_ADMIN_USERNAME'] = "admin"; + $_ENV['MAGENTO_ADMIN_USERNAME'] = 'admin'; } } } diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver/ModuleResolverService.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver/ModuleResolverService.php index 0f6513436..c3dad2118 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver/ModuleResolverService.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver/ModuleResolverService.php @@ -53,7 +53,7 @@ private function __construct() public static function getInstance() { if (self::$INSTANCE === null) { - return new self(); + self::$INSTANCE = new ModuleResolverService(); } return self::$INSTANCE; From 43f943603db2128cbc90c9d2f61c852faaa6afec Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Thu, 22 Jul 2021 18:32:32 +0300 Subject: [PATCH 667/888] 33309: Code review/refactoring, fixing failed tests --- .../Util/TestGeneratorTest.php | 74 ++++++++++++------- .../Util/Filesystem/CestFileCreatorUtil.php | 6 +- 2 files changed, 50 insertions(+), 30 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php index 3bc06de59..730493191 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php @@ -8,25 +8,27 @@ namespace tests\unit\Magento\FunctionalTestFramework\Util; use Exception; +use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Filter\FilterList; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Magento\FunctionalTestingFramework\Test\Objects\TestHookObject; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; use Magento\FunctionalTestingFramework\Util\Filesystem\CestFileCreatorUtil; +use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; +use Magento\FunctionalTestingFramework\Util\TestGenerator; use ReflectionProperty; use tests\unit\Util\MagentoTestCase; -use Magento\FunctionalTestingFramework\Util\TestGenerator; -use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use tests\unit\Util\TestLoggingUtil; -use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; class TestGeneratorTest extends MagentoTestCase { /** * Before method functionality. + * + * @return void */ - public function setUp(): void + protected function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); } @@ -36,7 +38,7 @@ public function setUp(): void * * @return void */ - public function tearDown(): void + protected function tearDown(): void { GenerationErrorHandler::getInstance()->reset(); } @@ -53,12 +55,12 @@ public function testEntityException(): void 'userInput' => '{{someEntity.entity}}' ]); - $testObject = new TestObject("sampleTest", ["merge123" => $actionObject], [], [], "filename"); - $testGeneratorObject = TestGenerator::getInstance("", ["sampleTest" => $testObject]); + $testObject = new TestObject('sampleTest', ['merge123' => $actionObject], [], [], 'filename'); + $testGeneratorObject = TestGenerator::getInstance('', ['sampleTest' => $testObject]); $testGeneratorObject->createAllTestFiles(null, []); // assert that no exception for createAllTestFiles and generation error is stored in GenerationErrorHandler - $errorMessage = '/' . preg_quote("Removed invalid test object sampleTest") . '/'; + $errorMessage = '/' . preg_quote('Removed invalid test object sampleTest') . '/'; TestLoggingUtil::getInstance()->validateMockLogStatmentRegex('error', $errorMessage, []); $testErrors = GenerationErrorHandler::getInstance()->getErrorsByType('test'); $this->assertArrayHasKey('sampleTest', $testErrors); @@ -78,9 +80,9 @@ public function testSkippedNoGeneration(): void ]); $annotations = ['skip' => ['issue']]; - $testObject = new TestObject("sampleTest", ["merge123" => $actionObject], $annotations, [], "filename"); + $testObject = new TestObject('sampleTest', ['merge123' => $actionObject], $annotations, [], 'filename'); - $testGeneratorObject = TestGenerator::getInstance("", ["sampleTest" => $testObject]); + $testGeneratorObject = TestGenerator::getInstance('', ['sampleTest' => $testObject]); $output = $testGeneratorObject->assembleTestPhp($testObject); $this->assertStringContainsString('This test is skipped', $output); @@ -97,7 +99,7 @@ public function testAllowSkipped(): void { // Mock allowSkipped for TestGenerator $mockConfig = $this->createMock(MftfApplicationConfig::class); - $mockConfig->expects($this->any()) + $mockConfig ->method('allowSkipped') ->willReturn(true); @@ -115,16 +117,16 @@ public function testAllowSkipped(): void ]); $annotations = ['skip' => ['issue']]; - $beforeHook = new TestHookObject("before", "sampleTest", ['beforeAction' => $beforeActionObject]); + $beforeHook = new TestHookObject('before', 'sampleTest', ['beforeAction' => $beforeActionObject]); $testObject = new TestObject( - "sampleTest", - ["fakeAction" => $actionObject], + 'sampleTest', + ['fakeAction' => $actionObject], $annotations, - ["before" => $beforeHook], - "filename" + ['before' => $beforeHook], + 'filename' ); - $testGeneratorObject = TestGenerator::getInstance("", ["sampleTest" => $testObject]); + $testGeneratorObject = TestGenerator::getInstance('', ['sampleTest' => $testObject]); $output = $testGeneratorObject->assembleTestPhp($testObject); $this->assertStringNotContainsString('This test is skipped', $output); @@ -141,8 +143,10 @@ public function testAllowSkipped(): void public function testFilter(): void { $mockConfig = $this->createMock(MftfApplicationConfig::class); - $fileList = new FilterList(['severity' => ["CRITICAL"]]); - $mockConfig->expects($this->once())->method('getFilterList')->willReturn($fileList); + $fileList = new FilterList(['severity' => ['CRITICAL']]); + $mockConfig + ->method('getFilterList') + ->willReturn($fileList); $property = new ReflectionProperty(MftfApplicationConfig::class, 'MFTF_APPLICATION_CONTEXT'); $property->setAccessible(true); @@ -156,24 +160,24 @@ public function testFilter(): void $annotation1 = ['severity' => ['CRITICAL']]; $annotation2 = ['severity' => ['MINOR']]; $test1 = new TestObject( - "test1", - ["fakeAction" => $actionObject], + 'test1', + ['fakeAction' => $actionObject], $annotation1, [], - "filename" + 'filename' ); $test2 = new TestObject( - "test2", - ["fakeAction" => $actionObject], + 'test2', + ['fakeAction' => $actionObject], $annotation2, [], - "filename" + 'filename' ); // Mock createCestFile to return name of tests that testGenerator tried to create $generatedTests = []; $cestFileCreatorUtil = $this->createMock(CestFileCreatorUtil::class); - $cestFileCreatorUtil->expects($this->once()) + $cestFileCreatorUtil ->method('create') ->will( $this->returnCallback( @@ -187,11 +191,27 @@ function ($filename) use (&$generatedTests) { $property->setAccessible(true); $property->setValue($cestFileCreatorUtil); - $testGeneratorObject = TestGenerator::getInstance("", ["sampleTest" => $test1, "test2" => $test2]); + $testGeneratorObject = TestGenerator::getInstance('', ['sampleTest' => $test1, 'test2' => $test2]); $testGeneratorObject->createAllTestFiles(); // Ensure Test1 was Generated but not Test 2 $this->assertArrayHasKey('test1Cest', $generatedTests); $this->assertArrayNotHasKey('test2Cest', $generatedTests); } + + /** + * @inheritDoc + */ + public static function tearDownAfterClass(): void + { + parent::tearDownAfterClass(); + + $cestFileCreatorUtilInstance = new ReflectionProperty(CestFileCreatorUtil::class, 'INSTANCE'); + $cestFileCreatorUtilInstance->setAccessible(true); + $cestFileCreatorUtilInstance->setValue(null); + + $mftfAppConfigInstance = new ReflectionProperty(MftfApplicationConfig::class, 'MFTF_APPLICATION_CONTEXT'); + $mftfAppConfigInstance->setAccessible(true); + $mftfAppConfigInstance->setValue(null); + } } diff --git a/src/Magento/FunctionalTestingFramework/Util/Filesystem/CestFileCreatorUtil.php b/src/Magento/FunctionalTestingFramework/Util/Filesystem/CestFileCreatorUtil.php index b3c896ccb..9fe205151 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Filesystem/CestFileCreatorUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/Filesystem/CestFileCreatorUtil.php @@ -30,10 +30,10 @@ private function __construct() * * @return CestFileCreatorUtil */ - public static function getInstance() + public static function getInstance(): CestFileCreatorUtil { - if (self::$INSTANCE === null) { - return new self(); + if (!self::$INSTANCE) { + self::$INSTANCE = new CestFileCreatorUtil(); } return self::$INSTANCE; From 45e2436ce3480f7cf8f6eb5b9c38841607590a77 Mon Sep 17 00:00:00 2001 From: "andrii.zinkevych" <a.zinkevych@atwix.com> Date: Thu, 22 Jul 2021 23:28:18 +0300 Subject: [PATCH 668/888] 33293: Removed Singleton and used Object Manager --- .../Handlers/PersistedObjectHandlerTest.php | 115 +++++++++++------- dev/tests/unit/Util/MagentoTestCase.php | 2 + .../DataGenerator/Persist/CurlHandler.php | 30 +---- .../Persist/DataPersistenceHandler.php | 22 +++- 4 files changed, 94 insertions(+), 75 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php index 4d70444b6..9072b2da1 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php @@ -9,8 +9,13 @@ use Exception; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; +use Magento\FunctionalTestingFramework\DataGenerator\Parsers\DataProfileSchemaParser; use Magento\FunctionalTestingFramework\DataGenerator\Persist\CurlHandler; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; +use Magento\FunctionalTestingFramework\ObjectManager; +use Magento\FunctionalTestingFramework\ObjectManagerFactory; +use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; use ReflectionProperty; use tests\unit\Util\MagentoTestCase; use tests\unit\Util\ObjectHandlerUtil; @@ -24,7 +29,7 @@ class PersistedObjectHandlerTest extends MagentoTestCase /** * @inheritDoc */ - public function setUp(): void + protected function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); } @@ -90,9 +95,7 @@ public function testCreateSimpleEntity(): void } "; - // Mock Classes - ObjectHandlerUtil::mockDataObjectHandlerWithData($parserOutput); - $this->mockCurlHandler($jsonResponse); + $this->mockCurlHandler($jsonResponse, $parserOutput); $handler = PersistedObjectHandler::getInstance(); // Call method @@ -140,8 +143,7 @@ public function testDeleteSimpleEntity(): void "; // Mock Classes - ObjectHandlerUtil::mockDataObjectHandlerWithData($parserOutput); - $this->mockCurlHandler($jsonResponse); + $this->mockCurlHandler($jsonResponse, $parserOutput); $handler = PersistedObjectHandler::getInstance(); // Call method @@ -194,8 +196,7 @@ public function testGetSimpleEntity(): void "; // Mock Classes - ObjectHandlerUtil::mockDataObjectHandlerWithData($parserOutput); - $this->mockCurlHandler($jsonResponse); + $this->mockCurlHandler($jsonResponse, $parserOutput); $handler = PersistedObjectHandler::getInstance(); // Call method @@ -334,7 +335,7 @@ public function testRetrieveEntityAcrossScopes(): void ] ] ]; - $jsonReponseOne = " + $jsonResponseOne = " { \"" . strtolower($dataKeyOne) . "\" : \"{$dataValueOne}\" } @@ -353,22 +354,21 @@ public function testRetrieveEntityAcrossScopes(): void // Mock Classes and Create Entities $handler = PersistedObjectHandler::getInstance(); - ObjectHandlerUtil::mockDataObjectHandlerWithData($parserOutputOne); - $this->mockCurlHandler($jsonReponseOne); + $this->mockCurlHandler($jsonResponseOne, $parserOutputOne); $handler->createEntity( $entityStepKeyOne, PersistedObjectHandler::TEST_SCOPE, $entityNameOne ); - $this->mockCurlHandler($jsonReponseTwo); + $this->mockCurlHandler($jsonReponseTwo, $parserOutputOne); $handler->createEntity( $entityStepKeyTwo, PersistedObjectHandler::HOOK_SCOPE, $entityNameTwo ); - $this->mockCurlHandler($jsonReponseThree); + $this->mockCurlHandler($jsonReponseThree, $parserOutputOne); $handler->createEntity( $entityStepKeyThree, PersistedObjectHandler::SUITE_SCOPE, @@ -432,7 +432,7 @@ public function testRetrieveEntityValidField( ] ] ]; - $jsonReponseOne = " + $jsonResponseOne = " { \"" . strtolower($key) . "\" : \"{$value}\" } @@ -440,9 +440,7 @@ public function testRetrieveEntityValidField( // Mock Classes and Create Entities $handler = PersistedObjectHandler::getInstance(); - - ObjectHandlerUtil::mockDataObjectHandlerWithData($parserOutputOne); - $this->mockCurlHandler($jsonReponseOne); + $this->mockCurlHandler($jsonResponseOne, $parserOutputOne); $handler->createEntity($stepKey, $scope, $name); // Call method @@ -463,7 +461,7 @@ public function testRetrieveEntityValidField( * @dataProvider entityDataProvider * * @return void - * @throws TestReferenceException + * @throws TestReferenceException|TestFrameworkException */ public function testRetrieveEntityInValidField( string $name, @@ -490,7 +488,7 @@ public function testRetrieveEntityInValidField( ] ] ]; - $jsonReponseOne = " + $jsonResponseOne = " { \"" . strtolower($key) . "\" : \"{$value}\" } @@ -498,8 +496,7 @@ public function testRetrieveEntityInValidField( // Mock Classes and Create Entities $handler = PersistedObjectHandler::getInstance(); - ObjectHandlerUtil::mockDataObjectHandlerWithData($parserOutputOne); - $this->mockCurlHandler($jsonReponseOne); + $this->mockCurlHandler($jsonResponseOne, $parserOutputOne); $handler->createEntity($stepKey, $scope, $name); // Call method @@ -514,7 +511,7 @@ public function testRetrieveEntityInValidField( } /** - * Data provider for testRetrieveEntityField + * Data provider for testRetrieveEntityField. * * @return array */ @@ -531,45 +528,79 @@ public static function entityDataProvider(): array * Create mock curl handler. * * @param string $response - * @throws Exception + * @param array $parserOutput + * + * @return void */ - public function mockCurlHandler(string $response): void + public function mockCurlHandler(string $response, array $parserOutput): void { - $mockCurlHandler = $this->createMock(CurlHandler::class); - $mockCurlHandler->expects($this->any()) + $dataObjectHandler = new ReflectionProperty(DataObjectHandler::class, 'INSTANCE'); + $dataObjectHandler->setAccessible(true); + $dataObjectHandler->setValue(null); + + $mockDataProfileSchemaParser = $this->createMock(DataProfileSchemaParser::class); + $mockDataProfileSchemaParser + ->method('readDataProfiles') + ->willReturn($parserOutput); + + $curlHandler = $this->createMock(CurlHandler::class); + $curlHandler ->method('executeRequest') ->willReturn($response); - $mockCurlHandler->expects($this->once()) + $curlHandler ->method('getRequestDataArray') ->willReturn([]); - $mockCurlHandler->expects($this->once()) + $curlHandler ->method('isContentTypeJson') ->willReturn(true); - $property = new ReflectionProperty(CurlHandler::class, "INSTANCE"); - $property->setAccessible(true); - $property->setValue($mockCurlHandler); + $objectManagerInstance = ObjectManagerFactory::getObjectManager(); + $objectManagerMockInstance = $this->createMock(ObjectManager::class); + $objectManagerMockInstance->expects($this->any()) + ->method('create') + ->will( + $this->returnCallback( + function ( + string $class, + array $arguments = [] + ) use ($curlHandler, $objectManagerInstance, $mockDataProfileSchemaParser) + { + if ($class === CurlHandler::class) { + return $curlHandler; + } + + if ($class === DataProfileSchemaParser::class) { + return $mockDataProfileSchemaParser; + } + + return $objectManagerInstance->create($class, $arguments); + } + ) + ); + + $objectManagerProperty = new ReflectionProperty(ObjectManager::class, 'instance'); + $objectManagerProperty->setAccessible(true); + $objectManagerProperty->setValue($objectManagerMockInstance); } /** - * @inheritDoc + * After class functionality. + * + * @return void */ - public function tearDown(): void + public static function tearDownAfterClass(): void { + parent::tearDownAfterClass(); + // Clear out Singleton between tests - $property = new ReflectionProperty(PersistedObjectHandler::class, 'INSTANCE'); + $property = new ReflectionProperty(PersistedObjectHandler::class, "INSTANCE"); $property->setAccessible(true); $property->setValue(null); - parent::tearDown(); // TODO: Change the autogenerated stub - } + $property = new ReflectionProperty(ObjectManager::class, 'instance'); + $property->setAccessible(true); + $property->setValue(null); - /** - * @inheritDoc - */ - public static function tearDownAfterClass(): void - { TestLoggingUtil::getInstance()->clearMockLoggingUtil(); - parent::tearDownAfterClass(); } } diff --git a/dev/tests/unit/Util/MagentoTestCase.php b/dev/tests/unit/Util/MagentoTestCase.php index 7760acfc6..bb38a0b5c 100644 --- a/dev/tests/unit/Util/MagentoTestCase.php +++ b/dev/tests/unit/Util/MagentoTestCase.php @@ -19,6 +19,8 @@ public static function setUpBeforeClass(): void if (!self::fileExists(DOCS_OUTPUT_DIR)) { mkdir(DOCS_OUTPUT_DIR, 0755, true); } + // Should be used to clean AspectMock mocking before using PHPUnit mocking and Reflection. + AspectMock::clean(); parent::setUpBeforeClass(); } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php index d5250c890..89055b83f 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php @@ -63,13 +63,6 @@ class CurlHandler */ private $isJson; - /** - * Singleton CurlHandler Instance. - * - * @var CurlHandler - */ - private static $INSTANCE; - /** * Operation to Curl method mapping. * @@ -89,7 +82,7 @@ class CurlHandler * @param EntityDataObject $entityObject * @param string $storeCode */ - private function __construct($operation, $entityObject, $storeCode = null) + public function __construct($operation, $entityObject, $storeCode = null) { $this->operation = $operation; $this->entityObject = $entityObject; @@ -102,27 +95,6 @@ private function __construct($operation, $entityObject, $storeCode = null) $this->isJson = false; } - /** - * Get CurlHandler instance. - * - * @param string $operation - * @param EntityDataObject $entityObject - * @param string|null $storeCode - * - * @return CurlHandler - */ - public static function getInstance( - string $operation, - EntityDataObject $entityObject, - ?string $storeCode = null - ) { - if (self::$INSTANCE === null) { - return new self($operation, $entityObject, $storeCode); - } - - return self::$INSTANCE; - } - /** * Executes an api request based on parameters given by constructor. * diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/DataPersistenceHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/DataPersistenceHandler.php index 0be6cc24e..19a577f0f 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/DataPersistenceHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/DataPersistenceHandler.php @@ -9,6 +9,7 @@ use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\ObjectManagerFactory; /** * Class DataPersistenceHandler @@ -86,7 +87,10 @@ public function createEntity($storeCode = null) if (!empty($storeCode)) { $this->storeCode = $storeCode; } - $curlHandler = CurlHandler::getInstance('create', $this->entityObject, $this->storeCode); + $curlHandler = ObjectManagerFactory::getObjectManager()->create( + CurlHandler::class, + ['create', $this->entityObject, $this->storeCode] + ); $result = $curlHandler->executeRequest($this->dependentObjects); $this->setCreatedObject( $result, @@ -111,7 +115,10 @@ public function updateEntity($updateDataName, $updateDependentObjects = []) $this->dependentObjects[] = $dependentObject->getCreatedObject(); } $updateEntityObject = DataObjectHandler::getInstance()->getObject($updateDataName); - $curlHandler = CurlHandler::getInstance('update', $updateEntityObject, $this->storeCode); + $curlHandler = ObjectManagerFactory::getObjectManager()->create( + CurlHandler::class, + ['update', $updateEntityObject, $this->storeCode] + ); $result = $curlHandler->executeRequest(array_merge($this->dependentObjects, [$this->createdObject])); $this->setCreatedObject( $result, @@ -134,7 +141,10 @@ public function getEntity($index = null, $storeCode = null) if (!empty($storeCode)) { $this->storeCode = $storeCode; } - $curlHandler = CurlHandler::getInstance('get', $this->entityObject, $this->storeCode); + $curlHandler = ObjectManagerFactory::getObjectManager()->create( + CurlHandler::class, + ['get', $this->entityObject, $this->storeCode] + ); $result = $curlHandler->executeRequest($this->dependentObjects); $this->setCreatedObject( $result, @@ -152,7 +162,11 @@ public function getEntity($index = null, $storeCode = null) */ public function deleteEntity() { - $curlHandler = CurlHandler::getInstance('delete', $this->createdObject, $this->storeCode); + $curlHandler = ObjectManagerFactory::getObjectManager()->create( + CurlHandler::class, + ['delete', $this->createdObject, $this->storeCode] + ); + $curlHandler->executeRequest($this->dependentObjects); } From 842f9f5ccc8469d64cb507a087c7bb4c96e647d6 Mon Sep 17 00:00:00 2001 From: "andrii.zinkevych" <a.zinkevych@atwix.com> Date: Thu, 22 Jul 2021 23:49:13 +0300 Subject: [PATCH 669/888] 33293: Fixed static-test --- .../Handlers/PersistedObjectHandlerTest.php | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php index 9072b2da1..3629271f3 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php @@ -538,8 +538,8 @@ public function mockCurlHandler(string $response, array $parserOutput): void $dataObjectHandler->setAccessible(true); $dataObjectHandler->setValue(null); - $mockDataProfileSchemaParser = $this->createMock(DataProfileSchemaParser::class); - $mockDataProfileSchemaParser + $dataProfileSchemaParser = $this->createMock(DataProfileSchemaParser::class); + $dataProfileSchemaParser ->method('readDataProfiles') ->willReturn($parserOutput); @@ -554,26 +554,22 @@ public function mockCurlHandler(string $response, array $parserOutput): void ->method('isContentTypeJson') ->willReturn(true); - $objectManagerInstance = ObjectManagerFactory::getObjectManager(); + $objectManager = ObjectManagerFactory::getObjectManager(); $objectManagerMockInstance = $this->createMock(ObjectManager::class); $objectManagerMockInstance->expects($this->any()) ->method('create') ->will( $this->returnCallback( - function ( - string $class, - array $arguments = [] - ) use ($curlHandler, $objectManagerInstance, $mockDataProfileSchemaParser) - { + function ($class, $arguments = []) use ($curlHandler, $objectManager, $dataProfileSchemaParser) { if ($class === CurlHandler::class) { return $curlHandler; } if ($class === DataProfileSchemaParser::class) { - return $mockDataProfileSchemaParser; + return $dataProfileSchemaParser; } - return $objectManagerInstance->create($class, $arguments); + return $objectManager->create($class, $arguments); } ) ); From c6025c464df14abbb080aacf6bd2231fcae3912f Mon Sep 17 00:00:00 2001 From: "andrii.zinkevych" <a.zinkevych@atwix.com> Date: Fri, 23 Jul 2021 11:08:39 +0300 Subject: [PATCH 670/888] 33299: Eliminated AspectMock usage from SuiteGeneratorTest.php --- .../Suite/SuiteGeneratorTest.php | 218 +++++++++++------- .../Suite/Service/SuiteGeneratorService.php | 151 ++++++++++++ .../Suite/SuiteGenerator.php | 82 +------ 3 files changed, 289 insertions(+), 162 deletions(-) create mode 100644 src/Magento/FunctionalTestingFramework/Suite/Service/SuiteGeneratorService.php diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php index 136b32e2a..a7178c624 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php @@ -3,12 +3,15 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace tests\unit\Magento\FunctionalTestFramework\Suite; -use AspectMock\Test as AspectMock; +use Exception; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; -use Magento\FunctionalTestingFramework\ObjectManager\ObjectManager; +use Magento\FunctionalTestingFramework\ObjectManager; use Magento\FunctionalTestingFramework\ObjectManagerFactory; +use Magento\FunctionalTestingFramework\Suite\Service\SuiteGeneratorService; use Magento\FunctionalTestingFramework\Suite\SuiteGenerator; use Magento\FunctionalTestingFramework\Suite\Generators\GroupClassGenerator; use Magento\FunctionalTestingFramework\Suite\Handlers\SuiteObjectHandler; @@ -18,41 +21,31 @@ use Magento\FunctionalTestingFramework\Test\Parsers\TestDataParser; use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; use Magento\FunctionalTestingFramework\Util\Manifest\DefaultTestManifest; +use ReflectionProperty; use tests\unit\Util\MagentoTestCase; use Magento\FunctionalTestingFramework\Util\Manifest\TestManifestFactory; use tests\unit\Util\SuiteDataArrayBuilder; use tests\unit\Util\TestDataArrayBuilder; use tests\unit\Util\TestLoggingUtil; -use tests\unit\Util\MockModuleResolverBuilder; class SuiteGeneratorTest extends MagentoTestCase { - /** - * Setup entry append and clear for Suite Generator - */ - public static function setUpBeforeClass(): void - { - AspectMock::double(SuiteGenerator::class, [ - 'clearPreviousSessionConfigEntries' => null, - 'appendEntriesToConfig' => null - ]); - } - /** * Before test functionality * @return void */ - public function setUp(): void + protected function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); - $resolverMock = new MockModuleResolverBuilder(); - $resolverMock->setup(); } /** - * Tests generating a single suite given a set of parsed test data + * Tests generating a single suite given a set of parsed test data. + * + * @return void + * @throws Exception */ - public function testGenerateSuite() + public function testGenerateSuite(): void { $suiteDataArrayBuilder = new SuiteDataArrayBuilder(); $mockData = $suiteDataArrayBuilder @@ -74,20 +67,23 @@ public function testGenerateSuite() // parse and generate suite object with mocked data $mockSuiteGenerator = SuiteGenerator::getInstance(); - $mockSuiteGenerator->generateSuite("basicTestSuite"); + $mockSuiteGenerator->generateSuite('basicTestSuite'); // assert that expected suite is generated TestLoggingUtil::getInstance()->validateMockLogStatement( 'info', - "suite generated", - ['suite' => 'basicTestSuite', 'relative_path' => "_generated" . DIRECTORY_SEPARATOR . "basicTestSuite"] + 'suite generated', + ['suite' => 'basicTestSuite', 'relative_path' => '_generated' . DIRECTORY_SEPARATOR . 'basicTestSuite'] ); } /** - * Tests generating all suites given a set of parsed test data + * Tests generating all suites given a set of parsed test data. + * + * @return void + * @throws Exception */ - public function testGenerateAllSuites() + public function testGenerateAllSuites(): void { $suiteDataArrayBuilder = new SuiteDataArrayBuilder(); $mockData = $suiteDataArrayBuilder @@ -108,22 +104,25 @@ public function testGenerateAllSuites() $this->setMockTestAndSuiteParserOutput($mockTestData, $mockData); // parse and retrieve suite object with mocked data - $exampleTestManifest = new DefaultTestManifest([], "sample" . DIRECTORY_SEPARATOR . "path"); + $exampleTestManifest = new DefaultTestManifest([], 'sample' . DIRECTORY_SEPARATOR . 'path'); $mockSuiteGenerator = SuiteGenerator::getInstance(); $mockSuiteGenerator->generateAllSuites($exampleTestManifest); // assert that expected suites are generated TestLoggingUtil::getInstance()->validateMockLogStatement( 'info', - "suite generated", - ['suite' => 'basicTestSuite', 'relative_path' => "_generated" . DIRECTORY_SEPARATOR . "basicTestSuite"] + 'suite generated', + ['suite' => 'basicTestSuite', 'relative_path' => '_generated' . DIRECTORY_SEPARATOR . 'basicTestSuite'] ); } /** - * Tests attempting to generate a suite with no included/excluded tests and no hooks + * Tests attempting to generate a suite with no included/excluded tests and no hooks. + * + * @return void + * @throws Exception */ - public function testGenerateEmptySuite() + public function testGenerateEmptySuite(): void { $testDataArrayBuilder = new TestDataArrayBuilder(); $mockTestData = $testDataArrayBuilder @@ -142,17 +141,20 @@ public function testGenerateEmptySuite() $this->setMockTestAndSuiteParserOutput($mockTestData, $mockData); // set expected error message - $this->expectExceptionMessage("Suite basicTestSuite is not defined in xml or is invalid"); + $this->expectExceptionMessage('Suite basicTestSuite is not defined in xml or is invalid'); // parse and generate suite object with mocked data $mockSuiteGenerator = SuiteGenerator::getInstance(); - $mockSuiteGenerator->generateSuite("basicTestSuite"); + $mockSuiteGenerator->generateSuite('basicTestSuite'); } /** - * Tests generating all suites with a suite containing invalid test reference + * Tests generating all suites with a suite containing invalid test reference. + * + * @return void + * @throws TestReferenceException */ - public function testInvalidSuiteTestPair() + public function testInvalidSuiteTestPair(): void { // Mock Suite1 => Test1 and Suite2 => Test2 $suiteDataArrayBuilder = new SuiteDataArrayBuilder(); @@ -198,9 +200,12 @@ public function testInvalidSuiteTestPair() } /** - * Tests generating all suites with a non-existing suite + * Tests generating all suites with a non-existing suite. + * + * @return void + * @throws TestReferenceException */ - public function testNonExistentSuiteTestPair() + public function testNonExistentSuiteTestPair(): void { $testDataArrayBuilder = new TestDataArrayBuilder(); $mockSimpleTest = $testDataArrayBuilder @@ -227,9 +232,12 @@ public function testNonExistentSuiteTestPair() } /** - * Tests generating split suites for parallel test generation + * Tests generating split suites for parallel test generation. + * + * @return void + * @throws TestReferenceException */ - public function testGenerateSplitSuiteFromTest() + public function testGenerateSplitSuiteFromTest(): void { $suiteDataArrayBuilder = new SuiteDataArrayBuilder(); $mockSuiteData = $suiteDataArrayBuilder @@ -272,8 +280,8 @@ public function testGenerateSplitSuiteFromTest() // assert last split suite group generated TestLoggingUtil::getInstance()->validateMockLogStatement( 'info', - "suite generated", - ['suite' => 'mockSuite_1_G', 'relative_path' => "_generated" . DIRECTORY_SEPARATOR . "mockSuite_1_G"] + 'suite generated', + ['suite' => 'mockSuite_1_G', 'relative_path' => '_generated' . DIRECTORY_SEPARATOR . 'mockSuite_1_G'] ); } @@ -282,75 +290,117 @@ public function testGenerateSplitSuiteFromTest() * * @param array $testData * @param array $suiteData - * @throws \Exception + * @throws Exception + */ + private function setMockTestAndSuiteParserOutput(array $testData, array $suiteData): void + { + $this->clearMockResolverProperties(); + $mockSuiteGeneratorService = $this->createMock(SuiteGeneratorService::class); + $mockSuiteGeneratorService + ->method('clearPreviousSessionConfigEntries') + ->willReturn(null); + + $mockSuiteGeneratorService + ->method('appendEntriesToConfig') + ->willReturn(null); + + $suiteGeneratorServiceProperty = new ReflectionProperty(SuiteGeneratorService::class, 'INSTANCE'); + $suiteGeneratorServiceProperty->setAccessible(true); + $suiteGeneratorServiceProperty->setValue($mockSuiteGeneratorService); + + $mockDataParser = $this->createMock(TestDataParser::class); + $mockDataParser + ->method('readTestData') + ->willReturn($testData); + + $mockSuiteDataParser = $this->createMock(SuiteDataParser::class); + $mockSuiteDataParser + ->method('readSuiteData') + ->willReturn($suiteData); + + $mockGroupClass = $this->createMock(GroupClassGenerator::class); + $mockGroupClass + ->method('generateGroupClass') + ->willReturn('namespace'); + + $objectManager = ObjectManagerFactory::getObjectManager(); + + $objectManagerMockInstance = $this->createMock(ObjectManager::class); + $objectManagerMockInstance + ->method('create') + ->will( + $this->returnCallback( + function (string $class, array $arguments = []) use ( + $mockDataParser, + $mockSuiteDataParser, + $mockGroupClass, + $objectManager + ) { + if ($class == TestDataParser::class) { + return $mockDataParser; + } + if ($class == SuiteDataParser::class) { + return $mockSuiteDataParser; + } + if ($class == GroupClassGenerator::class) { + return $mockGroupClass; + } + + return $objectManager->create($class, $arguments); + } + ) + ); + + $objectManagerProperty = new ReflectionProperty(ObjectManager::class, 'instance'); + $objectManagerProperty->setAccessible(true); + $objectManagerProperty->setValue($objectManagerMockInstance); + } + + /** + * Function used to clear mock properties. + * + * @return void */ - private function setMockTestAndSuiteParserOutput($testData, $suiteData) + private function clearMockResolverProperties(): void { - $property = new \ReflectionProperty(SuiteGenerator::class, 'instance'); + $property = new ReflectionProperty(SuiteGenerator::class, 'instance'); $property->setAccessible(true); $property->setValue(null); // clear test object handler value to inject parsed content - $property = new \ReflectionProperty(TestObjectHandler::class, 'testObjectHandler'); + $property = new ReflectionProperty(TestObjectHandler::class, 'testObjectHandler'); $property->setAccessible(true); $property->setValue(null); // clear suite object handler value to inject parsed content - $property = new \ReflectionProperty(SuiteObjectHandler::class, 'instance'); + $property = new ReflectionProperty(SuiteObjectHandler::class, 'instance'); $property->setAccessible(true); $property->setValue(null); - - $mockDataParser = AspectMock::double(TestDataParser::class, ['readTestData' => $testData])->make(); - $mockSuiteDataParser = AspectMock::double(SuiteDataParser::class, ['readSuiteData' => $suiteData])->make(); - $mockGroupClass = AspectMock::double( - GroupClassGenerator::class, - ['generateGroupClass' => 'namespace'] - )->make(); - $mockSuiteClass = AspectMock::double(SuiteGenerator::class, ['generateRelevantGroupTests' => null])->make(); - $instance = AspectMock::double( - ObjectManager::class, - ['create' => function ($clazz) use ( - $mockDataParser, - $mockSuiteDataParser, - $mockGroupClass, - $mockSuiteClass - ) { - if ($clazz == TestDataParser::class) { - return $mockDataParser; - } - if ($clazz == SuiteDataParser::class) { - return $mockSuiteDataParser; - } - if ($clazz == GroupClassGenerator::class) { - return $mockGroupClass; - } - if ($clazz == SuiteGenerator::class) { - return $mockSuiteClass; - } - }] - )->make(); - // bypass the private constructor - AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); - - $property = new \ReflectionProperty(SuiteGenerator::class, 'groupClassGenerator'); - $property->setAccessible(true); - $property->setValue($instance, $instance); } /** - * clean up function runs after each test + * @inheritDoc */ - public function tearDown(): void + protected function tearDown(): void { GenerationErrorHandler::getInstance()->reset(); } /** - * clean up function runs after all tests + * @inheritDoc */ public static function tearDownAfterClass(): void { - TestLoggingUtil::getInstance()->clearMockLoggingUtil(); parent::tearDownAfterClass(); + + $objectManagerProperty = new ReflectionProperty(ObjectManager::class, 'instance'); + $objectManagerProperty->setAccessible(true); + $objectManagerProperty->setValue(null); + + $suiteGeneratorServiceProperty = new ReflectionProperty(SuiteGeneratorService::class, 'INSTANCE'); + $suiteGeneratorServiceProperty->setAccessible(true); + $suiteGeneratorServiceProperty->setValue(null); + + TestLoggingUtil::getInstance()->clearMockLoggingUtil(); } } diff --git a/src/Magento/FunctionalTestingFramework/Suite/Service/SuiteGeneratorService.php b/src/Magento/FunctionalTestingFramework/Suite/Service/SuiteGeneratorService.php new file mode 100644 index 000000000..cec4b4997 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Suite/Service/SuiteGeneratorService.php @@ -0,0 +1,151 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\FunctionalTestingFramework\Suite\Service; + +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; +use Symfony\Component\Yaml\Yaml; + +/** + * Class SuiteGeneratorService + */ +class SuiteGeneratorService +{ + const YAML_CODECEPTION_DIST_FILENAME = 'codeception.dist.yml'; + const YAML_CODECEPTION_CONFIG_FILENAME = 'codeception.yml'; + const YAML_GROUPS_TAG = 'groups'; + const YAML_EXTENSIONS_TAG = 'extensions'; + const YAML_ENABLED_TAG = 'enabled'; + const YAML_COPYRIGHT_TEXT = + "# Copyright © Magento, Inc. All rights reserved.\n# See COPYING.txt for license details.\n"; + + + /** + * Singleton SuiteGeneratorService Instance. + * + * @var SuiteGeneratorService + */ + private static $INSTANCE; + + /** + * SuiteGeneratorService constructor. + */ + private function __construct() + { + } + + /** + * Get CestFileCreatorUtil instance. + * + * @return SuiteGeneratorService + */ + public static function getInstance(): SuiteGeneratorService + { + if (!self::$INSTANCE) { + self::$INSTANCE = new SuiteGeneratorService(); + } + + return self::$INSTANCE; + } + + /** + * Function which takes the current config.yml array and clears any previous configuration for suite group object + * files. + * + * @return void + * @throws TestFrameworkException + */ + public function clearPreviousSessionConfigEntries() + { + $ymlArray = self::getYamlFileContents(); + $newYmlArray = $ymlArray; + // if the yaml entries haven't already been cleared + if (array_key_exists(self::YAML_EXTENSIONS_TAG, $ymlArray)) { + foreach ($ymlArray[self::YAML_EXTENSIONS_TAG][self::YAML_ENABLED_TAG] as $key => $entry) { + if (preg_match('/(Group\\\\.*)/', $entry)) { + unset($newYmlArray[self::YAML_EXTENSIONS_TAG][self::YAML_ENABLED_TAG][$key]); + } + } + + // needed for proper yml file generation based on indices + $newYmlArray[self::YAML_EXTENSIONS_TAG][self::YAML_ENABLED_TAG] = + array_values($newYmlArray[self::YAML_EXTENSIONS_TAG][self::YAML_ENABLED_TAG]); + } + + if (array_key_exists(self::YAML_GROUPS_TAG, $newYmlArray)) { + unset($newYmlArray[self::YAML_GROUPS_TAG]); + } + + $ymlText = self::YAML_COPYRIGHT_TEXT . Yaml::dump($newYmlArray, 10); + file_put_contents(self::getYamlConfigFilePath() . self::YAML_CODECEPTION_CONFIG_FILENAME, $ymlText); + } + + + /** + * Function which accepts a suite name and suite path and appends a new group entry to the codeception.yml.dist + * file in order to register the set of tests as a new group. Also appends group object location if required + * by suite. + * + * @param string $suiteName + * @param string $suitePath + * @param string $groupNamespace + * + * @return void + * @throws TestFrameworkException + */ + public function appendEntriesToConfig(string $suiteName, string $suitePath, string $groupNamespace) + { + $relativeSuitePath = substr($suitePath, strlen(TESTS_BP)); + $relativeSuitePath = ltrim($relativeSuitePath, DIRECTORY_SEPARATOR); + $ymlArray = self::getYamlFileContents(); + + if (!array_key_exists(self::YAML_GROUPS_TAG, $ymlArray)) { + $ymlArray[self::YAML_GROUPS_TAG]= []; + } + + if ($groupNamespace) { + $ymlArray[self::YAML_EXTENSIONS_TAG][self::YAML_ENABLED_TAG][] = $groupNamespace; + } + + $ymlArray[self::YAML_GROUPS_TAG][$suiteName] = [$relativeSuitePath]; + $ymlText = self::YAML_COPYRIGHT_TEXT . Yaml::dump($ymlArray, 10); + file_put_contents(self::getYamlConfigFilePath() . self::YAML_CODECEPTION_CONFIG_FILENAME, $ymlText); + } + + /** + * Function to return contents of codeception.yml file for config changes. + * + * @return array + * @throws TestFrameworkException + */ + private static function getYamlFileContents(): array + { + $configYmlFile = self::getYamlConfigFilePath() . self::YAML_CODECEPTION_CONFIG_FILENAME; + $defaultConfigYmlFile = self::getYamlConfigFilePath() . self::YAML_CODECEPTION_DIST_FILENAME; + $ymlContents = null; + + if (file_exists($configYmlFile)) { + $ymlContents = file_get_contents($configYmlFile); + } else { + $ymlContents = file_get_contents($defaultConfigYmlFile); + } + + return Yaml::parse($ymlContents) ?? []; + } + + /** + * Static getter for the Config yml filepath (as path cannot be stored in a const). + * + * @return string + * @throws TestFrameworkException + */ + private static function getYamlConfigFilePath() + { + return FilePathFormatter::format(TESTS_BP); + } +} \ No newline at end of file diff --git a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php index 1f8fec586..57f70238c 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php @@ -8,12 +8,12 @@ use Magento\FunctionalTestingFramework\Exceptions\Collector\ExceptionCollector; use Magento\FunctionalTestingFramework\Exceptions\FastFailException; -use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Suite\Generators\GroupClassGenerator; use Magento\FunctionalTestingFramework\Suite\Handlers\SuiteObjectHandler; use Magento\FunctionalTestingFramework\Suite\Objects\SuiteObject; +use Magento\FunctionalTestingFramework\Suite\Service\SuiteGeneratorService; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; use Magento\FunctionalTestingFramework\Util\Filesystem\DirSetupUtil; use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; @@ -21,7 +21,6 @@ use Magento\FunctionalTestingFramework\Util\Manifest\BaseTestManifest; use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Magento\FunctionalTestingFramework\Util\TestGenerator; -use Symfony\Component\Yaml\Yaml; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; /** @@ -30,14 +29,6 @@ */ class SuiteGenerator { - const YAML_CODECEPTION_DIST_FILENAME = 'codeception.dist.yml'; - const YAML_CODECEPTION_CONFIG_FILENAME = 'codeception.yml'; - const YAML_GROUPS_TAG = 'groups'; - const YAML_EXTENSIONS_TAG = 'extensions'; - const YAML_ENABLED_TAG = 'enabled'; - const YAML_COPYRIGHT_TEXT = - "# Copyright © Magento, Inc. All rights reserved.\n# See COPYING.txt for license details.\n"; - /** * Singelton Variable Instance. * @@ -268,7 +259,7 @@ private function generateSplitSuiteFromTest($suiteName, $suiteContent) try { $this->generateSuiteFromTest($suiteSplitName, $tests, $suiteName); } catch (FastFailException $e) { - throw $e; + throw $e; } catch (\Exception $e) { // There are suites that include tests that reference tests from other Magento editions // To keep backward compatibility, we will catch such exceptions with no error. @@ -331,21 +322,7 @@ private function generateGroupFile($suiteName, $tests, $originalSuiteName) */ private function appendEntriesToConfig($suiteName, $suitePath, $groupNamespace) { - $relativeSuitePath = substr($suitePath, strlen(TESTS_BP)); - $relativeSuitePath = ltrim($relativeSuitePath, DIRECTORY_SEPARATOR); - - $ymlArray = self::getYamlFileContents(); - if (!array_key_exists(self::YAML_GROUPS_TAG, $ymlArray)) { - $ymlArray[self::YAML_GROUPS_TAG]= []; - } - - if ($groupNamespace) { - $ymlArray[self::YAML_EXTENSIONS_TAG][self::YAML_ENABLED_TAG][] = $groupNamespace; - } - $ymlArray[self::YAML_GROUPS_TAG][$suiteName] = [$relativeSuitePath]; - - $ymlText = self::YAML_COPYRIGHT_TEXT . Yaml::dump($ymlArray, 10); - file_put_contents(self::getYamlConfigFilePath() . self::YAML_CODECEPTION_CONFIG_FILENAME, $ymlText); + SuiteGeneratorService::getInstance()->appendEntriesToConfig($suiteName, $suitePath, $groupNamespace); } /** @@ -356,27 +333,7 @@ private function appendEntriesToConfig($suiteName, $suitePath, $groupNamespace) */ private static function clearPreviousSessionConfigEntries() { - $ymlArray = self::getYamlFileContents(); - $newYmlArray = $ymlArray; - // if the yaml entries haven't already been cleared - if (array_key_exists(self::YAML_EXTENSIONS_TAG, $ymlArray)) { - foreach ($ymlArray[self::YAML_EXTENSIONS_TAG][self::YAML_ENABLED_TAG] as $key => $entry) { - if (preg_match('/(Group\\\\.*)/', $entry)) { - unset($newYmlArray[self::YAML_EXTENSIONS_TAG][self::YAML_ENABLED_TAG][$key]); - } - } - - // needed for proper yml file generation based on indices - $newYmlArray[self::YAML_EXTENSIONS_TAG][self::YAML_ENABLED_TAG] = - array_values($newYmlArray[self::YAML_EXTENSIONS_TAG][self::YAML_ENABLED_TAG]); - } - - if (array_key_exists(self::YAML_GROUPS_TAG, $newYmlArray)) { - unset($newYmlArray[self::YAML_GROUPS_TAG]); - } - - $ymlText = self::YAML_COPYRIGHT_TEXT . Yaml::dump($newYmlArray, 10); - file_put_contents(self::getYamlConfigFilePath() . self::YAML_CODECEPTION_CONFIG_FILENAME, $ymlText); + SuiteGeneratorService::getInstance()->clearPreviousSessionConfigEntries(); } /** @@ -406,37 +363,6 @@ private static function clearPreviousGroupPreconditions() array_map('unlink', glob("$groupFilePath*.php")); } - /** - * Function to return contents of codeception.yml file for config changes. - * - * @return array - */ - private static function getYamlFileContents() - { - $configYmlFile = self::getYamlConfigFilePath() . self::YAML_CODECEPTION_CONFIG_FILENAME; - $defaultConfigYmlFile = self::getYamlConfigFilePath() . self::YAML_CODECEPTION_DIST_FILENAME; - - $ymlContents = null; - if (file_exists($configYmlFile)) { - $ymlContents = file_get_contents($configYmlFile); - } else { - $ymlContents = file_get_contents($defaultConfigYmlFile); - } - - return Yaml::parse($ymlContents) ?? []; - } - - /** - * Static getter for the Config yml filepath (as path cannot be stored in a const) - * - * @return string - * @throws TestFrameworkException - */ - private static function getYamlConfigFilePath() - { - return FilePathFormatter::format(TESTS_BP); - } - /** * Log error and throw collected exceptions * From 73416f085115b6b7420cd9d50646bdfc7375464a Mon Sep 17 00:00:00 2001 From: "andrii.zinkevych" <a.zinkevych@atwix.com> Date: Fri, 23 Jul 2021 14:39:04 +0300 Subject: [PATCH 671/888] 33299: Fixed static-test --- .../Suite/SuiteGeneratorTest.php | 5 +- .../Suite/Service/SuiteGeneratorService.php | 57 ++++++++----------- .../Suite/SuiteGenerator.php | 8 +++ 3 files changed, 37 insertions(+), 33 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php index a7178c624..85afe7cde 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php @@ -330,7 +330,10 @@ private function setMockTestAndSuiteParserOutput(array $testData, array $suiteDa ->method('create') ->will( $this->returnCallback( - function (string $class, array $arguments = []) use ( + function ( + string $class, + array $arguments = [] + ) use ( $mockDataParser, $mockSuiteDataParser, $mockGroupClass, diff --git a/src/Magento/FunctionalTestingFramework/Suite/Service/SuiteGeneratorService.php b/src/Magento/FunctionalTestingFramework/Suite/Service/SuiteGeneratorService.php index cec4b4997..9aed81c5c 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Service/SuiteGeneratorService.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Service/SuiteGeneratorService.php @@ -8,6 +8,7 @@ namespace Magento\FunctionalTestingFramework\Suite\Service; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Suite\SuiteGenerator; use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Symfony\Component\Yaml\Yaml; @@ -16,15 +17,6 @@ */ class SuiteGeneratorService { - const YAML_CODECEPTION_DIST_FILENAME = 'codeception.dist.yml'; - const YAML_CODECEPTION_CONFIG_FILENAME = 'codeception.yml'; - const YAML_GROUPS_TAG = 'groups'; - const YAML_EXTENSIONS_TAG = 'extensions'; - const YAML_ENABLED_TAG = 'enabled'; - const YAML_COPYRIGHT_TEXT = - "# Copyright © Magento, Inc. All rights reserved.\n# See COPYING.txt for license details.\n"; - - /** * Singleton SuiteGeneratorService Instance. * @@ -65,56 +57,57 @@ public function clearPreviousSessionConfigEntries() $ymlArray = self::getYamlFileContents(); $newYmlArray = $ymlArray; // if the yaml entries haven't already been cleared - if (array_key_exists(self::YAML_EXTENSIONS_TAG, $ymlArray)) { - foreach ($ymlArray[self::YAML_EXTENSIONS_TAG][self::YAML_ENABLED_TAG] as $key => $entry) { + if (array_key_exists(SuiteGenerator::YAML_EXTENSIONS_TAG, $ymlArray)) { + $ymlEntries = $ymlArray[SuiteGenerator::YAML_EXTENSIONS_TAG][SuiteGenerator::YAML_ENABLED_TAG]; + + foreach ($ymlEntries as $key => $entry) { if (preg_match('/(Group\\\\.*)/', $entry)) { - unset($newYmlArray[self::YAML_EXTENSIONS_TAG][self::YAML_ENABLED_TAG][$key]); + unset($newYmlArray[SuiteGenerator::YAML_EXTENSIONS_TAG][SuiteGenerator::YAML_ENABLED_TAG][$key]); } } // needed for proper yml file generation based on indices - $newYmlArray[self::YAML_EXTENSIONS_TAG][self::YAML_ENABLED_TAG] = - array_values($newYmlArray[self::YAML_EXTENSIONS_TAG][self::YAML_ENABLED_TAG]); + $newYmlArray[SuiteGenerator::YAML_EXTENSIONS_TAG][SuiteGenerator::YAML_ENABLED_TAG] = + array_values($newYmlArray[SuiteGenerator::YAML_EXTENSIONS_TAG][SuiteGenerator::YAML_ENABLED_TAG]); } - if (array_key_exists(self::YAML_GROUPS_TAG, $newYmlArray)) { - unset($newYmlArray[self::YAML_GROUPS_TAG]); + if (array_key_exists(SuiteGenerator::YAML_GROUPS_TAG, $newYmlArray)) { + unset($newYmlArray[SuiteGenerator::YAML_GROUPS_TAG]); } - $ymlText = self::YAML_COPYRIGHT_TEXT . Yaml::dump($newYmlArray, 10); - file_put_contents(self::getYamlConfigFilePath() . self::YAML_CODECEPTION_CONFIG_FILENAME, $ymlText); + $ymlText = SuiteGenerator::YAML_COPYRIGHT_TEXT . Yaml::dump($newYmlArray, 10); + file_put_contents(self::getYamlConfigFilePath() . SuiteGenerator::YAML_CODECEPTION_CONFIG_FILENAME, $ymlText); } - /** * Function which accepts a suite name and suite path and appends a new group entry to the codeception.yml.dist * file in order to register the set of tests as a new group. Also appends group object location if required * by suite. * - * @param string $suiteName - * @param string $suitePath - * @param string $groupNamespace + * @param string $suiteName + * @param string $suitePath + * @param string|null $groupNamespace * * @return void * @throws TestFrameworkException */ - public function appendEntriesToConfig(string $suiteName, string $suitePath, string $groupNamespace) + public function appendEntriesToConfig(string $suiteName, string $suitePath, ?string $groupNamespace) { $relativeSuitePath = substr($suitePath, strlen(TESTS_BP)); $relativeSuitePath = ltrim($relativeSuitePath, DIRECTORY_SEPARATOR); $ymlArray = self::getYamlFileContents(); - if (!array_key_exists(self::YAML_GROUPS_TAG, $ymlArray)) { - $ymlArray[self::YAML_GROUPS_TAG]= []; + if (!array_key_exists(SuiteGenerator::YAML_GROUPS_TAG, $ymlArray)) { + $ymlArray[SuiteGenerator::YAML_GROUPS_TAG] = []; } if ($groupNamespace) { - $ymlArray[self::YAML_EXTENSIONS_TAG][self::YAML_ENABLED_TAG][] = $groupNamespace; + $ymlArray[SuiteGenerator::YAML_EXTENSIONS_TAG][SuiteGenerator::YAML_ENABLED_TAG][] = $groupNamespace; } - $ymlArray[self::YAML_GROUPS_TAG][$suiteName] = [$relativeSuitePath]; - $ymlText = self::YAML_COPYRIGHT_TEXT . Yaml::dump($ymlArray, 10); - file_put_contents(self::getYamlConfigFilePath() . self::YAML_CODECEPTION_CONFIG_FILENAME, $ymlText); + $ymlArray[SuiteGenerator::YAML_GROUPS_TAG][$suiteName] = [$relativeSuitePath]; + $ymlText = SuiteGenerator::YAML_COPYRIGHT_TEXT . Yaml::dump($ymlArray, 10); + file_put_contents(self::getYamlConfigFilePath() . SuiteGenerator::YAML_CODECEPTION_CONFIG_FILENAME, $ymlText); } /** @@ -125,8 +118,8 @@ public function appendEntriesToConfig(string $suiteName, string $suitePath, stri */ private static function getYamlFileContents(): array { - $configYmlFile = self::getYamlConfigFilePath() . self::YAML_CODECEPTION_CONFIG_FILENAME; - $defaultConfigYmlFile = self::getYamlConfigFilePath() . self::YAML_CODECEPTION_DIST_FILENAME; + $configYmlFile = self::getYamlConfigFilePath() . SuiteGenerator::YAML_CODECEPTION_CONFIG_FILENAME; + $defaultConfigYmlFile = self::getYamlConfigFilePath() . SuiteGenerator::YAML_CODECEPTION_DIST_FILENAME; $ymlContents = null; if (file_exists($configYmlFile)) { @@ -148,4 +141,4 @@ private static function getYamlConfigFilePath() { return FilePathFormatter::format(TESTS_BP); } -} \ No newline at end of file +} diff --git a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php index 57f70238c..37e370242 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php @@ -29,6 +29,14 @@ */ class SuiteGenerator { + const YAML_CODECEPTION_DIST_FILENAME = 'codeception.dist.yml'; + const YAML_CODECEPTION_CONFIG_FILENAME = 'codeception.yml'; + const YAML_GROUPS_TAG = 'groups'; + const YAML_EXTENSIONS_TAG = 'extensions'; + const YAML_ENABLED_TAG = 'enabled'; + const YAML_COPYRIGHT_TEXT = + "# Copyright © Magento, Inc. All rights reserved.\n# See COPYING.txt for license details.\n"; + /** * Singelton Variable Instance. * From 74a08921b87b66cb04f90abbccf4d0074e77bde1 Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Fri, 23 Jul 2021 15:16:31 +0300 Subject: [PATCH 672/888] 33299: code refactoring after code review --- .../Suite/SuiteGeneratorTest.php | 16 ++++++++--- .../Suite/Service/SuiteGeneratorService.php | 28 +++++++++++++++---- .../Suite/SuiteGenerator.php | 8 +++--- 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php index 85afe7cde..15d6b4a5f 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php @@ -31,7 +31,8 @@ class SuiteGeneratorTest extends MagentoTestCase { /** - * Before test functionality + * Before test functionality. + * * @return void */ protected function setUp(): void @@ -290,19 +291,27 @@ public function testGenerateSplitSuiteFromTest(): void * * @param array $testData * @param array $suiteData + * + * @return void * @throws Exception */ private function setMockTestAndSuiteParserOutput(array $testData, array $suiteData): void { $this->clearMockResolverProperties(); $mockSuiteGeneratorService = $this->createMock(SuiteGeneratorService::class); + $mockVoidReturnCallback = function () {};// phpcs:ignore + $mockSuiteGeneratorService ->method('clearPreviousSessionConfigEntries') - ->willReturn(null); + ->will($this->returnCallback($mockVoidReturnCallback)); $mockSuiteGeneratorService ->method('appendEntriesToConfig') - ->willReturn(null); + ->will($this->returnCallback($mockVoidReturnCallback)); + + $mockSuiteGeneratorService + ->method('generateRelevantGroupTests') + ->will($this->returnCallback($mockVoidReturnCallback)); $suiteGeneratorServiceProperty = new ReflectionProperty(SuiteGeneratorService::class, 'INSTANCE'); $suiteGeneratorServiceProperty->setAccessible(true); @@ -324,7 +333,6 @@ private function setMockTestAndSuiteParserOutput(array $testData, array $suiteDa ->willReturn('namespace'); $objectManager = ObjectManagerFactory::getObjectManager(); - $objectManagerMockInstance = $this->createMock(ObjectManager::class); $objectManagerMockInstance ->method('create') diff --git a/src/Magento/FunctionalTestingFramework/Suite/Service/SuiteGeneratorService.php b/src/Magento/FunctionalTestingFramework/Suite/Service/SuiteGeneratorService.php index 9aed81c5c..58823e195 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Service/SuiteGeneratorService.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Service/SuiteGeneratorService.php @@ -8,8 +8,10 @@ namespace Magento\FunctionalTestingFramework\Suite\Service; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Suite\SuiteGenerator; use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; +use Magento\FunctionalTestingFramework\Util\TestGenerator; use Symfony\Component\Yaml\Yaml; /** @@ -52,7 +54,7 @@ public static function getInstance(): SuiteGeneratorService * @return void * @throws TestFrameworkException */ - public function clearPreviousSessionConfigEntries() + public function clearPreviousSessionConfigEntries(): void { $ymlArray = self::getYamlFileContents(); $newYmlArray = $ymlArray; @@ -65,7 +67,6 @@ public function clearPreviousSessionConfigEntries() unset($newYmlArray[SuiteGenerator::YAML_EXTENSIONS_TAG][SuiteGenerator::YAML_ENABLED_TAG][$key]); } } - // needed for proper yml file generation based on indices $newYmlArray[SuiteGenerator::YAML_EXTENSIONS_TAG][SuiteGenerator::YAML_ENABLED_TAG] = array_values($newYmlArray[SuiteGenerator::YAML_EXTENSIONS_TAG][SuiteGenerator::YAML_ENABLED_TAG]); @@ -74,7 +75,6 @@ public function clearPreviousSessionConfigEntries() if (array_key_exists(SuiteGenerator::YAML_GROUPS_TAG, $newYmlArray)) { unset($newYmlArray[SuiteGenerator::YAML_GROUPS_TAG]); } - $ymlText = SuiteGenerator::YAML_COPYRIGHT_TEXT . Yaml::dump($newYmlArray, 10); file_put_contents(self::getYamlConfigFilePath() . SuiteGenerator::YAML_CODECEPTION_CONFIG_FILENAME, $ymlText); } @@ -91,7 +91,7 @@ public function clearPreviousSessionConfigEntries() * @return void * @throws TestFrameworkException */ - public function appendEntriesToConfig(string $suiteName, string $suitePath, ?string $groupNamespace) + public function appendEntriesToConfig(string $suiteName, string $suitePath, ?string $groupNamespace): void { $relativeSuitePath = substr($suitePath, strlen(TESTS_BP)); $relativeSuitePath = ltrim($relativeSuitePath, DIRECTORY_SEPARATOR); @@ -110,6 +110,23 @@ public function appendEntriesToConfig(string $suiteName, string $suitePath, ?str file_put_contents(self::getYamlConfigFilePath() . SuiteGenerator::YAML_CODECEPTION_CONFIG_FILENAME, $ymlText); } + /** + * Function which takes a string which is the desired output directory (under _generated) and an array of tests + * relevant to the suite to be generated. The function takes this information and creates a new instance of the + * test generator which is then called to create all the test files for the suite. + * + * @param string $path + * @param array $tests + * + * @return void + * @throws TestReferenceException + */ + public function generateRelevantGroupTests(string $path, array $tests): void + { + $testGenerator = TestGenerator::getInstance($path, $tests); + $testGenerator->createAllTestFiles(null, []); + } + /** * Function to return contents of codeception.yml file for config changes. * @@ -120,7 +137,6 @@ private static function getYamlFileContents(): array { $configYmlFile = self::getYamlConfigFilePath() . SuiteGenerator::YAML_CODECEPTION_CONFIG_FILENAME; $defaultConfigYmlFile = self::getYamlConfigFilePath() . SuiteGenerator::YAML_CODECEPTION_DIST_FILENAME; - $ymlContents = null; if (file_exists($configYmlFile)) { $ymlContents = file_get_contents($configYmlFile); @@ -137,7 +153,7 @@ private static function getYamlFileContents(): array * @return string * @throws TestFrameworkException */ - private static function getYamlConfigFilePath() + private static function getYamlConfigFilePath(): string { return FilePathFormatter::format(TESTS_BP); } diff --git a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php index 37e370242..ced0ac552 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php @@ -346,18 +346,18 @@ private static function clearPreviousSessionConfigEntries() /** * Function which takes a string which is the desired output directory (under _generated) and an array of tests - * relevant to the suite to be generated. The function takes this information and creates a new instance of the test - * generator which is then called to create all the test files for the suite. + * relevant to the suite to be generated. The function takes this information and creates a new instance of the + * test generator which is then called to create all the test files for the suite. * * @param string $path * @param array $tests + * * @return void * @throws TestReferenceException */ private function generateRelevantGroupTests($path, $tests) { - $testGenerator = TestGenerator::getInstance($path, $tests); - $testGenerator->createAllTestFiles(null, []); + SuiteGeneratorService::getInstance()->generateRelevantGroupTests($path, $tests); } /** From b0e9c2e7aa915ec5ca6cdbb1eb7584c470cb97f8 Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Fri, 23 Jul 2021 17:29:18 +0300 Subject: [PATCH 673/888] 33294: Eliminated singleton usage --- .../Allure/AllureHelperTest.php | 49 +++++++++++++------ .../Allure/AllureHelper.php | 22 +++++++-- .../Allure/Event/AddUniqueAttachmentEvent.php | 29 ----------- 3 files changed, 52 insertions(+), 48 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php index 1e17b780d..832a43978 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Allure/AllureHelperTest.php @@ -9,6 +9,7 @@ use Magento\FunctionalTestingFramework\Allure\AllureHelper; use Magento\FunctionalTestingFramework\Allure\Event\AddUniqueAttachmentEvent; +use Magento\FunctionalTestingFramework\ObjectManager; use PHPUnit\Framework\TestCase; use ReflectionProperty; use Yandex\Allure\Adapter\Allure; @@ -21,19 +22,6 @@ class AllureHelperTest extends TestCase { private const MOCK_FILENAME = 'filename'; - /** - * Clear Allure Lifecycle. - * - * @return void - */ - protected function tearDown(): void - { - Allure::setDefaultLifecycle(); - $instanceProperty = new ReflectionProperty(AddUniqueAttachmentEvent::class, 'instance'); - $instanceProperty->setAccessible(true); - $instanceProperty->setValue(null); - } - /** * The AddAttachmentToStep should add an attachment to the current step. * @@ -121,6 +109,20 @@ public function testAddAttachmentUniqueName(): void $this->assertNotEquals($attachmentOne, $attachmentTwo); } + /** + * Clear Allure Lifecycle. + * + * @return void + */ + protected function tearDown(): void + { + Allure::setDefaultLifecycle(); + + $objectManagerProperty = new ReflectionProperty(ObjectManager::class, 'instance'); + $objectManagerProperty->setAccessible(true); + $objectManagerProperty->setValue(null); + } + /** * Mock entire attachment writing mechanisms. * @@ -141,8 +143,23 @@ private function mockAttachmentWriteEvent(string $filePathOrContents, string $ca ->method('getAttachmentFileName') ->willReturn(self::MOCK_FILENAME); - $instanceProperty = new ReflectionProperty(AddUniqueAttachmentEvent::class, 'instance'); - $instanceProperty->setAccessible(true); - $instanceProperty->setValue($mockInstance, $mockInstance); + $objectManagerMockInstance = $this->createMock(ObjectManager::class); + $objectManagerMockInstance + ->method('create') + ->will( + $this->returnCallback( + function (string $class) use ($mockInstance) { + if ($class === AddUniqueAttachmentEvent::class) { + return $mockInstance; + } + + return null; + } + ) + ); + + $objectManagerProperty = new ReflectionProperty(ObjectManager::class, 'instance'); + $objectManagerProperty->setAccessible(true); + $objectManagerProperty->setValue($objectManagerMockInstance, $objectManagerMockInstance); } } diff --git a/src/Magento/FunctionalTestingFramework/Allure/AllureHelper.php b/src/Magento/FunctionalTestingFramework/Allure/AllureHelper.php index 6263908bc..4fbd65eb7 100644 --- a/src/Magento/FunctionalTestingFramework/Allure/AllureHelper.php +++ b/src/Magento/FunctionalTestingFramework/Allure/AllureHelper.php @@ -8,6 +8,7 @@ namespace Magento\FunctionalTestingFramework\Allure; use Magento\FunctionalTestingFramework\Allure\Event\AddUniqueAttachmentEvent; +use Magento\FunctionalTestingFramework\ObjectManagerFactory; use Yandex\Allure\Adapter\Allure; use Yandex\Allure\Adapter\AllureException; @@ -24,7 +25,15 @@ class AllureHelper */ public static function addAttachmentToCurrentStep($data, $caption): void { - Allure::lifecycle()->fire(AddUniqueAttachmentEvent::getInstance($data, $caption)); + /** @var AddUniqueAttachmentEvent $event */ + $event = ObjectManagerFactory::getObjectManager()->create( + AddUniqueAttachmentEvent::class, + [ + 'filePathOrContents' => $data, + 'caption' => $caption + ] + ); + Allure::lifecycle()->fire($event); } /** @@ -45,8 +54,15 @@ public static function addAttachmentToLastStep($data, $caption): void // Nothing to attach to; do not fire off allure event return; } - - $attachmentEvent = AddUniqueAttachmentEvent::getInstance($data, $caption); + + /** @var AddUniqueAttachmentEvent $attachmentEvent */ + $attachmentEvent = ObjectManagerFactory::getObjectManager()->create( + AddUniqueAttachmentEvent::class, + [ + 'filePathOrContents' => $data, + 'caption' => $caption + ] + ); $attachmentEvent->process($trueLastStep); } } diff --git a/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php b/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php index 990cd5f10..d6f36f953 100644 --- a/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php +++ b/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php @@ -18,11 +18,6 @@ class AddUniqueAttachmentEvent extends AddAttachmentEvent private const DEFAULT_FILE_EXTENSION = 'txt'; private const DEFAULT_MIME_TYPE = 'text/plain'; - /** - * @var AddUniqueAttachmentEvent|null - */ - private static $instance; - /** * Near copy of parent function, added uniqid call for filename to prevent buggy allure behavior. * @@ -58,30 +53,6 @@ public function getAttachmentFileName($filePathOrContents, $type): string return $this->getOutputFileName($fileSha1, $fileExtension); } - /** - * Unit test helper function. - * - * @param mixed $filePathOrContents - * @param string $caption - * @param string|null $type - * - * @return AddUniqueAttachmentEvent - */ - public static function getInstance( - $filePathOrContents, - string $caption, - ?string $type = null - ): AddUniqueAttachmentEvent { - if (!self::$instance) { - self::$instance = new AddUniqueAttachmentEvent( - $filePathOrContents, - $caption, - $type - ); - } - return self::$instance; - } - /** * Copies file from one path to another. Wrapper for mocking in unit test. * From 04ea4ab25fdfd8e3f88d44fb2163d0c22a17ea50 Mon Sep 17 00:00:00 2001 From: "andrii.zinkevych" <a.zinkevych@atwix.com> Date: Fri, 23 Jul 2021 17:43:11 +0300 Subject: [PATCH 674/888] 33299: Fixed Code --- .../DataGenerator/Persist/DataPersistenceHandler.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/DataPersistenceHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/DataPersistenceHandler.php index 19a577f0f..fe4a10186 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/DataPersistenceHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/DataPersistenceHandler.php @@ -89,7 +89,7 @@ public function createEntity($storeCode = null) } $curlHandler = ObjectManagerFactory::getObjectManager()->create( CurlHandler::class, - ['create', $this->entityObject, $this->storeCode] + ['operation' => 'create', 'entityObject' => $this->entityObject, 'storeCode' => $this->storeCode] ); $result = $curlHandler->executeRequest($this->dependentObjects); $this->setCreatedObject( @@ -117,7 +117,7 @@ public function updateEntity($updateDataName, $updateDependentObjects = []) $updateEntityObject = DataObjectHandler::getInstance()->getObject($updateDataName); $curlHandler = ObjectManagerFactory::getObjectManager()->create( CurlHandler::class, - ['update', $updateEntityObject, $this->storeCode] + ['operation' => 'update', 'entityObject' => $updateEntityObject, 'storeCode' => $this->storeCode] ); $result = $curlHandler->executeRequest(array_merge($this->dependentObjects, [$this->createdObject])); $this->setCreatedObject( @@ -143,7 +143,7 @@ public function getEntity($index = null, $storeCode = null) } $curlHandler = ObjectManagerFactory::getObjectManager()->create( CurlHandler::class, - ['get', $this->entityObject, $this->storeCode] + ['operation' => 'get', 'entityObject' => $this->entityObject, 'storeCode' => $this->storeCode] ); $result = $curlHandler->executeRequest($this->dependentObjects); $this->setCreatedObject( @@ -164,7 +164,7 @@ public function deleteEntity() { $curlHandler = ObjectManagerFactory::getObjectManager()->create( CurlHandler::class, - ['delete', $this->createdObject, $this->storeCode] + ['operation' => 'delete', 'entityObject' => $this->createdObject, 'storeCode' => $this->storeCode] ); $curlHandler->executeRequest($this->dependentObjects); From 8e67f95eb298e7bb794348753b3677aa59981e44 Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Mon, 26 Jul 2021 13:10:11 +0300 Subject: [PATCH 675/888] MFTF-33583: Eliminated MockModuleResolverBuilder usage --- .../Test/Handlers/TestObjectHandlerTest.php | 110 ++++++++++++++---- .../Util/ModulePathExtractorTest.php | 65 ++++++++--- .../Util/TestGeneratorTest.php | 9 ++ .../unit/Util/MockModuleResolverBuilder.php | 61 ---------- .../Test/Handlers/TestObjectHandler.php | 12 +- 5 files changed, 158 insertions(+), 99 deletions(-) delete mode 100644 dev/tests/unit/Util/MockModuleResolverBuilder.php diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php index b5d461db9..a2779bdd1 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php @@ -8,15 +8,20 @@ namespace tests\unit\Magento\FunctionalTestFramework\Test\Handlers; use Exception; +use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\ObjectManager; +use Magento\FunctionalTestingFramework\ObjectManagerFactory; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Magento\FunctionalTestingFramework\Test\Objects\TestHookObject; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; +use Magento\FunctionalTestingFramework\Test\Parsers\TestDataParser; use Magento\FunctionalTestingFramework\Test\Util\TestObjectExtractor; use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; +use Magento\FunctionalTestingFramework\Util\ModuleResolver; +use ReflectionProperty; use tests\unit\Util\MagentoTestCase; -use tests\unit\Util\MockModuleResolverBuilder; -use tests\unit\Util\ObjectHandlerUtil; use tests\unit\Util\TestDataArrayBuilder; use tests\unit\Util\TestLoggingUtil; @@ -51,9 +56,7 @@ public function testGetTestObject(): void ->withTestActions() ->build(); - $resolverMock = new MockModuleResolverBuilder(); - $resolverMock->setup(); - ObjectHandlerUtil::mockTestObjectHandlerWitData($mockData); + $this->mockTestObjectHandler($mockData); // run object handler method $toh = TestObjectHandler::getInstance(); @@ -146,9 +149,7 @@ public function testGetTestsByGroup(): void ->withTestActions() ->build(); - $resolverMock = new MockModuleResolverBuilder(); - $resolverMock->setup(); - ObjectHandlerUtil::mockTestObjectHandlerWitData(array_merge($includeTest, $excludeTest)); + $this->mockTestObjectHandler(array_merge($includeTest, $excludeTest)); // execute test method $toh = TestObjectHandler::getInstance(); @@ -195,10 +196,8 @@ public function testGetTestWithModuleName(): void ->withFileName($file) ->build(); - $resolverMock = new MockModuleResolverBuilder(); - $resolverMock->setup(['Vendor_' . $moduleExpected => $filepath]); + $this->mockTestObjectHandler($mockData, ['Vendor_' . $moduleExpected => $filepath]); - ObjectHandlerUtil::mockTestObjectHandlerWitData($mockData); // Execute Test Method $toh = TestObjectHandler::getInstance(); $actualTestObject = $toh->getObject($testDataArrayBuilder->testName); @@ -225,13 +224,11 @@ public function testGetTestObjectWithInvalidExtends(): void ->withBeforeHook() ->withTestActions() ->build(); - $resolverMock = new MockModuleResolverBuilder(); - $resolverMock->setup(); - ObjectHandlerUtil::mockTestObjectHandlerWitData($testOne); - $toh = TestObjectHandler::getInstance(); + $this->mockTestObjectHandler($testOne); - $this->expectException(\Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException::class); + $toh = TestObjectHandler::getInstance(); + $this->expectException(TestFrameworkException::class); $this->expectExceptionMessage("Mftf Test can not extend from itself: " . "testOne"); $toh->getObject('testOne'); @@ -264,9 +261,7 @@ public function testGetAllTestObjectsWithInvalidExtends(): void ->withTestActions() ->build(); - $resolverMock = new MockModuleResolverBuilder(); - $resolverMock->setup(); - ObjectHandlerUtil::mockTestObjectHandlerWitData(array_merge($testOne, $testTwo)); + $this->mockTestObjectHandler(array_merge($testOne, $testTwo)); $toh = TestObjectHandler::getInstance(); $toh->getAllObjects(); @@ -297,9 +292,7 @@ public function testGetTestObjectWhenEnablePause(): void ->withTestActions() ->build(); - $resolverMock = new MockModuleResolverBuilder(); - $resolverMock->setup(); - ObjectHandlerUtil::mockTestObjectHandlerWitData($mockData); + $this->mockTestObjectHandler($mockData); // run object handler method $toh = TestObjectHandler::getInstance(); @@ -381,4 +374,77 @@ protected function tearDown(): void TestLoggingUtil::getInstance()->clearMockLoggingUtil(); parent::tearDownAfterClass(); } + + /** + * Mock test object handler. + * + * @param array $data + * @param array|null $paths + * + * @return void + */ + private function mockTestObjectHandler(array $data, ?array $paths = null): void + { + if (!$paths) { + $paths = ['Magento_Module' => '/base/path/some/other/path/Magento/Module']; + } + // clear test object handler value to inject parsed content + $property = new ReflectionProperty(TestObjectHandler::class, 'testObjectHandler'); + $property->setAccessible(true); + $property->setValue(null); + + $mockDataParser = $this->createMock(TestDataParser::class); + $mockDataParser + ->method('readTestData') + ->willReturn($data); + + $mockConfig = $this->createMock(MftfApplicationConfig::class); + $mockConfig + ->method('forceGenerateEnabled') + ->willReturn(false); + + $mockResolver = $this->createMock(ModuleResolver::class); + $mockResolver + ->method('getEnabledModules') + ->willReturn([]); + + $objectManager = ObjectManagerFactory::getObjectManager(); + $objectManagerMockInstance = $this->createMock(ObjectManager::class); + $objectManagerMockInstance + ->method('create') + ->will( + $this->returnCallback( + function ( + $class, + $arguments = [] + ) use ( + $objectManager, + $mockDataParser, + $mockConfig, + $mockResolver + ) { + if ($class === TestDataParser::class) { + return $mockDataParser; + } + if ($class === MftfApplicationConfig::class) { + return $mockConfig; + } + if ($class === ModuleResolver::class) { + return $mockResolver; + } + + return $objectManager->create($class, $arguments); + } + ) + ); + + $objectManagerProperty = new ReflectionProperty(ObjectManager::class, 'instance'); + $objectManagerProperty->setAccessible(true); + $objectManagerProperty->setValue($objectManagerMockInstance); + + $resolver = ModuleResolver::getInstance(); + $property = new ReflectionProperty(ModuleResolver::class, 'enabledModuleNameAndPaths'); + $property->setAccessible(true); + $property->setValue($resolver, $paths); + } } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModulePathExtractorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModulePathExtractorTest.php index 3f2ba1962..00be96582 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModulePathExtractorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModulePathExtractorTest.php @@ -3,12 +3,15 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace tests\unit\Magento\FunctionalTestFramework\Util; +use Magento\FunctionalTestingFramework\ObjectManager; use Magento\FunctionalTestingFramework\Util\ModulePathExtractor; +use Magento\FunctionalTestingFramework\Util\ModuleResolver; +use ReflectionProperty; use tests\unit\Util\MagentoTestCase; -use tests\unit\Util\MockModuleResolverBuilder; class ModulePathExtractorTest extends MagentoTestCase { @@ -36,8 +39,7 @@ public function testGetModuleAppCode() { $mockPath = '/base/path/app/code/Magento/ModuleA/Test/Mftf/Test/SomeTest.xml'; - $resolverMock = new MockModuleResolverBuilder(); - $resolverMock->setup($this->mockTestModulePaths); + $this->mockModuleResolver($this->mockTestModulePaths); $extractor = new ModulePathExtractor(); $this->assertEquals('ModuleA', $extractor->extractModuleName($mockPath)); } @@ -51,8 +53,7 @@ public function testGetVendorAppCode() { $mockPath = '/base/path/app/code/VendorB/ModuleB/Test/Mftf/Test/SomeTest.xml'; - $resolverMock = new MockModuleResolverBuilder(); - $resolverMock->setup($this->mockTestModulePaths); + $this->mockModuleResolver($this->mockTestModulePaths); $extractor = new ModulePathExtractor(); $this->assertEquals('VendorB', $extractor->getExtensionPath($mockPath)); } @@ -66,8 +67,7 @@ public function testGetModuleDevTests() { $mockPath = '/base/path/dev/tests/acceptance/tests/functional/Magento/ModuleCTest/Test/SomeTest.xml'; - $resolverMock = new MockModuleResolverBuilder(); - $resolverMock->setup($this->mockTestModulePaths); + $this->mockModuleResolver($this->mockTestModulePaths); $extractor = new ModulePathExtractor(); $this->assertEquals('ModuleC', $extractor->extractModuleName($mockPath)); } @@ -81,8 +81,7 @@ public function testGetVendorDevTests() { $mockPath = '/base/path/dev/tests/acceptance/tests/functional/VendorD/ModuleDTest/Test/SomeTest.xml'; - $resolverMock = new MockModuleResolverBuilder(); - $resolverMock->setup($this->mockTestModulePaths); + $this->mockModuleResolver($this->mockTestModulePaths); $extractor = new ModulePathExtractor(); $this->assertEquals('VendorD', $extractor->getExtensionPath($mockPath)); } @@ -96,8 +95,7 @@ public function testGetModule() { $mockPath = '/base/path/dev/tests/acceptance/tests/functional/FunctionalTest/SomeModuleE/Test/SomeTest.xml'; - $resolverMock = new MockModuleResolverBuilder(); - $resolverMock->setup($this->mockTestModulePaths); + $this->mockModuleResolver($this->mockTestModulePaths); $extractor = new ModulePathExtractor(); $this->assertEquals('NO MODULE DETECTED', $extractor->extractModuleName($mockPath)); } @@ -111,8 +109,7 @@ public function testGetModuleVendorDir() { $mockPath = '/base/path/vendor/magento/module-modulef/Test/Mftf/Test/SomeTest.xml'; - $resolverMock = new MockModuleResolverBuilder(); - $resolverMock->setup($this->mockTestModulePaths); + $this->mockModuleResolver($this->mockTestModulePaths); $extractor = new ModulePathExtractor(); $this->assertEquals('ModuleF', $extractor->extractModuleName($mockPath)); } @@ -126,9 +123,47 @@ public function testGetVendorVendorDir() { $mockPath = '/base/path/vendor/vendorg/module-moduleg-test/Test/SomeTest.xml'; - $resolverMock = new MockModuleResolverBuilder(); - $resolverMock->setup($this->mockTestModulePaths); + $this->mockModuleResolver($this->mockTestModulePaths); $extractor = new ModulePathExtractor(); $this->assertEquals('VendorG', $extractor->getExtensionPath($mockPath)); } + + /** + * Mock module resolver. + * + * @param array $paths + * + * @return void + */ + private function mockModuleResolver(array $paths): void + { + $mockResolver = $this->createMock(ModuleResolver::class); + $mockResolver + ->method('getEnabledModules') + ->willReturn([]); + + $objectManagerMockInstance = $this->createMock(ObjectManager::class); + $objectManagerMockInstance + ->method('create') + ->will( + $this->returnCallback( + function ($class) use ($mockResolver) { + if ($class === ModuleResolver::class) { + return $mockResolver; + } + + return null; + } + ) + ); + + $objectManagerProperty = new ReflectionProperty(ObjectManager::class, 'instance'); + $objectManagerProperty->setAccessible(true); + $objectManagerProperty->setValue($objectManagerMockInstance); + + $resolver = ModuleResolver::getInstance(); + $property = new ReflectionProperty(ModuleResolver::class, 'enabledModuleNameAndPaths'); + $property->setAccessible(true); + $property->setValue($resolver, $paths); + } } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php index 730493191..c4dc291c1 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php @@ -11,6 +11,7 @@ use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Filter\FilterList; +use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Magento\FunctionalTestingFramework\Test\Objects\TestHookObject; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; @@ -31,6 +32,10 @@ class TestGeneratorTest extends MagentoTestCase protected function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); + // Used to mock initTestData method running. + $shouldSkipInitTestDataProperty = new ReflectionProperty(TestObjectHandler::class, 'shouldSkipInitTestData'); + $shouldSkipInitTestDataProperty->setAccessible(true); + $shouldSkipInitTestDataProperty->setValue(true); } /** @@ -41,6 +46,10 @@ protected function setUp(): void protected function tearDown(): void { GenerationErrorHandler::getInstance()->reset(); + + $shouldSkipInitTestDataProperty = new ReflectionProperty(TestObjectHandler::class, 'shouldSkipInitTestData'); + $shouldSkipInitTestDataProperty->setAccessible(true); + $shouldSkipInitTestDataProperty->setValue(false); } /** diff --git a/dev/tests/unit/Util/MockModuleResolverBuilder.php b/dev/tests/unit/Util/MockModuleResolverBuilder.php deleted file mode 100644 index 0e1b6fc31..000000000 --- a/dev/tests/unit/Util/MockModuleResolverBuilder.php +++ /dev/null @@ -1,61 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace tests\unit\Util; - -use AspectMock\Test as AspectMock; -use Magento\FunctionalTestingFramework\ObjectManager; -use Magento\FunctionalTestingFramework\ObjectManagerFactory; -use Magento\FunctionalTestingFramework\Util\ModuleResolver; -use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; - -class MockModuleResolverBuilder -{ - /** - * Default paths for mock ModuleResolver - * - * @var array - */ - private $defaultPaths = ['Magento_Module' => '/base/path/some/other/path/Magento/Module']; - - /** - * Mock ModuleResolver builder - * - * @param array $paths - * @return void - * @throws \Exception - */ - public function setup($paths = null) - { - if (empty($paths)) { - $paths = $this->defaultPaths; - } - - $mockConfig = AspectMock::double(MftfApplicationConfig::class, ['forceGenerateEnabled' => false]); - $instance = AspectMock::double(ObjectManager::class, ['create' => $mockConfig->make(), 'get' => null])->make(); - AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); - - $property = new \ReflectionProperty(ModuleResolver::class, 'instance'); - $property->setAccessible(true); - $property->setValue(null); - - $mockResolver = AspectMock::double( - ModuleResolver::class, - [ - 'getAdminToken' => false, - 'globRelevantPaths' => [], - 'getEnabledModules' => [] - ] - ); - $instance = AspectMock::double(ObjectManager::class, ['create' => $mockResolver->make(), 'get' => null]) - ->make(); - AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); - - $resolver = ModuleResolver::getInstance(); - $property = new \ReflectionProperty(ModuleResolver::class, 'enabledModuleNameAndPaths'); - $property->setAccessible(true); - $property->setValue($resolver, $paths); - } -} diff --git a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php index 4abc26c36..407fc89d9 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php @@ -44,6 +44,13 @@ class TestObjectHandler implements ObjectHandlerInterface */ private $tests = []; + /** + * Check if initTestData method should be skipped during object initialization. + * + * @var boolean + */ + private static $shouldSkipInitTestData = false; + /** * Instance of ObjectExtensionUtil class * @@ -62,7 +69,10 @@ public static function getInstance($validateAnnotations = true) { if (!self::$testObjectHandler) { self::$testObjectHandler = new TestObjectHandler(); - self::$testObjectHandler->initTestData($validateAnnotations); + + if (!self::$shouldSkipInitTestData) { + self::$testObjectHandler->initTestData($validateAnnotations); + } } return self::$testObjectHandler; From ac6cef43ce6876430a17cfc63c9b6ce49b4a148d Mon Sep 17 00:00:00 2001 From: "andrii.zinkevych" <a.zinkevych@atwix.com> Date: Mon, 26 Jul 2021 14:35:30 +0300 Subject: [PATCH 676/888] 33581: Eliminated AspectMock where it was imported but never used --- .../Handlers/DataObjectHandlerTest.php | 81 +++--- .../OperationDefinitionObjectHandlerTest.php | 222 +++++++++------- .../Page/Handlers/PageObjectHandlerTest.php | 112 +++++---- .../Handlers/SectionObjectHandlerTest.php | 79 +++--- .../Handlers/ActionGroupObjectHandlerTest.php | 34 +-- .../ActionGroupAnnotationExtractorTest.php | 34 +-- .../Test/Util/AnnotationExtractorTest.php | 236 ++++++++++-------- 7 files changed, 461 insertions(+), 337 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php index 745789501..57cdb6a64 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php @@ -3,15 +3,14 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace tests\unit\Magento\FunctionalTestFramework\DataGenerator\Handlers; -use AspectMock\Test as AspectMock; +use Exception; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; -use Magento\FunctionalTestingFramework\DataGenerator\Parsers\DataProfileSchemaParser; -use Magento\FunctionalTestingFramework\ObjectManager; -use Magento\FunctionalTestingFramework\ObjectManagerFactory; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use tests\unit\Util\MagentoTestCase; use tests\unit\Util\ObjectHandlerUtil; use tests\unit\Util\TestLoggingUtil; @@ -22,9 +21,9 @@ class DataObjectHandlerTest extends MagentoTestCase { /** - * Setup method + * @inheritDoc */ - public function setUp(): void + protected function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); } @@ -145,9 +144,12 @@ public function setUp(): void ]; /** - * getAllObjects should contain the expected data object + * Validate getAllObjects should contain the expected data object. + * + * @return void + * @throws Exception */ - public function testGetAllObjects() + public function testGetAllObjects(): void { ObjectHandlerUtil::mockDataObjectHandlerWithData(self::PARSER_OUTPUT); @@ -161,9 +163,12 @@ public function testGetAllObjects() } /** - * test deprecated data object + * Validate test deprecated data object. + * + * @return void + * @throws Exception */ - public function testDeprecatedDataObject() + public function testDeprecatedDataObject(): void { ObjectHandlerUtil::mockDataObjectHandlerWithData(self::PARSER_OUTPUT_DEPRECATED); @@ -173,15 +178,18 @@ public function testDeprecatedDataObject() //validate deprecation warning TestLoggingUtil::getInstance()->validateMockLogStatement( 'warning', - "DEPRECATION: The data entity 'EntityOne' is deprecated.", - ["fileName" => "filename.xml", "deprecatedMessage" => "deprecation message"] + 'DEPRECATION: The data entity \'EntityOne\' is deprecated.', + ['fileName' => 'filename.xml', 'deprecatedMessage' => 'deprecation message'] ); } /** - * getObject should return the expected data object if it exists + * Validate getObject should return the expected data object if it exists. + * + * @return void + * @throws Exception */ - public function testGetObject() + public function testGetObject(): void { ObjectHandlerUtil::mockDataObjectHandlerWithData(self::PARSER_OUTPUT); @@ -194,9 +202,12 @@ public function testGetObject() } /** - * getAllObjects should return the expected data object if it exists + * Validate getAllObjects should return the expected data object if it exists. + * + * @return void + * @throws Exception */ - public function testGetObjectNull() + public function testGetObjectNull(): void { ObjectHandlerUtil::mockDataObjectHandlerWithData(self::PARSER_OUTPUT); @@ -205,9 +216,12 @@ public function testGetObjectNull() } /** - * getAllObjects should contain the expected data object with extends + * Validate getAllObjects should contain the expected data object with extends. + * + * @return void + * @throws Exception */ - public function testGetAllObjectsWithDataExtends() + public function testGetAllObjectsWithDataExtends(): void { ObjectHandlerUtil::mockDataObjectHandlerWithData(self::PARSER_OUTPUT_WITH_EXTEND); @@ -229,9 +243,12 @@ public function testGetAllObjectsWithDataExtends() } /** - * getObject should return the expected data object with extended data if it exists + * Validate getObject should return the expected data object with extended data if it exists. + * + * @return void + * @throws Exception */ - public function testGetObjectWithDataExtends() + public function testGetObjectWithDataExtends(): void { ObjectHandlerUtil::mockDataObjectHandlerWithData(self::PARSER_OUTPUT_WITH_EXTEND); @@ -252,15 +269,18 @@ public function testGetObjectWithDataExtends() } /** - * getAllObjects should throw TestFrameworkException exception if some data extends itself + * Validate getAllObjects should throw TestFrameworkException exception if some data extends itself. + * + * @return void + * @throws Exception */ - public function testGetAllObjectsWithDataExtendsItself() + public function testGetAllObjectsWithDataExtendsItself(): void { ObjectHandlerUtil::mockDataObjectHandlerWithData(self::PARSER_OUTPUT_WITH_EXTEND_INVALID); - $this->expectException(\Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException::class); + $this->expectException(TestFrameworkException::class); $this->expectExceptionMessage( - "Mftf Data can not extend from itself: " + 'Mftf Data can not extend from itself: ' . self::PARSER_OUTPUT_WITH_EXTEND_INVALID['entity']['EntityOne']['name'] ); @@ -269,15 +289,18 @@ public function testGetAllObjectsWithDataExtendsItself() } /** - * getObject should throw TestFrameworkException exception if requested data extends itself + * Validate getObject should throw TestFrameworkException exception if requested data extends itself. + * + * @return void + * @throws Exception */ - public function testGetObjectWithDataExtendsItself() + public function testGetObjectWithDataExtendsItself(): void { ObjectHandlerUtil::mockDataObjectHandlerWithData(self::PARSER_OUTPUT_WITH_EXTEND_INVALID); - $this->expectException(\Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException::class); + $this->expectException(TestFrameworkException::class); $this->expectExceptionMessage( - "Mftf Data can not extend from itself: " + 'Mftf Data can not extend from itself: ' . self::PARSER_OUTPUT_WITH_EXTEND_INVALID['entity']['EntityOne']['name'] ); @@ -288,7 +311,7 @@ public function testGetObjectWithDataExtendsItself() } /** - * clean up function runs after all tests + * @inheritDoc */ public static function tearDownAfterClass(): void { diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php index 35b06a24a..6c8fc7c45 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php @@ -3,16 +3,14 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace tests\unit\Magento\FunctionalTestFramework\DataGenerator\Handlers; -use AspectMock\Test as AspectMock; +use Exception; +use Magento\FunctionalTestingFramework\DataGenerator\Handlers\OperationDefinitionObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Objects\OperationDefinitionObject; use Magento\FunctionalTestingFramework\DataGenerator\Objects\OperationElement; -use Magento\FunctionalTestingFramework\ObjectManager; -use Magento\FunctionalTestingFramework\ObjectManagerFactory; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\OperationDefinitionObjectHandler; -use Magento\FunctionalTestingFramework\DataGenerator\Parsers\OperationDefinitionParser; use tests\unit\Util\MagentoTestCase; use tests\unit\Util\ObjectHandlerUtil; use tests\unit\Util\TestLoggingUtil; @@ -23,19 +21,25 @@ class OperationDefinitionObjectHandlerTest extends MagentoTestCase { /** - * Setup method + * @inheritDoc */ - public function setUp(): void + protected function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); } - public function testGetMultipleObjects() + /** + * Validate testGetMultipleObjects. + * + * @return void + * @throws Exception + */ + public function testGetMultipleObjects(): void { // Data Variables for Assertions - $dataType1 = "type1"; - $operationType1 = "create"; - $operationType2 = "update"; + $dataType1 = 'type1'; + $operationType1 = 'create'; + $operationType2 = 'update'; /** * Parser Output. Just two simple pieces of metadata with 1 field each @@ -48,31 +52,31 @@ public function testGetMultipleObjects() * key=id, value=integer */ $mockData = [OperationDefinitionObjectHandler::ENTITY_OPERATION_ROOT_TAG => [ - "testOperationName" => [ + 'testOperationName' => [ OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE => $dataType1, OperationDefinitionObjectHandler::ENTITY_OPERATION_TYPE => $operationType1, - OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH => "auth", - OperationDefinitionObjectHandler::ENTITY_OPERATION_URL => "V1/Type1", - OperationDefinitionObjectHandler::ENTITY_OPERATION_METHOD => "POST", + OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH => 'auth', + OperationDefinitionObjectHandler::ENTITY_OPERATION_URL => 'V1/Type1', + OperationDefinitionObjectHandler::ENTITY_OPERATION_METHOD => 'POST', OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY => [ 0 => [ - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => "id", - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => "integer" + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => 'id', + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => 'integer' ], - ] - ],[ + ] + ],[ OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE => $dataType1, OperationDefinitionObjectHandler::ENTITY_OPERATION_TYPE => $operationType2, - OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH => "auth", - OperationDefinitionObjectHandler::ENTITY_OPERATION_URL => "V1/Type1/{id}", - OperationDefinitionObjectHandler::ENTITY_OPERATION_METHOD => "PUT", + OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH => 'auth', + OperationDefinitionObjectHandler::ENTITY_OPERATION_URL => 'V1/Type1/{id}', + OperationDefinitionObjectHandler::ENTITY_OPERATION_METHOD => 'PUT', OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY => [ 0 => [ - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => "id", - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => "integer" + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => 'id', + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => 'integer' ], ] - ]]]; + ]]]; ObjectHandlerUtil::mockOperationHandlerWithData($mockData); //Perform Assertions @@ -82,11 +86,17 @@ public function testGetMultipleObjects() $this->assertArrayHasKey($operationType2 . $dataType1, $operations); } - public function testDeprecatedOperation() + /** + * Validate testDeprecatedOperation. + * + * @return void + * @throws Exception + */ + public function testDeprecatedOperation(): void { // Data Variables for Assertions - $dataType1 = "type1"; - $operationType1 = "create"; + $dataType1 = 'type1'; + $operationType1 = 'create'; /** * Parser Output. Just one metadata with 1 field @@ -96,16 +106,16 @@ public function testDeprecatedOperation() * key=id, value=integer */ $mockData = [OperationDefinitionObjectHandler::ENTITY_OPERATION_ROOT_TAG => [ - "testOperationName" => [ + 'testOperationName' => [ OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE => $dataType1, OperationDefinitionObjectHandler::ENTITY_OPERATION_TYPE => $operationType1, - OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH => "auth", - OperationDefinitionObjectHandler::ENTITY_OPERATION_URL => "V1/Type1", - OperationDefinitionObjectHandler::ENTITY_OPERATION_METHOD => "POST", + OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH => 'auth', + OperationDefinitionObjectHandler::ENTITY_OPERATION_URL => 'V1/Type1', + OperationDefinitionObjectHandler::ENTITY_OPERATION_METHOD => 'POST', OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY => [ 0 => [ - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => "id", - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => "integer" + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => 'id', + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => 'integer' ], ], OperationDefinitionObjectHandler::OBJ_DEPRECATED => 'deprecation message' @@ -119,7 +129,7 @@ public function testDeprecatedOperation() $this->assertArrayHasKey($operationType1 . $dataType1, $operations); TestLoggingUtil::getInstance()->validateMockLogStatement( 'notice', - "NOTICE: 1 metadata operation name violations detected. See mftf.log for details.", + 'NOTICE: 1 metadata operation name violations detected. See mftf.log for details.', [] ); // test run time deprecation notice @@ -127,33 +137,39 @@ public function testDeprecatedOperation() $operation->logDeprecated(); TestLoggingUtil::getInstance()->validateMockLogStatement( 'warning', - "DEPRECATION: The operation testOperationName is deprecated.", + 'DEPRECATION: The operation testOperationName is deprecated.', ['operationType' => 'create', 'deprecatedMessage' => 'deprecation message'] ); } - public function testObjectCreation() + /** + * Validate testObjectCreation. + * + * @return void + * @throws Exception + */ + public function testObjectCreation(): void { // Data Variables for Assertions - $testDataTypeName1 = "type1"; - $testAuth = "auth"; - $testUrl = "V1/dataType"; - $testOperationType = "create"; - $testMethod = "POST"; - $testSuccessRegex = "/messages-message-success/"; - $testContentType = "application/json"; - $testHeaderParam = "testParameter"; - $testHeaderValue = "testHeader"; + $testDataTypeName1 = 'type1'; + $testAuth = 'auth'; + $testUrl = 'V1/dataType'; + $testOperationType = 'create'; + $testMethod = 'POST'; + $testSuccessRegex = '/messages-message-success/'; + $testContentType = 'application/json'; + $testHeaderParam = 'testParameter'; + $testHeaderValue = 'testHeader'; // Nested Object variables - $nestedObjectKey = "objectKey"; - $nestedObjectType = "objectType"; - $nestedEntryKey1 = "id"; - $nestedEntryValue1 = "integer"; - $nestedEntryKey2 = "name"; - $nestedEntryValue2 = "string"; - $nestedEntryRequired2 = "true"; - $nestedEntryKey3 = "active"; - $nestedEntryValue3 = "boolean"; + $nestedObjectKey = 'objectKey'; + $nestedObjectType = 'objectType'; + $nestedEntryKey1 = 'id'; + $nestedEntryValue1 = 'integer'; + $nestedEntryKey2 = 'name'; + $nestedEntryValue2 = 'string'; + $nestedEntryRequired2 = 'true'; + $nestedEntryKey3 = 'active'; + $nestedEntryValue3 = 'boolean'; /** * Complex Object @@ -172,7 +188,7 @@ public function testObjectCreation() * */ $mockData = [OperationDefinitionObjectHandler::ENTITY_OPERATION_ROOT_TAG => [ - "testOperationName" => [ + 'testOperationName' => [ OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE => $testDataTypeName1, OperationDefinitionObjectHandler::ENTITY_OPERATION_TYPE => $testOperationType, OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH => $testAuth, @@ -181,7 +197,7 @@ public function testObjectCreation() OperationDefinitionObjectHandler::ENTITY_OPERATION_SUCCESS_REGEX => $testSuccessRegex, OperationDefinitionObjectHandler::ENTITY_OPERATION_CONTENT_TYPE => [ 0 => [ - "value" => $testContentType + 'value' => $testContentType ] ], OperationDefinitionObjectHandler::ENTITY_OPERATION_HEADER => [ @@ -192,8 +208,8 @@ public function testObjectCreation() ], OperationDefinitionObjectHandler::ENTITY_OPERATION_URL_PARAM => [ 0 => [ - OperationDefinitionObjectHandler::ENTITY_OPERATION_URL_PARAM_KEY => "testUrlParamKey", - OperationDefinitionObjectHandler::ENTITY_OPERATION_URL_PARAM_VALUE => "testUrlParamValue" + OperationDefinitionObjectHandler::ENTITY_OPERATION_URL_PARAM_KEY => 'testUrlParamKey', + OperationDefinitionObjectHandler::ENTITY_OPERATION_URL_PARAM_VALUE => 'testUrlParamValue' ] ], OperationDefinitionObjectHandler::ENTITY_OPERATION_OBJECT => [ @@ -220,7 +236,14 @@ public function testObjectCreation() ]]]; // Prepare objects to compare against $field = OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY; - $expectedNestedField = new OperationElement($nestedEntryKey1, $nestedEntryValue1, $field, false, [], null); + $expectedNestedField = new OperationElement( + $nestedEntryKey1, + $nestedEntryValue1, + $field, + false, + [], + null + ); $expectedNestedField2 = new OperationElement( $nestedEntryKey2, $nestedEntryValue2, @@ -229,14 +252,25 @@ public function testObjectCreation() [], null ); - $expectedNestedField3 = new OperationElement($nestedEntryKey3, $nestedEntryValue3, $field, false, [], null); + $expectedNestedField3 = new OperationElement( + $nestedEntryKey3, + $nestedEntryValue3, + $field, + false, + [], + null + ); $expectedOperation = new OperationElement( $nestedObjectKey, $nestedObjectType, OperationDefinitionObjectHandler::ENTITY_OPERATION_OBJECT, false, [], - [0 => $expectedNestedField, 1 => $expectedNestedField2, 2 =>$expectedNestedField3] + [ + 0 => $expectedNestedField, + 1 => $expectedNestedField2, + 2 => $expectedNestedField3 + ] ); // Set up mocked data output @@ -264,16 +298,22 @@ public function testObjectCreation() $this->assertEquals($expectedOperation, $operation->getOperationMetadata()[0]); } - public function testObjectArrayCreation() + /** + * Validate testObjectArrayCreation. + * + * @return void + * @throws Exception + */ + public function testObjectArrayCreation(): void { // Data Variables for Assertions - $dataType1 = "type1"; - $operationType1 = "create"; - $objectArrayKey = "ObjectArray"; - $twiceNestedObjectKey = "nestedObjectKey"; - $twiceNestedObjectType = "nestedObjectType"; - $twiceNestedEntryKey = "nestedFieldKey"; - $twiceNestedEntryValue = "string"; + $dataType1 = 'type1'; + $operationType1 = 'create'; + $objectArrayKey = 'ObjectArray'; + $twiceNestedObjectKey = 'nestedObjectKey'; + $twiceNestedObjectType = 'nestedObjectType'; + $twiceNestedEntryKey = 'nestedFieldKey'; + $twiceNestedEntryValue = 'string'; // Parser Output /** * Metadata with nested array of objects, with a single field @@ -284,12 +324,12 @@ public function testObjectArrayCreation() * has field with key = nestedFieldKey, value = string */ $mockData = [OperationDefinitionObjectHandler::ENTITY_OPERATION_ROOT_TAG => [ - "testOperationName" => [ + 'testOperationName' => [ OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE => $dataType1, OperationDefinitionObjectHandler::ENTITY_OPERATION_TYPE => $operationType1, - OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH => "auth", - OperationDefinitionObjectHandler::ENTITY_OPERATION_URL => "V1/Type1", - OperationDefinitionObjectHandler::ENTITY_OPERATION_METHOD => "POST", + OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH => 'auth', + OperationDefinitionObjectHandler::ENTITY_OPERATION_URL => 'V1/Type1', + OperationDefinitionObjectHandler::ENTITY_OPERATION_METHOD => 'POST', OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY => [ 0 => [ OperationDefinitionObjectHandler::ENTITY_OPERATION_OBJECT_KEY => $objectArrayKey, @@ -325,7 +365,9 @@ public function testObjectArrayCreation() OperationDefinitionObjectHandler::ENTITY_OPERATION_OBJECT, false, [], - [0 => $twoLevelNestedMetadata] + [ + 0 => $twoLevelNestedMetadata + ] ); $expectedOperation = new OperationElement( @@ -333,7 +375,9 @@ public function testObjectArrayCreation() $twiceNestedObjectType, $twiceNestedObjectKey, false, - [$twiceNestedObjectKey => $oneLevelNestedMetadata], + [ + $twiceNestedObjectKey => $oneLevelNestedMetadata + ], null ); @@ -348,15 +392,21 @@ public function testObjectArrayCreation() $this->assertEquals($expectedOperation, $operation->getOperationMetadata()[0]); } - public function testLooseJsonCreation() + /** + * Validate testLooseJsonCreation. + * + * @return void + * @throws Exception + */ + public function testLooseJsonCreation(): void { // Data Variables for Assertions - $dataType = "dataType"; - $operationType = "create"; - $entryKey = "id"; - $entryValue = "integer"; - $arrayKey = "arrayKey"; - $arrayValue = "string"; + $dataType = 'dataType'; + $operationType = 'create'; + $entryKey = 'id'; + $entryValue = 'integer'; + $arrayKey = 'arrayKey'; + $arrayValue = 'string'; /** * Operation with no objects, just an entry and an array of strings * testOperationName @@ -366,7 +416,7 @@ public function testLooseJsonCreation() * fields of value = string */ $mockData = [OperationDefinitionObjectHandler::ENTITY_OPERATION_ROOT_TAG => [ - "testOperationName" => [ + 'testOperationName' => [ OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE => $dataType, OperationDefinitionObjectHandler::ENTITY_OPERATION_TYPE => $operationType, OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY => [ @@ -418,10 +468,12 @@ public function testLooseJsonCreation() } /** - * clean up function runs after all tests + * @inheritDoc */ public static function tearDownAfterClass(): void { + parent::tearDownAfterClass(); + TestLoggingUtil::getInstance()->clearMockLoggingUtil(); } } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/PageObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/PageObjectHandlerTest.php index eb305bc4d..bfa1fa8e0 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/PageObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/PageObjectHandlerTest.php @@ -3,109 +3,125 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace tests\unit\Magento\FunctionalTestFramework\Page\Handlers; -use AspectMock\Test as AspectMock; -use Magento\FunctionalTestingFramework\ObjectManager; -use Magento\FunctionalTestingFramework\ObjectManagerFactory; +use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Page\Handlers\PageObjectHandler; -use Magento\FunctionalTestingFramework\XmlParser\PageParser; use tests\unit\Util\MagentoTestCase; use tests\unit\Util\ObjectHandlerUtil; use tests\unit\Util\TestLoggingUtil; +/** + * Class PageObjectHandlerTest + */ class PageObjectHandlerTest extends MagentoTestCase { /** - * Setup method + * @inheritDoc */ - public function setUp(): void + protected function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); } - public function testGetPageObject() + /** + * Validate testGetPageObject. + * + * @return void + * @throws XmlException + */ + public function testGetPageObject(): void { $mockData = [ - "testPage1" => [ - "url" => "testURL1", - "module" => "testModule1", - "section" => [ - "someSection1" => [], - "someSection2" => [] + 'testPage1' => [ + 'url' => 'testURL1', + 'module' => 'testModule1', + 'section' => [ + 'someSection1' => [], + 'someSection2' => [] ], - "area" => "test" + 'area' => 'test' ], - "testPage2" => [ - "url" => "testURL2", - "module" => "testModule2", - "parameterized" => true, - "section" => [ - "someSection1" => [] + 'testPage2' => [ + 'url' => 'testURL2', + 'module' => 'testModule2', + 'parameterized' => true, + 'section' => [ + 'someSection1' => [] ], - "area" => "test" + 'area' => 'test' ]]; - ObjectHandlerUtil::mockPageObjectHandlerWithData($mockData); - // get pages + ObjectHandlerUtil::mockPageObjectHandlerWithData($mockData); $pageHandler = PageObjectHandler::getInstance(); $pages = $pageHandler->getAllObjects(); - $page = $pageHandler->getObject('testPage1'); + $pageHandler->getObject('testPage1'); $invalidPage = $pageHandler->getObject('someInvalidPage'); // perform asserts $this->assertCount(2, $pages); - $this->assertArrayHasKey("testPage1", $pages); - $this->assertArrayHasKey("testPage2", $pages); + $this->assertArrayHasKey('testPage1', $pages); + $this->assertArrayHasKey('testPage2', $pages); $this->assertNull($invalidPage); } - public function testGetEmptyPage() + /** + * Validate testGetEmptyPage. + * + * @return void + * @throws XmlException + */ + public function testGetEmptyPage(): void { $mockData = [ - "testPage1" => [ - "url" => "testURL1", - "module" => "testModule1", - "section" => [ + 'testPage1' => [ + 'url' => 'testURL1', + 'module' => 'testModule1', + 'section' => [ ], - "area" => "test" + 'area' => 'test' ]]; - ObjectHandlerUtil::mockPageObjectHandlerWithData($mockData); - // get pages - $page = PageObjectHandler::getInstance()->getObject('testPage1'); + ObjectHandlerUtil::mockPageObjectHandlerWithData($mockData); + PageObjectHandler::getInstance()->getObject('testPage1'); // Empty page has been read in and gotten without an exception being thrown. $this->addToAssertionCount(1); } - public function testDeprecatedPage() + /** + * Validate testDeprecatedPage. + * + * @return void + * @throws XmlException + */ + public function testDeprecatedPage(): void { $mockData = [ - "testPage1" => [ - "url" => "testURL1", - "module" => "testModule1", - "section" => [ + 'testPage1' => [ + 'url' => 'testURL1', + 'module' => 'testModule1', + 'section' => [ ], - "area" => "test", - "deprecated" => "deprecation message", - "filename" => "filename.xml" + 'area' => 'test', + 'deprecated' => 'deprecation message', + 'filename' => 'filename.xml' ]]; - ObjectHandlerUtil::mockPageObjectHandlerWithData($mockData); - // get pages - $page = PageObjectHandler::getInstance()->getObject('testPage1'); + ObjectHandlerUtil::mockPageObjectHandlerWithData($mockData); + PageObjectHandler::getInstance()->getObject('testPage1'); TestLoggingUtil::getInstance()->validateMockLogStatement( 'notice', - "NOTICE: 1 Page name violations detected. See mftf.log for details.", + 'NOTICE: 1 Page name violations detected. See mftf.log for details.', [] ); } /** - * clean up function runs after all tests + * @inheritDoc */ public static function tearDownAfterClass(): void { diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/SectionObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/SectionObjectHandlerTest.php index 69088944a..79ad32b4c 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/SectionObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/SectionObjectHandlerTest.php @@ -3,45 +3,52 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace tests\unit\Magento\FunctionalTestFramework\Page\Handlers; -use AspectMock\Test as AspectMock; -use Magento\FunctionalTestingFramework\ObjectManager; -use Magento\FunctionalTestingFramework\ObjectManagerFactory; +use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Page\Handlers\SectionObjectHandler; -use Magento\FunctionalTestingFramework\XmlParser\SectionParser; use tests\unit\Util\MagentoTestCase; use tests\unit\Util\ObjectHandlerUtil; use tests\unit\Util\TestLoggingUtil; +/** + * Class SectionObjectHandlerTest + */ class SectionObjectHandlerTest extends MagentoTestCase { /** - * Setup method + * @inheritDoc */ - public function setUp(): void + protected function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); } - public function testGetSectionObject() + /** + * Validate testGetSectionObject. + * + * @return void + * @throws XmlException + */ + public function testGetSectionObject(): void { $mockData = [ - "testSection1" => [ - "element" => [ - "testElement" => [ - "type" => "input", - "selector" => "#element" + 'testSection1' => [ + 'element' => [ + 'testElement' => [ + 'type' => 'input', + 'selector' => '#element' ] ] ], - "testSection2" => [ - "element" => [ - "testElement" => [ - "type" => "input", - "selector" => "#element" + 'testSection2' => [ + 'element' => [ + 'testElement' => [ + 'type' => 'input', + 'selector' => '#element' ] ] ] @@ -52,29 +59,35 @@ public function testGetSectionObject() // get sections $sectionHandler = SectionObjectHandler::getInstance(); $sections = $sectionHandler->getAllObjects(); - $section = $sectionHandler->getObject("testSection1"); - $invalidSection = $sectionHandler->getObject("InvalidSection"); + $sectionHandler->getObject('testSection1'); + $invalidSection = $sectionHandler->getObject('InvalidSection'); // perform asserts $this->assertCount(2, $sections); - $this->assertArrayHasKey("testSection1", $sections); - $this->assertArrayHasKey("testSection2", $sections); + $this->assertArrayHasKey('testSection1', $sections); + $this->assertArrayHasKey('testSection2', $sections); $this->assertNull($invalidSection); } - public function testDeprecatedSection() + /** + * Validate testDeprecatedSection. + * + * @return void + * @throws XmlException + */ + public function testDeprecatedSection(): void { $mockData = [ - "testSection1" => [ - "element" => [ - "testElement" => [ - "type" => "input", - "selector" => "#element", - "deprecated" => "element deprecation message" + 'testSection1' => [ + 'element' => [ + 'testElement' => [ + 'type' => 'input', + 'selector' => '#element', + 'deprecated' => 'element deprecation message' ] ], - "filename" => "filename.xml", - "deprecated" => "section deprecation message" + 'filename' => 'filename.xml', + 'deprecated' => 'section deprecation message' ] ]; @@ -82,18 +95,18 @@ public function testDeprecatedSection() // get sections $sectionHandler = SectionObjectHandler::getInstance(); - $section = $sectionHandler->getObject("testSection1"); + $sectionHandler->getObject('testSection1'); //validate deprecation warning TestLoggingUtil::getInstance()->validateMockLogStatement( 'notice', - "NOTICE: 1 Section name violations detected. See mftf.log for details.", + 'NOTICE: 1 Section name violations detected. See mftf.log for details.', [] ); } /** - * clean up function runs after all tests + * @inheritDoc */ public static function tearDownAfterClass(): void { diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/ActionGroupObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/ActionGroupObjectHandlerTest.php index 71c1833ba..71da6d492 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/ActionGroupObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/ActionGroupObjectHandlerTest.php @@ -3,28 +3,29 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace tests\unit\Magento\FunctionalTestFramework\Test\Handlers; -use AspectMock\Test as AspectMock; - -use Go\Aop\Aspect; -use Magento\FunctionalTestingFramework\ObjectManager; -use Magento\FunctionalTestingFramework\ObjectManagerFactory; +use Exception; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Test\Handlers\ActionGroupObjectHandler; -use tests\unit\Util\MagentoTestCase; use tests\unit\Util\ActionGroupArrayBuilder; -use Magento\FunctionalTestingFramework\Test\Parsers\ActionGroupDataParser; +use tests\unit\Util\MagentoTestCase; use tests\unit\Util\ObjectHandlerUtil; +/** + * Class ActionGroupObjectHandlerTest + */ class ActionGroupObjectHandlerTest extends MagentoTestCase { /** - * getObject should throw exception if test extends from itself + * Validate getObject should throw exception if test extends from itself. * - * @throws \Exception + * @return void + * @throws Exception */ - public function testGetTestObjectWithInvalidExtends() + public function testGetTestObjectWithInvalidExtends(): void { // Set up action group data $nameOne = 'actionGroupOne'; @@ -39,15 +40,16 @@ public function testGetTestObjectWithInvalidExtends() $handler = ActionGroupObjectHandler::getInstance(); - $this->expectException(\Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException::class); - $this->expectExceptionMessage("Mftf Action Group can not extend from itself: " . $nameOne); + $this->expectException(TestFrameworkException::class); + $this->expectExceptionMessage('Mftf Action Group can not extend from itself: ' . $nameOne); $handler->getObject('actionGroupOne'); } /** - * getAllObjects should throw exception if test extends from itself + * Validate getAllObjects should throw exception if test extends from itself * - * @throws \Exception + * @return void + * @throws Exception */ public function testGetAllTestObjectsWithInvalidExtends() { @@ -80,8 +82,8 @@ public function testGetAllTestObjectsWithInvalidExtends() $handler = ActionGroupObjectHandler::getInstance(); - $this->expectException(\Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException::class); - $this->expectExceptionMessage("Mftf Action Group can not extend from itself: " . $nameOne); + $this->expectException(TestFrameworkException::class); + $this->expectExceptionMessage('Mftf Action Group can not extend from itself: ' . $nameOne); $handler->getAllObjects(); } } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionGroupAnnotationExtractorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionGroupAnnotationExtractorTest.php index a3d2cca86..23c97fd4a 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionGroupAnnotationExtractorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionGroupAnnotationExtractorTest.php @@ -3,50 +3,54 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace tests\unit\Magento\FunctionalTestFramework\Test\Util; -use AspectMock\Test as AspectMock; +use Exception; use Magento\FunctionalTestingFramework\Test\Util\ActionGroupAnnotationExtractor; use PHPUnit\Framework\TestCase; use tests\unit\Util\TestLoggingUtil; +/** + * Class ActionGroupAnnotationExtractorTest + */ class ActionGroupAnnotationExtractorTest extends TestCase { /** - * Before test functionality - * @return void + * @inheritDoc */ - public function setUp(): void + protected function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); } /** - * Annotation extractor takes in raw array and condenses it to expected format + * Annotation extractor takes in raw array and condenses it to expected format. * - * @throws \Exception + * @return void + * @throws Exception */ - public function testActionGroupExtractAnnotations() + public function testActionGroupExtractAnnotations(): void { // Test Data $actionGroupAnnotations = [ - "nodeName" => "annotations", - "description" => [ - "nodeName" => "description", - "value" => "someDescription" + 'nodeName' => 'annotations', + 'description' => [ + 'nodeName' => 'description', + 'value' => 'someDescription' ] ]; // Perform Test $extractor = new ActionGroupAnnotationExtractor(); - $returnedAnnotations = $extractor->extractAnnotations($actionGroupAnnotations, "fileName"); + $returnedAnnotations = $extractor->extractAnnotations($actionGroupAnnotations, 'fileName'); // Asserts - $this->assertEquals("someDescription", $returnedAnnotations['description']); + $this->assertEquals('someDescription', $returnedAnnotations['description']); } /** - * After class functionality - * @return void + * @inheritDoc */ public static function tearDownAfterClass(): void { diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/AnnotationExtractorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/AnnotationExtractorTest.php index 735c33492..44ec3a7aa 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/AnnotationExtractorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/AnnotationExtractorTest.php @@ -3,114 +3,119 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace tests\unit\Magento\FunctionalTestFramework\Test\Util; -use AspectMock\Proxy\Verifier; -use AspectMock\Test as AspectMock; +use Exception; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Test\Util\AnnotationExtractor; -use Monolog\Handler\TestHandler; -use Monolog\Logger; +use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; use PHPUnit\Framework\TestCase; use tests\unit\Util\TestLoggingUtil; -use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; +/** + * Class AnnotationExtractorTest + */ class AnnotationExtractorTest extends TestCase { /** - * Before test functionality - * @return void + * @inheritDoc */ - public function setUp(): void + protected function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); } /** - * Annotation extractor takes in raw array and condenses it to expected format + * Annotation extractor takes in raw array and condenses it to expected format. * - * @throws \Exception + * @return void + * @throws Exception */ - public function testExtractAnnotations() + public function testExtractAnnotations(): void { // Test Data $testAnnotations = [ - "nodeName" => "annotations", - "features" => [ + 'nodeName' => 'annotations', + 'features' => [ [ - "nodeName" => "features", - "value" => "TestFeatures" + 'nodeName' => 'features', + 'value' => 'TestFeatures' ] ], - "stories" => [ + 'stories' => [ [ - "nodeName" => "stories", - "value" => "TestStories" + 'nodeName' => 'stories', + 'value' => 'TestStories' ] ], - "description" => [ + 'description' => [ [ - "nodeName" => "description", - "value" => "TestDescription" + 'nodeName' => 'description', + 'value' => 'TestDescription' ] ], - "severity" => [ + 'severity' => [ [ - "nodeName" => "severity", - "value" => "CRITICAL" + 'nodeName' => 'severity', + 'value' => 'CRITICAL' ] ], - "group" => [ + 'group' => [ [ - "nodeName" => "group", - "value" => "TestGroup" + 'nodeName' => 'group', + 'value' => 'TestGroup' ] ], ]; // Perform Test $extractor = new AnnotationExtractor(); - $returnedAnnotations = $extractor->extractAnnotations($testAnnotations, "testFileName"); + $returnedAnnotations = $extractor->extractAnnotations($testAnnotations, 'testFileName'); // Asserts - $this->assertEquals("TestFeatures", $returnedAnnotations['features'][0]); - $this->assertEquals("TestStories", $returnedAnnotations['stories'][0]); - $this->assertEquals("TestDescription", $returnedAnnotations['description'][0]); - $this->assertEquals("CRITICAL", $returnedAnnotations['severity'][0]); - $this->assertEquals("TestGroup", $returnedAnnotations['group'][0]); + $this->assertEquals('TestFeatures', $returnedAnnotations['features'][0]); + $this->assertEquals('TestStories', $returnedAnnotations['stories'][0]); + $this->assertEquals('TestDescription', $returnedAnnotations['description'][0]); + $this->assertEquals('CRITICAL', $returnedAnnotations['severity'][0]); + $this->assertEquals('TestGroup', $returnedAnnotations['group'][0]); } /** - * Annotation extractor should throw warning when required annotations are missing + * Annotation extractor should throw warning when required annotations are missing. * - * @throws \Exception + * @return void + * @throws Exception */ - public function testMissingAnnotations() + public function testMissingAnnotations(): void { // Test Data, missing title, description, and severity $testAnnotations = [ - "nodeName" => "annotations", - "features" => [ + 'nodeName' => 'annotations', + 'features' => [ [ - "nodeName" => "features", - "value" => "TestFeatures" + 'nodeName' => 'features', + 'value' => 'TestFeatures' ] ], - "stories" => [ + 'stories' => [ [ - "nodeName" => "stories", - "value" => "TestStories" + 'nodeName' => 'stories', + 'value' => 'TestStories' ] ], - "group" => [ + 'group' => [ [ - "nodeName" => "group", - "value" => "TestGroup" + 'nodeName' => 'group', + 'value' => 'TestGroup' ] ], ]; // Perform Test $extractor = new AnnotationExtractor(); - $returnedAnnotations = $extractor->extractAnnotations($testAnnotations, "testFileName"); + $extractor->extractAnnotations($testAnnotations, 'testFileName'); // Asserts TestLoggingUtil::getInstance()->validateMockLogStatement( @@ -118,61 +123,62 @@ public function testMissingAnnotations() 'DEPRECATION: Test testFileName is missing required annotations.', [ 'testName' => 'testFileName', - 'missingAnnotations' => "title, description, severity" + 'missingAnnotations' => 'title, description, severity' ] ); } /** - * Annotation extractor should throw warning when required annotations are empty + * Annotation extractor should throw warning when required annotations are empty. * - * @throws \Exception + * @return void + * @throws Exception */ - public function testEmptyRequiredAnnotations() + public function testEmptyRequiredAnnotations(): void { // Test Data, missing title, description, and severity $testAnnotations = [ - "nodeName" => "annotations", - "features" => [ + 'nodeName' => 'annotations', + 'features' => [ [ - "nodeName" => "features", - "value" => "" + 'nodeName' => 'features', + 'value' => '' ] ], - "stories" => [ + 'stories' => [ [ - "nodeName" => "stories", - "value" => "TestStories" + 'nodeName' => 'stories', + 'value' => 'TestStories' ] ], - "title" => [ + 'title' => [ [ - "nodeName" => "title", - "value" => " " + 'nodeName' => 'title', + 'value' => ' ' ] ], - "description" => [ + 'description' => [ [ - "nodeName" => "description", - "value" => "\t" + 'nodeName' => 'description', + 'value' => "\t" ] ], - "severity" => [ + 'severity' => [ [ - "nodeName" => "severity", - "value" => "" + 'nodeName' => 'severity', + 'value' => '' ] ], - "group" => [ + 'group' => [ [ - "nodeName" => "group", - "value" => "TestGroup" + 'nodeName' => 'group', + 'value' => 'TestGroup' ] ], ]; // Perform Test $extractor = new AnnotationExtractor(); - $returnedAnnotations = $extractor->extractAnnotations($testAnnotations, "testFileName"); + $returnedAnnotations = $extractor->extractAnnotations($testAnnotations, 'testFileName'); // Asserts TestLoggingUtil::getInstance()->validateMockLogStatement( @@ -180,90 +186,96 @@ public function testEmptyRequiredAnnotations() 'DEPRECATION: Test testFileName is missing required annotations.', [ 'testName' => 'testFileName', - 'missingAnnotations' => "title, description, severity" + 'missingAnnotations' => 'title, description, severity' ] ); } - public function testTestCaseIdUniqueness() + /** + * Validate testTestCaseIdUniqueness. + * + * @return void + * @throws TestFrameworkException|XmlException + */ + public function testTestCaseIdUniqueness(): void { // Test Data $firstTestAnnotation = [ - "nodeName" => "annotations", - "features" => [ + 'nodeName' => 'annotations', + 'features' => [ [ - "nodeName" => "features", - "value" => "TestFeatures" + 'nodeName' => 'features', + 'value' => 'TestFeatures' ] ], - "stories" => [ + 'stories' => [ [ - "nodeName" => "stories", - "value" => "TestStories" + 'nodeName' => 'stories', + 'value' => 'TestStories' ] ], - "title" => [ + 'title' => [ [ - "nodeName" => "title", - "value" => "TEST TITLE" + 'nodeName' => 'title', + 'value' => 'TEST TITLE' ] ], - "severity" => [ + 'severity' => [ [ - "nodeName" => "severity", - "value" => "CRITICAL" + 'nodeName' => 'severity', + 'value' => 'CRITICAL' ] ], - "testCaseId" => [ + 'testCaseId' => [ [ - "nodeName" => "testCaseId", - "value" => "MQE-0001" + 'nodeName' => 'testCaseId', + 'value' => 'MQE-0001' ] ], ]; $secondTestannotation = [ - "nodeName" => "annotations", - "features" => [ + 'nodeName' => 'annotations', + 'features' => [ [ - "nodeName" => "features", - "value" => "TestFeatures" + 'nodeName' => 'features', + 'value' => 'TestFeatures' ] ], - "stories" => [ + 'stories' => [ [ - "nodeName" => "stories", - "value" => "TestStories" + 'nodeName' => 'stories', + 'value' => 'TestStories' ] ], - "title" => [ + 'title' => [ [ - "nodeName" => "title", - "value" => "TEST TITLE" + 'nodeName' => 'title', + 'value' => 'TEST TITLE' ] ], - "severity" => [ + 'severity' => [ [ - "nodeName" => "severity", - "value" => "CRITICAL" + 'nodeName' => 'severity', + 'value' => 'CRITICAL' ] ], - "testCaseId" => [ + 'testCaseId' => [ [ - "nodeName" => "testCaseId", - "value" => "MQE-0001" + 'nodeName' => 'testCaseId', + 'value' => 'MQE-0001' ] ], ]; // Perform Test $extractor = new AnnotationExtractor(); - $extractor->extractAnnotations($firstTestAnnotation, "firstTest"); - $extractor->extractAnnotations($secondTestannotation, "secondTest"); + $extractor->extractAnnotations($firstTestAnnotation, 'firstTest'); + $extractor->extractAnnotations($secondTestannotation, 'secondTest'); $extractor->validateTestCaseIdTitleUniqueness(); // assert that no exception for validateTestCaseIdTitleUniqueness // and validation error is stored in GenerationErrorHandler $errorMessage = '/' - . preg_quote("TestCaseId and Title pairs is not unique in Tests 'firstTest', 'secondTest'") + . preg_quote('TestCaseId and Title pairs is not unique in Tests \'firstTest\', \'secondTest\'') . '/'; TestLoggingUtil::getInstance()->validateMockLogStatmentRegex('error', $errorMessage, []); $testErrors = GenerationErrorHandler::getInstance()->getErrorsByType('test'); @@ -271,14 +283,16 @@ public function testTestCaseIdUniqueness() $this->assertArrayHasKey('secondTest', $testErrors); } - public function tearDown(): void + /** + * @inheritDoc + */ + protected function tearDown(): void { GenerationErrorHandler::getInstance()->reset(); } /** - * After class functionality - * @return void + * @inheritDoc */ public static function tearDownAfterClass(): void { From c43042dfa8104367889abed88ab345c33857b931 Mon Sep 17 00:00:00 2001 From: "andrii.zinkevych" <a.zinkevych@atwix.com> Date: Mon, 26 Jul 2021 15:21:33 +0300 Subject: [PATCH 677/888] 33582: Eliminated AspectMock from MagentoTestCase.php --- dev/tests/unit/Util/MagentoTestCase.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/dev/tests/unit/Util/MagentoTestCase.php b/dev/tests/unit/Util/MagentoTestCase.php index 7760acfc6..35127d660 100644 --- a/dev/tests/unit/Util/MagentoTestCase.php +++ b/dev/tests/unit/Util/MagentoTestCase.php @@ -3,10 +3,10 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace tests\unit\Util; -use AspectMock\Test as AspectMock; use PHPUnit\Framework\TestCase; /** @@ -14,22 +14,25 @@ */ class MagentoTestCase extends TestCase { + /** + * @inheritDoc + */ public static function setUpBeforeClass(): void { - if (!self::fileExists(DOCS_OUTPUT_DIR)) { + if (!file_exists(DOCS_OUTPUT_DIR)) { mkdir(DOCS_OUTPUT_DIR, 0755, true); } + parent::setUpBeforeClass(); } /** - * Teardown for removing AspectMock Double References - * @return void + * @inheritDoc */ public static function tearDownAfterClass(): void { - AspectMock::clean(); array_map('unlink', glob(DOCS_OUTPUT_DIR . DIRECTORY_SEPARATOR . "*")); + if (file_exists(DOCS_OUTPUT_DIR)) { rmdir(DOCS_OUTPUT_DIR); } From 35c190d22cab744d7934b00a8cc56cb3bbea2529 Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Mon, 26 Jul 2021 15:48:46 +0300 Subject: [PATCH 678/888] MFTF-33585: Eliminated AspectMock usage from TestLoggingUtil --- dev/tests/unit/Util/TestLoggingUtil.php | 57 ++++++++++++++++--------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/dev/tests/unit/Util/TestLoggingUtil.php b/dev/tests/unit/Util/TestLoggingUtil.php index 1b0bce1f9..f275a5c97 100644 --- a/dev/tests/unit/Util/TestLoggingUtil.php +++ b/dev/tests/unit/Util/TestLoggingUtil.php @@ -3,16 +3,17 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace tests\unit\Util; -use AspectMock\Test as AspectMock; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; use Magento\FunctionalTestingFramework\Util\Logger\MftfLogger; use Monolog\Handler\TestHandler; -use PHPUnit\Framework\Assert; +use PHPUnit\Framework\TestCase; +use ReflectionProperty; -class TestLoggingUtil extends Assert +class TestLoggingUtil extends TestCase { /** * @var TestLoggingUtil @@ -25,24 +26,23 @@ class TestLoggingUtil extends Assert private $testLogHandler; /** - * TestLoggingUtil constructor. + * Private constructor. */ private function __construct() { - // private constructor + parent::__construct(null, [], ''); } /** - * Static singleton get function + * Static singleton get function. * * @return TestLoggingUtil */ - public static function getInstance() + public static function getInstance(): TestLoggingUtil { if (self::$instance == null) { self::$instance = new TestLoggingUtil(); } - return self::$instance; } @@ -51,21 +51,28 @@ public static function getInstance() * * @return void */ - public function setMockLoggingUtil() + public function setMockLoggingUtil(): void { $this->testLogHandler = new TestHandler(); $testLogger = new MftfLogger('testLogger'); $testLogger->pushHandler($this->testLogHandler); - $mockLoggingUtil = AspectMock::double( - LoggingUtil::class, - ['getLogger' => $testLogger] - )->make(); - $property = new \ReflectionProperty(LoggingUtil::class, 'instance'); + + $mockLoggingUtil = $this->createMock(LoggingUtil::class); + $mockLoggingUtil + ->method('getLogger') + ->willReturn($testLogger); + + $property = new ReflectionProperty(LoggingUtil::class, 'instance'); $property->setAccessible(true); $property->setValue($mockLoggingUtil); } - public function validateMockLogEmpty() + /** + * Check if mock log is empty. + * + * @return void + */ + public function validateMockLogEmpty(): void { $records = $this->testLogHandler->getRecords(); $this->assertTrue(empty($records)); @@ -77,9 +84,10 @@ public function validateMockLogEmpty() * @param string $type * @param string $message * @param array $context + * * @return void */ - public function validateMockLogStatement($type, $message, $context) + public function validateMockLogStatement(string $type, string $message, array $context): void { $records = $this->testLogHandler->getRecords(); $record = $records[count($records)-1]; // we assume the latest record is what requires validation @@ -88,7 +96,16 @@ public function validateMockLogStatement($type, $message, $context) $this->assertEquals($context, $record['context']); } - public function validateMockLogStatmentRegex($type, $regex, $context) + /** + * Check mock log statement regular expression. + * + * @param string $type + * @param string $regex + * @param array $context + * + * @return void + */ + public function validateMockLogStatmentRegex(string $type, string $regex, array $context): void { $records = $this->testLogHandler->getRecords(); $record = $records[count($records)-1]; // we assume the latest record is what requires validation @@ -103,8 +120,10 @@ public function validateMockLogStatmentRegex($type, $regex, $context) * * @return void */ - public function clearMockLoggingUtil() + public function clearMockLoggingUtil(): void { - AspectMock::clean(LoggingUtil::class); + $property = new ReflectionProperty(LoggingUtil::class, 'instance'); + $property->setAccessible(true); + $property->setValue(null); } } From 5da9853d690ad9eba8d9b22f9af8aab95ea9d428 Mon Sep 17 00:00:00 2001 From: "andrii.zinkevych" <a.zinkevych@atwix.com> Date: Tue, 27 Jul 2021 15:10:31 +0300 Subject: [PATCH 679/888] 33584: Eliminated AspectMock from ObjectHandlerUtil --- .../Handlers/DataObjectHandlerTest.php | 76 ++++++- .../OperationDefinitionObjectHandlerTest.php | 78 +++++++- .../Handlers/PersistedObjectHandlerTest.php | 20 +- .../Page/Handlers/PageObjectHandlerTest.php | 65 +++++- .../Handlers/SectionObjectHandlerTest.php | 62 +++++- .../DeprecatedEntityUsageCheckTest.php | 187 +++++++++++++++--- .../Handlers/ActionGroupObjectHandlerTest.php | 71 ++++++- dev/tests/unit/Util/ObjectHandlerUtil.php | 145 -------------- 8 files changed, 485 insertions(+), 219 deletions(-) delete mode 100644 dev/tests/unit/Util/ObjectHandlerUtil.php diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php index 57cdb6a64..552b951a0 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php @@ -10,9 +10,12 @@ use Exception; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; +use Magento\FunctionalTestingFramework\DataGenerator\Parsers\DataProfileSchemaParser; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\ObjectManager; +use Magento\FunctionalTestingFramework\ObjectManagerFactory; +use ReflectionProperty; use tests\unit\Util\MagentoTestCase; -use tests\unit\Util\ObjectHandlerUtil; use tests\unit\Util\TestLoggingUtil; /** @@ -151,7 +154,7 @@ protected function setUp(): void */ public function testGetAllObjects(): void { - ObjectHandlerUtil::mockDataObjectHandlerWithData(self::PARSER_OUTPUT); + $this->mockDataObjectHandlerWithData(self::PARSER_OUTPUT); // Call the method under test $actual = DataObjectHandler::getInstance()->getAllObjects(); @@ -170,10 +173,10 @@ public function testGetAllObjects(): void */ public function testDeprecatedDataObject(): void { - ObjectHandlerUtil::mockDataObjectHandlerWithData(self::PARSER_OUTPUT_DEPRECATED); + $this->mockDataObjectHandlerWithData(self::PARSER_OUTPUT_DEPRECATED); // Call the method under test - $actual = DataObjectHandler::getInstance()->getAllObjects(); + DataObjectHandler::getInstance()->getAllObjects(); //validate deprecation warning TestLoggingUtil::getInstance()->validateMockLogStatement( @@ -191,7 +194,7 @@ public function testDeprecatedDataObject(): void */ public function testGetObject(): void { - ObjectHandlerUtil::mockDataObjectHandlerWithData(self::PARSER_OUTPUT); + $this->mockDataObjectHandlerWithData(self::PARSER_OUTPUT); // Call the method under test $actual = DataObjectHandler::getInstance()->getObject('EntityOne'); @@ -209,7 +212,7 @@ public function testGetObject(): void */ public function testGetObjectNull(): void { - ObjectHandlerUtil::mockDataObjectHandlerWithData(self::PARSER_OUTPUT); + $this->mockDataObjectHandlerWithData(self::PARSER_OUTPUT); $actual = DataObjectHandler::getInstance()->getObject('h953u789h0g73t521'); // doesnt exist $this->assertNull($actual); @@ -223,7 +226,7 @@ public function testGetObjectNull(): void */ public function testGetAllObjectsWithDataExtends(): void { - ObjectHandlerUtil::mockDataObjectHandlerWithData(self::PARSER_OUTPUT_WITH_EXTEND); + $this->mockDataObjectHandlerWithData(self::PARSER_OUTPUT_WITH_EXTEND); // Call the method under test $actual = DataObjectHandler::getInstance()->getAllObjects(); @@ -250,7 +253,7 @@ public function testGetAllObjectsWithDataExtends(): void */ public function testGetObjectWithDataExtends(): void { - ObjectHandlerUtil::mockDataObjectHandlerWithData(self::PARSER_OUTPUT_WITH_EXTEND); + $this->mockDataObjectHandlerWithData(self::PARSER_OUTPUT_WITH_EXTEND); // Call the method under test $actual = DataObjectHandler::getInstance()->getObject('EntityTwo'); @@ -276,7 +279,7 @@ public function testGetObjectWithDataExtends(): void */ public function testGetAllObjectsWithDataExtendsItself(): void { - ObjectHandlerUtil::mockDataObjectHandlerWithData(self::PARSER_OUTPUT_WITH_EXTEND_INVALID); + $this->mockDataObjectHandlerWithData(self::PARSER_OUTPUT_WITH_EXTEND_INVALID); $this->expectException(TestFrameworkException::class); $this->expectExceptionMessage( @@ -296,7 +299,7 @@ public function testGetAllObjectsWithDataExtendsItself(): void */ public function testGetObjectWithDataExtendsItself(): void { - ObjectHandlerUtil::mockDataObjectHandlerWithData(self::PARSER_OUTPUT_WITH_EXTEND_INVALID); + $this->mockDataObjectHandlerWithData(self::PARSER_OUTPUT_WITH_EXTEND_INVALID); $this->expectException(TestFrameworkException::class); $this->expectExceptionMessage( @@ -310,11 +313,64 @@ public function testGetObjectWithDataExtendsItself(): void ); } + /** + * Create mock data object handler with data. + * + * @param array $mockData + * + * @return void + */ + private function mockDataObjectHandlerWithData(array $mockData): void + { + $dataObjectHandlerProperty = new ReflectionProperty(DataObjectHandler::class, "INSTANCE"); + $dataObjectHandlerProperty->setAccessible(true); + $dataObjectHandlerProperty->setValue(null); + + $mockDataProfileSchemaParser = $this->createMock(DataProfileSchemaParser::class); + $mockDataProfileSchemaParser + ->method('readDataProfiles') + ->willReturn($mockData); + + $objectManager = ObjectManagerFactory::getObjectManager(); + $mockObjectManagerInstance = $this->createMock(ObjectManager::class); + $mockObjectManagerInstance + ->method('create') + ->will( + $this->returnCallback( + function ( + string $class, + array $arguments = [] + ) use ($objectManager, $mockDataProfileSchemaParser) { + + if ($class === DataProfileSchemaParser::class) { + return $mockDataProfileSchemaParser; + } + + return $objectManager->create($class, $arguments); + } + ) + ); + + $property = new ReflectionProperty(ObjectManager::class, 'instance'); + $property->setAccessible(true); + $property->setValue($mockObjectManagerInstance); + } + /** * @inheritDoc */ public static function tearDownAfterClass(): void { + parent::tearDownAfterClass(); + + $dataObjectHandlerProperty = new ReflectionProperty(DataObjectHandler::class, "INSTANCE"); + $dataObjectHandlerProperty->setAccessible(true); + $dataObjectHandlerProperty->setValue(null); + + $objectManagerProperty = new ReflectionProperty(ObjectManager::class, 'instance'); + $objectManagerProperty->setAccessible(true); + $objectManagerProperty->setValue(null); + TestLoggingUtil::getInstance()->clearMockLoggingUtil(); } } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php index 6c8fc7c45..9923170c4 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php @@ -11,8 +11,11 @@ use Magento\FunctionalTestingFramework\DataGenerator\Handlers\OperationDefinitionObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Objects\OperationDefinitionObject; use Magento\FunctionalTestingFramework\DataGenerator\Objects\OperationElement; +use Magento\FunctionalTestingFramework\DataGenerator\Parsers\OperationDefinitionParser; +use Magento\FunctionalTestingFramework\ObjectManager; +use Magento\FunctionalTestingFramework\ObjectManagerFactory; +use ReflectionProperty; use tests\unit\Util\MagentoTestCase; -use tests\unit\Util\ObjectHandlerUtil; use tests\unit\Util\TestLoggingUtil; /** @@ -63,8 +66,8 @@ public function testGetMultipleObjects(): void OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => 'id', OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => 'integer' ], - ] - ],[ + ] + ],[ OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE => $dataType1, OperationDefinitionObjectHandler::ENTITY_OPERATION_TYPE => $operationType2, OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH => 'auth', @@ -76,8 +79,8 @@ public function testGetMultipleObjects(): void OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => 'integer' ], ] - ]]]; - ObjectHandlerUtil::mockOperationHandlerWithData($mockData); + ]]]; + $this->mockOperationHandlerWithData($mockData); //Perform Assertions $operationDefinitionManager = OperationDefinitionObjectHandler::getInstance(); @@ -120,7 +123,7 @@ public function testDeprecatedOperation(): void ], OperationDefinitionObjectHandler::OBJ_DEPRECATED => 'deprecation message' ]]]; - ObjectHandlerUtil::mockOperationHandlerWithData($mockData); + $this->mockOperationHandlerWithData($mockData); //Perform Assertions $operationDefinitionManager = OperationDefinitionObjectHandler::getInstance(); @@ -274,7 +277,7 @@ public function testObjectCreation(): void ); // Set up mocked data output - ObjectHandlerUtil::mockOperationHandlerWithData($mockData); + $this->mockOperationHandlerWithData($mockData); // Get Operation $operationDefinitionManager = OperationDefinitionObjectHandler::getInstance(); @@ -382,7 +385,7 @@ public function testObjectArrayCreation(): void ); // Set up mocked data output - ObjectHandlerUtil::mockOperationHandlerWithData($mockData); + $this->mockOperationHandlerWithData($mockData); // Get Operation $operationDefinitionManager = OperationDefinitionObjectHandler::getInstance(); @@ -456,7 +459,7 @@ public function testLooseJsonCreation(): void ); // Set up mocked data output - ObjectHandlerUtil::mockOperationHandlerWithData($mockData); + $this->mockOperationHandlerWithData($mockData); // get Operations $operationDefinitionManager = OperationDefinitionObjectHandler::getInstance(); @@ -467,6 +470,52 @@ public function testLooseJsonCreation(): void $this->assertEquals($array, $operation->getOperationMetadata()[1]); } + /** + * Create mock operation handler with data. + * + * @param array $mockData + * + * @return void + */ + private function mockOperationHandlerWithData(array $mockData): void + { + $operationDefinitionObjectHandlerProperty = new ReflectionProperty( + OperationDefinitionObjectHandler::class, + 'INSTANCE' + ); + $operationDefinitionObjectHandlerProperty->setAccessible(true); + $operationDefinitionObjectHandlerProperty->setValue(null); + + $mockOperationParser = $this->createMock(OperationDefinitionParser::class); + $mockOperationParser + ->method('readOperationMetadata') + ->willReturn($mockData); + + $objectManager = ObjectManagerFactory::getObjectManager(); + $mockObjectManagerInstance = $this->createMock(ObjectManager::class); + $mockObjectManagerInstance + ->method('create') + ->will( + $this->returnCallback( + function ( + string $class, + array $arguments = [] + ) use ($objectManager, $mockOperationParser) { + + if ($class === OperationDefinitionParser::class) { + return $mockOperationParser; + } + + return $objectManager->create($class, $arguments); + } + ) + ); + + $property = new ReflectionProperty(ObjectManager::class, 'instance'); + $property->setAccessible(true); + $property->setValue($mockObjectManagerInstance); + } + /** * @inheritDoc */ @@ -474,6 +523,17 @@ public static function tearDownAfterClass(): void { parent::tearDownAfterClass(); + $operationDefinitionObjectHandlerProperty = new ReflectionProperty( + OperationDefinitionObjectHandler::class, + 'INSTANCE' + ); + $operationDefinitionObjectHandlerProperty->setAccessible(true); + $operationDefinitionObjectHandlerProperty->setValue(null); + + $objectManagerProperty = new ReflectionProperty(ObjectManager::class, 'instance'); + $objectManagerProperty->setAccessible(true); + $objectManagerProperty->setValue(null); + TestLoggingUtil::getInstance()->clearMockLoggingUtil(); } } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php index 3629271f3..f4b798ec5 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php @@ -8,6 +8,7 @@ namespace tests\unit\Magento\FunctionalTestFramework\DataGenerator\Handlers; use Exception; +use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Parsers\DataProfileSchemaParser; use Magento\FunctionalTestingFramework\DataGenerator\Persist\CurlHandler; @@ -15,10 +16,8 @@ use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\ObjectManager; use Magento\FunctionalTestingFramework\ObjectManagerFactory; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; use ReflectionProperty; use tests\unit\Util\MagentoTestCase; -use tests\unit\Util\ObjectHandlerUtil; use tests\unit\Util\TestLoggingUtil; /** @@ -261,15 +260,14 @@ public function testUpdateSimpleEntity(): void "; // Mock Classes - ObjectHandlerUtil::mockDataObjectHandlerWithData($parserOutput); - $this->mockCurlHandler($jsonResponse); + $this->mockCurlHandler($jsonResponse, $parserOutput); $handler = PersistedObjectHandler::getInstance(); $handler->createEntity( $entityStepKey, $scope, $entityName ); - $this->mockCurlHandler($updatedResponse); + $this->mockCurlHandler($updatedResponse, $parserOutput); // Call method $handler->updateEntity( @@ -589,13 +587,13 @@ public static function tearDownAfterClass(): void parent::tearDownAfterClass(); // Clear out Singleton between tests - $property = new ReflectionProperty(PersistedObjectHandler::class, "INSTANCE"); - $property->setAccessible(true); - $property->setValue(null); + $persistedObjectHandlerProperty = new ReflectionProperty(PersistedObjectHandler::class, "INSTANCE"); + $persistedObjectHandlerProperty->setAccessible(true); + $persistedObjectHandlerProperty->setValue(null); - $property = new ReflectionProperty(ObjectManager::class, 'instance'); - $property->setAccessible(true); - $property->setValue(null); + $objectManagerProperty = new ReflectionProperty(ObjectManager::class, 'instance'); + $objectManagerProperty->setAccessible(true); + $objectManagerProperty->setValue(null); TestLoggingUtil::getInstance()->clearMockLoggingUtil(); } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/PageObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/PageObjectHandlerTest.php index bfa1fa8e0..8de63d849 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/PageObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/PageObjectHandlerTest.php @@ -8,9 +8,12 @@ namespace tests\unit\Magento\FunctionalTestFramework\Page\Handlers; use Magento\FunctionalTestingFramework\Exceptions\XmlException; +use Magento\FunctionalTestingFramework\ObjectManager; +use Magento\FunctionalTestingFramework\ObjectManagerFactory; use Magento\FunctionalTestingFramework\Page\Handlers\PageObjectHandler; +use Magento\FunctionalTestingFramework\XmlParser\PageParser; +use ReflectionProperty; use tests\unit\Util\MagentoTestCase; -use tests\unit\Util\ObjectHandlerUtil; use tests\unit\Util\TestLoggingUtil; /** @@ -54,7 +57,7 @@ public function testGetPageObject(): void 'area' => 'test' ]]; - ObjectHandlerUtil::mockPageObjectHandlerWithData($mockData); + $this->mockPageObjectHandlerWithData($mockData); $pageHandler = PageObjectHandler::getInstance(); $pages = $pageHandler->getAllObjects(); $pageHandler->getObject('testPage1'); @@ -84,7 +87,7 @@ public function testGetEmptyPage(): void 'area' => 'test' ]]; - ObjectHandlerUtil::mockPageObjectHandlerWithData($mockData); + $this->mockPageObjectHandlerWithData($mockData); PageObjectHandler::getInstance()->getObject('testPage1'); // Empty page has been read in and gotten without an exception being thrown. @@ -110,7 +113,7 @@ public function testDeprecatedPage(): void 'filename' => 'filename.xml' ]]; - ObjectHandlerUtil::mockPageObjectHandlerWithData($mockData); + $this->mockPageObjectHandlerWithData($mockData); PageObjectHandler::getInstance()->getObject('testPage1'); TestLoggingUtil::getInstance()->validateMockLogStatement( @@ -120,11 +123,65 @@ public function testDeprecatedPage(): void ); } + /** + * Create mock page object handler with data. + * + * @param array $mockData + * + * @return void + */ + private function mockPageObjectHandlerWithData(array $mockData): void + { + $pageObjectHandlerProperty = new ReflectionProperty(PageObjectHandler::class, 'INSTANCE'); + $pageObjectHandlerProperty->setAccessible(true); + $pageObjectHandlerProperty->setValue(null); + + $mockSectionParser = $this->createMock(PageParser::class); + $mockSectionParser + ->method('getData') + ->willReturn($mockData); + + $objectManager = ObjectManagerFactory::getObjectManager(); + $mockObjectManagerInstance = $this->createMock(ObjectManager::class); + $mockObjectManagerInstance + ->method('get') + ->will( + $this->returnCallback( + function ( + string $class, + array $arguments = [] + ) use ($objectManager, $mockSectionParser) { + + if ($class === PageParser::class) { + return $mockSectionParser; + } + + return $objectManager->create($class, $arguments); + } + ) + ); + + $property = new ReflectionProperty(ObjectManager::class, 'instance'); + $property->setAccessible(true); + $property->setValue($mockObjectManagerInstance); + } + + /** * @inheritDoc */ public static function tearDownAfterClass(): void { + parent::tearDownAfterClass(); + + $pageObjectHandlerProperty = new ReflectionProperty(PageObjectHandler::class, 'INSTANCE'); + $pageObjectHandlerProperty->setAccessible(true); + $pageObjectHandlerProperty->setValue(null); + + $objectManagerProperty = new ReflectionProperty(ObjectManager::class, 'instance'); + $objectManagerProperty->setAccessible(true); + $objectManagerProperty->setValue(null); + TestLoggingUtil::getInstance()->clearMockLoggingUtil(); } } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/SectionObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/SectionObjectHandlerTest.php index 79ad32b4c..cb6792218 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/SectionObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/SectionObjectHandlerTest.php @@ -8,9 +8,12 @@ namespace tests\unit\Magento\FunctionalTestFramework\Page\Handlers; use Magento\FunctionalTestingFramework\Exceptions\XmlException; +use Magento\FunctionalTestingFramework\ObjectManager; +use Magento\FunctionalTestingFramework\ObjectManagerFactory; use Magento\FunctionalTestingFramework\Page\Handlers\SectionObjectHandler; +use Magento\FunctionalTestingFramework\XmlParser\SectionParser; +use ReflectionProperty; use tests\unit\Util\MagentoTestCase; -use tests\unit\Util\ObjectHandlerUtil; use tests\unit\Util\TestLoggingUtil; /** @@ -54,7 +57,7 @@ public function testGetSectionObject(): void ] ]; - ObjectHandlerUtil::mockSectionObjectHandlerWithData($mockData); + $this->mockSectionObjectHandlerWithData($mockData); // get sections $sectionHandler = SectionObjectHandler::getInstance(); @@ -91,7 +94,7 @@ public function testDeprecatedSection(): void ] ]; - ObjectHandlerUtil::mockSectionObjectHandlerWithData($mockData); + $this->mockSectionObjectHandlerWithData($mockData); // get sections $sectionHandler = SectionObjectHandler::getInstance(); @@ -105,11 +108,64 @@ public function testDeprecatedSection(): void ); } + /** + * Create mock section object handler with data. + * + * @param array $mockData + * + * @return void + */ + private function mockSectionObjectHandlerWithData(array $mockData): void + { + $sectionObjectHandlerProperty = new ReflectionProperty(SectionObjectHandler::class, "INSTANCE"); + $sectionObjectHandlerProperty->setAccessible(true); + $sectionObjectHandlerProperty->setValue(null); + + $mockSectionParser = $this->createMock(SectionParser::class); + $mockSectionParser + ->method('getData') + ->willReturn($mockData); + + $objectManager = ObjectManagerFactory::getObjectManager(); + $mockObjectManagerInstance = $this->createMock(ObjectManager::class); + $mockObjectManagerInstance + ->method('get') + ->will( + $this->returnCallback( + function ( + string $class, + array $arguments = [] + ) use ($objectManager, $mockSectionParser) { + + if ($class === SectionParser::class) { + return $mockSectionParser; + } + + return $objectManager->create($class, $arguments); + } + ) + ); + + $property = new ReflectionProperty(ObjectManager::class, 'instance'); + $property->setAccessible(true); + $property->setValue($mockObjectManagerInstance); + } + /** * @inheritDoc */ public static function tearDownAfterClass(): void { + parent::tearDownAfterClass(); + + $sectionObjectHandlerProperty = new ReflectionProperty(SectionObjectHandler::class, "INSTANCE"); + $sectionObjectHandlerProperty->setAccessible(true); + $sectionObjectHandlerProperty->setValue(null); + + $objectManagerProperty = new ReflectionProperty(ObjectManager::class, 'instance'); + $objectManagerProperty->setAccessible(true); + $objectManagerProperty->setValue(null); + TestLoggingUtil::getInstance()->clearMockLoggingUtil(); } } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/StaticCheck/DeprecatedEntityUsageCheckTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/StaticCheck/DeprecatedEntityUsageCheckTest.php index bb4c96e89..01cc8588f 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/StaticCheck/DeprecatedEntityUsageCheckTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/StaticCheck/DeprecatedEntityUsageCheckTest.php @@ -3,37 +3,54 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace tests\unit\Magento\FunctionalTestFramework\StaticCheck; +use InvalidArgumentException; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\OperationDefinitionObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; +use Magento\FunctionalTestingFramework\DataGenerator\Parsers\OperationDefinitionParser; +use Magento\FunctionalTestingFramework\ObjectManager; +use Magento\FunctionalTestingFramework\ObjectManagerFactory; use Magento\FunctionalTestingFramework\Page\Objects\ElementObject; use Magento\FunctionalTestingFramework\Page\Objects\PageObject; use Magento\FunctionalTestingFramework\Page\Objects\SectionObject; use Magento\FunctionalTestingFramework\StaticCheck\DeprecatedEntityUsageCheck; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; +use ReflectionClass; +use ReflectionException; +use ReflectionProperty; use Symfony\Component\Console\Input\InputInterface; use tests\unit\Util\MagentoTestCase; -use ReflectionClass; -use InvalidArgumentException; -use tests\unit\Util\ObjectHandlerUtil; +/** + * Class DeprecatedEntityUsageCheckTest + */ class DeprecatedEntityUsageCheckTest extends MagentoTestCase { - /** @var DeprecatedEntityUsageCheck */ + /** @var DeprecatedEntityUsageCheck */ private $staticCheck; /** @var ReflectionClass*/ private $staticCheckClass; + /** + * @inheritDoc + */ public function setUp(): void { $this->staticCheck = new DeprecatedEntityUsageCheck(); - $this->staticCheckClass = new \ReflectionClass($this->staticCheck); + $this->staticCheckClass = new ReflectionClass($this->staticCheck); } - public function testInvalidPathOption() + /** + * Validate testInvalidPathOption. + * + * @return void + * @throws ReflectionException + */ + public function testInvalidPathOption(): void { $input = $this->getMockBuilder(InputInterface::class) ->disableOriginalConstructor() @@ -50,7 +67,13 @@ public function testInvalidPathOption() $loadAllXmlFiles->invoke($this->staticCheck, $input); } - public function testViolatingElementReferences() + /** + * Validate testViolatingElementReferences. + * + * @return void + * @throws ReflectionException + */ + public function testViolatingElementReferences(): void { //variables for assertions $elementName = 'elementOne'; @@ -73,13 +96,19 @@ public function testViolatingElementReferences() $this->assertEquals($actual, $expected); } - public function testViolatingPageReferences() + /** + * Validate testViolatingPageReferences. + * + * @return void + * @throws ReflectionException + */ + public function testViolatingPageReferences(): void { //Page variables for assertions $pageName = 'Page'; $fileName = 'page.xml'; - $page = new PageObject($pageName, '/url.html', 'Test', [], false, "test", $fileName, 'deprecated'); + $page = new PageObject($pageName, '/url.html', 'Test', [], false, 'test', $fileName, 'deprecated'); $references = ['Page' => $page]; $actual = $this->callViolatingReferences($references); $expected = [ @@ -93,7 +122,13 @@ public function testViolatingPageReferences() $this->assertEquals($actual, $expected); } - public function testViolatingDataReferences() + /** + * Validate testViolatingDataReferences. + * + * @return void + * @throws ReflectionException + */ + public function testViolatingDataReferences(): void { //Data entity variables for assertions $entityName = 'EntityOne'; @@ -123,7 +158,13 @@ public function testViolatingDataReferences() $this->assertEquals($actual, $expected); } - public function testViolatingTestReferences() + /** + * Validate testViolatingTestReferences. + * + * @return void + * @throws ReflectionException + */ + public function testViolatingTestReferences(): void { // test variables for assertions $testName = 'Test1'; @@ -143,12 +184,18 @@ public function testViolatingTestReferences() $this->assertEquals($actual, $expected); } - public function testViolatingMetaDataReferences() + /** + * Validate testViolatingMetaDataReferences. + * + * @return void + * @throws ReflectionException + */ + public function testViolatingMetaDataReferences(): void { // Data Variables for Assertions - $dataType1 = "type1"; - $operationType1 = "create"; - $operationType2 = "update"; + $dataType1 = 'type1'; + $operationType1 = 'create'; + $operationType2 = 'update'; /** * Parser Output. @@ -161,34 +208,34 @@ public function testViolatingMetaDataReferences() * key=id, value=integer */ $mockData = [OperationDefinitionObjectHandler::ENTITY_OPERATION_ROOT_TAG => [ - "testOperationName" => [ + 'testOperationName' => [ OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE => $dataType1, OperationDefinitionObjectHandler::ENTITY_OPERATION_TYPE => $operationType1, - OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH => "auth", - OperationDefinitionObjectHandler::ENTITY_OPERATION_URL => "V1/Type1", - OperationDefinitionObjectHandler::ENTITY_OPERATION_METHOD => "POST", + OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH => 'auth', + OperationDefinitionObjectHandler::ENTITY_OPERATION_URL => 'V1/Type1', + OperationDefinitionObjectHandler::ENTITY_OPERATION_METHOD => 'POST', OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY => [ 0 => [ - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => "id", - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => "integer" + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => 'id', + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => 'integer' ], ], OperationDefinitionObjectHandler::OBJ_DEPRECATED => 'deprecated' ],[ OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE => $dataType1, OperationDefinitionObjectHandler::ENTITY_OPERATION_TYPE => $operationType2, - OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH => "auth", - OperationDefinitionObjectHandler::ENTITY_OPERATION_URL => "V1/Type1/{id}", - OperationDefinitionObjectHandler::ENTITY_OPERATION_METHOD => "PUT", + OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH => 'auth', + OperationDefinitionObjectHandler::ENTITY_OPERATION_URL => 'V1/Type1/{id}', + OperationDefinitionObjectHandler::ENTITY_OPERATION_METHOD => 'PUT', OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY => [ 0 => [ - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => "id", - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => "integer" + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => 'id', + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => 'integer' ], ] ]]]; - ObjectHandlerUtil::mockOperationHandlerWithData($mockData); + $this->mockOperationHandlerWithData($mockData); $dataName = 'dataName1'; $references = [ $dataName => [ @@ -213,7 +260,13 @@ public function testViolatingMetaDataReferences() $this->assertEquals($actual, $expected); } - public function testIsDeprecated() + /** + * Validate testIsDeprecated. + * + * @return void + * @throws ReflectionException + */ + public function testIsDeprecated(): void { // Test Data $contents = '<tests> @@ -230,16 +283,86 @@ public function testIsDeprecated() $this->assertTrue($output); } + /** - * Invoke findViolatingReferences - * @param $references + * Create mock operation handler with data. + * + * @param array $mockData + * + * @return void + */ + private function mockOperationHandlerWithData(array $mockData): void + { + $operationDefinitionObjectHandlerProperty = new ReflectionProperty( + OperationDefinitionObjectHandler::class, + 'INSTANCE' + ); + $operationDefinitionObjectHandlerProperty->setAccessible(true); + $operationDefinitionObjectHandlerProperty->setValue(null); + + $mockOperationParser = $this->createMock(OperationDefinitionParser::class); + $mockOperationParser + ->method('readOperationMetadata') + ->willReturn($mockData); + + $objectManager = ObjectManagerFactory::getObjectManager(); + $mockObjectManagerInstance = $this->createMock(ObjectManager::class); + $mockObjectManagerInstance + ->method('create') + ->will( + $this->returnCallback( + function ( + string $class, + array $arguments = [] + ) use ($objectManager, $mockOperationParser) { + + if ($class === OperationDefinitionParser::class) { + return $mockOperationParser; + } + + return $objectManager->create($class, $arguments); + } + ) + ); + + $property = new ReflectionProperty(ObjectManager::class, 'instance'); + $property->setAccessible(true); + $property->setValue($mockObjectManagerInstance); + } + + /** + * @inheritDoc + */ + public static function tearDownAfterClass(): void + { + parent::tearDownAfterClass(); + + $operationDefinitionObjectHandlerProperty = new ReflectionProperty( + OperationDefinitionObjectHandler::class, + 'INSTANCE' + ); + $operationDefinitionObjectHandlerProperty->setAccessible(true); + $operationDefinitionObjectHandlerProperty->setValue(null); + + $objectManagerProperty = new ReflectionProperty(ObjectManager::class, 'instance'); + $objectManagerProperty->setAccessible(true); + $objectManagerProperty->setValue(null); + } + + + /** + * Invoke findViolatingReferences. + * + * @param array $references + * * @return mixed - * @throws \ReflectionException + * @throws ReflectionException */ - public function callViolatingReferences($references) + public function callViolatingReferences(array $references) { $property = $this->staticCheckClass->getMethod('findViolatingReferences'); $property->setAccessible(true); + return $property->invoke($this->staticCheck, $references); } } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/ActionGroupObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/ActionGroupObjectHandlerTest.php index 71da6d492..cfa546de5 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/ActionGroupObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/ActionGroupObjectHandlerTest.php @@ -9,10 +9,13 @@ use Exception; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\ObjectManager; +use Magento\FunctionalTestingFramework\ObjectManagerFactory; use Magento\FunctionalTestingFramework\Test\Handlers\ActionGroupObjectHandler; +use Magento\FunctionalTestingFramework\Test\Parsers\ActionGroupDataParser; +use ReflectionProperty; use tests\unit\Util\ActionGroupArrayBuilder; use tests\unit\Util\MagentoTestCase; -use tests\unit\Util\ObjectHandlerUtil; /** * Class ActionGroupObjectHandlerTest @@ -36,7 +39,7 @@ public function testGetTestObjectWithInvalidExtends(): void ->withFilename() ->withActionObjects() ->build(); - ObjectHandlerUtil::mockActionGroupObjectHandlerWithData(['actionGroups' => $actionGroupOne]); + $this->mockActionGroupObjectHandlerWithData(['actionGroups' => $actionGroupOne]); $handler = ActionGroupObjectHandler::getInstance(); @@ -46,12 +49,12 @@ public function testGetTestObjectWithInvalidExtends(): void } /** - * Validate getAllObjects should throw exception if test extends from itself + * Validate getAllObjects should throw exception if test extends from itself. * * @return void * @throws Exception */ - public function testGetAllTestObjectsWithInvalidExtends() + public function testGetAllTestObjectsWithInvalidExtends(): void { // Set up action group data $nameOne = 'actionGroupOne'; @@ -71,7 +74,7 @@ public function testGetAllTestObjectsWithInvalidExtends() ->withActionObjects() ->build(); - ObjectHandlerUtil::mockActionGroupObjectHandlerWithData( + $this->mockActionGroupObjectHandlerWithData( [ 'actionGroups' => array_merge( $actionGroupOne, @@ -86,4 +89,62 @@ public function testGetAllTestObjectsWithInvalidExtends() $this->expectExceptionMessage('Mftf Action Group can not extend from itself: ' . $nameOne); $handler->getAllObjects(); } + + /** + * Create mock action group object handler with data. + * + * @param array $mockData + * + * @return void + */ + private function mockActionGroupObjectHandlerWithData(array $mockData): void + { + $actionGroupObjectHandlerProperty = new ReflectionProperty(ActionGroupObjectHandler::class, 'instance'); + $actionGroupObjectHandlerProperty->setAccessible(true); + $actionGroupObjectHandlerProperty->setValue(null); + + $mockOperationParser = $this->createMock(ActionGroupDataParser::class); + $mockOperationParser + ->method('readActionGroupData') + ->willReturn($mockData); + $objectManager = ObjectManagerFactory::getObjectManager(); + $mockObjectManagerInstance = $this->createMock(ObjectManager::class); + $mockObjectManagerInstance + ->method('create') + ->will( + $this->returnCallback( + function ( + string $class, + array $arguments = [] + ) use ($objectManager, $mockOperationParser) { + + if ($class === ActionGroupDataParser::class) { + return $mockOperationParser; + } + + return $objectManager->create($class, $arguments); + } + ) + ); + + $property = new ReflectionProperty(ObjectManager::class, 'instance'); + $property->setAccessible(true); + $property->setValue($mockObjectManagerInstance); + } + + /** + * @inheritDoc + */ + public static function tearDownAfterClass(): void + { + parent::tearDownAfterClass(); + + $actionGroupObjectHandlerProperty = new ReflectionProperty(ActionGroupObjectHandler::class, 'instance'); + $actionGroupObjectHandlerProperty->setAccessible(true); + $actionGroupObjectHandlerProperty->setValue(null); + + $objectManagerProperty = new ReflectionProperty(ObjectManager::class, 'instance'); + $objectManagerProperty->setAccessible(true); + $objectManagerProperty->setValue(null); + } } diff --git a/dev/tests/unit/Util/ObjectHandlerUtil.php b/dev/tests/unit/Util/ObjectHandlerUtil.php deleted file mode 100644 index 0e4543f2b..000000000 --- a/dev/tests/unit/Util/ObjectHandlerUtil.php +++ /dev/null @@ -1,145 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace tests\unit\Util; - -use AspectMock\Test as AspectMock; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\OperationDefinitionObjectHandler; -use Magento\FunctionalTestingFramework\DataGenerator\Parsers\DataProfileSchemaParser; -use Magento\FunctionalTestingFramework\DataGenerator\Parsers\OperationDefinitionParser; -use Magento\FunctionalTestingFramework\ObjectManager; -use Magento\FunctionalTestingFramework\ObjectManagerFactory; -use Magento\FunctionalTestingFramework\Page\Handlers\PageObjectHandler; -use Magento\FunctionalTestingFramework\Page\Handlers\SectionObjectHandler; -use Magento\FunctionalTestingFramework\Test\Handlers\ActionGroupObjectHandler; -use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; -use Magento\FunctionalTestingFramework\Test\Parsers\ActionGroupDataParser; -use Magento\FunctionalTestingFramework\Test\Parsers\TestDataParser; -use Magento\FunctionalTestingFramework\XmlParser\PageParser; -use Magento\FunctionalTestingFramework\XmlParser\SectionParser; - -class ObjectHandlerUtil -{ - /** - * Set up everything required to mock OperationDefinitionObjectHandler::getInstance() with $data value - * @param array $data - * @throws \Exception - */ - public static function mockOperationHandlerWithData($data) - { - // Clear OperationDefinitionObjectHandler singleton if already set - $property = new \ReflectionProperty( - OperationDefinitionObjectHandler::class, - 'INSTANCE' - ); - $property->setAccessible(true); - $property->setValue(null); - - $mockOperationParser = AspectMock::double( - OperationDefinitionParser::class, - ["readOperationMetadata" => $data] - )->make(); - $instance = AspectMock::double(ObjectManager::class, ['create' => $mockOperationParser])->make(); - AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); - } - - /** - * Set up everything required to mock DataObjectHandler::getInstance() with $data value - * - * @param array $data - */ - public static function mockDataObjectHandlerWithData($data) - { - // Clear DataObjectHandler singleton if already set - $property = new \ReflectionProperty(DataObjectHandler::class, "INSTANCE"); - $property->setAccessible(true); - $property->setValue(null); - - $mockDataProfileSchemaParser = AspectMock::double(DataProfileSchemaParser::class, [ - 'readDataProfiles' => $data - ])->make(); - - $mockObjectManager = AspectMock::double(ObjectManager::class, [ - 'create' => $mockDataProfileSchemaParser - ])->make(); - - AspectMock::double(ObjectManagerFactory::class, [ - 'getObjectManager' => $mockObjectManager - ]); - } - - /** - * Set up everything required to mock PageObjectHandler::getInstance() with $data value - * - * @param array $data - */ - public static function mockPageObjectHandlerWithData($data) - { - // clear section object handler value to inject parsed content - $property = new \ReflectionProperty(PageObjectHandler::class, 'INSTANCE'); - $property->setAccessible(true); - $property->setValue(null); - - $mockSectionParser = AspectMock::double(PageParser::class, ["getData" => $data])->make(); - $instance = AspectMock::double(ObjectManager::class, ['get' => $mockSectionParser])->make(); - AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); - } - - /** - * Set up everything required to mock SectionObjectHandler::getInstance() with $data value - * - * @param array $data - */ - public static function mockSectionObjectHandlerWithData($data) - { - // clear section object handler value to inject parsed content - $property = new \ReflectionProperty(SectionObjectHandler::class, "INSTANCE"); - $property->setAccessible(true); - $property->setValue(null); - - $mockSectionParser = AspectMock::double(SectionParser::class, ["getData" => $data])->make(); - $instance = AspectMock::double(ObjectManager::class, ["get" => $mockSectionParser])->make(); - AspectMock::double(ObjectManagerFactory::class, ["getObjectManager" => $instance]); - } - - /** - * Set up everything required to mock TestObjectHandler::getInstance() with $data value - * - * @param array $data - * @throws \Exception - */ - public static function mockTestObjectHandlerWitData($data) - { - // clear test object handler value to inject parsed content - $property = new \ReflectionProperty(TestObjectHandler::class, 'testObjectHandler'); - $property->setAccessible(true); - $property->setValue(null); - - $mockDataParser = AspectMock::double(TestDataParser::class, ['readTestData' => $data])->make(); - $instance = AspectMock::double(ObjectManager::class, ['create' => $mockDataParser]) - ->make(); // bypass the private constructor - AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); - } - - /** - * Set up everything required to mock ActionGroupObjectHandler::getInstance() with $data value - * - * @param array $data - * @throws \Exception - */ - public static function mockActionGroupObjectHandlerWithData($data) - { - // Clear action group object handler value to inject parsed content - $property = new \ReflectionProperty(ActionGroupObjectHandler::class, 'instance'); - $property->setAccessible(true); - $property->setValue(null); - - $mockDataParser = AspectMock::double(ActionGroupDataParser::class, ['readActionGroupData' => $data])->make(); - $instance = AspectMock::double(ObjectManager::class, ['create' => $mockDataParser]) - ->make(); // bypass the private constructor - AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); - } -} From 591aaa7ba78ccd5aa43454ec6306ea6e844e4c8d Mon Sep 17 00:00:00 2001 From: "andrii.zinkevych" <a.zinkevych@atwix.com> Date: Tue, 27 Jul 2021 15:34:32 +0300 Subject: [PATCH 680/888] 33584: Fixed static-tests --- .../DataGenerator/Handlers/DataObjectHandlerTest.php | 6 ++++-- .../Handlers/OperationDefinitionObjectHandlerTest.php | 6 ++++-- .../Page/Handlers/PageObjectHandlerTest.php | 7 ++++--- .../Page/Handlers/SectionObjectHandlerTest.php | 6 ++++-- .../StaticCheck/DeprecatedEntityUsageCheckTest.php | 8 ++++---- .../Test/Handlers/ActionGroupObjectHandlerTest.php | 6 ++++-- 6 files changed, 24 insertions(+), 15 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php index 552b951a0..7ef84a53d 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php @@ -340,8 +340,10 @@ private function mockDataObjectHandlerWithData(array $mockData): void function ( string $class, array $arguments = [] - ) use ($objectManager, $mockDataProfileSchemaParser) { - + ) use ( + $objectManager, + $mockDataProfileSchemaParser + ) { if ($class === DataProfileSchemaParser::class) { return $mockDataProfileSchemaParser; } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php index 9923170c4..c5747e8cb 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php @@ -500,8 +500,10 @@ private function mockOperationHandlerWithData(array $mockData): void function ( string $class, array $arguments = [] - ) use ($objectManager, $mockOperationParser) { - + ) use ( + $objectManager, + $mockOperationParser + ) { if ($class === OperationDefinitionParser::class) { return $mockOperationParser; } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/PageObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/PageObjectHandlerTest.php index 8de63d849..c611cc6a7 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/PageObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/PageObjectHandlerTest.php @@ -150,8 +150,10 @@ private function mockPageObjectHandlerWithData(array $mockData): void function ( string $class, array $arguments = [] - ) use ($objectManager, $mockSectionParser) { - + ) use ( + $objectManager, + $mockSectionParser + ) { if ($class === PageParser::class) { return $mockSectionParser; } @@ -166,7 +168,6 @@ function ( $property->setValue($mockObjectManagerInstance); } - /** * @inheritDoc */ diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/SectionObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/SectionObjectHandlerTest.php index cb6792218..b0ce0a4b8 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/SectionObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/SectionObjectHandlerTest.php @@ -135,8 +135,10 @@ private function mockSectionObjectHandlerWithData(array $mockData): void function ( string $class, array $arguments = [] - ) use ($objectManager, $mockSectionParser) { - + ) use ( + $objectManager, + $mockSectionParser + ) { if ($class === SectionParser::class) { return $mockSectionParser; } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/StaticCheck/DeprecatedEntityUsageCheckTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/StaticCheck/DeprecatedEntityUsageCheckTest.php index 01cc8588f..d4286060f 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/StaticCheck/DeprecatedEntityUsageCheckTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/StaticCheck/DeprecatedEntityUsageCheckTest.php @@ -283,7 +283,6 @@ public function testIsDeprecated(): void $this->assertTrue($output); } - /** * Create mock operation handler with data. * @@ -314,8 +313,10 @@ private function mockOperationHandlerWithData(array $mockData): void function ( string $class, array $arguments = [] - ) use ($objectManager, $mockOperationParser) { - + ) use ( + $objectManager, + $mockOperationParser + ) { if ($class === OperationDefinitionParser::class) { return $mockOperationParser; } @@ -349,7 +350,6 @@ public static function tearDownAfterClass(): void $objectManagerProperty->setValue(null); } - /** * Invoke findViolatingReferences. * diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/ActionGroupObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/ActionGroupObjectHandlerTest.php index cfa546de5..c91d12a29 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/ActionGroupObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/ActionGroupObjectHandlerTest.php @@ -116,8 +116,10 @@ private function mockActionGroupObjectHandlerWithData(array $mockData): void function ( string $class, array $arguments = [] - ) use ($objectManager, $mockOperationParser) { - + ) use ( + $objectManager, + $mockOperationParser + ) { if ($class === ActionGroupDataParser::class) { return $mockOperationParser; } From ac8d40e871f04eaf6005f0abc43d40a23c8d8642 Mon Sep 17 00:00:00 2001 From: Dan Mooney <30629803+danmooney2@users.noreply.github.com> Date: Tue, 27 Jul 2021 09:58:05 -0500 Subject: [PATCH 681/888] Add access/secret key config parameters --- docs/configuration.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/docs/configuration.md b/docs/configuration.md index 4eb273824..bd48d1554 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -408,6 +408,26 @@ Example: REMOTE_STORAGE_AWSS3_PREFIX=local ``` +### REMOTE_STORAGE_AWSS3_ACCESS_KEY + +The optional access key for the S3 bucket. + +Example: + +```conf +REMOTE_STORAGE_AWSS3_ACCESS_KEY=access-key +``` + +### REMOTE_STORAGE_AWSS3_SECRET_KEY + +The optional secret key for the S3 bucket. + +Example: + +```conf +REMOTE_STORAGE_AWSS3_SECRET_KEY=secret-key +``` + ### MAGENTO_ADMIN_WEBAPI_TOKEN_LIFETIME The lifetime (in seconds) of Magento Admin WebAPI token; if token is older than this value a refresh attempt will be made just before the next WebAPI call. From 6563d302b9d6b35018a90356a4ef4904250e98d4 Mon Sep 17 00:00:00 2001 From: Karyna <k.tsymbal@atwix.com> Date: Wed, 28 Jul 2021 12:15:40 +0300 Subject: [PATCH 682/888] Refactor CredentialStorage after FileStorage constructor elimination --- .../DataGenerator/Handlers/CredentialStore.php | 6 ++++-- .../DataGenerator/Handlers/SecretStorage/FileStorage.php | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php index d6e6b9a69..36b2daf41 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php @@ -221,11 +221,13 @@ private function initializeCredentialStorage() * * @return void */ - private function initializeFileStorage() + private function initializeFileStorage(): void { // Initialize file storage try { - $this->credStorage[self::ARRAY_KEY_FOR_FILE] = new FileStorage(); + $fileStorage = new FileStorage(); + $fileStorage->initialize(); + $this->credStorage[self::ARRAY_KEY_FOR_FILE] = $fileStorage; } catch (TestFrameworkException $e) { // Print error message in console print_r($e->getMessage()); diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/FileStorage.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/FileStorage.php index 62ecfbedc..479c608e4 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/FileStorage.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/FileStorage.php @@ -26,7 +26,7 @@ class FileStorage extends BaseStorage * @return void * @throws TestFrameworkException */ - private function initialize(): void + public function initialize(): void { if (!$this->secretData) { $creds = $this->readInCredentialsFile(); From 63a1ed4f6ee65c1a083d16bb99faf397219c4302 Mon Sep 17 00:00:00 2001 From: "andrii.zinkevych" <a.zinkevych@atwix.com> Date: Wed, 28 Jul 2021 17:02:58 +0300 Subject: [PATCH 683/888] 33293: Fixed code --- .../DataGenerator/Handlers/PersistedObjectHandlerTest.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php index 3629271f3..33215430a 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/PersistedObjectHandlerTest.php @@ -8,6 +8,7 @@ namespace tests\unit\Magento\FunctionalTestFramework\DataGenerator\Handlers; use Exception; +use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Parsers\DataProfileSchemaParser; use Magento\FunctionalTestingFramework\DataGenerator\Persist\CurlHandler; @@ -15,10 +16,8 @@ use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\ObjectManager; use Magento\FunctionalTestingFramework\ObjectManagerFactory; -use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; use ReflectionProperty; use tests\unit\Util\MagentoTestCase; -use tests\unit\Util\ObjectHandlerUtil; use tests\unit\Util\TestLoggingUtil; /** @@ -261,15 +260,14 @@ public function testUpdateSimpleEntity(): void "; // Mock Classes - ObjectHandlerUtil::mockDataObjectHandlerWithData($parserOutput); - $this->mockCurlHandler($jsonResponse); + $this->mockCurlHandler($jsonResponse, $parserOutput); $handler = PersistedObjectHandler::getInstance(); $handler->createEntity( $entityStepKey, $scope, $entityName ); - $this->mockCurlHandler($updatedResponse); + $this->mockCurlHandler($updatedResponse, $parserOutput); // Call method $handler->updateEntity( From aa82e94357f321d8aca5bba48b7b4f410a9aee1c Mon Sep 17 00:00:00 2001 From: "andrii.zinkevych" <a.zinkevych@atwix.com> Date: Thu, 29 Jul 2021 11:44:35 +0300 Subject: [PATCH 684/888] 33308: Fixed and add removed tests --- .../Util/ModuleResolverTest.php | 310 ++++++++++++++++-- .../Util/ModuleResolver.php | 89 +---- .../ModuleResolver/ModuleResolverService.php | 105 ++++++ 3 files changed, 393 insertions(+), 111 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php index cec3b9461..368fd2149 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php @@ -17,12 +17,13 @@ use tests\unit\Util\MagentoTestCase; use tests\unit\Util\TestLoggingUtil; +/** + * Class ModuleResolverTest + */ class ModuleResolverTest extends MagentoTestCase { /** - * Before test functionality. - * - * @return void + * @inheritDoc */ protected function setUp(): void { @@ -30,9 +31,7 @@ protected function setUp(): void } /** - * After class functionality. - * - * @return void + * @inheritDoc */ public static function tearDownAfterClass(): void { @@ -70,7 +69,9 @@ public function testGetModulePathsAggregate(): void { $this->mockForceGenerate(false); - $moduleResolverService = $this->createMock(ModuleResolverService::class); + $moduleResolverService = $this->createPartialMock( + ModuleResolverService::class, ['getRegisteredModuleList', 'aggregateTestModulePaths'] + ); $moduleResolverService->expects($this->any()) ->method('getRegisteredModuleList') ->willReturn( @@ -100,6 +101,99 @@ public function testGetModulePathsAggregate(): void ); } + /** + * Validate aggregateTestModulePaths() when module path part of DEV_TESTS. + * + * @return void + * @throws Exception + */ + public function testAggregateTestModulePathsDevTests(): void + { + $origin = TESTS_MODULE_PATH; + $modulePath = ModuleResolver::DEV_TESTS . DIRECTORY_SEPARATOR . "Magento"; + putenv("TESTS_MODULE_PATH=$modulePath"); + + $this->mockForceGenerate(false); + $moduleResolverService = $this->createPartialMock(ModuleResolverService::class, ['globRelevantPaths']); + $moduleResolverService + ->method('globRelevantPaths') + ->withConsecutive() + ->will( + $this->returnCallback( + function ($codePath, $pattern) use ($modulePath) { + if ($codePath === $modulePath && $pattern === '') { + $this->fail(sprintf( + 'Not expected parameter: \'%s\' when invoked method globRelevantPaths().', + $modulePath + )); + } + + return []; + } + ) + ); + $this->setMockResolverCreatorProperties($moduleResolverService); + $resolver = ModuleResolver::getInstance(); + $this->setMockResolverProperties($resolver, null, []); + $this->assertEquals([], $resolver->getModulesPath()); + + + putenv("TESTS_MODULE_PATH=$origin"); + } + + /** + * Validate correct path locations are fed into globRelevantPaths. + * + * @return void + * @throws Exception + */ + public function testGetModulePathsLocations(): void + { + // clear test object handler value to inject parsed content + $property = new ReflectionProperty(ModuleResolver::class, 'instance'); + $property->setAccessible(true); + $property->setValue(null); + + $this->mockForceGenerate(false); + // Define the Module paths from default TESTS_MODULE_PATH + $modulePath = defined('TESTS_MODULE_PATH') ? TESTS_MODULE_PATH : TESTS_BP; + + // Define the Module paths from app/code + $magentoBaseCodePath = MAGENTO_BP; + + $moduleResolverService = $this->createPartialMock(ModuleResolverService::class, ['globRelevantPaths']); + $moduleResolverService + ->method('globRelevantPaths') + ->withConsecutive() + ->will( + $this->returnCallback( + function ($codePath, $pattern) use ($modulePath, $magentoBaseCodePath) { + if ($codePath === $modulePath && $pattern === '') { + return []; + } + + if ($codePath === $magentoBaseCodePath . '/vendor' && $pattern === 'Test/Mftf') { + return []; + } + + if ($codePath === $magentoBaseCodePath . "/app/code" && $pattern === 'Test/Mftf') { + return []; + } + + $this->fail(sprintf( + 'Not expected parameter: \'%s\' when invoked method globRelevantPaths().', + $modulePath + )); + } + ) + ); + + $this->setMockResolverCreatorProperties($moduleResolverService); + $resolver = ModuleResolver::getInstance(); + $this->setMockResolverProperties($resolver, null, []); + $this->assertEquals([], $resolver->getModulesPath()); + } + /** * Validate aggregateTestModulePathsFromComposerJson. * @@ -110,8 +204,11 @@ public function testAggregateTestModulePathsFromComposerJson(): void { $this->mockForceGenerate(false); - $moduleResolverService = $this->createMock(ModuleResolverService::class); - $moduleResolverService->expects($this->any()) + $moduleResolverService = $this->createPartialMock( + ModuleResolverService::class, ['getComposerJsonTestModulePaths'] + ); + $moduleResolverService + ->expects($this->any()) ->method('getComposerJsonTestModulePaths') ->willReturn( [ @@ -139,6 +236,63 @@ public function testAggregateTestModulePathsFromComposerJson(): void ); } + /** + * Validate getComposerJsonTestModulePaths with paths invocation. + * + * @return void + * @throws Exception + */ + public function testGetComposerJsonTestModulePathsForPathInvocation(): void + { + $this->mockForceGenerate(false); + + // Expected dev tests path + $expectedSearchPaths[] = MAGENTO_BP + . DIRECTORY_SEPARATOR + . 'dev' + . DIRECTORY_SEPARATOR + . 'tests' + . DIRECTORY_SEPARATOR + . 'acceptance' + . DIRECTORY_SEPARATOR + . 'tests' + . DIRECTORY_SEPARATOR + . 'functional'; + + // Expected test module path + $testModulePath = defined('TESTS_MODULE_PATH') ? TESTS_MODULE_PATH : TESTS_BP; + + if (array_search($testModulePath, $expectedSearchPaths) === false) { + $expectedSearchPaths[] = $testModulePath; + } + + $moduleResolverService = $this->createPartialMock( + ModuleResolverService::class, + ['getComposerJsonTestModulePaths'] + ); + $moduleResolverService + ->method('getComposerJsonTestModulePaths') + ->will( + $this->returnCallback( + function ($codePaths) use ($expectedSearchPaths) { + if ($codePaths === $expectedSearchPaths) { + return []; + } + + $this->fail(sprintf( + 'Not expected parameter: \'%s\' when invoked method getComposerJsonTestModulePaths().', + $codePaths + )); + } + ) + ); + + $this->setMockResolverCreatorProperties($moduleResolverService); + $resolver = ModuleResolver::getInstance(); + $this->setMockResolverProperties($resolver, null, []); + $this->assertEquals([], $resolver->getModulesPath()); + } + /** * Validate aggregateTestModulePathsFromComposerInstaller. * @@ -148,7 +302,9 @@ public function testAggregateTestModulePathsFromComposerJson(): void public function testAggregateTestModulePathsFromComposerInstaller(): void { $this->mockForceGenerate(false); - $moduleResolverService = $this->createMock(ModuleResolverService::class); + $moduleResolverService = $this->createPartialMock( + ModuleResolverService::class, ['getComposerInstalledTestModulePaths'] + ); $moduleResolverService->expects($this->any()) ->method('getComposerInstalledTestModulePaths') ->willReturn( @@ -182,6 +338,45 @@ public function testAggregateTestModulePathsFromComposerInstaller(): void ); } + /** + * Validate getComposerInstalledTestModulePaths with paths invocation. + * + * @return void + * @throws Exception + */ + public function testGetComposerInstalledTestModulePathsForPathInvocation(): void + { + $this->mockForceGenerate(false); + + // Expected file path + $expectedSearchPath = MAGENTO_BP . DIRECTORY_SEPARATOR . 'composer.json'; + $moduleResolverService = $this->createPartialMock( + ModuleResolverService::class, + ['getComposerInstalledTestModulePaths'] + ); + $moduleResolverService + ->method('getComposerInstalledTestModulePaths') + ->will( + $this->returnCallback( + function ($composerFile) use ($expectedSearchPath) { + if ($composerFile === $expectedSearchPath) { + return []; + } + + $this->fail(sprintf( + 'Not expected parameter: \'%s\' when invoked method getComposerInstalledTestModulePaths().', + $composerFile + )); + } + ) + ); + + $this->setMockResolverCreatorProperties($moduleResolverService); + $resolver = ModuleResolver::getInstance(); + $this->setMockResolverProperties($resolver, null, []); + $this->assertEquals([], $resolver->getModulesPath()); + } + /** * Validate mergeModulePaths() and flipAndFilterModulePathsArray(). * @@ -191,7 +386,10 @@ public function testAggregateTestModulePathsFromComposerInstaller(): void public function testMergeFlipAndFilterModulePathsNoForceGenerate(): void { $this->mockForceGenerate(false); - $moduleResolverService = $this->createMock(ModuleResolverService::class); + $moduleResolverService = $this->createPartialMock( + ModuleResolverService::class, + ['getComposerJsonTestModulePaths', 'getComposerInstalledTestModulePaths', 'aggregateTestModulePaths'] + ); $moduleResolverService->expects($this->any()) ->method('getComposerJsonTestModulePaths') ->willReturn( @@ -278,7 +476,10 @@ public function testMergeFlipAndFilterModulePathsNoForceGenerate(): void public function testMergeFlipNoSortModulePathsNoForceGenerate(): void { $this->mockForceGenerate(false); - $moduleResolverService = $this->createMock(ModuleResolverService::class); + $moduleResolverService = $this->createPartialMock( + ModuleResolverService::class, + ['getComposerJsonTestModulePaths', 'getComposerInstalledTestModulePaths', 'aggregateTestModulePaths'] + ); $moduleResolverService->expects($this->any()) ->method('getComposerJsonTestModulePaths') ->willReturn( @@ -357,7 +558,10 @@ public function testMergeFlipNoSortModulePathsNoForceGenerate(): void public function testMergeFlipAndSortModulePathsForceGenerate(): void { $this->mockForceGenerate(true); - $moduleResolverService = $this->createMock(ModuleResolverService::class); + $moduleResolverService = $this->createPartialMock( + ModuleResolverService::class, + ['getComposerJsonTestModulePaths', 'getComposerInstalledTestModulePaths', 'aggregateTestModulePaths'] + ); $moduleResolverService->expects($this->any()) ->method('getComposerJsonTestModulePaths') ->willReturn( @@ -441,7 +645,10 @@ public function testMergeFlipAndSortModulePathsForceGenerate(): void public function testMergeFlipAndFilterModulePathsWithLogging(): void { $this->mockForceGenerate(false); - $moduleResolverService = $this->createMock(ModuleResolverService::class); + $moduleResolverService = $this->createPartialMock( + ModuleResolverService::class, + ['getComposerJsonTestModulePaths', 'getComposerInstalledTestModulePaths'] + ); $moduleResolverService->expects($this->any()) ->method('getComposerJsonTestModulePaths') ->willReturn( @@ -506,11 +713,18 @@ public function testMergeFlipAndFilterModulePathsWithLogging(): void public function testApplyCustomModuleMethods(): void { $this->mockForceGenerate(true); - $moduleResolverService = $this->createMock(ModuleResolverService::class); + $moduleResolverService = $this->createPartialMock( + ModuleResolverService::class, + ['getCustomModulePaths', 'aggregateTestModulePaths'] + ); $moduleResolverService->expects($this->any()) ->method('getCustomModulePaths') ->willReturn(['Magento_Module' => 'otherPath']); + $moduleResolverService + ->method('aggregateTestModulePaths') + ->willReturn([]); + $this->setMockResolverCreatorProperties($moduleResolverService); $resolver = ModuleResolver::getInstance(); $this->setMockResolverProperties($resolver); @@ -531,7 +745,7 @@ public function testApplyCustomModuleMethods(): void public function testGetModulePathsBlocklist(): void { $this->mockForceGenerate(true); - $moduleResolverService = $this->createMock(ModuleResolverService::class); + $moduleResolverService = $this->createPartialMock(ModuleResolverService::class, ['aggregateTestModulePaths']); $moduleResolverService->expects($this->any()) ->method('aggregateTestModulePaths') ->willReturn( @@ -567,6 +781,12 @@ public function testGetModulePathsNoAdminToken(): void { // Set --force to false $this->mockForceGenerate(false); + $moduleResolverService = $this->createPartialMock(ModuleResolverService::class, ['applyCustomModuleMethods']); + $moduleResolverService + ->method('applyCustomModuleMethods') + ->willReturn(["example" . DIRECTORY_SEPARATOR . "paths"]); + + $this->setMockResolverCreatorProperties($moduleResolverService); $resolver = ModuleResolver::getInstance(); $this->setMockResolverProperties($resolver); @@ -575,17 +795,52 @@ public function testGetModulePathsNoAdminToken(): void $resolver->getModulesPath(); } + /** + * Validates that getAdminToken is not called when --force is enabled. + * + * @return void + * @throws Exception + */ + public function testGetAdminTokenNotCalledWhenForce(): void + { + // Set --force to true + $this->mockForceGenerate(true); + + // Mock ModuleResolver and applyCustomModuleMethods() + $moduleResolverService = $this->createMock(ModuleResolverService::class); + $moduleResolverService + ->method('getAdminToken') + ->with( + $this->returnCallback( + function () { + $this->fail('Not expected to call method \'getAdminToken()\'.'); + } + ) + ); + + $this->setMockResolverCreatorProperties($moduleResolverService); + $resolver = ModuleResolver::getInstance(); + $this->setMockResolverProperties($resolver, null, []); + $resolver->getModulesPath(); + $this->addToAssertionCount(1); + } + /** * Verify the getAdminToken method returns throws an exception if ENV is not fully loaded. + * + * @return void + * @throws Exception */ public function testGetAdminTokenWithMissingEnv(): void { // Set --force to false $this->mockForceGenerate(false); + $this->setMockResolverCreatorProperties(null); // Unset env unset($_ENV['MAGENTO_ADMIN_USERNAME']); $resolver = ModuleResolver::getInstance(); + $this->setMockResolverProperties($resolver); // Expect exception $this->expectException(FastFailException::class); @@ -594,12 +849,18 @@ public function testGetAdminTokenWithMissingEnv(): void /** * Verify the getAdminToken method returns throws an exception if Token was bad. + * + * @return void + * @throws Exception */ public function testGetAdminTokenWithBadResponse(): void { // Set --force to false $this->mockForceGenerate(false); + $this->setMockResolverCreatorProperties(null); + $resolver = ModuleResolver::getInstance(); + $this->setMockResolverProperties($resolver); // Expect exception $this->expectException(FastFailException::class); @@ -610,18 +871,17 @@ public function testGetAdminTokenWithBadResponse(): void * Function used to set mock for Resolver properties. * * @param ModuleResolver $instance - * @param array $mockPaths - * @param array $mockModules - * @param array $mockBlocklist + * @param null $mockPaths + * @param null $mockModules + * @param array $mockBlockList * * @return void - * @throws Exception */ private function setMockResolverProperties( ModuleResolver $instance, $mockPaths = null, $mockModules = null, - $mockBlocklist = [] + $mockBlockList = [] ): void { $property = new ReflectionProperty(ModuleResolver::class, 'enabledModulePaths'); $property->setAccessible(true); @@ -631,19 +891,19 @@ private function setMockResolverProperties( $property->setAccessible(true); $property->setValue($instance, $mockModules); - $property = new ReflectionProperty(ModuleResolver::class, 'moduleBlocklist'); + $property = new ReflectionProperty(ModuleResolverService::class, 'moduleBlockList'); $property->setAccessible(true); - $property->setValue($instance, $mockBlocklist); + $property->setValue($mockBlockList); } /** * Function used to set mock for ResolverCreator properties. * - * @param MockObject $moduleResolverService + * @param MockObject|null $moduleResolverService * * @return void */ - private function setMockResolverCreatorProperties(MockObject $moduleResolverService): void + private function setMockResolverCreatorProperties(?MockObject $moduleResolverService): void { $property = new ReflectionProperty(ModuleResolverService::class, 'INSTANCE'); $property->setAccessible(true); diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index 09ff90dfc..4a8ff1403 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -12,7 +12,6 @@ use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; -use Magento\FunctionalTestingFramework\DataTransport\Auth\WebApiAuth; use \Magento\FunctionalTestingFramework\Util\ModuleResolver\AlphabeticSequenceSorter; use \Magento\FunctionalTestingFramework\Util\ModuleResolver\SequenceSorterInterface; @@ -128,15 +127,6 @@ class ModuleResolver */ protected $sequenceSorter; - /** - * List of module names that will be ignored. - * - * @var array - */ - protected $moduleBlocklist = [ - 'SampleTests', 'SampleTemplates' - ]; - /** * Get ModuleResolver instance. * @@ -180,7 +170,7 @@ public function getEnabledModules() $this->printMagentoVersionInfo(); } - $token = WebApiAuth::getAdminToken(); + $token = ModuleResolverService::getInstance()->getAdminToken(); $url = UrlFormatter::format(getenv('MAGENTO_BASE_URL')) . $this->moduleUrl; @@ -515,24 +505,6 @@ private function normalizeModuleNames($codePaths) return $normalizedCodePaths; } - /** - * Takes a multidimensional array of module paths and flattens to return a one dimensional array of test paths - * - * @param array $modulePaths - * @return array - */ - private function flattenAllModulePaths($modulePaths) - { - $it = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($modulePaths)); - $resultArray = []; - - foreach ($it as $value) { - $resultArray[] = $value; - } - - return $resultArray; - } - /** * Executes a REST call to the supplied Magento Base Url for version information to display during generation * @@ -569,66 +541,11 @@ private function printMagentoVersionInfo() * * @param array $modulesPath * @return string[] + * @throws TestFrameworkException */ protected function applyCustomModuleMethods($modulesPath) { - $modulePathsResult = $this->removeBlocklistModules($modulesPath); - $customModulePaths = $this->getCustomModulePaths(); - - array_map(function ($key, $value) { - LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->info( - "including custom module", - [$key => $value] - ); - }, array_keys($customModulePaths), $customModulePaths); - - if (!isset($this->enabledModuleNameAndPaths)) { - $this->enabledModuleNameAndPaths = array_merge($modulePathsResult, $customModulePaths); - } - return $this->flattenAllModulePaths(array_merge($modulePathsResult, $customModulePaths)); - } - - /** - * Remove blocklist modules from input module paths. - * - * @param array $modulePaths - * @return string[] - */ - private function removeBlocklistModules($modulePaths) - { - $modulePathsResult = $modulePaths; - foreach ($modulePathsResult as $moduleName => $modulePath) { - // Remove module if it is in blocklist - if (in_array($moduleName, $this->getModuleBlocklist())) { - unset($modulePathsResult[$moduleName]); - LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->info( - "excluding module", - ['module' => $moduleName] - ); - } - } - - return $modulePathsResult; - } - - /** - * Returns an array of custom module paths defined by the user - * - * @return string[] - */ - private function getCustomModulePaths() - { - return ModuleResolverService::getInstance()->getCustomModulePaths(); - } - - /** - * Getter for moduleBlocklist. - * - * @return string[] - */ - private function getModuleBlocklist() - { - return $this->moduleBlocklist; + return ModuleResolverService::getInstance()->applyCustomModuleMethods($modulesPath); } /** diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver/ModuleResolverService.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver/ModuleResolverService.php index c3dad2118..0efcb4c54 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver/ModuleResolverService.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver/ModuleResolverService.php @@ -9,11 +9,15 @@ use Magento\Framework\Component\ComponentRegistrar; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\DataTransport\Auth\WebApiAuth; +use Magento\FunctionalTestingFramework\Exceptions\FastFailException; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Util\ComposerModuleResolver; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; use Magento\FunctionalTestingFramework\Util\ModuleResolver; use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; +use RecursiveArrayIterator; +use RecursiveIteratorIterator; class ModuleResolverService { @@ -38,6 +42,15 @@ class ModuleResolverService */ private $composerInstalledModulePaths = null; + /** + * List of module names that will be ignored. + * + * @var array + */ + private static $moduleBlockList = [ + 'SampleTests', 'SampleTemplates' + ]; + /** * ModuleResolverService constructor. */ @@ -319,4 +332,96 @@ private function findVendorNameFromPath(string $path): string return $possibleVendorName; } + + /** + * Getter for moduleBlockList. + * + * @return string[] + */ + private function getModuleBlockList(): array + { + return self::$moduleBlockList; + } + + /** + * Get admin token. + * + * @return string + * @throws FastFailException + */ + public function getAdminToken(): string + { + return WebApiAuth::getAdminToken(); + } + + /** + * A wrapping method for any custom logic which needs to be applied to the module list. + * + * @param array $modulesPath + * + * @return string[] + * @throws TestFrameworkException + */ + public function applyCustomModuleMethods(array $modulesPath): array + { + $modulePathsResult = $this->removeBlockListModules($modulesPath); + $customModulePaths = $this->getCustomModulePaths(); + + array_map(function ($key, $value) { + LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->info( + "including custom module", + [$key => $value] + ); + }, array_keys($customModulePaths), $customModulePaths); + + if (!isset($this->enabledModuleNameAndPaths)) { + $this->enabledModuleNameAndPaths = array_merge($modulePathsResult, $customModulePaths); + } + return $this->flattenAllModulePaths(array_merge($modulePathsResult, $customModulePaths)); + } + + /** + * Remove blockList modules from input module paths. + * + * @param array $modulePaths + * + * @return string[] + * @throws TestFrameworkException + */ + private function removeBlockListModules(array $modulePaths): array + { + $modulePathsResult = $modulePaths; + + foreach ($modulePathsResult as $moduleName => $modulePath) { + // Remove module if it is in blocklist + if (in_array($moduleName, $this->getModuleBlockList())) { + unset($modulePathsResult[$moduleName]); + LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->info( + "excluding module", + ['module' => $moduleName] + ); + } + } + + return $modulePathsResult; + } + + /** + * Takes a multidimensional array of module paths and flattens to return a one dimensional array of test paths. + * + * @param array $modulePaths + * + * @return array + */ + private function flattenAllModulePaths(array $modulePaths): array + { + $it = new RecursiveIteratorIterator(new RecursiveArrayIterator($modulePaths)); + $resultArray = []; + + foreach ($it as $value) { + $resultArray[] = $value; + } + + return $resultArray; + } } From d4af1784c7132d516636e11dc81fce9dea9dc8f3 Mon Sep 17 00:00:00 2001 From: "andrii.zinkevych" <a.zinkevych@atwix.com> Date: Thu, 29 Jul 2021 11:54:24 +0300 Subject: [PATCH 685/888] 33308: Fixed static-tests --- .../Util/ModuleResolverTest.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php index 368fd2149..9339798dc 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php @@ -70,7 +70,8 @@ public function testGetModulePathsAggregate(): void $this->mockForceGenerate(false); $moduleResolverService = $this->createPartialMock( - ModuleResolverService::class, ['getRegisteredModuleList', 'aggregateTestModulePaths'] + ModuleResolverService::class, + ['getRegisteredModuleList', 'aggregateTestModulePaths'] ); $moduleResolverService->expects($this->any()) ->method('getRegisteredModuleList') @@ -137,7 +138,6 @@ function ($codePath, $pattern) use ($modulePath) { $this->setMockResolverProperties($resolver, null, []); $this->assertEquals([], $resolver->getModulesPath()); - putenv("TESTS_MODULE_PATH=$origin"); } @@ -205,7 +205,8 @@ public function testAggregateTestModulePathsFromComposerJson(): void $this->mockForceGenerate(false); $moduleResolverService = $this->createPartialMock( - ModuleResolverService::class, ['getComposerJsonTestModulePaths'] + ModuleResolverService::class, + ['getComposerJsonTestModulePaths'] ); $moduleResolverService ->expects($this->any()) @@ -303,7 +304,8 @@ public function testAggregateTestModulePathsFromComposerInstaller(): void { $this->mockForceGenerate(false); $moduleResolverService = $this->createPartialMock( - ModuleResolverService::class, ['getComposerInstalledTestModulePaths'] + ModuleResolverService::class, + ['getComposerInstalledTestModulePaths'] ); $moduleResolverService->expects($this->any()) ->method('getComposerInstalledTestModulePaths') From 3330a671ee21f09f7ffd3da90bf51bb5c123cb33 Mon Sep 17 00:00:00 2001 From: "andrii.zinkevych" <a.zinkevych@atwix.com> Date: Thu, 29 Jul 2021 14:00:20 +0300 Subject: [PATCH 686/888] 33308: Fixed verification-tests --- .../Util/ModuleResolverTest.php | 9 +- .../Util/ModuleResolver.php | 87 +++++++++++++++++- .../ModuleResolver/ModuleResolverService.php | 92 ------------------- 3 files changed, 86 insertions(+), 102 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php index 9339798dc..dab34e37e 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php @@ -783,12 +783,7 @@ public function testGetModulePathsNoAdminToken(): void { // Set --force to false $this->mockForceGenerate(false); - $moduleResolverService = $this->createPartialMock(ModuleResolverService::class, ['applyCustomModuleMethods']); - $moduleResolverService - ->method('applyCustomModuleMethods') - ->willReturn(["example" . DIRECTORY_SEPARATOR . "paths"]); - $this->setMockResolverCreatorProperties($moduleResolverService); $resolver = ModuleResolver::getInstance(); $this->setMockResolverProperties($resolver); @@ -893,9 +888,9 @@ private function setMockResolverProperties( $property->setAccessible(true); $property->setValue($instance, $mockModules); - $property = new ReflectionProperty(ModuleResolverService::class, 'moduleBlockList'); + $property = new ReflectionProperty(ModuleResolver::class, 'moduleBlocklist'); $property->setAccessible(true); - $property->setValue($mockBlockList); + $property->setValue($instance, $mockBlockList); } /** diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index 4a8ff1403..d3511bbea 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -127,6 +127,15 @@ class ModuleResolver */ protected $sequenceSorter; + /** + * List of module names that will be ignored. + * + * @var array + */ + protected $moduleBlocklist = [ + 'SampleTests', 'SampleTemplates' + ]; + /** * Get ModuleResolver instance. * @@ -315,7 +324,6 @@ private function aggregateTestModulePathsFromComposerJson() * Retrieve all module code paths that have test module composer json files * * @param array $codePaths - * * @return array */ private function getComposerJsonTestModulePaths($codePaths) @@ -505,6 +513,24 @@ private function normalizeModuleNames($codePaths) return $normalizedCodePaths; } + /** + * Takes a multidimensional array of module paths and flattens to return a one dimensional array of test paths + * + * @param array $modulePaths + * @return array + */ + private function flattenAllModulePaths($modulePaths) + { + $it = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($modulePaths)); + $resultArray = []; + + foreach ($it as $value) { + $resultArray[] = $value; + } + + return $resultArray; + } + /** * Executes a REST call to the supplied Magento Base Url for version information to display during generation * @@ -541,11 +567,66 @@ private function printMagentoVersionInfo() * * @param array $modulesPath * @return string[] - * @throws TestFrameworkException */ protected function applyCustomModuleMethods($modulesPath) { - return ModuleResolverService::getInstance()->applyCustomModuleMethods($modulesPath); + $modulePathsResult = $this->removeBlocklistModules($modulesPath); + $customModulePaths = $this->getCustomModulePaths(); + + array_map(function ($key, $value) { + LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->info( + "including custom module", + [$key => $value] + ); + }, array_keys($customModulePaths), $customModulePaths); + + if (!isset($this->enabledModuleNameAndPaths)) { + $this->enabledModuleNameAndPaths = array_merge($modulePathsResult, $customModulePaths); + } + return $this->flattenAllModulePaths(array_merge($modulePathsResult, $customModulePaths)); + } + + /** + * Remove blocklist modules from input module paths. + * + * @param array $modulePaths + * @return string[] + */ + private function removeBlocklistModules($modulePaths) + { + $modulePathsResult = $modulePaths; + foreach ($modulePathsResult as $moduleName => $modulePath) { + // Remove module if it is in blocklist + if (in_array($moduleName, $this->getModuleBlocklist())) { + unset($modulePathsResult[$moduleName]); + LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->info( + "excluding module", + ['module' => $moduleName] + ); + } + } + + return $modulePathsResult; + } + + /** + * Returns an array of custom module paths defined by the user + * + * @return string[] + */ + private function getCustomModulePaths() + { + return ModuleResolverService::getInstance()->getCustomModulePaths(); + } + + /** + * Getter for moduleBlocklist. + * + * @return string[] + */ + private function getModuleBlocklist() + { + return $this->moduleBlocklist; } /** diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver/ModuleResolverService.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver/ModuleResolverService.php index 0efcb4c54..015fa4e9f 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver/ModuleResolverService.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver/ModuleResolverService.php @@ -16,8 +16,6 @@ use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; use Magento\FunctionalTestingFramework\Util\ModuleResolver; use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; -use RecursiveArrayIterator; -use RecursiveIteratorIterator; class ModuleResolverService { @@ -42,15 +40,6 @@ class ModuleResolverService */ private $composerInstalledModulePaths = null; - /** - * List of module names that will be ignored. - * - * @var array - */ - private static $moduleBlockList = [ - 'SampleTests', 'SampleTemplates' - ]; - /** * ModuleResolverService constructor. */ @@ -333,16 +322,6 @@ private function findVendorNameFromPath(string $path): string return $possibleVendorName; } - /** - * Getter for moduleBlockList. - * - * @return string[] - */ - private function getModuleBlockList(): array - { - return self::$moduleBlockList; - } - /** * Get admin token. * @@ -353,75 +332,4 @@ public function getAdminToken(): string { return WebApiAuth::getAdminToken(); } - - /** - * A wrapping method for any custom logic which needs to be applied to the module list. - * - * @param array $modulesPath - * - * @return string[] - * @throws TestFrameworkException - */ - public function applyCustomModuleMethods(array $modulesPath): array - { - $modulePathsResult = $this->removeBlockListModules($modulesPath); - $customModulePaths = $this->getCustomModulePaths(); - - array_map(function ($key, $value) { - LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->info( - "including custom module", - [$key => $value] - ); - }, array_keys($customModulePaths), $customModulePaths); - - if (!isset($this->enabledModuleNameAndPaths)) { - $this->enabledModuleNameAndPaths = array_merge($modulePathsResult, $customModulePaths); - } - return $this->flattenAllModulePaths(array_merge($modulePathsResult, $customModulePaths)); - } - - /** - * Remove blockList modules from input module paths. - * - * @param array $modulePaths - * - * @return string[] - * @throws TestFrameworkException - */ - private function removeBlockListModules(array $modulePaths): array - { - $modulePathsResult = $modulePaths; - - foreach ($modulePathsResult as $moduleName => $modulePath) { - // Remove module if it is in blocklist - if (in_array($moduleName, $this->getModuleBlockList())) { - unset($modulePathsResult[$moduleName]); - LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->info( - "excluding module", - ['module' => $moduleName] - ); - } - } - - return $modulePathsResult; - } - - /** - * Takes a multidimensional array of module paths and flattens to return a one dimensional array of test paths. - * - * @param array $modulePaths - * - * @return array - */ - private function flattenAllModulePaths(array $modulePaths): array - { - $it = new RecursiveIteratorIterator(new RecursiveArrayIterator($modulePaths)); - $resultArray = []; - - foreach ($it as $value) { - $resultArray[] = $value; - } - - return $resultArray; - } } From caa283c02056f9c312980f119c501d370404a090 Mon Sep 17 00:00:00 2001 From: "andrii.zinkevych" <a.zinkevych@atwix.com> Date: Fri, 30 Jul 2021 22:54:10 +0300 Subject: [PATCH 687/888] 33308: Fixed code after review --- .../Util/ModuleResolver.php | 63 ++----------------- 1 file changed, 5 insertions(+), 58 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index d3511bbea..b04168673 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -214,6 +214,7 @@ public function getEnabledModules() * * @param boolean $verbosePath * @return array + * @throws TestFrameworkException */ public function getModulesPath($verbosePath = false) { @@ -226,7 +227,7 @@ public function getModulesPath($verbosePath = false) } // Find test modules paths by searching patterns (Test/Mftf, etc) - $allModulePaths = $this->aggregateTestModulePaths(); + $allModulePaths = ModuleResolverService::getInstance()->aggregateTestModulePaths(); // Find test modules paths by searching test composer.json files $composerBasedModulePaths = $this->aggregateTestModulePathsFromComposerJson(); @@ -282,17 +283,6 @@ protected function getModuleAllowlist() return array_map('trim', explode(',', $moduleAllowlist)); } - /** - * Retrieves all module directories which might contain pertinent test code. - * - * @return array - * @throws TestFrameworkException - */ - private function aggregateTestModulePaths() - { - return ModuleResolverService::getInstance()->aggregateTestModulePaths(); - } - /** * Aggregate all code paths with test module composer json files * @@ -317,18 +307,7 @@ private function aggregateTestModulePathsFromComposerJson() $searchCodePaths[] = $modulePath; } - return $this->getComposerJsonTestModulePaths($searchCodePaths); - } - - /** - * Retrieve all module code paths that have test module composer json files - * - * @param array $codePaths - * @return array - */ - private function getComposerJsonTestModulePaths($codePaths) - { - return ModuleResolverService::getInstance()->getComposerJsonTestModulePaths($codePaths); + return ModuleResolverService::getInstance()->getComposerJsonTestModulePaths($searchCodePaths); } /** @@ -342,18 +321,6 @@ private function aggregateTestModulePathsFromComposerInstaller() $magentoBaseCodePath = MAGENTO_BP; $composerFile = $magentoBaseCodePath . DIRECTORY_SEPARATOR . 'composer.json'; - return $this->getComposerInstalledTestModulePaths($composerFile); - } - - /** - * Retrieve composer installed test module code paths - * - * @param string $composerFile - * - * @return array - */ - private function getComposerInstalledTestModulePaths($composerFile) - { return ModuleResolverService::getInstance()->getComposerInstalledTestModulePaths($composerFile); } @@ -495,7 +462,7 @@ private function mergeModulePaths($oneToOneArray, $oneToManyArray) */ private function normalizeModuleNames($codePaths) { - $allComponents = $this->getRegisteredModuleList(); + $allComponents = ModuleResolverService::getInstance()->getRegisteredModuleList(); if (empty($allComponents)) { return $codePaths; } @@ -571,7 +538,7 @@ private function printMagentoVersionInfo() protected function applyCustomModuleMethods($modulesPath) { $modulePathsResult = $this->removeBlocklistModules($modulesPath); - $customModulePaths = $this->getCustomModulePaths(); + $customModulePaths = ModuleResolverService::getInstance()->getCustomModulePaths(); array_map(function ($key, $value) { LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->info( @@ -609,16 +576,6 @@ private function removeBlocklistModules($modulePaths) return $modulePathsResult; } - /** - * Returns an array of custom module paths defined by the user - * - * @return string[] - */ - private function getCustomModulePaths() - { - return ModuleResolverService::getInstance()->getCustomModulePaths(); - } - /** * Getter for moduleBlocklist. * @@ -629,16 +586,6 @@ private function getModuleBlocklist() return $this->moduleBlocklist; } - /** - * Calls Magento method for determining registered modules. - * - * @return string[] - */ - private function getRegisteredModuleList() - { - return ModuleResolverService::getInstance()->getRegisteredModuleList(); - } - /** * Find vendor and module name from path * From 3a1ae0dd7575b077b3ae8fadfb684de82469244b Mon Sep 17 00:00:00 2001 From: "andrii.zinkevych" <a.zinkevych@atwix.com> Date: Wed, 4 Aug 2021 11:35:21 +0300 Subject: [PATCH 688/888] 33308: Fixed method testGetModulePathsLocations --- .../Util/ModuleResolverTest.php | 51 +++++++++++++------ 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php index dab34e37e..25fd20d73 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php @@ -118,7 +118,6 @@ public function testAggregateTestModulePathsDevTests(): void $moduleResolverService = $this->createPartialMock(ModuleResolverService::class, ['globRelevantPaths']); $moduleResolverService ->method('globRelevantPaths') - ->withConsecutive() ->will( $this->returnCallback( function ($codePath, $pattern) use ($modulePath) { @@ -157,32 +156,42 @@ public function testGetModulePathsLocations(): void $this->mockForceGenerate(false); // Define the Module paths from default TESTS_MODULE_PATH $modulePath = defined('TESTS_MODULE_PATH') ? TESTS_MODULE_PATH : TESTS_BP; - - // Define the Module paths from app/code - $magentoBaseCodePath = MAGENTO_BP; + $invokedWithParams = $expectedParams = [ + [ + $modulePath, + '' + ], + [ + MAGENTO_BP . '/vendor', + 'Test/Mftf' + ], + [ + MAGENTO_BP . '/app/code', + 'Test/Mftf' + ] + ]; $moduleResolverService = $this->createPartialMock(ModuleResolverService::class, ['globRelevantPaths']); $moduleResolverService ->method('globRelevantPaths') - ->withConsecutive() ->will( $this->returnCallback( - function ($codePath, $pattern) use ($modulePath, $magentoBaseCodePath) { - if ($codePath === $modulePath && $pattern === '') { - return []; - } + function ($codePath, $pattern) use (&$invokedWithParams, $expectedParams) { + foreach ($expectedParams as $key => $parameter) { + list($expectedCodePath, $expectedPattern) = $parameter; - if ($codePath === $magentoBaseCodePath . '/vendor' && $pattern === 'Test/Mftf') { - return []; - } + if ($codePath === $expectedCodePath && $pattern === $expectedPattern) { + if (isset($invokedWithParams[$key])) { + unset($invokedWithParams[$key]); + } - if ($codePath === $magentoBaseCodePath . "/app/code" && $pattern === 'Test/Mftf') { - return []; + return []; + } } $this->fail(sprintf( - 'Not expected parameter: \'%s\' when invoked method globRelevantPaths().', - $modulePath + 'Not expected parameter: [%s] when invoked method globRelevantPaths().', + $codePath . ';' . $pattern )); } ) @@ -192,6 +201,16 @@ function ($codePath, $pattern) use ($modulePath, $magentoBaseCodePath) { $resolver = ModuleResolver::getInstance(); $this->setMockResolverProperties($resolver, null, []); $this->assertEquals([], $resolver->getModulesPath()); + + if ($invokedWithParams) { + $parameters = ''; + + foreach ($invokedWithParams as $parameter) { + $parameters .= sprintf('[%s]', implode(';', $parameter)); + } + + $this->fail('The method globRelevantPaths() was not called with expected parameters:' . $parameters); + } } /** From d98d930606cecd8b0ace8fc75080ef840c3a7509 Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Mon, 9 Aug 2021 15:03:08 +0300 Subject: [PATCH 689/888] MFTF-33306: Fixed error after branch actualization --- .../Util/TestGeneratorTest.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php index 730493191..66a2919d4 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php @@ -11,11 +11,13 @@ use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Filter\FilterList; +use Magento\FunctionalTestingFramework\ObjectManager; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Magento\FunctionalTestingFramework\Test\Objects\TestHookObject; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; use Magento\FunctionalTestingFramework\Util\Filesystem\CestFileCreatorUtil; use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; +use Magento\FunctionalTestingFramework\Util\ModuleResolver; use Magento\FunctionalTestingFramework\Util\TestGenerator; use ReflectionProperty; use tests\unit\Util\MagentoTestCase; @@ -23,6 +25,22 @@ class TestGeneratorTest extends MagentoTestCase { + /** + * @inheritdoc + */ + public static function setUpBeforeClass(): void + { + parent::setUpBeforeClass(); + + $property = new ReflectionProperty(ObjectManager::class, 'instance'); + $property->setAccessible(true); + $property->setValue(null); + + $property = new ReflectionProperty(ModuleResolver::class, 'instance'); + $property->setAccessible(true); + $property->setValue(null); + } + /** * Before method functionality. * From d920627c788f95c3e6a43829623e8b2bfdb2ba3f Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Mon, 9 Aug 2021 17:45:45 +0300 Subject: [PATCH 690/888] MFTF-33294: Fixed strict type issue --- .../Allure/Event/AddUniqueAttachmentEvent.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php b/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php index d6f36f953..af0ed2c52 100644 --- a/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php +++ b/src/Magento/FunctionalTestingFramework/Allure/Event/AddUniqueAttachmentEvent.php @@ -31,7 +31,7 @@ public function getAttachmentFileName($filePathOrContents, $type): string { $filePath = $filePathOrContents; - if (!file_exists($filePath) || !is_file($filePath)) { + if (!is_string($filePath) || !file_exists($filePath) || !is_file($filePath)) { //Save contents to temporary file $filePath = tempnam(sys_get_temp_dir(), 'allure-attachment'); if (!file_put_contents($filePath, $filePathOrContents)) { From 3ace8dcc8a4bea05fbdf317e42aa0b8c801b400c Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Mon, 9 Aug 2021 21:10:54 +0300 Subject: [PATCH 691/888] MFTF-33306: Fixed wrong action count value for test --- .../Util/Sorter/ParallelGroupSorterTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Sorter/ParallelGroupSorterTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Sorter/ParallelGroupSorterTest.php index e289532b5..edc244e1b 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Sorter/ParallelGroupSorterTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Sorter/ParallelGroupSorterTest.php @@ -64,7 +64,7 @@ public function testBasicTestsSplitByTime(): void public function testTestsAndSuitesSplitByTime(): void { // mock tests for test object handler. - $this->createMockForTest(0); + $this->createMockForTest(0, [300, 275]); // create test to size array $sampleTestArray = [ @@ -421,17 +421,17 @@ public static function tearDownAfterClass(): void * Mock test object and test object handler. * * @param int $numberOfCalls + * @param array $actionCount * * @return void */ - private function createMockForTest(int $numberOfCalls): void + private function createMockForTest(int $numberOfCalls, array $actionCount = [300, 275, 300, 275]): void { $mockTest1 = $this->createMock(TestObject::class); $mockTest1 ->method('getEstimatedDuration') ->willReturnCallback( - function () use (&$numberOfCalls) { - $actionCount = [300, 275, 300, 275]; + function () use (&$numberOfCalls, $actionCount) { $result = $actionCount[$numberOfCalls]; $numberOfCalls++; From 89812a2233590fea15518edc5928b45a0d806451 Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Wed, 11 Aug 2021 16:52:08 +0300 Subject: [PATCH 692/888] MFTF-33308: Fixed failed test --- .../Util/TestGeneratorTest.php | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php index 66a2919d4..800c506f1 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php @@ -12,6 +12,7 @@ use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Filter\FilterList; use Magento\FunctionalTestingFramework\ObjectManager; +use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Magento\FunctionalTestingFramework\Test\Objects\TestHookObject; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; @@ -19,6 +20,7 @@ use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; use Magento\FunctionalTestingFramework\Util\ModuleResolver; use Magento\FunctionalTestingFramework\Util\TestGenerator; +use ReflectionClass; use ReflectionProperty; use tests\unit\Util\MagentoTestCase; use tests\unit\Util\TestLoggingUtil; @@ -75,6 +77,8 @@ public function testEntityException(): void $testObject = new TestObject('sampleTest', ['merge123' => $actionObject], [], [], 'filename'); $testGeneratorObject = TestGenerator::getInstance('', ['sampleTest' => $testObject]); + $this->mockTestObjectHandler(); + $testGeneratorObject->createAllTestFiles(null, []); // assert that no exception for createAllTestFiles and generation error is stored in GenerationErrorHandler @@ -231,5 +235,25 @@ public static function tearDownAfterClass(): void $mftfAppConfigInstance = new ReflectionProperty(MftfApplicationConfig::class, 'MFTF_APPLICATION_CONTEXT'); $mftfAppConfigInstance->setAccessible(true); $mftfAppConfigInstance->setValue(null); + + $property = new ReflectionProperty(TestObjectHandler::class, 'testObjectHandler'); + $property->setAccessible(true); + $property->setValue(null); + } + + /** + * Mock test object handler for test. + */ + private function mockTestObjectHandler(): void + { + $testObjectHandlerClass = new ReflectionClass(TestObjectHandler::class); + $testObjectHandlerConstructor = $testObjectHandlerClass->getConstructor(); + $testObjectHandlerConstructor->setAccessible(true); + $testObjectHandler = $testObjectHandlerClass->newInstanceWithoutConstructor(); + $testObjectHandlerConstructor->invoke($testObjectHandler); + + $property = new ReflectionProperty(TestObjectHandler::class, 'testObjectHandler'); + $property->setAccessible(true); + $property->setValue($testObjectHandler); } } From de0e75bf95566887cd1be84077e4e0f42a20c222 Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Wed, 11 Aug 2021 17:39:48 +0300 Subject: [PATCH 693/888] MFTF-33583: Reverted mocking with new created property --- .../Util/TestGeneratorTest.php | 8 -------- .../Test/Handlers/TestObjectHandler.php | 12 +----------- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php index c01a5aa09..800c506f1 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php @@ -51,10 +51,6 @@ public static function setUpBeforeClass(): void protected function setUp(): void { TestLoggingUtil::getInstance()->setMockLoggingUtil(); - // Used to mock initTestData method running. - $shouldSkipInitTestDataProperty = new ReflectionProperty(TestObjectHandler::class, 'shouldSkipInitTestData'); - $shouldSkipInitTestDataProperty->setAccessible(true); - $shouldSkipInitTestDataProperty->setValue(true); } /** @@ -65,10 +61,6 @@ protected function setUp(): void protected function tearDown(): void { GenerationErrorHandler::getInstance()->reset(); - - $shouldSkipInitTestDataProperty = new ReflectionProperty(TestObjectHandler::class, 'shouldSkipInitTestData'); - $shouldSkipInitTestDataProperty->setAccessible(true); - $shouldSkipInitTestDataProperty->setValue(false); } /** diff --git a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php index 407fc89d9..4abc26c36 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php @@ -44,13 +44,6 @@ class TestObjectHandler implements ObjectHandlerInterface */ private $tests = []; - /** - * Check if initTestData method should be skipped during object initialization. - * - * @var boolean - */ - private static $shouldSkipInitTestData = false; - /** * Instance of ObjectExtensionUtil class * @@ -69,10 +62,7 @@ public static function getInstance($validateAnnotations = true) { if (!self::$testObjectHandler) { self::$testObjectHandler = new TestObjectHandler(); - - if (!self::$shouldSkipInitTestData) { - self::$testObjectHandler->initTestData($validateAnnotations); - } + self::$testObjectHandler->initTestData($validateAnnotations); } return self::$testObjectHandler; From 42dedf0226cd4cd588d952de63c5c53e82c60baf Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Wed, 11 Aug 2021 17:52:49 +0300 Subject: [PATCH 694/888] MFTF-33584: Code refactoring --- .../OperationDefinitionObjectHandlerTest.php | 264 ++++++++++-------- 1 file changed, 143 insertions(+), 121 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php index c5747e8cb..33079b6cd 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php @@ -54,32 +54,36 @@ public function testGetMultipleObjects(): void * has field * key=id, value=integer */ - $mockData = [OperationDefinitionObjectHandler::ENTITY_OPERATION_ROOT_TAG => [ - 'testOperationName' => [ - OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE => $dataType1, - OperationDefinitionObjectHandler::ENTITY_OPERATION_TYPE => $operationType1, - OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH => 'auth', - OperationDefinitionObjectHandler::ENTITY_OPERATION_URL => 'V1/Type1', - OperationDefinitionObjectHandler::ENTITY_OPERATION_METHOD => 'POST', - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY => [ - 0 => [ - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => 'id', - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => 'integer' - ], + $mockData = [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_ROOT_TAG => [ + 'testOperationName' => [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE => $dataType1, + OperationDefinitionObjectHandler::ENTITY_OPERATION_TYPE => $operationType1, + OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH => 'auth', + OperationDefinitionObjectHandler::ENTITY_OPERATION_URL => 'V1/Type1', + OperationDefinitionObjectHandler::ENTITY_OPERATION_METHOD => 'POST', + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY => [ + 0 => [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => 'id', + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => 'integer' + ], + ] + ], + [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE => $dataType1, + OperationDefinitionObjectHandler::ENTITY_OPERATION_TYPE => $operationType2, + OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH => 'auth', + OperationDefinitionObjectHandler::ENTITY_OPERATION_URL => 'V1/Type1/{id}', + OperationDefinitionObjectHandler::ENTITY_OPERATION_METHOD => 'PUT', + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY => [ + 0 => [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => 'id', + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => 'integer' + ], ] - ],[ - OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE => $dataType1, - OperationDefinitionObjectHandler::ENTITY_OPERATION_TYPE => $operationType2, - OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH => 'auth', - OperationDefinitionObjectHandler::ENTITY_OPERATION_URL => 'V1/Type1/{id}', - OperationDefinitionObjectHandler::ENTITY_OPERATION_METHOD => 'PUT', - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY => [ - 0 => [ - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => 'id', - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => 'integer' - ], ] - ]]]; + ] + ]; $this->mockOperationHandlerWithData($mockData); //Perform Assertions @@ -108,21 +112,24 @@ public function testDeprecatedOperation(): void * has field * key=id, value=integer */ - $mockData = [OperationDefinitionObjectHandler::ENTITY_OPERATION_ROOT_TAG => [ - 'testOperationName' => [ - OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE => $dataType1, - OperationDefinitionObjectHandler::ENTITY_OPERATION_TYPE => $operationType1, - OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH => 'auth', - OperationDefinitionObjectHandler::ENTITY_OPERATION_URL => 'V1/Type1', - OperationDefinitionObjectHandler::ENTITY_OPERATION_METHOD => 'POST', - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY => [ - 0 => [ - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => 'id', - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => 'integer' + $mockData = [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_ROOT_TAG => [ + 'testOperationName' => [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE => $dataType1, + OperationDefinitionObjectHandler::ENTITY_OPERATION_TYPE => $operationType1, + OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH => 'auth', + OperationDefinitionObjectHandler::ENTITY_OPERATION_URL => 'V1/Type1', + OperationDefinitionObjectHandler::ENTITY_OPERATION_METHOD => 'POST', + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY => [ + 0 => [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => 'id', + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => 'integer' + ], ], - ], - OperationDefinitionObjectHandler::OBJ_DEPRECATED => 'deprecation message' - ]]]; + OperationDefinitionObjectHandler::OBJ_DEPRECATED => 'deprecation message' + ] + ] + ]; $this->mockOperationHandlerWithData($mockData); //Perform Assertions @@ -190,53 +197,60 @@ public function testObjectCreation(): void * key active, value boolean * */ - $mockData = [OperationDefinitionObjectHandler::ENTITY_OPERATION_ROOT_TAG => [ - 'testOperationName' => [ - OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE => $testDataTypeName1, - OperationDefinitionObjectHandler::ENTITY_OPERATION_TYPE => $testOperationType, - OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH => $testAuth, - OperationDefinitionObjectHandler::ENTITY_OPERATION_URL => $testUrl, - OperationDefinitionObjectHandler::ENTITY_OPERATION_METHOD => $testMethod, - OperationDefinitionObjectHandler::ENTITY_OPERATION_SUCCESS_REGEX => $testSuccessRegex, - OperationDefinitionObjectHandler::ENTITY_OPERATION_CONTENT_TYPE => [ - 0 => [ - 'value' => $testContentType - ] - ], - OperationDefinitionObjectHandler::ENTITY_OPERATION_HEADER => [ - 0 => [ - OperationDefinitionObjectHandler::ENTITY_OPERATION_HEADER_PARAM => $testHeaderParam, - OperationDefinitionObjectHandler::ENTITY_OPERATION_HEADER_VALUE => $testHeaderValue, - ] - ], - OperationDefinitionObjectHandler::ENTITY_OPERATION_URL_PARAM => [ - 0 => [ - OperationDefinitionObjectHandler::ENTITY_OPERATION_URL_PARAM_KEY => 'testUrlParamKey', - OperationDefinitionObjectHandler::ENTITY_OPERATION_URL_PARAM_VALUE => 'testUrlParamValue' - ] - ], - OperationDefinitionObjectHandler::ENTITY_OPERATION_OBJECT => [ - 0 => [ - OperationDefinitionObjectHandler::ENTITY_OPERATION_OBJECT_KEY => $nestedObjectKey, - OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE => $nestedObjectType, - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY => [ - 0 => [ - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => $nestedEntryKey1, - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => $nestedEntryValue1 - ], - 1 => [ - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => $nestedEntryKey2, - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => $nestedEntryValue2, - OperationDefinitionObjectHandler::ENTITY_OPERATION_REQUIRED => $nestedEntryRequired2 - ], - 2 => [ - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => $nestedEntryKey3, - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => $nestedEntryValue3 + $mockData = [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_ROOT_TAG => [ + 'testOperationName' => [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE => $testDataTypeName1, + OperationDefinitionObjectHandler::ENTITY_OPERATION_TYPE => $testOperationType, + OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH => $testAuth, + OperationDefinitionObjectHandler::ENTITY_OPERATION_URL => $testUrl, + OperationDefinitionObjectHandler::ENTITY_OPERATION_METHOD => $testMethod, + OperationDefinitionObjectHandler::ENTITY_OPERATION_SUCCESS_REGEX => $testSuccessRegex, + OperationDefinitionObjectHandler::ENTITY_OPERATION_CONTENT_TYPE => [ + 0 => [ + 'value' => $testContentType + ] + ], + OperationDefinitionObjectHandler::ENTITY_OPERATION_HEADER => [ + 0 => [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_HEADER_PARAM => $testHeaderParam, + OperationDefinitionObjectHandler::ENTITY_OPERATION_HEADER_VALUE => $testHeaderValue, + ] + ], + OperationDefinitionObjectHandler::ENTITY_OPERATION_URL_PARAM => [ + 0 => [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_URL_PARAM_KEY => 'testUrlParamKey', + OperationDefinitionObjectHandler::ENTITY_OPERATION_URL_PARAM_VALUE => 'testUrlParamValue' + ] + ], + OperationDefinitionObjectHandler::ENTITY_OPERATION_OBJECT => [ + 0 => [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_OBJECT_KEY => $nestedObjectKey, + OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE => $nestedObjectType, + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY => [ + 0 => [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => $nestedEntryKey1, + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => + $nestedEntryValue1 + ], + 1 => [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => $nestedEntryKey2, + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => + $nestedEntryValue2, + OperationDefinitionObjectHandler::ENTITY_OPERATION_REQUIRED => + $nestedEntryRequired2 + ], + 2 => [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => $nestedEntryKey3, + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => + $nestedEntryValue3 + ] ] ] - ] - ], - ]]]; + ], + ] + ] + ]; // Prepare objects to compare against $field = OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY; $expectedNestedField = new OperationElement( @@ -326,32 +340,38 @@ public function testObjectArrayCreation(): void * objects with key = nestedObjectKey, type = nestedObjectType * has field with key = nestedFieldKey, value = string */ - $mockData = [OperationDefinitionObjectHandler::ENTITY_OPERATION_ROOT_TAG => [ - 'testOperationName' => [ - OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE => $dataType1, - OperationDefinitionObjectHandler::ENTITY_OPERATION_TYPE => $operationType1, - OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH => 'auth', - OperationDefinitionObjectHandler::ENTITY_OPERATION_URL => 'V1/Type1', - OperationDefinitionObjectHandler::ENTITY_OPERATION_METHOD => 'POST', - OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY => [ - 0 => [ - OperationDefinitionObjectHandler::ENTITY_OPERATION_OBJECT_KEY => $objectArrayKey, - OperationDefinitionObjectHandler::ENTITY_OPERATION_OBJECT => [ - 0 => [ - OperationDefinitionObjectHandler::ENTITY_OPERATION_OBJECT_KEY => $twiceNestedObjectKey, - OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE => $twiceNestedObjectType, - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY => [ - 0 => [ - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => - $twiceNestedEntryKey, - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => - $twiceNestedEntryValue + $mockData = [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_ROOT_TAG => [ + 'testOperationName' => [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE => $dataType1, + OperationDefinitionObjectHandler::ENTITY_OPERATION_TYPE => $operationType1, + OperationDefinitionObjectHandler::ENTITY_OPERATION_AUTH => 'auth', + OperationDefinitionObjectHandler::ENTITY_OPERATION_URL => 'V1/Type1', + OperationDefinitionObjectHandler::ENTITY_OPERATION_METHOD => 'POST', + OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY => [ + 0 => [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_OBJECT_KEY => $objectArrayKey, + OperationDefinitionObjectHandler::ENTITY_OPERATION_OBJECT => [ + 0 => [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_OBJECT_KEY => + $twiceNestedObjectKey, + OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE => + $twiceNestedObjectType, + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY => [ + 0 => [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => + $twiceNestedEntryKey, + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => + $twiceNestedEntryValue + ] ] ] ] ] ] - ]]]]; + ] + ] + ]; // Prepare Objects to compare against $twoLevelNestedMetadata = new OperationElement( $twiceNestedEntryKey, @@ -418,28 +438,30 @@ public function testLooseJsonCreation(): void * has array key = arrayKey * fields of value = string */ - $mockData = [OperationDefinitionObjectHandler::ENTITY_OPERATION_ROOT_TAG => [ - 'testOperationName' => [ - OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE => $dataType, - OperationDefinitionObjectHandler::ENTITY_OPERATION_TYPE => $operationType, - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY => [ - 0 => [ - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => $entryKey, - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => $entryValue - ] - ], - OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY => [ - 0 => [ - OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY_KEY => $arrayKey, - OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY_VALUE => [ - 0 => [ - OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => $arrayValue + $mockData = [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_ROOT_TAG => [ + 'testOperationName' => [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_DATA_TYPE => $dataType, + OperationDefinitionObjectHandler::ENTITY_OPERATION_TYPE => $operationType, + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY => [ + 0 => [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY => $entryKey, + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => $entryValue + ] + ], + OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY => [ + 0 => [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY_KEY => $arrayKey, + OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY_VALUE => [ + 0 => [ + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE => $arrayValue + ] ] ] ] ] ] - ]]; + ]; // Prepare Objects to assert against $entry = new OperationElement( $entryKey, From 85513e832f77c32e61191814b152c1a5b22aab62 Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Wed, 11 Aug 2021 23:59:53 +0300 Subject: [PATCH 695/888] MFTF-33582: Eliminated AspectMock remnants --- dev/tests/_bootstrap.php | 17 --------------- .../verification/TestModule/Test/testFile.xml | 1 + .../Tests/SchemaValidationTest.php | 14 ++++++++----- .../DeprecationStaticCheckTest.php | 16 ++++++++++++-- .../PauseActionStaticCheckTest.php | 21 +++++++++++++++---- 5 files changed, 41 insertions(+), 28 deletions(-) create mode 100644 dev/tests/verification/TestModule/Test/testFile.xml diff --git a/dev/tests/_bootstrap.php b/dev/tests/_bootstrap.php index 9d3750ec6..3b31c6e4a 100644 --- a/dev/tests/_bootstrap.php +++ b/dev/tests/_bootstrap.php @@ -15,23 +15,6 @@ require_once $mftfTestCasePath; require_once $mftfStaticTestCasePath; -// Set up AspectMock -$kernel = \AspectMock\Kernel::getInstance(); -$kernel->init([ - 'debug' => true, - 'includePaths' => [ - PROJECT_ROOT . DIRECTORY_SEPARATOR . 'src', - PROJECT_ROOT . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'allure-framework' - ], - 'cacheDir' => PROJECT_ROOT . - DIRECTORY_SEPARATOR . - 'dev' . - DIRECTORY_SEPARATOR . - 'tests' . - DIRECTORY_SEPARATOR . - '.cache' -]); - // set mftf appplication context \Magento\FunctionalTestingFramework\Config\MftfApplicationConfig::create( true, diff --git a/dev/tests/verification/TestModule/Test/testFile.xml b/dev/tests/verification/TestModule/Test/testFile.xml new file mode 100644 index 000000000..3be22cff3 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/testFile.xml @@ -0,0 +1 @@ +<tests><test name='testName'><annotations>a</annotations></test></tests> \ No newline at end of file diff --git a/dev/tests/verification/Tests/SchemaValidationTest.php b/dev/tests/verification/Tests/SchemaValidationTest.php index c6187974c..7da43a15d 100644 --- a/dev/tests/verification/Tests/SchemaValidationTest.php +++ b/dev/tests/verification/Tests/SchemaValidationTest.php @@ -6,8 +6,8 @@ namespace tests\verification\Tests; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use ReflectionProperty; use tests\util\MftfTestCase; -use AspectMock\Test as AspectMock; class SchemaValidationTest extends MftfTestCase { @@ -19,7 +19,10 @@ class SchemaValidationTest extends MftfTestCase */ public function testInvalidTestSchema() { - AspectMock::double(MftfApplicationConfig::class, ['getDebugLevel' => MftfApplicationConfig::LEVEL_DEVELOPER]); + $property = new ReflectionProperty(MftfApplicationConfig::class, 'debugLevel'); + $property->setAccessible(true); + $property->setValue(MftfApplicationConfig::LEVEL_DEVELOPER); + $testFile = ['testFile.xml' => "<tests><test name='testName'><annotations>a</annotations></test></tests>"]; $expectedError = TESTS_MODULE_PATH . DIRECTORY_SEPARATOR . @@ -32,11 +35,12 @@ public function testInvalidTestSchema() } /** - * After method functionality - * @return void + * @inheritdoc */ protected function tearDown(): void { - AspectMock::clean(); + $property = new ReflectionProperty(MftfApplicationConfig::class, 'debugLevel'); + $property->setAccessible(true); + $property->setValue(null); } } diff --git a/dev/tests/verification/Tests/StaticCheck/DeprecationStaticCheckTest.php b/dev/tests/verification/Tests/StaticCheck/DeprecationStaticCheckTest.php index f6aef65f6..58875d660 100644 --- a/dev/tests/verification/Tests/StaticCheck/DeprecationStaticCheckTest.php +++ b/dev/tests/verification/Tests/StaticCheck/DeprecationStaticCheckTest.php @@ -5,9 +5,9 @@ */ namespace tests\verification\Tests; -use AspectMock\Test as AspectMock; use Magento\FunctionalTestingFramework\StaticCheck\DeprecatedEntityUsageCheck; use Magento\FunctionalTestingFramework\StaticCheck\StaticChecksList; +use ReflectionProperty; use Symfony\Component\Console\Input\InputInterface; use tests\util\MftfStaticTestCase; @@ -33,7 +33,9 @@ public function testDeprecatedEntityUsageCheck() $staticCheck = new DeprecatedEntityUsageCheck(); $input = $this->mockInputInterface(self::TEST_MODULE_PATH); - AspectMock::double(StaticChecksList::class, ['getErrorFilesPath' => self::STATIC_RESULTS_DIR]); + $property = new ReflectionProperty(StaticChecksList::class, 'errorFilesPath'); + $property->setAccessible(true); + $property->setValue(self::STATIC_RESULTS_DIR); /** @var InputInterface $input */ $staticCheck->execute($input); @@ -47,4 +49,14 @@ public function testDeprecatedEntityUsageCheck() self::LOG_FILE ); } + + /** + * @inheritdoc + */ + public function tearDown(): void + { + $property = new ReflectionProperty(StaticChecksList::class, 'errorFilesPath'); + $property->setAccessible(true); + $property->setValue(null); + } } diff --git a/dev/tests/verification/Tests/StaticCheck/PauseActionStaticCheckTest.php b/dev/tests/verification/Tests/StaticCheck/PauseActionStaticCheckTest.php index 7c8f77c2f..4c579b6c0 100644 --- a/dev/tests/verification/Tests/StaticCheck/PauseActionStaticCheckTest.php +++ b/dev/tests/verification/Tests/StaticCheck/PauseActionStaticCheckTest.php @@ -5,11 +5,11 @@ */ namespace tests\verification\Tests; -use AspectMock\Test as AspectMock; +use Exception; use Magento\FunctionalTestingFramework\StaticCheck\PauseActionUsageCheck; use Magento\FunctionalTestingFramework\StaticCheck\StaticChecksList; +use ReflectionProperty; use Symfony\Component\Console\Input\InputInterface; - use tests\util\MftfStaticTestCase; class PauseActionStaticCheckTest extends MftfStaticTestCase @@ -27,14 +27,17 @@ class PauseActionStaticCheckTest extends MftfStaticTestCase /** * test static-check PauseActionUsageCheck. * - * @throws \Exception + * @throws Exception */ public function testPauseActionUsageCheck() { $staticCheck = new PauseActionUsageCheck(); $input = $this->mockInputInterface(self::TEST_MODULE_PATH); - AspectMock::double(StaticChecksList::class, ['getErrorFilesPath' => self::STATIC_RESULTS_DIR]); + + $property = new ReflectionProperty(StaticChecksList::class, 'errorFilesPath'); + $property->setAccessible(true); + $property->setValue(self::STATIC_RESULTS_DIR); /** @var InputInterface $input */ $staticCheck->execute($input); @@ -48,4 +51,14 @@ public function testPauseActionUsageCheck() self::LOG_FILE ); } + + /** + * @inheritdoc + */ + public static function tearDownAfterClass(): void + { + $property = new ReflectionProperty(StaticChecksList::class, 'errorFilesPath'); + $property->setAccessible(true); + $property->setValue(null); + } } From 71596baf1a47b13c338f9958589d6917e4c52956 Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Thu, 12 Aug 2021 00:07:26 +0300 Subject: [PATCH 696/888] MFTF-33582: Removed AspectMock package --- composer.json | 1 - composer.lock | 341 +----------------- .../verification/TestModule/Test/testFile.xml | 1 - 3 files changed, 1 insertion(+), 342 deletions(-) delete mode 100644 dev/tests/verification/TestModule/Test/testFile.xml diff --git a/composer.json b/composer.json index bdf92ca3d..f3d6f8fb0 100755 --- a/composer.json +++ b/composer.json @@ -41,7 +41,6 @@ "require-dev": { "brainmaestro/composer-git-hooks": "^2.3.1", "codacy/coverage": "^1.4", - "codeception/aspect-mock": "^3.0", "php-coveralls/php-coveralls": "^1.0||^2.2", "phpmd/phpmd": "^2.8.0", "phpunit/phpunit": "^9.0", diff --git a/composer.lock b/composer.lock index 226426ef8..232e98fb7 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "9bec96d8a169a4286803657bbf61004c", + "content-hash": "e68ce0fa4b36ffbd17d27cc6f1f39846", "packages": [ { "name": "allure-framework/allure-codeception", @@ -7424,153 +7424,6 @@ "abandoned": true, "time": "2020-01-10T10:52:12+00:00" }, - { - "name": "codeception/aspect-mock", - "version": "3.1.1", - "source": { - "type": "git", - "url": "https://github.com/Codeception/AspectMock.git", - "reference": "eef5e5e9ebd66c89d6184416e83851c354963e9c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Codeception/AspectMock/zipball/eef5e5e9ebd66c89d6184416e83851c354963e9c", - "reference": "eef5e5e9ebd66c89d6184416e83851c354963e9c", - "shasum": "" - }, - "require": { - "goaop/framework": "^2.2.0", - "php": "^7.0", - "phpunit/phpunit": "> 6.0.0", - "symfony/finder": ">=2.4 <6.0" - }, - "require-dev": { - "codeception/codeception": "^4.0", - "codeception/specify": "^1.0", - "codeception/verify": "^1.2" - }, - "type": "library", - "autoload": { - "psr-0": { - "AspectMock": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Bodnarchuk", - "email": "davert@codeception.com" - } - ], - "description": "Experimental Mocking Framework powered by Aspects", - "support": { - "issues": "https://github.com/Codeception/AspectMock/issues", - "source": "https://github.com/Codeception/AspectMock/tree/3.1.1" - }, - "time": "2021-04-10T19:47:51+00:00" - }, - { - "name": "doctrine/cache", - "version": "1.11.3", - "source": { - "type": "git", - "url": "https://github.com/doctrine/cache.git", - "reference": "3bb5588cec00a0268829cc4a518490df6741af9d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/3bb5588cec00a0268829cc4a518490df6741af9d", - "reference": "3bb5588cec00a0268829cc4a518490df6741af9d", - "shasum": "" - }, - "require": { - "php": "~7.1 || ^8.0" - }, - "conflict": { - "doctrine/common": ">2.2,<2.4", - "psr/cache": ">=3" - }, - "require-dev": { - "alcaeus/mongo-php-adapter": "^1.1", - "cache/integration-tests": "dev-master", - "doctrine/coding-standard": "^8.0", - "mongodb/mongodb": "^1.1", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", - "predis/predis": "~1.0", - "psr/cache": "^1.0 || ^2.0", - "symfony/cache": "^4.4 || ^5.2" - }, - "suggest": { - "alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.", - "homepage": "https://www.doctrine-project.org/projects/cache.html", - "keywords": [ - "abstraction", - "apcu", - "cache", - "caching", - "couchdb", - "memcached", - "php", - "redis", - "xcache" - ], - "support": { - "issues": "https://github.com/doctrine/cache/issues", - "source": "https://github.com/doctrine/cache/tree/1.11.3" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcache", - "type": "tidelift" - } - ], - "time": "2021-05-25T09:01:55+00:00" - }, { "name": "gitonomy/gitlib", "version": "v1.2.3", @@ -7641,198 +7494,6 @@ ], "time": "2020-12-29T16:48:45+00:00" }, - { - "name": "goaop/framework", - "version": "2.3.5", - "source": { - "type": "git", - "url": "https://github.com/goaop/framework.git", - "reference": "19a6f2110c71aed99081ca23c359436b723a6cdf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/goaop/framework/zipball/19a6f2110c71aed99081ca23c359436b723a6cdf", - "reference": "19a6f2110c71aed99081ca23c359436b723a6cdf", - "shasum": "" - }, - "require": { - "doctrine/annotations": "^1.2.3", - "doctrine/cache": "^1.5", - "goaop/parser-reflection": "~2.0", - "jakubledl/dissect": "~1.0", - "php": "~7.0", - "symfony/finder": "^3.4|^4.2|^5.0" - }, - "require-dev": { - "adlawson/vfs": "^0.12", - "doctrine/orm": "^2.5", - "phpunit/phpunit": "^5.7", - "symfony/console": "^2.7|^3.0", - "symfony/filesystem": "^3.3", - "symfony/process": "^3.3", - "webmozart/glob": "^4.1" - }, - "suggest": { - "symfony/console": "Enables the usage of the command-line tool." - }, - "bin": [ - "bin/aspect" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "psr-4": { - "Go\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Lisachenko Alexander", - "homepage": "https://github.com/lisachenko" - } - ], - "description": "Framework for aspect-oriented programming in PHP.", - "homepage": "http://go.aopphp.com/", - "keywords": [ - "aop", - "aspect", - "library", - "php" - ], - "support": { - "issues": "https://github.com/goaop/framework/issues", - "source": "https://github.com/goaop/framework/tree/2.3.5" - }, - "funding": [ - { - "url": "https://github.com/lisachenko", - "type": "github" - } - ], - "time": "2021-06-11T16:17:30+00:00" - }, - { - "name": "goaop/parser-reflection", - "version": "2.1.3", - "source": { - "type": "git", - "url": "https://github.com/goaop/parser-reflection.git", - "reference": "2e837e150e15d38f7004b0dbcd0af4abe034c9e2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/goaop/parser-reflection/zipball/2e837e150e15d38f7004b0dbcd0af4abe034c9e2", - "reference": "2e837e150e15d38f7004b0dbcd0af4abe034c9e2", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.0 <4.7.0", - "php": ">=7.1" - }, - "require-dev": { - "phpunit/phpunit": "~4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Go\\ParserReflection\\": "src" - }, - "files": [ - "src/bootstrap.php" - ], - "exclude-from-classmap": [ - "/tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Alexander Lisachenko", - "email": "lisachenko.it@gmail.com" - } - ], - "description": "Provides reflection information, based on raw source", - "support": { - "issues": "https://github.com/goaop/parser-reflection/issues", - "source": "https://github.com/goaop/parser-reflection/tree/2.x" - }, - "time": "2020-08-13T21:02:42+00:00" - }, - { - "name": "jakubledl/dissect", - "version": "v1.0.1", - "source": { - "type": "git", - "url": "https://github.com/jakubledl/dissect.git", - "reference": "d3a391de31e45a247e95cef6cf58a91c05af67c4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/jakubledl/dissect/zipball/d3a391de31e45a247e95cef6cf58a91c05af67c4", - "reference": "d3a391de31e45a247e95cef6cf58a91c05af67c4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "symfony/console": "~2.1" - }, - "suggest": { - "symfony/console": "for the command-line tool" - }, - "bin": [ - "bin/dissect.php", - "bin/dissect" - ], - "type": "library", - "autoload": { - "psr-0": { - "Dissect": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "unlicense" - ], - "authors": [ - { - "name": "Jakub Lédl", - "email": "jakubledl@gmail.com" - } - ], - "description": "Lexing and parsing in pure PHP", - "homepage": "https://github.com/jakubledl/dissect", - "keywords": [ - "ast", - "lexing", - "parser", - "parsing" - ], - "support": { - "issues": "https://github.com/jakubledl/dissect/issues", - "source": "https://github.com/jakubledl/dissect/tree/v1.0.1" - }, - "time": "2013-01-29T21:29:14+00:00" - }, { "name": "pdepend/pdepend", "version": "2.9.1", diff --git a/dev/tests/verification/TestModule/Test/testFile.xml b/dev/tests/verification/TestModule/Test/testFile.xml deleted file mode 100644 index 3be22cff3..000000000 --- a/dev/tests/verification/TestModule/Test/testFile.xml +++ /dev/null @@ -1 +0,0 @@ -<tests><test name='testName'><annotations>a</annotations></test></tests> \ No newline at end of file From 6fa4ad0ae4718559d481367a435539716108d8f0 Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Thu, 12 Aug 2021 00:21:29 +0300 Subject: [PATCH 697/888] MFTF-33582: Fixing verification test --- dev/tests/verification/Tests/SchemaValidationTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dev/tests/verification/Tests/SchemaValidationTest.php b/dev/tests/verification/Tests/SchemaValidationTest.php index 7da43a15d..e4e5aea40 100644 --- a/dev/tests/verification/Tests/SchemaValidationTest.php +++ b/dev/tests/verification/Tests/SchemaValidationTest.php @@ -19,9 +19,10 @@ class SchemaValidationTest extends MftfTestCase */ public function testInvalidTestSchema() { + $config = MftfApplicationConfig::getConfig(); $property = new ReflectionProperty(MftfApplicationConfig::class, 'debugLevel'); $property->setAccessible(true); - $property->setValue(MftfApplicationConfig::LEVEL_DEVELOPER); + $property->setValue($config, MftfApplicationConfig::LEVEL_DEVELOPER); $testFile = ['testFile.xml' => "<tests><test name='testName'><annotations>a</annotations></test></tests>"]; $expectedError = TESTS_MODULE_PATH . @@ -39,8 +40,9 @@ public function testInvalidTestSchema() */ protected function tearDown(): void { + $config = MftfApplicationConfig::getConfig(); $property = new ReflectionProperty(MftfApplicationConfig::class, 'debugLevel'); $property->setAccessible(true); - $property->setValue(null); + $property->setValue($config, MftfApplicationConfig::LEVEL_DEFAULT); } } From 41bd267e3b71f2ce4f378ceb6e2529815e20490b Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Mon, 16 Aug 2021 15:27:08 +0300 Subject: [PATCH 698/888] MFTF-33782: Added empty query and fragment testing to the UrlFormatterTest --- .../Util/Path/UrlFormatterTest.php | 50 +++++++++++-------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/UrlFormatterTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/UrlFormatterTest.php index 48fc9f337..dcb076b91 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/UrlFormatterTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/UrlFormatterTest.php @@ -3,39 +3,41 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace tests\unit\Magento\FunctionalTestFramework\Util\Path; -use tests\unit\Util\MagentoTestCase; -use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; +use tests\unit\Util\MagentoTestCase; class UrlFormatterTest extends MagentoTestCase { /** - * Test url format + * Test url format. * - * @dataProvider formatDataProvider * @param string $path - * @param boolean $withTrailingSeparator - * @param mixed string|boolean $expectedPath + * @param bool $withTrailingSeparator + * @param string $expectedPath + * * @return void - * @throws TestFrameworkException + * @dataProvider formatDataProvider */ - public function testFormat($path, $withTrailingSeparator, $expectedPath) + public function testFormat(string $path, bool $withTrailingSeparator, string $expectedPath): void { $this->assertEquals($expectedPath, UrlFormatter::format($path, $withTrailingSeparator)); } /** - * Test url format with exception + * Test url format with exception. * - * @dataProvider formatExceptionDataProvider * @param string $path - * @param boolean $withTrailingSeparator + * @param bool $withTrailingSeparator + * * @return void - * @throws TestFrameworkException + * @dataProvider formatExceptionDataProvider */ - public function testFormatWithException($path, $withTrailingSeparator) + public function testFormatWithException(string $path, bool $withTrailingSeparator): void { $this->expectException(TestFrameworkException::class); $this->expectExceptionMessage("Invalid url: $path\n"); @@ -43,11 +45,11 @@ public function testFormatWithException($path, $withTrailingSeparator) } /** - * Data input + * Data input. * * @return array */ - public function formatDataProvider() + public function formatDataProvider(): array { $url1 = 'http://magento.local/index.php'; $url2 = $url1 . '/'; @@ -58,34 +60,38 @@ public function formatDataProvider() $url7 = 'http://127.0.0.1:8200'; $url8 = 'wwøw.goåoøgle.coøm'; $url9 = 'http://www.google.com'; + return [ - [$url1, null, $url1], + [$url1, false, $url1], [$url1, false, $url1], [$url1, true, $url2], - [$url2, null, $url1], + [$url2, false, $url1], [$url2, false, $url1], [$url2, true, $url2], - [$url3, null, $url3], + [$url3, false, $url3], [$url3, false, $url3], [$url3, true, $url4], - [$url4, null, $url3], + [$url4, false, $url3], [$url4, false, $url3], [$url4, true, $url4], [$url5, true, $url6], [$url7, false, $url7], [$url8, false, $url9], + ['https://magento.local/path?', false, 'https://magento.local/path?'], + ['https://magento.local/path#', false, 'https://magento.local/path#'], + ['https://magento.local/path?#', false, 'https://magento.local/path?#'] ]; } /** - * Invalid data input + * Invalid data input. * * @return array */ - public function formatExceptionDataProvider() + public function formatExceptionDataProvider(): array { return [ - ['', null], + ['', false] ]; } } From debd9bac6e40fc0a591739886718e1726b30b2ee Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 16 Aug 2021 11:14:09 -0500 Subject: [PATCH 699/888] MQE-2729: [PHP 8] Investigate and fix code related to changes in implode() --- .github/workflows/main.yml | 8 +- composer.json | 2 +- composer.lock | 1163 +++++++++++++++++++++--------------- 3 files changed, 672 insertions(+), 501 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e75a0f228..cc7811a75 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,7 +12,7 @@ jobs: strategy: fail-fast: false matrix: - php-versions: ['7.3', '7.4'] + php-versions: ['7.3', '7.4', '8.0'] steps: - uses: actions/checkout@v2 @@ -54,7 +54,7 @@ jobs: strategy: fail-fast: false matrix: - php-versions: ['7.3', '7.4'] + php-versions: ['7.3', '7.4', '8.0'] steps: - uses: actions/checkout@v2 @@ -86,7 +86,7 @@ jobs: strategy: fail-fast: false matrix: - php-versions: ['7.3', '7.4'] + php-versions: ['7.3', '7.4', '8.0'] steps: - uses: actions/checkout@v2 @@ -118,7 +118,7 @@ jobs: strategy: fail-fast: false matrix: - php-versions: ['7.3', '7.4'] + php-versions: ['7.3', '7.4', '8.0'] services: chrome: diff --git a/composer.json b/composer.json index f3d6f8fb0..337c0519b 100755 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ "sort-packages": true }, "require": { - "php": "^7.3", + "php": ">7.3", "ext-curl": "*", "ext-dom": "*", "ext-intl": "*", diff --git a/composer.lock b/composer.lock index 232e98fb7..2ab461e57 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e68ce0fa4b36ffbd17d27cc6f1f39846", + "content-hash": "cb8347aab3be241fe1517983f3fc044c", "packages": [ { "name": "allure-framework/allure-codeception", @@ -127,16 +127,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.180.1", + "version": "3.190.2", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "7801112fd8be227954a6ecfbfd85b01ee4a7cae4" + "reference": "8ca6a5f9834de3eb3fb84b28fc12c9088bc01293" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/7801112fd8be227954a6ecfbfd85b01ee4a7cae4", - "reference": "7801112fd8be227954a6ecfbfd85b01ee4a7cae4", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/8ca6a5f9834de3eb3fb84b28fc12c9088bc01293", + "reference": "8ca6a5f9834de3eb3fb84b28fc12c9088bc01293", "shasum": "" }, "require": { @@ -211,9 +211,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.180.1" + "source": "https://github.com/aws/aws-sdk-php/tree/3.190.2" }, - "time": "2021-05-04T18:14:38+00:00" + "time": "2021-08-13T18:12:28+00:00" }, { "name": "beberlei/assert", @@ -348,16 +348,16 @@ }, { "name": "brick/math", - "version": "0.9.2", + "version": "0.9.3", "source": { "type": "git", "url": "https://github.com/brick/math.git", - "reference": "dff976c2f3487d42c1db75a3b180e2b9f0e72ce0" + "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/dff976c2f3487d42c1db75a3b180e2b9f0e72ce0", - "reference": "dff976c2f3487d42c1db75a3b180e2b9f0e72ce0", + "url": "https://api.github.com/repos/brick/math/zipball/ca57d18f028f84f777b2168cd1911b0dee2343ae", + "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae", "shasum": "" }, "require": { @@ -367,7 +367,7 @@ "require-dev": { "php-coveralls/php-coveralls": "^2.2", "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0", - "vimeo/psalm": "4.3.2" + "vimeo/psalm": "4.9.2" }, "type": "library", "autoload": { @@ -392,28 +392,32 @@ ], "support": { "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.9.2" + "source": "https://github.com/brick/math/tree/0.9.3" }, "funding": [ + { + "url": "https://github.com/BenMorel", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/brick/math", "type": "tidelift" } ], - "time": "2021-01-20T22:51:39+00:00" + "time": "2021-08-15T20:50:18+00:00" }, { "name": "codeception/codeception", - "version": "4.1.21", + "version": "4.1.22", "source": { "type": "git", "url": "https://github.com/Codeception/Codeception.git", - "reference": "c25f20d842a7e3fa0a8e6abf0828f102c914d419" + "reference": "9777ec3690ceedc4bce2ed13af7af4ca4ee3088f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/Codeception/zipball/c25f20d842a7e3fa0a8e6abf0828f102c914d419", - "reference": "c25f20d842a7e3fa0a8e6abf0828f102c914d419", + "url": "https://api.github.com/repos/Codeception/Codeception/zipball/9777ec3690ceedc4bce2ed13af7af4ca4ee3088f", + "reference": "9777ec3690ceedc4bce2ed13af7af4ca4ee3088f", "shasum": "" }, "require": { @@ -424,7 +428,7 @@ "ext-curl": "*", "ext-json": "*", "ext-mbstring": "*", - "guzzlehttp/psr7": "~1.4", + "guzzlehttp/psr7": "^1.4 | ^2.0", "php": ">=5.6.0 <9.0", "symfony/console": ">=2.7 <6.0", "symfony/css-selector": ">=2.7 <6.0", @@ -487,7 +491,7 @@ ], "support": { "issues": "https://github.com/Codeception/Codeception/issues", - "source": "https://github.com/Codeception/Codeception/tree/4.1.21" + "source": "https://github.com/Codeception/Codeception/tree/4.1.22" }, "funding": [ { @@ -495,7 +499,7 @@ "type": "open_collective" } ], - "time": "2021-05-28T17:43:39+00:00" + "time": "2021-08-06T17:15:34+00:00" }, { "name": "codeception/lib-asserts", @@ -793,16 +797,16 @@ }, { "name": "composer/ca-bundle", - "version": "1.2.9", + "version": "1.2.10", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5" + "reference": "9fdb22c2e97a614657716178093cd1da90a64aa8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/78a0e288fdcebf92aa2318a8d3656168da6ac1a5", - "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/9fdb22c2e97a614657716178093cd1da90a64aa8", + "reference": "9fdb22c2e97a614657716178093cd1da90a64aa8", "shasum": "" }, "require": { @@ -849,7 +853,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.2.9" + "source": "https://github.com/composer/ca-bundle/tree/1.2.10" }, "funding": [ { @@ -865,20 +869,20 @@ "type": "tidelift" } ], - "time": "2021-01-12T12:10:35+00:00" + "time": "2021-06-07T13:58:28+00:00" }, { "name": "composer/composer", - "version": "2.0.13", + "version": "2.1.5", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "986e8b86b7b570632ad0a905c3726c33dd4c0efb" + "reference": "ac679902e9f66b85a8f9d8c1c88180f609a8745d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/986e8b86b7b570632ad0a905c3726c33dd4c0efb", - "reference": "986e8b86b7b570632ad0a905c3726c33dd4c0efb", + "url": "https://api.github.com/repos/composer/composer/zipball/ac679902e9f66b85a8f9d8c1c88180f609a8745d", + "reference": "ac679902e9f66b85a8f9d8c1c88180f609a8745d", "shasum": "" }, "require": { @@ -886,21 +890,21 @@ "composer/metadata-minifier": "^1.0", "composer/semver": "^3.0", "composer/spdx-licenses": "^1.2", - "composer/xdebug-handler": "^1.1", - "justinrainbow/json-schema": "^5.2.10", + "composer/xdebug-handler": "^2.0", + "justinrainbow/json-schema": "^5.2.11", "php": "^5.3.2 || ^7.0 || ^8.0", "psr/log": "^1.0", "react/promise": "^1.2 || ^2.7", "seld/jsonlint": "^1.4", "seld/phar-utils": "^1.0", - "symfony/console": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0", - "symfony/filesystem": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0", - "symfony/finder": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0", - "symfony/process": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0" + "symfony/console": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0", + "symfony/filesystem": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0", + "symfony/finder": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0", + "symfony/process": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0" }, "require-dev": { "phpspec/prophecy": "^1.10", - "symfony/phpunit-bridge": "^4.2 || ^5.0" + "symfony/phpunit-bridge": "^4.2 || ^5.0 || ^6.0" }, "suggest": { "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages", @@ -913,7 +917,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "2.1-dev" } }, "autoload": { @@ -947,7 +951,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/composer/issues", - "source": "https://github.com/composer/composer/tree/2.0.13" + "source": "https://github.com/composer/composer/tree/2.1.5" }, "funding": [ { @@ -963,7 +967,7 @@ "type": "tidelift" } ], - "time": "2021-04-27T11:11:08+00:00" + "time": "2021-07-23T08:35:47+00:00" }, { "name": "composer/metadata-minifier", @@ -1036,16 +1040,16 @@ }, { "name": "composer/semver", - "version": "3.2.4", + "version": "3.2.5", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "a02fdf930a3c1c3ed3a49b5f63859c0c20e10464" + "reference": "31f3ea725711245195f62e54ffa402d8ef2fdba9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/a02fdf930a3c1c3ed3a49b5f63859c0c20e10464", - "reference": "a02fdf930a3c1c3ed3a49b5f63859c0c20e10464", + "url": "https://api.github.com/repos/composer/semver/zipball/31f3ea725711245195f62e54ffa402d8ef2fdba9", + "reference": "31f3ea725711245195f62e54ffa402d8ef2fdba9", "shasum": "" }, "require": { @@ -1097,7 +1101,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.2.4" + "source": "https://github.com/composer/semver/tree/3.2.5" }, "funding": [ { @@ -1113,7 +1117,7 @@ "type": "tidelift" } ], - "time": "2020-11-13T08:59:24+00:00" + "time": "2021-05-24T12:41:47+00:00" }, { "name": "composer/spdx-licenses", @@ -1196,21 +1200,21 @@ }, { "name": "composer/xdebug-handler", - "version": "1.4.6", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "f27e06cd9675801df441b3656569b328e04aa37c" + "reference": "84674dd3a7575ba617f5a76d7e9e29a7d3891339" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/f27e06cd9675801df441b3656569b328e04aa37c", - "reference": "f27e06cd9675801df441b3656569b328e04aa37c", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/84674dd3a7575ba617f5a76d7e9e29a7d3891339", + "reference": "84674dd3a7575ba617f5a76d7e9e29a7d3891339", "shasum": "" }, "require": { "php": "^5.3.2 || ^7.0 || ^8.0", - "psr/log": "^1.0" + "psr/log": "^1 || ^2 || ^3" }, "require-dev": { "phpstan/phpstan": "^0.12.55", @@ -1240,7 +1244,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/1.4.6" + "source": "https://github.com/composer/xdebug-handler/tree/2.0.2" }, "funding": [ { @@ -1256,7 +1260,7 @@ "type": "tidelift" } ], - "time": "2021-03-25T17:01:18+00:00" + "time": "2021-07-31T17:03:58+00:00" }, { "name": "csharpru/vault-php", @@ -1361,20 +1365,21 @@ "issues": "https://github.com/CSharpRU/vault-php-guzzle6-transport/issues", "source": "https://github.com/CSharpRU/vault-php-guzzle6-transport/tree/master" }, + "abandoned": true, "time": "2019-03-10T06:17:37+00:00" }, { "name": "doctrine/annotations", - "version": "1.13.1", + "version": "1.13.2", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "e6e7b7d5b45a2f2abc5460cc6396480b2b1d321f" + "reference": "5b668aef16090008790395c02c893b1ba13f7e08" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/e6e7b7d5b45a2f2abc5460cc6396480b2b1d321f", - "reference": "e6e7b7d5b45a2f2abc5460cc6396480b2b1d321f", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/5b668aef16090008790395c02c893b1ba13f7e08", + "reference": "5b668aef16090008790395c02c893b1ba13f7e08", "shasum": "" }, "require": { @@ -1431,9 +1436,9 @@ ], "support": { "issues": "https://github.com/doctrine/annotations/issues", - "source": "https://github.com/doctrine/annotations/tree/1.13.1" + "source": "https://github.com/doctrine/annotations/tree/1.13.2" }, - "time": "2021-05-16T18:07:53+00:00" + "time": "2021-08-05T19:00:23+00:00" }, { "name": "doctrine/instantiator", @@ -2472,20 +2477,20 @@ }, { "name": "jms/serializer", - "version": "3.12.3", + "version": "3.14.0", "source": { "type": "git", "url": "https://github.com/schmittjoh/serializer.git", - "reference": "f908d17afd08f0aab9c083322022682b41483c5b" + "reference": "bf371f55d8137fec4ff096bd45ff19e2db02ac4c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/f908d17afd08f0aab9c083322022682b41483c5b", - "reference": "f908d17afd08f0aab9c083322022682b41483c5b", + "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/bf371f55d8137fec4ff096bd45ff19e2db02ac4c", + "reference": "bf371f55d8137fec4ff096bd45ff19e2db02ac4c", "shasum": "" }, "require": { - "doctrine/annotations": "^1.0", + "doctrine/annotations": "^1.10.4", "doctrine/instantiator": "^1.0.3", "doctrine/lexer": "^1.1", "jms/metadata": "^2.0", @@ -2513,14 +2518,14 @@ "twig/twig": "~1.34|~2.4|^3.0" }, "suggest": { - "doctrine/cache": "Required if you like to use cache functionality.", "doctrine/collections": "Required if you like to use doctrine collection types as ArrayCollection.", + "symfony/cache": "Required if you like to use cache functionality.", "symfony/yaml": "Required if you'd like to use the YAML metadata format." }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.12-dev" + "dev-master": "3.14-dev" } }, "autoload": { @@ -2553,7 +2558,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/serializer/issues", - "source": "https://github.com/schmittjoh/serializer/tree/3.12.3" + "source": "https://github.com/schmittjoh/serializer/tree/3.14.0" }, "funding": [ { @@ -2561,20 +2566,20 @@ "type": "github" } ], - "time": "2021-04-25T11:03:24+00:00" + "time": "2021-08-06T12:10:02+00:00" }, { "name": "justinrainbow/json-schema", - "version": "5.2.10", + "version": "5.2.11", "source": { "type": "git", "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "2ba9c8c862ecd5510ed16c6340aa9f6eadb4f31b" + "reference": "2ab6744b7296ded80f8cc4f9509abbff393399aa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/2ba9c8c862ecd5510ed16c6340aa9f6eadb4f31b", - "reference": "2ba9c8c862ecd5510ed16c6340aa9f6eadb4f31b", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/2ab6744b7296ded80f8cc4f9509abbff393399aa", + "reference": "2ab6744b7296ded80f8cc4f9509abbff393399aa", "shasum": "" }, "require": { @@ -2629,22 +2634,22 @@ ], "support": { "issues": "https://github.com/justinrainbow/json-schema/issues", - "source": "https://github.com/justinrainbow/json-schema/tree/5.2.10" + "source": "https://github.com/justinrainbow/json-schema/tree/5.2.11" }, - "time": "2020-05-27T16:41:55+00:00" + "time": "2021-07-22T09:24:00+00:00" }, { "name": "monolog/monolog", - "version": "2.3.1", + "version": "2.3.2", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "9738e495f288eec0b187e310b7cdbbb285777dbe" + "reference": "71312564759a7db5b789296369c1a264efc43aad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/9738e495f288eec0b187e310b7cdbbb285777dbe", - "reference": "9738e495f288eec0b187e310b7cdbbb285777dbe", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/71312564759a7db5b789296369c1a264efc43aad", + "reference": "71312564759a7db5b789296369c1a264efc43aad", "shasum": "" }, "require": { @@ -2715,7 +2720,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/2.3.1" + "source": "https://github.com/Seldaek/monolog/tree/2.3.2" }, "funding": [ { @@ -2727,20 +2732,20 @@ "type": "tidelift" } ], - "time": "2021-07-14T11:56:39+00:00" + "time": "2021-07-23T07:42:52+00:00" }, { "name": "mtdowling/jmespath.php", - "version": "2.6.0", + "version": "2.6.1", "source": { "type": "git", "url": "https://github.com/jmespath/jmespath.php.git", - "reference": "42dae2cbd13154083ca6d70099692fef8ca84bfb" + "reference": "9b87907a81b87bc76d19a7fb2d61e61486ee9edb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/42dae2cbd13154083ca6d70099692fef8ca84bfb", - "reference": "42dae2cbd13154083ca6d70099692fef8ca84bfb", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/9b87907a81b87bc76d19a7fb2d61e61486ee9edb", + "reference": "9b87907a81b87bc76d19a7fb2d61e61486ee9edb", "shasum": "" }, "require": { @@ -2748,7 +2753,7 @@ "symfony/polyfill-mbstring": "^1.17" }, "require-dev": { - "composer/xdebug-handler": "^1.4", + "composer/xdebug-handler": "^1.4 || ^2.0", "phpunit/phpunit": "^4.8.36 || ^7.5.15" }, "bin": [ @@ -2786,9 +2791,9 @@ ], "support": { "issues": "https://github.com/jmespath/jmespath.php/issues", - "source": "https://github.com/jmespath/jmespath.php/tree/2.6.0" + "source": "https://github.com/jmespath/jmespath.php/tree/2.6.1" }, - "time": "2020-07-31T21:01:56+00:00" + "time": "2021-06-14T00:11:39+00:00" }, { "name": "mustache/mustache", @@ -2900,16 +2905,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.6.0", + "version": "v4.12.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "c346bbfafe2ff60680258b631afb730d186ed864" + "reference": "6608f01670c3cc5079e18c1dab1104e002579143" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/c346bbfafe2ff60680258b631afb730d186ed864", - "reference": "c346bbfafe2ff60680258b631afb730d186ed864", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6608f01670c3cc5079e18c1dab1104e002579143", + "reference": "6608f01670c3cc5079e18c1dab1104e002579143", "shasum": "" }, "require": { @@ -2917,8 +2922,8 @@ "php": ">=7.0" }, "require-dev": { - "ircmaxell/php-yacc": "0.0.5", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0" + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" }, "bin": [ "bin/php-parse" @@ -2926,7 +2931,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "4.9-dev" } }, "autoload": { @@ -2950,9 +2955,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.6.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.12.0" }, - "time": "2020-07-02T17:12:47+00:00" + "time": "2021-07-21T10:44:31+00:00" }, { "name": "paragonie/constant_time_encoding", @@ -3023,28 +3028,29 @@ }, { "name": "phar-io/manifest", - "version": "1.0.3", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" + "reference": "97803eca37d319dfa7826cc2437fc020857acb53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", - "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53", "shasum": "" }, "require": { "ext-dom": "*", "ext-phar": "*", - "phar-io/version": "^2.0", - "php": "^5.6 || ^7.0" + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -3076,26 +3082,26 @@ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "support": { "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/master" + "source": "https://github.com/phar-io/manifest/tree/2.0.3" }, - "time": "2018-07-08T19:23:20+00:00" + "time": "2021-07-20T11:28:43+00:00" }, { "name": "phar-io/version", - "version": "2.0.1", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/phar-io/version.git", - "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" + "reference": "bae7c545bef187884426f042434e561ab1ddb182" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", - "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "url": "https://api.github.com/repos/phar-io/version/zipball/bae7c545bef187884426f042434e561ab1ddb182", + "reference": "bae7c545bef187884426f042434e561ab1ddb182", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "php": "^7.2 || ^8.0" }, "type": "library", "autoload": { @@ -3127,9 +3133,9 @@ "description": "Library for handling version information and constraints", "support": { "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/master" + "source": "https://github.com/phar-io/version/tree/3.1.0" }, - "time": "2018-07-08T19:19:57+00:00" + "time": "2021-02-23T14:00:09+00:00" }, { "name": "php-webdriver/webdriver", @@ -3424,28 +3430,27 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "0.5.4", + "version": "0.5.5", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "e352d065af1ae9b41c12d1dfd309e90f7b1f55c9" + "reference": "ea0b17460ec38e20d7eb64e7ec49b5d44af5d28c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/e352d065af1ae9b41c12d1dfd309e90f7b1f55c9", - "reference": "e352d065af1ae9b41c12d1dfd309e90f7b1f55c9", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/ea0b17460ec38e20d7eb64e7ec49b5d44af5d28c", + "reference": "ea0b17460ec38e20d7eb64e7ec49b5d44af5d28c", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "require-dev": { - "phing/phing": "^2.16.3", "php-parallel-lint/php-parallel-lint": "^1.2", "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^0.12.60", + "phpstan/phpstan": "^0.12.87", "phpstan/phpstan-strict-rules": "^0.12.5", - "phpunit/phpunit": "^7.5.20", + "phpunit/phpunit": "^9.5", "symfony/process": "^5.2" }, "type": "library", @@ -3468,38 +3473,41 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/0.5.4" + "source": "https://github.com/phpstan/phpdoc-parser/tree/0.5.5" }, - "time": "2021-04-03T14:46:19+00:00" + "time": "2021-06-11T13:24:46+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "8.0.2", + "version": "9.2.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "ca6647ffddd2add025ab3f21644a441d7c146cdc" + "reference": "f6293e1b30a2354e8428e004689671b83871edde" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca6647ffddd2add025ab3f21644a441d7c146cdc", - "reference": "ca6647ffddd2add025ab3f21644a441d7c146cdc", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f6293e1b30a2354e8428e004689671b83871edde", + "reference": "f6293e1b30a2354e8428e004689671b83871edde", "shasum": "" }, "require": { "ext-dom": "*", + "ext-libxml": "*", "ext-xmlwriter": "*", - "php": "^7.3", - "phpunit/php-file-iterator": "^3.0", - "phpunit/php-text-template": "^2.0", - "phpunit/php-token-stream": "^4.0", - "sebastian/code-unit-reverse-lookup": "^2.0", - "sebastian/environment": "^5.0", - "sebastian/version": "^3.0", - "theseer/tokenizer": "^1.1.3" + "nikic/php-parser": "^4.10.2", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-text-template": "^2.0.2", + "sebastian/code-unit-reverse-lookup": "^2.0.2", + "sebastian/complexity": "^2.0", + "sebastian/environment": "^5.1.2", + "sebastian/lines-of-code": "^1.0.3", + "sebastian/version": "^3.0.1", + "theseer/tokenizer": "^1.2.0" }, "require-dev": { - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" }, "suggest": { "ext-pcov": "*", @@ -3508,7 +3516,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "8.0-dev" + "dev-master": "9.2-dev" } }, "autoload": { @@ -3536,7 +3544,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/8.0.2" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.6" }, "funding": [ { @@ -3544,7 +3552,7 @@ "type": "github" } ], - "time": "2020-05-23T08:02:54+00:00" + "time": "2021-03-28T07:26:59+00:00" }, { "name": "phpunit/php-file-iterator", @@ -3787,78 +3795,18 @@ ], "time": "2020-10-26T13:16:10+00:00" }, - { - "name": "phpunit/php-token-stream", - "version": "4.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/a853a0e183b9db7eed023d7933a858fa1c8d25a3", - "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": "^7.3 || ^8.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", - "keywords": [ - "tokenizer" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-token-stream/issues", - "source": "https://github.com/sebastianbergmann/php-token-stream/tree/master" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "abandoned": true, - "time": "2020-08-04T08:28:15+00:00" - }, { "name": "phpunit/phpunit", - "version": "9.2.6", + "version": "9.5.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "1c6a9e4312e209e659f1fce3ce88dd197c2448f6" + "reference": "191768ccd5c85513b4068bdbe99bb6390c7d54fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1c6a9e4312e209e659f1fce3ce88dd197c2448f6", - "reference": "1c6a9e4312e209e659f1fce3ce88dd197c2448f6", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/191768ccd5c85513b4068bdbe99bb6390c7d54fb", + "reference": "191768ccd5c85513b4068bdbe99bb6390c7d54fb", "shasum": "" }, "require": { @@ -3869,30 +3817,31 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.9.5", - "phar-io/manifest": "^1.0.3", - "phar-io/version": "^2.0.1", - "php": "^7.3", - "phpspec/prophecy": "^1.10.3", - "phpunit/php-code-coverage": "^8.0.2", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-invoker": "^3.0.2", - "phpunit/php-text-template": "^2.0.2", - "phpunit/php-timer": "^5.0.1", - "sebastian/code-unit": "^1.0.5", - "sebastian/comparator": "^4.0.3", - "sebastian/diff": "^4.0.1", - "sebastian/environment": "^5.1.2", - "sebastian/exporter": "^4.0.2", - "sebastian/global-state": "^4.0", - "sebastian/object-enumerator": "^4.0.2", - "sebastian/resource-operations": "^3.0.2", - "sebastian/type": "^2.1.1", - "sebastian/version": "^3.0.1" + "myclabs/deep-copy": "^1.10.1", + "phar-io/manifest": "^2.0.3", + "phar-io/version": "^3.0.2", + "php": ">=7.3", + "phpspec/prophecy": "^1.12.1", + "phpunit/php-code-coverage": "^9.2.3", + "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-invoker": "^3.1.1", + "phpunit/php-text-template": "^2.0.3", + "phpunit/php-timer": "^5.0.2", + "sebastian/cli-parser": "^1.0.1", + "sebastian/code-unit": "^1.0.6", + "sebastian/comparator": "^4.0.5", + "sebastian/diff": "^4.0.3", + "sebastian/environment": "^5.1.3", + "sebastian/exporter": "^4.0.3", + "sebastian/global-state": "^5.0.1", + "sebastian/object-enumerator": "^4.0.3", + "sebastian/resource-operations": "^3.0.3", + "sebastian/type": "^2.3.4", + "sebastian/version": "^3.0.2" }, "require-dev": { "ext-pdo": "*", - "phpspec/prophecy-phpunit": "^2.0" + "phpspec/prophecy-phpunit": "^2.0.1" }, "suggest": { "ext-soap": "*", @@ -3904,7 +3853,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.2-dev" + "dev-master": "9.5-dev" } }, "autoload": { @@ -3935,7 +3884,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.2.6" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.8" }, "funding": [ { @@ -3947,7 +3896,7 @@ "type": "github" } ], - "time": "2020-07-13T17:55:55+00:00" + "time": "2021-07-31T15:17:34+00:00" }, { "name": "psr/cache", @@ -4302,20 +4251,21 @@ }, { "name": "ramsey/collection", - "version": "1.1.3", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/ramsey/collection.git", - "reference": "28a5c4ab2f5111db6a60b2b4ec84057e0f43b9c1" + "reference": "eaca1dc1054ddd10cbd83c1461907bee6fb528fa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/collection/zipball/28a5c4ab2f5111db6a60b2b4ec84057e0f43b9c1", - "reference": "28a5c4ab2f5111db6a60b2b4ec84057e0f43b9c1", + "url": "https://api.github.com/repos/ramsey/collection/zipball/eaca1dc1054ddd10cbd83c1461907bee6fb528fa", + "reference": "eaca1dc1054ddd10cbd83c1461907bee6fb528fa", "shasum": "" }, "require": { - "php": "^7.2 || ^8" + "php": "^7.3 || ^8", + "symfony/polyfill-php81": "^1.23" }, "require-dev": { "captainhook/captainhook": "^5.3", @@ -4325,6 +4275,7 @@ "hamcrest/hamcrest-php": "^2", "jangregor/phpstan-prophecy": "^0.8", "mockery/mockery": "^1.3", + "phpspec/prophecy-phpunit": "^2.0", "phpstan/extension-installer": "^1", "phpstan/phpstan": "^0.12.32", "phpstan/phpstan-mockery": "^0.12.5", @@ -4352,7 +4303,7 @@ "homepage": "https://benramsey.com" } ], - "description": "A PHP 7.2+ library for representing and manipulating collections.", + "description": "A PHP library for representing and manipulating collections.", "keywords": [ "array", "collection", @@ -4363,7 +4314,7 @@ ], "support": { "issues": "https://github.com/ramsey/collection/issues", - "source": "https://github.com/ramsey/collection/tree/1.1.3" + "source": "https://github.com/ramsey/collection/tree/1.2.1" }, "funding": [ { @@ -4375,20 +4326,20 @@ "type": "tidelift" } ], - "time": "2021-01-21T17:40:04+00:00" + "time": "2021-08-06T03:41:06+00:00" }, { "name": "ramsey/uuid", - "version": "4.1.1", + "version": "4.2.1", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "cd4032040a750077205918c86049aa0f43d22947" + "reference": "fe665a03df4f056aa65af552a96e1976df8c8dae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/cd4032040a750077205918c86049aa0f43d22947", - "reference": "cd4032040a750077205918c86049aa0f43d22947", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/fe665a03df4f056aa65af552a96e1976df8c8dae", + "reference": "fe665a03df4f056aa65af552a96e1976df8c8dae", "shasum": "" }, "require": { @@ -4402,26 +4353,26 @@ "rhumsaa/uuid": "self.version" }, "require-dev": { - "codeception/aspect-mock": "^3", - "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7.0", + "captainhook/captainhook": "^5.10", + "captainhook/plugin-composer": "^5.3", + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", "doctrine/annotations": "^1.8", - "goaop/framework": "^2", + "ergebnis/composer-normalize": "^2.15", "mockery/mockery": "^1.3", "moontoast/math": "^1.1", "paragonie/random-lib": "^2", + "php-mock/php-mock": "^2.2", "php-mock/php-mock-mockery": "^1.3", - "php-mock/php-mock-phpunit": "^2.5", "php-parallel-lint/php-parallel-lint": "^1.1", - "phpbench/phpbench": "^0.17.1", + "phpbench/phpbench": "^1.0", "phpstan/extension-installer": "^1.0", "phpstan/phpstan": "^0.12", "phpstan/phpstan-mockery": "^0.12", "phpstan/phpstan-phpunit": "^0.12", - "phpunit/phpunit": "^8.5", - "psy/psysh": "^0.10.0", - "slevomat/coding-standard": "^6.0", + "phpunit/phpunit": "^8.5 || ^9", + "slevomat/coding-standard": "^7.0", "squizlabs/php_codesniffer": "^3.5", - "vimeo/psalm": "3.9.4" + "vimeo/psalm": "^4.9" }, "suggest": { "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", @@ -4434,7 +4385,10 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.x-dev" + "dev-main": "4.x-dev" + }, + "captainhook": { + "force-install": true } }, "autoload": { @@ -4450,7 +4404,6 @@ "MIT" ], "description": "A PHP library for generating and working with universally unique identifiers (UUIDs).", - "homepage": "https://github.com/ramsey/uuid", "keywords": [ "guid", "identifier", @@ -4458,16 +4411,19 @@ ], "support": { "issues": "https://github.com/ramsey/uuid/issues", - "rss": "https://github.com/ramsey/uuid/releases.atom", - "source": "https://github.com/ramsey/uuid" + "source": "https://github.com/ramsey/uuid/tree/4.2.1" }, "funding": [ { "url": "https://github.com/ramsey", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/ramsey/uuid", + "type": "tidelift" } ], - "time": "2020-08-18T17:17:46+00:00" + "time": "2021-08-11T01:06:55+00:00" }, { "name": "react/promise", @@ -4519,6 +4475,62 @@ }, "time": "2020-05-12T15:16:56+00:00" }, + { + "name": "sebastian/cli-parser", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:08:49+00:00" + }, { "name": "sebastian/code-unit", "version": "1.0.8", @@ -4704,6 +4716,63 @@ ], "time": "2020-10-26T15:49:45+00:00" }, + { + "name": "sebastian/complexity", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.7", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T15:52:27+00:00" + }, { "name": "sebastian/diff", "version": "4.0.4", @@ -4912,26 +4981,26 @@ }, { "name": "sebastian/global-state", - "version": "4.0.0", + "version": "5.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bdb1e7c79e592b8c82cb1699be3c8743119b8a72" + "reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bdb1e7c79e592b8c82cb1699be3c8743119b8a72", - "reference": "bdb1e7c79e592b8c82cb1699be3c8743119b8a72", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/23bd5951f7ff26f12d4e3242864df3e08dec4e49", + "reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49", "shasum": "" }, "require": { - "php": "^7.3", + "php": ">=7.3", "sebastian/object-reflector": "^2.0", "sebastian/recursion-context": "^4.0" }, "require-dev": { "ext-dom": "*", - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" }, "suggest": { "ext-uopz": "*" @@ -4939,7 +5008,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -4964,9 +5033,72 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/master" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.3" }, - "time": "2020-02-07T06:11:37+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-06-11T13:31:12+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.6", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-28T06:42:11+00:00" }, { "name": "sebastian/object-enumerator", @@ -5200,16 +5332,16 @@ }, { "name": "sebastian/type", - "version": "2.3.1", + "version": "2.3.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2" + "reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/81cd61ab7bbf2de744aba0ea61fae32f721df3d2", - "reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/b8cd8a1c753c90bc1a0f5372170e3e489136f914", + "reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914", "shasum": "" }, "require": { @@ -5244,7 +5376,7 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/2.3.1" + "source": "https://github.com/sebastianbergmann/type/tree/2.3.4" }, "funding": [ { @@ -5252,7 +5384,7 @@ "type": "github" } ], - "time": "2020-10-26T13:18:59+00:00" + "time": "2021-06-15T12:49:02+00:00" }, { "name": "sebastian/version", @@ -5495,36 +5627,37 @@ }, { "name": "symfony/console", - "version": "v4.4.22", + "version": "v4.4.29", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "36bbd079b69b94bcc9c9c9e1e37ca3b1e7971625" + "reference": "8baf0bbcfddfde7d7225ae8e04705cfd1081cd7b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/36bbd079b69b94bcc9c9c9e1e37ca3b1e7971625", - "reference": "36bbd079b69b94bcc9c9c9e1e37ca3b1e7971625", + "url": "https://api.github.com/repos/symfony/console/zipball/8baf0bbcfddfde7d7225ae8e04705cfd1081cd7b", + "reference": "8baf0bbcfddfde7d7225ae8e04705cfd1081cd7b", "shasum": "" }, "require": { "php": ">=7.1.3", "symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-php73": "^1.8", - "symfony/polyfill-php80": "^1.15", + "symfony/polyfill-php80": "^1.16", "symfony/service-contracts": "^1.1|^2" }, "conflict": { + "psr/log": ">=3", "symfony/dependency-injection": "<3.4", "symfony/event-dispatcher": "<4.3|>=5", "symfony/lock": "<4.4", "symfony/process": "<3.3" }, "provide": { - "psr/log-implementation": "1.0" + "psr/log-implementation": "1.0|2.0" }, "require-dev": { - "psr/log": "~1.0", + "psr/log": "^1|^2", "symfony/config": "^3.4|^4.0|^5.0", "symfony/dependency-injection": "^3.4|^4.0|^5.0", "symfony/event-dispatcher": "^4.3", @@ -5564,7 +5697,7 @@ "description": "Eases the creation of beautiful and testable command line interfaces", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/console/tree/v4.4.22" + "source": "https://github.com/symfony/console/tree/v4.4.29" }, "funding": [ { @@ -5580,24 +5713,25 @@ "type": "tidelift" } ], - "time": "2021-04-16T17:32:19+00:00" + "time": "2021-07-27T19:04:53+00:00" }, { "name": "symfony/css-selector", - "version": "v5.2.7", + "version": "v5.3.4", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "59a684f5ac454f066ecbe6daecce6719aed283fb" + "reference": "7fb120adc7f600a59027775b224c13a33530dd90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/59a684f5ac454f066ecbe6daecce6719aed283fb", - "reference": "59a684f5ac454f066ecbe6daecce6719aed283fb", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/7fb120adc7f600a59027775b224c13a33530dd90", + "reference": "7fb120adc7f600a59027775b224c13a33530dd90", "shasum": "" }, "require": { - "php": ">=7.2.5" + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.16" }, "type": "library", "autoload": { @@ -5629,7 +5763,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v5.3.0-BETA1" + "source": "https://github.com/symfony/css-selector/tree/v5.3.4" }, "funding": [ { @@ -5645,7 +5779,7 @@ "type": "tidelift" } ], - "time": "2021-04-07T16:07:52+00:00" + "time": "2021-07-21T12:38:00+00:00" }, { "name": "symfony/deprecation-contracts", @@ -5716,21 +5850,22 @@ }, { "name": "symfony/event-dispatcher", - "version": "v4.4.20", + "version": "v4.4.27", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "c352647244bd376bf7d31efbd5401f13f50dad0c" + "reference": "958a128b184fcf0ba45ec90c0e88554c9327c2e9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/c352647244bd376bf7d31efbd5401f13f50dad0c", - "reference": "c352647244bd376bf7d31efbd5401f13f50dad0c", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/958a128b184fcf0ba45ec90c0e88554c9327c2e9", + "reference": "958a128b184fcf0ba45ec90c0e88554c9327c2e9", "shasum": "" }, "require": { "php": ">=7.1.3", - "symfony/event-dispatcher-contracts": "^1.1" + "symfony/event-dispatcher-contracts": "^1.1", + "symfony/polyfill-php80": "^1.16" }, "conflict": { "symfony/dependency-injection": "<3.4" @@ -5740,7 +5875,7 @@ "symfony/event-dispatcher-implementation": "1.1" }, "require-dev": { - "psr/log": "~1.0", + "psr/log": "^1|^2|^3", "symfony/config": "^3.4|^4.0|^5.0", "symfony/dependency-injection": "^3.4|^4.0|^5.0", "symfony/error-handler": "~3.4|~4.4", @@ -5779,7 +5914,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.20" + "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.27" }, "funding": [ { @@ -5795,7 +5930,7 @@ "type": "tidelift" } ], - "time": "2021-01-27T09:09:26+00:00" + "time": "2021-07-23T15:41:52+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -5878,21 +6013,22 @@ }, { "name": "symfony/filesystem", - "version": "v5.2.7", + "version": "v5.3.4", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "056e92acc21d977c37e6ea8e97374b2a6c8551b0" + "reference": "343f4fe324383ca46792cae728a3b6e2f708fb32" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/056e92acc21d977c37e6ea8e97374b2a6c8551b0", - "reference": "056e92acc21d977c37e6ea8e97374b2a6c8551b0", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/343f4fe324383ca46792cae728a3b6e2f708fb32", + "reference": "343f4fe324383ca46792cae728a3b6e2f708fb32", "shasum": "" }, "require": { "php": ">=7.2.5", - "symfony/polyfill-ctype": "~1.8" + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.16" }, "type": "library", "autoload": { @@ -5920,7 +6056,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.2.7" + "source": "https://github.com/symfony/filesystem/tree/v5.3.4" }, "funding": [ { @@ -5936,24 +6072,25 @@ "type": "tidelift" } ], - "time": "2021-04-01T10:42:13+00:00" + "time": "2021-07-21T12:40:44+00:00" }, { "name": "symfony/finder", - "version": "v5.2.4", + "version": "v5.3.4", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "0d639a0943822626290d169965804f79400e6a04" + "reference": "17f50e06018baec41551a71a15731287dbaab186" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/0d639a0943822626290d169965804f79400e6a04", - "reference": "0d639a0943822626290d169965804f79400e6a04", + "url": "https://api.github.com/repos/symfony/finder/zipball/17f50e06018baec41551a71a15731287dbaab186", + "reference": "17f50e06018baec41551a71a15731287dbaab186", "shasum": "" }, "require": { - "php": ">=7.2.5" + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.16" }, "type": "library", "autoload": { @@ -5981,7 +6118,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.2.4" + "source": "https://github.com/symfony/finder/tree/v5.3.4" }, "funding": [ { @@ -5997,27 +6134,27 @@ "type": "tidelift" } ], - "time": "2021-02-15T18:55:04+00:00" + "time": "2021-07-23T15:54:19+00:00" }, { "name": "symfony/http-foundation", - "version": "v5.2.7", + "version": "v5.3.6", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "a416487a73bb9c9d120e9ba3a60547f4a3fb7a1f" + "reference": "a8388f7b7054a7401997008ce9cd8c6b0ab7ac75" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/a416487a73bb9c9d120e9ba3a60547f4a3fb7a1f", - "reference": "a416487a73bb9c9d120e9ba3a60547f4a3fb7a1f", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/a8388f7b7054a7401997008ce9cd8c6b0ab7ac75", + "reference": "a8388f7b7054a7401997008ce9cd8c6b0ab7ac75", "shasum": "" }, "require": { "php": ">=7.2.5", "symfony/deprecation-contracts": "^2.1", "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16" }, "require-dev": { "predis/predis": "~1.0", @@ -6054,7 +6191,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v5.2.7" + "source": "https://github.com/symfony/http-foundation/tree/v5.3.6" }, "funding": [ { @@ -6070,20 +6207,20 @@ "type": "tidelift" } ], - "time": "2021-05-01T13:46:24+00:00" + "time": "2021-07-27T17:08:17+00:00" }, { "name": "symfony/mime", - "version": "v5.2.7", + "version": "v5.3.4", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "7af452bf51c46f18da00feb32e1ad36db9426515" + "reference": "633e4e8afe9e529e5599d71238849a4218dd497b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/7af452bf51c46f18da00feb32e1ad36db9426515", - "reference": "7af452bf51c46f18da00feb32e1ad36db9426515", + "url": "https://api.github.com/repos/symfony/mime/zipball/633e4e8afe9e529e5599d71238849a4218dd497b", + "reference": "633e4e8afe9e529e5599d71238849a4218dd497b", "shasum": "" }, "require": { @@ -6091,7 +6228,7 @@ "symfony/deprecation-contracts": "^2.1", "symfony/polyfill-intl-idn": "^1.10", "symfony/polyfill-mbstring": "^1.0", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16" }, "conflict": { "egulias/email-validator": "~3.0.0", @@ -6137,7 +6274,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v5.2.7" + "source": "https://github.com/symfony/mime/tree/v5.3.4" }, "funding": [ { @@ -6153,20 +6290,20 @@ "type": "tidelift" } ], - "time": "2021-04-29T20:47:09+00:00" + "time": "2021-07-21T12:40:44+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.22.1", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "c6c942b1ac76c82448322025e084cadc56048b4e" + "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/c6c942b1ac76c82448322025e084cadc56048b4e", - "reference": "c6c942b1ac76c82448322025e084cadc56048b4e", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce", + "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce", "shasum": "" }, "require": { @@ -6178,7 +6315,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -6216,7 +6353,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0" }, "funding": [ { @@ -6232,20 +6369,20 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2021-02-19T12:13:01+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.22.1", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "2d63434d922daf7da8dd863e7907e67ee3031483" + "reference": "65bd267525e82759e7d8c4e8ceea44f398838e65" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/2d63434d922daf7da8dd863e7907e67ee3031483", - "reference": "2d63434d922daf7da8dd863e7907e67ee3031483", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/65bd267525e82759e7d8c4e8ceea44f398838e65", + "reference": "65bd267525e82759e7d8c4e8ceea44f398838e65", "shasum": "" }, "require": { @@ -6259,7 +6396,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -6303,7 +6440,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.23.0" }, "funding": [ { @@ -6319,20 +6456,20 @@ "type": "tidelift" } ], - "time": "2021-01-22T09:19:47+00:00" + "time": "2021-05-27T09:27:20+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.22.1", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248" + "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/43a0283138253ed1d48d352ab6d0bdb3f809f248", - "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8", + "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8", "shasum": "" }, "require": { @@ -6344,7 +6481,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -6387,7 +6524,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.23.0" }, "funding": [ { @@ -6403,20 +6540,20 @@ "type": "tidelift" } ], - "time": "2021-01-22T09:19:47+00:00" + "time": "2021-02-19T12:13:01+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.23.0", + "version": "v1.23.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1" + "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2df51500adbaebdc4c38dea4c89a2e131c45c8a1", - "reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9174a3d80210dca8daa7f31fec659150bbeabfc6", + "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6", "shasum": "" }, "require": { @@ -6467,7 +6604,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.1" }, "funding": [ { @@ -6483,20 +6620,20 @@ "type": "tidelift" } ], - "time": "2021-05-27T09:27:20+00:00" + "time": "2021-05-27T12:26:48+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.22.1", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9" + "reference": "9a142215a36a3888e30d0a9eeea9766764e96976" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", - "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9a142215a36a3888e30d0a9eeea9766764e96976", + "reference": "9a142215a36a3888e30d0a9eeea9766764e96976", "shasum": "" }, "require": { @@ -6505,7 +6642,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -6543,7 +6680,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-php72/tree/v1.23.0" }, "funding": [ { @@ -6559,20 +6696,20 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2021-05-27T09:17:38+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.22.1", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2" + "reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", - "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fba8933c384d6476ab14fb7b8526e5287ca7e010", + "reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010", "shasum": "" }, "require": { @@ -6581,7 +6718,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -6622,7 +6759,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.23.0" }, "funding": [ { @@ -6638,20 +6775,20 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2021-02-19T12:13:01+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.22.1", + "version": "v1.23.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91" + "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dc3063ba22c2a1fd2f45ed856374d79114998f91", - "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/1100343ed1a92e3a38f9ae122fc0eb21602547be", + "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be", "shasum": "" }, "require": { @@ -6660,7 +6797,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -6705,7 +6842,86 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.23.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-07-28T13:41:28+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.23.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "e66119f3de95efc359483f810c4c3e6436279436" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/e66119f3de95efc359483f810c4c3e6436279436", + "reference": "e66119f3de95efc359483f810c4c3e6436279436", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.23.0" }, "funding": [ { @@ -6721,24 +6937,25 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2021-05-21T13:25:03+00:00" }, { "name": "symfony/process", - "version": "v4.4.25", + "version": "v4.4.27", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "cd61e6dd273975c6625316de9d141ebd197f93c9" + "reference": "0b7dc5599ac4aa6d7b936c8f7d10abae64f6cf7f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/cd61e6dd273975c6625316de9d141ebd197f93c9", - "reference": "cd61e6dd273975c6625316de9d141ebd197f93c9", + "url": "https://api.github.com/repos/symfony/process/zipball/0b7dc5599ac4aa6d7b936c8f7d10abae64f6cf7f", + "reference": "0b7dc5599ac4aa6d7b936c8f7d10abae64f6cf7f", "shasum": "" }, "require": { - "php": ">=7.1.3" + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" }, "type": "library", "autoload": { @@ -6766,7 +6983,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v4.4.25" + "source": "https://github.com/symfony/process/tree/v4.4.27" }, "funding": [ { @@ -6782,7 +6999,7 @@ "type": "tidelift" } ], - "time": "2021-05-26T11:20:16+00:00" + "time": "2021-07-23T15:41:52+00:00" }, { "name": "symfony/service-contracts", @@ -6865,31 +7082,35 @@ }, { "name": "symfony/yaml", - "version": "v4.4.22", + "version": "v5.3.6", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "1c2fd24147961525eaefb65b11987cab75adab59" + "reference": "4500fe63dc9c6ffc32d3b1cb0448c329f9c814b7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/1c2fd24147961525eaefb65b11987cab75adab59", - "reference": "1c2fd24147961525eaefb65b11987cab75adab59", + "url": "https://api.github.com/repos/symfony/yaml/zipball/4500fe63dc9c6ffc32d3b1cb0448c329f9c814b7", + "reference": "4500fe63dc9c6ffc32d3b1cb0448c329f9c814b7", "shasum": "" }, "require": { - "php": ">=7.1.3", + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", "symfony/polyfill-ctype": "~1.8" }, "conflict": { - "symfony/console": "<3.4" + "symfony/console": "<4.4" }, "require-dev": { - "symfony/console": "^3.4|^4.0|^5.0" + "symfony/console": "^4.4|^5.0" }, "suggest": { "symfony/console": "For validating YAML files using the lint command" }, + "bin": [ + "Resources/bin/yaml-lint" + ], "type": "library", "autoload": { "psr-4": { @@ -6916,7 +7137,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v4.4.22" + "source": "https://github.com/symfony/yaml/tree/v5.3.6" }, "funding": [ { @@ -6932,7 +7153,7 @@ "type": "tidelift" } ], - "time": "2021-04-23T12:09:37+00:00" + "time": "2021-07-29T06:20:01+00:00" }, { "name": "thecodingmachine/safe", @@ -7075,16 +7296,16 @@ }, { "name": "theseer/tokenizer", - "version": "1.2.0", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "75a63c33a8577608444246075ea0af0d052e452a" + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/75a63c33a8577608444246075ea0af0d052e452a", - "reference": "75a63c33a8577608444246075ea0af0d052e452a", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", "shasum": "" }, "require": { @@ -7113,7 +7334,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/master" + "source": "https://github.com/theseer/tokenizer/tree/1.2.1" }, "funding": [ { @@ -7121,7 +7342,7 @@ "type": "github" } ], - "time": "2020-07-12T23:59:07+00:00" + "time": "2021-07-28T10:34:58+00:00" }, { "name": "vlucas/phpdotenv", @@ -7496,16 +7717,16 @@ }, { "name": "pdepend/pdepend", - "version": "2.9.1", + "version": "2.10.0", "source": { "type": "git", "url": "https://github.com/pdepend/pdepend.git", - "reference": "1632f0cee84512ffd6dde71e58536b3b06528c41" + "reference": "1fd30f4352b630ad53fec3fd5e8b8ba760f85596" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pdepend/pdepend/zipball/1632f0cee84512ffd6dde71e58536b3b06528c41", - "reference": "1632f0cee84512ffd6dde71e58536b3b06528c41", + "url": "https://api.github.com/repos/pdepend/pdepend/zipball/1fd30f4352b630ad53fec3fd5e8b8ba760f85596", + "reference": "1fd30f4352b630ad53fec3fd5e8b8ba760f85596", "shasum": "" }, "require": { @@ -7541,7 +7762,7 @@ "description": "Official version of pdepend to be handled with Composer", "support": { "issues": "https://github.com/pdepend/pdepend/issues", - "source": "https://github.com/pdepend/pdepend/tree/2.9.1" + "source": "https://github.com/pdepend/pdepend/tree/2.10.0" }, "funding": [ { @@ -7549,7 +7770,7 @@ "type": "tidelift" } ], - "time": "2021-04-15T21:36:28+00:00" + "time": "2021-07-20T09:56:09+00:00" }, { "name": "php-coveralls/php-coveralls", @@ -7636,22 +7857,22 @@ }, { "name": "phpmd/phpmd", - "version": "2.10.0", + "version": "2.10.2", "source": { "type": "git", "url": "https://github.com/phpmd/phpmd.git", - "reference": "58ef9e746a1ab50ad3360d5d301e1229ed2612cb" + "reference": "1bc74db7cf834662d83abebae265be11bb2eec3a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpmd/phpmd/zipball/58ef9e746a1ab50ad3360d5d301e1229ed2612cb", - "reference": "58ef9e746a1ab50ad3360d5d301e1229ed2612cb", + "url": "https://api.github.com/repos/phpmd/phpmd/zipball/1bc74db7cf834662d83abebae265be11bb2eec3a", + "reference": "1bc74db7cf834662d83abebae265be11bb2eec3a", "shasum": "" }, "require": { - "composer/xdebug-handler": "^1.0", + "composer/xdebug-handler": "^1.0 || ^2.0", "ext-xml": "*", - "pdepend/pdepend": "^2.9.1", + "pdepend/pdepend": "^2.10.0", "php": ">=5.3.9" }, "require-dev": { @@ -7707,7 +7928,7 @@ "support": { "irc": "irc://irc.freenode.org/phpmd", "issues": "https://github.com/phpmd/phpmd/issues", - "source": "https://github.com/phpmd/phpmd/tree/2.10.0" + "source": "https://github.com/phpmd/phpmd/tree/2.10.2" }, "funding": [ { @@ -7715,63 +7936,7 @@ "type": "tidelift" } ], - "time": "2021-04-26T18:44:44+00:00" - }, - { - "name": "sebastian/cli-parser", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for parsing CLI options", - "homepage": "https://github.com/sebastianbergmann/cli-parser", - "support": { - "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T06:08:49+00:00" + "time": "2021-07-22T09:56:23+00:00" }, { "name": "sebastian/phpcpd", @@ -7892,32 +8057,35 @@ }, { "name": "symfony/config", - "version": "v4.4.22", + "version": "v5.3.4", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "f6d8318c14e4be81525ae47b30e618f0bed4c7b3" + "reference": "4268f3059c904c61636275182707f81645517a37" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/f6d8318c14e4be81525ae47b30e618f0bed4c7b3", - "reference": "f6d8318c14e4be81525ae47b30e618f0bed4c7b3", + "url": "https://api.github.com/repos/symfony/config/zipball/4268f3059c904c61636275182707f81645517a37", + "reference": "4268f3059c904c61636275182707f81645517a37", "shasum": "" }, "require": { - "php": ">=7.1.3", - "symfony/filesystem": "^3.4|^4.0|^5.0", - "symfony/polyfill-ctype": "~1.8" + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/filesystem": "^4.4|^5.0", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.16", + "symfony/polyfill-php81": "^1.22" }, "conflict": { - "symfony/finder": "<3.4" + "symfony/finder": "<4.4" }, "require-dev": { - "symfony/event-dispatcher": "^3.4|^4.0|^5.0", - "symfony/finder": "^3.4|^4.0|^5.0", - "symfony/messenger": "^4.1|^5.0", + "symfony/event-dispatcher": "^4.4|^5.0", + "symfony/finder": "^4.4|^5.0", + "symfony/messenger": "^4.4|^5.0", "symfony/service-contracts": "^1.1|^2", - "symfony/yaml": "^3.4|^4.0|^5.0" + "symfony/yaml": "^4.4|^5.0" }, "suggest": { "symfony/yaml": "To use the yaml reference dumper" @@ -7948,7 +8116,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v4.4.22" + "source": "https://github.com/symfony/config/tree/v5.3.4" }, "funding": [ { @@ -7964,41 +8132,44 @@ "type": "tidelift" } ], - "time": "2021-04-07T15:47:03+00:00" + "time": "2021-07-21T12:40:44+00:00" }, { "name": "symfony/dependency-injection", - "version": "v4.4.22", + "version": "v5.3.4", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "778b140b3e8f6890f43dc2c978e58e69f188909a" + "reference": "5a825e4b386066167a8b55487091cb62beec74c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/778b140b3e8f6890f43dc2c978e58e69f188909a", - "reference": "778b140b3e8f6890f43dc2c978e58e69f188909a", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/5a825e4b386066167a8b55487091cb62beec74c2", + "reference": "5a825e4b386066167a8b55487091cb62beec74c2", "shasum": "" }, "require": { - "php": ">=7.1.3", - "psr/container": "^1.0", + "php": ">=7.2.5", + "psr/container": "^1.1.1", + "symfony/deprecation-contracts": "^2.1", + "symfony/polyfill-php80": "^1.16", "symfony/service-contracts": "^1.1.6|^2" }, "conflict": { - "symfony/config": "<4.3|>=5.0", - "symfony/finder": "<3.4", - "symfony/proxy-manager-bridge": "<3.4", - "symfony/yaml": "<3.4" + "ext-psr": "<1.1|>=2", + "symfony/config": "<5.3", + "symfony/finder": "<4.4", + "symfony/proxy-manager-bridge": "<4.4", + "symfony/yaml": "<4.4" }, "provide": { "psr/container-implementation": "1.0", "symfony/service-implementation": "1.0|2.0" }, "require-dev": { - "symfony/config": "^4.3", - "symfony/expression-language": "^3.4|^4.0|^5.0", - "symfony/yaml": "^3.4|^4.0|^5.0" + "symfony/config": "^5.3", + "symfony/expression-language": "^4.4|^5.0", + "symfony/yaml": "^4.4|^5.0" }, "suggest": { "symfony/config": "", @@ -8033,7 +8204,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v4.4.22" + "source": "https://github.com/symfony/dependency-injection/tree/v5.3.4" }, "funding": [ { @@ -8049,20 +8220,20 @@ "type": "tidelift" } ], - "time": "2021-04-07T15:47:03+00:00" + "time": "2021-07-23T15:55:36+00:00" }, { "name": "symfony/stopwatch", - "version": "v5.3.0", + "version": "v5.3.4", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "313d02f59d6543311865007e5ff4ace05b35ee65" + "reference": "b24c6a92c6db316fee69e38c80591e080e41536c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/313d02f59d6543311865007e5ff4ace05b35ee65", - "reference": "313d02f59d6543311865007e5ff4ace05b35ee65", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/b24c6a92c6db316fee69e38c80591e080e41536c", + "reference": "b24c6a92c6db316fee69e38c80591e080e41536c", "shasum": "" }, "require": { @@ -8095,7 +8266,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v5.3.0" + "source": "https://github.com/symfony/stopwatch/tree/v5.3.4" }, "funding": [ { @@ -8111,7 +8282,7 @@ "type": "tidelift" } ], - "time": "2021-05-26T17:43:10+00:00" + "time": "2021-07-10T08:58:57+00:00" } ], "aliases": [], @@ -8120,7 +8291,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^7.3", + "php": ">7.3", "ext-curl": "*", "ext-dom": "*", "ext-intl": "*", @@ -8128,5 +8299,5 @@ "ext-openssl": "*" }, "platform-dev": [], - "plugin-api-version": "2.0.0" + "plugin-api-version": "2.1.0" } From 918e7ec112f1250ff99df11b93ee6788b5d1ca4b Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 16 Aug 2021 12:40:31 -0500 Subject: [PATCH 700/888] MQE-2729: [PHP 8] Investigate and fix code related to changes in implode() - Remove usage of \ReflectionParameter::getClass() --- .../FunctionalTestingFramework/Code/Reader/ClassReader.php | 5 ++++- .../FunctionalTestingFramework/System/Code/ClassReader.php | 7 +++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Code/Reader/ClassReader.php b/src/Magento/FunctionalTestingFramework/Code/Reader/ClassReader.php index bc29d47fc..3d359a5f2 100644 --- a/src/Magento/FunctionalTestingFramework/Code/Reader/ClassReader.php +++ b/src/Magento/FunctionalTestingFramework/Code/Reader/ClassReader.php @@ -24,9 +24,12 @@ public function getConstructor($className) /** @var $parameter \ReflectionParameter */ foreach ($constructor->getParameters() as $parameter) { try { + $name = $parameter->getType() && !$parameter->getType()->isBuiltin() + ? new \ReflectionClass($parameter->getType()->getName()) + : null; $result[] = [ $parameter->getName(), - $parameter->getClass() !== null ? $parameter->getClass()->getName() : null, + $name !== null ? $name->getName() : null, !$parameter->isOptional(), $parameter->isOptional() ? ($parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : null) diff --git a/src/Magento/FunctionalTestingFramework/System/Code/ClassReader.php b/src/Magento/FunctionalTestingFramework/System/Code/ClassReader.php index 5f44ea104..ad3f3b054 100644 --- a/src/Magento/FunctionalTestingFramework/System/Code/ClassReader.php +++ b/src/Magento/FunctionalTestingFramework/System/Code/ClassReader.php @@ -31,9 +31,12 @@ public function getParameters($className, $method) /** @var $parameter \ReflectionParameter */ foreach ($method->getParameters() as $parameter) { try { - $result[$parameter->getName()] = [ + $name = $parameter->getType() && !$parameter->getType()->isBuiltin() + ? new \ReflectionClass($parameter->getType()->getName()) + : null; + $result[$parameter->getName()] = [ $parameter->getName(), - ($parameter->getClass() !== null) ? $parameter->getClass()->getName() : null, + $name !== null ? $name->getName() : null, !$parameter->isOptional(), $parameter->isOptional() ? $parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : null : From ebaac57a0a86b3cfefc0cfd567ba78293cc7b095 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 16 Aug 2021 13:28:53 -0500 Subject: [PATCH 701/888] MQE-2729: [PHP 8] Investigate and fix code related to changes in implode() - Remove usage of \ReflectionParameter::getClass() --- .../FunctionalTestingFramework/System/Code/ClassReader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/System/Code/ClassReader.php b/src/Magento/FunctionalTestingFramework/System/Code/ClassReader.php index ad3f3b054..1ccb28cc6 100644 --- a/src/Magento/FunctionalTestingFramework/System/Code/ClassReader.php +++ b/src/Magento/FunctionalTestingFramework/System/Code/ClassReader.php @@ -34,7 +34,7 @@ public function getParameters($className, $method) $name = $parameter->getType() && !$parameter->getType()->isBuiltin() ? new \ReflectionClass($parameter->getType()->getName()) : null; - $result[$parameter->getName()] = [ + $result[$parameter->getName()] = [ $parameter->getName(), $name !== null ? $name->getName() : null, !$parameter->isOptional(), From 2a40fdfd1614d75569724fcf3894e313da1706c0 Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Mon, 16 Aug 2021 21:37:34 +0300 Subject: [PATCH 702/888] MFTF-33782: Code refactoring --- .../Util/Path/FilePathFormatterTest.php | 45 ++++++++------ .../Util/Path/FilePathFormatter.php | 6 +- .../Util/Path/FormatterInterface.php | 6 +- .../Util/Path/UrlFormatter.php | 61 +++++++++++-------- 4 files changed, 70 insertions(+), 48 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/FilePathFormatterTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/FilePathFormatterTest.php index 1bad633e2..34365ac5d 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/FilePathFormatterTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/FilePathFormatterTest.php @@ -3,25 +3,28 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace tests\unit\Magento\FunctionalTestFramework\Util\Path; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; -use tests\unit\Util\MagentoTestCase; use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; +use tests\unit\Util\MagentoTestCase; class FilePathFormatterTest extends MagentoTestCase { /** - * Test file format + * Test file format. * - * @dataProvider formatDataProvider * @param string $path - * @param boolean $withTrailingSeparator - * @param mixed string|boolean $expectedPath + * @param bool $withTrailingSeparator + * @param string|null $expectedPath + * * @return void * @throws TestFrameworkException + * @dataProvider formatDataProvider */ - public function testFormat($path, $withTrailingSeparator, $expectedPath) + public function testFormat(string $path, bool $withTrailingSeparator, ?string $expectedPath): void { if (null !== $expectedPath) { $this->assertEquals($expectedPath, FilePathFormatter::format($path, $withTrailingSeparator)); @@ -33,15 +36,16 @@ public function testFormat($path, $withTrailingSeparator, $expectedPath) } /** - * Test file format with exception + * Test file format with exception. * - * @dataProvider formatExceptionDataProvider * @param string $path - * @param boolean $withTrailingSeparator + * @param bool $withTrailingSeparator + * * @return void * @throws TestFrameworkException + * @dataProvider formatExceptionDataProvider */ - public function testFormatWithException($path, $withTrailingSeparator) + public function testFormatWithException(string $path, bool $withTrailingSeparator): void { $this->expectException(TestFrameworkException::class); $this->expectExceptionMessage("Invalid or non-existing file: $path\n"); @@ -49,36 +53,37 @@ public function testFormatWithException($path, $withTrailingSeparator) } /** - * Data input + * Data input. * * @return array */ - public function formatDataProvider() + public function formatDataProvider(): array { $path1 = rtrim(TESTS_BP, '/'); $path2 = $path1 . DIRECTORY_SEPARATOR; + return [ - [$path1, null, $path1], + [$path1, false, $path1], [$path1, false, $path1], [$path1, true, $path2], - [$path2, null, $path1], + [$path2, false, $path1], [$path2, false, $path1], [$path2, true, $path2], - [__DIR__. DIRECTORY_SEPARATOR . basename(__FILE__), null, __FILE__], - ['', null, null] // Empty string is valid + [__DIR__. DIRECTORY_SEPARATOR . basename(__FILE__), false, __FILE__], + ['', false, null] // Empty string is valid ]; } /** - * Invalid data input + * Invalid data input. * * @return array */ - public function formatExceptionDataProvider() + public function formatExceptionDataProvider(): array { return [ - ['abc', null], - ['X://some\dir/@', null], + ['abc', false], + ['X://some\dir/@', false] ]; } } diff --git a/src/Magento/FunctionalTestingFramework/Util/Path/FilePathFormatter.php b/src/Magento/FunctionalTestingFramework/Util/Path/FilePathFormatter.php index 8b496e739..092e060b5 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Path/FilePathFormatter.php +++ b/src/Magento/FunctionalTestingFramework/Util/Path/FilePathFormatter.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\FunctionalTestingFramework\Util\Path; @@ -11,14 +12,15 @@ class FilePathFormatter implements FormatterInterface { /** - * Return formatted full file path from input string, or false on error + * Return formatted full file path from input string, or false on error. * * @param string $path * @param boolean $withTrailingSeparator + * * @return string * @throws TestFrameworkException */ - public static function format($path, $withTrailingSeparator = true) + public static function format(string $path, bool $withTrailingSeparator = true): string { $validPath = realpath($path); diff --git a/src/Magento/FunctionalTestingFramework/Util/Path/FormatterInterface.php b/src/Magento/FunctionalTestingFramework/Util/Path/FormatterInterface.php index 11de71204..0da9fe6d8 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Path/FormatterInterface.php +++ b/src/Magento/FunctionalTestingFramework/Util/Path/FormatterInterface.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\FunctionalTestingFramework\Util\Path; @@ -11,12 +12,13 @@ interface FormatterInterface { /** - * Return formatted path (file path, url, etc) from input string, or false on error + * Return formatted path (file path, url, etc) from input string, or false on error. * * @param string $input * @param boolean $withTrailingSeparator + * * @return string * @throws TestFrameworkException */ - public static function format($input, $withTrailingSeparator = true); + public static function format(string $input, bool $withTrailingSeparator = true): string; } diff --git a/src/Magento/FunctionalTestingFramework/Util/Path/UrlFormatter.php b/src/Magento/FunctionalTestingFramework/Util/Path/UrlFormatter.php index c7b60b6ab..49f5e0e18 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Path/UrlFormatter.php +++ b/src/Magento/FunctionalTestingFramework/Util/Path/UrlFormatter.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\FunctionalTestingFramework\Util\Path; @@ -11,14 +12,15 @@ class UrlFormatter implements FormatterInterface { /** - * Return formatted url path from input string + * Return formatted url path from input string. * * @param string $url * @param boolean $withTrailingSeparator + * * @return string * @throws TestFrameworkException */ - public static function format($url, $withTrailingSeparator = true) + public static function format(string $url, bool $withTrailingSeparator = true): string { $sanitizedUrl = rtrim($url, '/'); @@ -47,12 +49,13 @@ public static function format($url, $withTrailingSeparator = true) } /** - * Try to build missing url scheme and host + * Try to build missing url scheme and host. * * @param string $url + * * @return string */ - private static function buildUrl($url) + private static function buildUrl(string $url): string { $urlParts = parse_url($url); @@ -76,32 +79,42 @@ private static function buildUrl($url) /** * 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 static function merge(array $parts) + private static function merge(array $parts): string { $get = function ($key) use ($parts) { - return isset($parts[$key]) ? $parts[$key] : null; + return $parts[$key] ?? ''; }; - $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" : ''); + $pass = $get('pass'); + $user = $get('user'); + $userinfo = $pass !== '' ? "$user:$pass" : $user; + $port = $get('port'); + $scheme = $get('scheme'); + $query = $get('query'); + $fragment = $get('fragment'); + $authority = ($userinfo !== '' ? "$userinfo@" : '') . $get('host') . ($port ? ":$port" : ''); + + return str_replace( + [ + '%scheme', + '%authority', + '%path', + '%query', + '%fragment' + ], + [ + strlen($scheme) ? "$scheme:" : '', + strlen($authority) ? "//$authority" : '', + $get('path'), + strlen($query) ? "?$query" : '', + strlen($fragment) ? "#$fragment" : '' + ], + '%scheme%authority%path%query%fragment' + ); } } From bbd90dc6067cc13dc31aca2215ad5d265420937d Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 16 Aug 2021 15:40:00 -0500 Subject: [PATCH 703/888] MQE-2729: [PHP 8] Investigate and fix code related to changes in implode() - update ParallelGroupSorter to avoid issues with 'asort' function --- .../Util/Sorter/ParallelGroupSorterTest.php | 28 +++++++++---------- .../Util/Sorter/ParallelGroupSorter.php | 13 +++++---- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Sorter/ParallelGroupSorterTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Sorter/ParallelGroupSorterTest.php index edc244e1b..5429ec92a 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Sorter/ParallelGroupSorterTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Sorter/ParallelGroupSorterTest.php @@ -49,8 +49,8 @@ public function testBasicTestsSplitByTime(): void $actualResult = $testSorter->getTestsGroupedBySize([], $sampleTestArray, 200); $this->assertCount(5, $actualResult); - foreach ($actualResult as $gropuNumber => $actualTests) { - $expectedTests = $expectedResult[$gropuNumber]; + foreach ($actualResult as $groupNumber => $actualTests) { + $expectedTests = $expectedResult[$groupNumber]; $this->assertEquals($expectedTests, array_keys($actualTests)); } } @@ -134,18 +134,18 @@ public function testBasicTestsSplitByGroup(): void $expectedResult = [ 1 => ['test2', 'test8'], - 2 => ['test11', 'test9', 'test17', 'test19', 'test13'], - 3 => ['test7', 'test18', 'test14', 'test21'], - 4 => ['test6', 'test12', 'test20', 'test5', 'test10'], - 5 => ['test1', 'test16', 'test4', 'test3', 'test15'] + 2 => ['test7', 'test18', 'test14', 'test21'], + 3 => ['test6', 'test12', 'test20', 'test5', 'test10'], + 4 => ['test1', 'test16', 'test4', 'test3', 'test15'], + 5 => ['test11', 'test9', 'test17', 'test19', 'test13'], ]; $testSorter = new ParallelGroupSorter(); $actualResult = $testSorter->getTestsGroupedByFixedGroupCount([], $sampleTestArray, 5); $this->assertCount(5, $actualResult); - foreach ($actualResult as $gropuNumber => $actualTests) { - $expectedTests = $expectedResult[$gropuNumber]; + foreach ($actualResult as $groupNumber => $actualTests) { + $expectedTests = $expectedResult[$groupNumber]; $this->assertEquals($expectedTests, array_keys($actualTests)); } } @@ -178,8 +178,8 @@ public function testBasicTestsSplitByBigGroupNumber(): void $actualResult = $testSorter->getTestsGroupedByFixedGroupCount([], $sampleTestArray, 10); $this->assertCount(5, $actualResult); - foreach ($actualResult as $gropuNumber => $actualTests) { - $expectedTests = $expectedResult[$gropuNumber]; + foreach ($actualResult as $groupNumber => $actualTests) { + $expectedTests = $expectedResult[$groupNumber]; $this->assertEquals($expectedTests, array_keys($actualTests)); } } @@ -208,8 +208,8 @@ public function testBasicTestsSplitByMinGroupNumber(): void $actualResult = $testSorter->getTestsGroupedByFixedGroupCount([], $sampleTestArray, 1); $this->assertCount(1, $actualResult); - foreach ($actualResult as $gropuNumber => $actualTests) { - $expectedTests = $expectedResult[$gropuNumber]; + foreach ($actualResult as $groupNumber => $actualTests) { + $expectedTests = $expectedResult[$groupNumber]; $this->assertEquals($expectedTests, array_keys($actualTests)); } } @@ -274,14 +274,14 @@ public function testTestsAndSuitesSplitByGroup(): void $this->assertCount(15, $actualResult); $expectedResults = [ - 1 => ['test31', 'test8', 'test1'], + 1 => ['test31', 'test3'], 2 => ['test6', 'test5'], 3 => ['test33', 'test17'], 4 => ['test25', 'test32'], 5 => ['test7', 'test22'], 6 => ['test10', 'test30'], 7 => ['test29', 'test12'], - 8 => ['test13', 'test11', 'test3'], + 8 => ['test13', 'test11', 'test8', 'test1'], 9 => ['test21', 'test26', 'test14'], 10 => ['test24', 'test27', 'test18'], 11 => ['test9', 'test4', 'test23'], diff --git a/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php b/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php index a0651e051..660dafb62 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php +++ b/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php @@ -215,16 +215,17 @@ private function getSuiteGroupCountFromGroupTime($suiteNameToTestSize, $time) private function splitTestsIntoGroups($tests, $groupCnt) { // Reverse sort the test array by size - arsort($tests); + uasort($tests, function ($a, $b) { + return $a >= $b ? -1 : 1; + }); $groups = array_fill(0, $groupCnt, []); + $sums = array_fill(0, $groupCnt, 0); foreach ($tests as $test => $size) { - for ($i = 0; $i < $groupCnt; $i++) { - $sums[$i] = array_sum($groups[$i]); - } - asort($sums); // Always add the next test to the group with the smallest sum - $groups[array_key_first($sums)][$test] = $size; + $key = array_search(min($sums), $sums); + $groups[$key][$test] = $size; + $sums[$key] += $size; } // Filter empty array return array_filter($groups); From ee3f81fc7bcb3dfa2c4ac24c8e9309043cba4861 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 16 Aug 2021 16:58:00 -0500 Subject: [PATCH 704/888] MQE-2729: [PHP 8] Investigate and fix code related to changes in implode() - add 'match' as reserved word to static tests --- .../Magento/Sniffs/NamingConventions/ReservedWordsSniff.php | 1 + 1 file changed, 1 insertion(+) diff --git a/dev/tests/static/Magento/Sniffs/NamingConventions/ReservedWordsSniff.php b/dev/tests/static/Magento/Sniffs/NamingConventions/ReservedWordsSniff.php index f41c235a6..7d1957195 100644 --- a/dev/tests/static/Magento/Sniffs/NamingConventions/ReservedWordsSniff.php +++ b/dev/tests/static/Magento/Sniffs/NamingConventions/ReservedWordsSniff.php @@ -32,6 +32,7 @@ class ReservedWordsSniff implements Sniff 'object' => '7', 'mixed' => '7', 'numeric' => '7', + 'match' => '8', ]; /** From 3e453ac900dbbae800cd1ec4b4fbfb2788345b65 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Tue, 17 Aug 2021 10:37:04 -0500 Subject: [PATCH 705/888] MQE-2729: [PHP 8] Investigate and fix code related to changes in implode() - update MFTF phpunit.xml file to follow latest schema --- dev/tests/phpunit.xml | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/dev/tests/phpunit.xml b/dev/tests/phpunit.xml index 1014ec7c3..049977650 100644 --- a/dev/tests/phpunit.xml +++ b/dev/tests/phpunit.xml @@ -1,16 +1,25 @@ +<?xml version="1.0"?> <!-- /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> - -<phpunit - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.1/phpunit.xsd" - convertNoticesToExceptions="false" - bootstrap="_bootstrap.php" - backupGlobals="false"> +<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd" convertNoticesToExceptions="false" + bootstrap="_bootstrap.php" backupGlobals="false"> + <coverage processUncoveredFiles="false"> + <include> + <directory suffix=".php">../../src/Magento/FunctionalTestingFramework/DataGenerator</directory> + <directory suffix=".php">../../src/Magento/FunctionalTestingFramework/Page</directory> + <directory suffix=".php">../../src/Magento/FunctionalTestingFramework/Suite</directory> + <directory suffix=".php">../../src/Magento/FunctionalTestingFramework/Test</directory> + <directory suffix=".php">../../src/Magento/FunctionalTestingFramework/Util</directory> + </include> + <report> + <clover outputFile="build/logs/clover.xml"/> + </report> + </coverage> <testsuites> <testsuite name="verification"> <directory>verification</directory> @@ -19,16 +28,5 @@ <directory>unit</directory> </testsuite> </testsuites> - <filter> - <whitelist processUncoveredFilesFromWhitelist="false"> - <directory suffix=".php">../../src/Magento/FunctionalTestingFramework/DataGenerator</directory> - <directory suffix=".php">../../src/Magento/FunctionalTestingFramework/Page</directory> - <directory suffix=".php">../../src/Magento/FunctionalTestingFramework/Suite</directory> - <directory suffix=".php">../../src/Magento/FunctionalTestingFramework/Test</directory> - <directory suffix=".php">../../src/Magento/FunctionalTestingFramework/Util</directory> - </whitelist> - </filter> - <logging> - <log type="coverage-clover" target="build/logs/clover.xml"/> - </logging> + <logging/> </phpunit> From bbf9b20c1f6a90deaa843b53bdf8793db684f043 Mon Sep 17 00:00:00 2001 From: Karyna <k.tsymbal@atwix.com> Date: Wed, 18 Aug 2021 14:44:12 +0300 Subject: [PATCH 706/888] PHP 8 support - fix code related to changes in CURL --- .../DataTransport/Protocol/CurlTransport.php | 17 ++++++++++++----- .../Extension/TestContextExtension.php | 5 ++++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/DataTransport/Protocol/CurlTransport.php b/src/Magento/FunctionalTestingFramework/DataTransport/Protocol/CurlTransport.php index a34bad6ce..6d064feb5 100644 --- a/src/Magento/FunctionalTestingFramework/DataTransport/Protocol/CurlTransport.php +++ b/src/Magento/FunctionalTestingFramework/DataTransport/Protocol/CurlTransport.php @@ -132,18 +132,18 @@ public function write($url, $body = [], $method = CurlInterface::POST, $headers CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_COOKIEFILE => '', - CURLOPT_HTTPHEADER => $headers, + CURLOPT_HTTPHEADER => is_object($headers) ? (array) $headers : $headers, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => false, ]; switch ($method) { case CurlInterface::POST: $options[CURLOPT_POST] = true; - $options[CURLOPT_POSTFIELDS] = $body; + $options[CURLOPT_POSTFIELDS] = is_object($body) ? (array) $body : $body; break; case CurlInterface::PUT: $options[CURLOPT_CUSTOMREQUEST] = self::PUT; - $options[CURLOPT_POSTFIELDS] = $body; + $options[CURLOPT_POSTFIELDS] = is_object($body) ? (array) $body : $body; break; case CurlInterface::DELETE: $options[CURLOPT_CUSTOMREQUEST] = self::DELETE; @@ -189,7 +189,10 @@ public function read($successRegex = null, $returnRegex = null, $returnIndex = n */ public function close() { - curl_close($this->getResource()); + if (version_compare(PHP_VERSION, '8.0') < 0) { + // this function no longer has an effect in PHP 8.0, but it's required in earlier versions + curl_close($this->getResource()); + } $this->resource = null; } @@ -271,7 +274,11 @@ public function multiRequest(array $urls, array $options = []) $result[$key] = curl_multi_getcontent($handle); curl_multi_remove_handle($multiHandle, $handle); } - curl_multi_close($multiHandle); + if (version_compare(PHP_VERSION, '8.0') < 0) { + // this function no longer has an effect in PHP 8.0, but it's required in earlier versions + curl_multi_close($multiHandle); + } + return $result; } diff --git a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php index e4f433a2a..bc3777c4c 100644 --- a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php +++ b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php @@ -72,7 +72,10 @@ public function testStart(\Codeception\Event\TestEvent $e) CURLOPT_URL => getenv('MAGENTO_BASE_URL') . "/test.php?test=" . $this->currentTest, ]); curl_exec($cURLConnection); - curl_close($cURLConnection); + if (version_compare(PHP_VERSION, '8.0') < 0) { + // this function no longer has an effect in PHP 8.0, but it's required in earlier versions + curl_close($cURLConnection); + } } PersistedObjectHandler::getInstance()->clearHookObjects(); From f884ba807b1995c7af3cb3d7f910e98c27d7eac0 Mon Sep 17 00:00:00 2001 From: Andrii Beziazychnyi <a.beziazychnyi@atwix.com> Date: Wed, 18 Aug 2021 15:38:25 +0300 Subject: [PATCH 707/888] The `squizlabs/php_codesniffer` composer dependency has been updated to 3.6.0 --- composer.json | 2 +- composer.lock | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/composer.json b/composer.json index 337c0519b..4a29f72e3 100755 --- a/composer.json +++ b/composer.json @@ -45,7 +45,7 @@ "phpmd/phpmd": "^2.8.0", "phpunit/phpunit": "^9.0", "sebastian/phpcpd": "~6.0.0", - "squizlabs/php_codesniffer": "~3.5.4" + "squizlabs/php_codesniffer": "~3.6.0" }, "autoload": { "files": ["src/Magento/FunctionalTestingFramework/_bootstrap.php"], diff --git a/composer.lock b/composer.lock index 2ab461e57..f12838d3b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "cb8347aab3be241fe1517983f3fc044c", + "content-hash": "56d4fb53d9dbda3444499d2fce97e9fc", "packages": [ { "name": "allure-framework/allure-codeception", @@ -8001,16 +8001,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.5.8", + "version": "3.6.0", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "9d583721a7157ee997f235f327de038e7ea6dac4" + "reference": "ffced0d2c8fa8e6cdc4d695a743271fab6c38625" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/9d583721a7157ee997f235f327de038e7ea6dac4", - "reference": "9d583721a7157ee997f235f327de038e7ea6dac4", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ffced0d2c8fa8e6cdc4d695a743271fab6c38625", + "reference": "ffced0d2c8fa8e6cdc4d695a743271fab6c38625", "shasum": "" }, "require": { @@ -8053,7 +8053,7 @@ "source": "https://github.com/squizlabs/PHP_CodeSniffer", "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" }, - "time": "2020-10-23T02:01:07+00:00" + "time": "2021-04-09T00:54:41+00:00" }, { "name": "symfony/config", From 860a39e280091930e8110e1711e333054330ebaa Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Wed, 18 Aug 2021 17:39:18 +0300 Subject: [PATCH 708/888] MFTF-33782: Made NULL value equal to the default argument value --- .../Util/Path/FilePathFormatterTest.php | 39 ++++++++++++------- .../Util/Path/UrlFormatterTest.php | 27 ++++++++----- 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/FilePathFormatterTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/FilePathFormatterTest.php index 34365ac5d..c833fc6be 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/FilePathFormatterTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/FilePathFormatterTest.php @@ -16,21 +16,29 @@ class FilePathFormatterTest extends MagentoTestCase /** * Test file format. * - * @param string $path - * @param bool $withTrailingSeparator + * @param string $path + * @param bool|null $withTrailingSeparator * @param string|null $expectedPath * * @return void * @throws TestFrameworkException * @dataProvider formatDataProvider */ - public function testFormat(string $path, bool $withTrailingSeparator, ?string $expectedPath): void + public function testFormat(string $path, ?bool $withTrailingSeparator, ?string $expectedPath): void { if (null !== $expectedPath) { + if ($withTrailingSeparator === null) { + $this->assertEquals($expectedPath, FilePathFormatter::format($path)); + return; + } $this->assertEquals($expectedPath, FilePathFormatter::format($path, $withTrailingSeparator)); } else { // Assert no exception - FilePathFormatter::format($path, $withTrailingSeparator); + if ($withTrailingSeparator === null) { + FilePathFormatter::format($path); + } else { + FilePathFormatter::format($path, $withTrailingSeparator); + } $this->assertTrue(true); } } @@ -38,17 +46,22 @@ public function testFormat(string $path, bool $withTrailingSeparator, ?string $e /** * Test file format with exception. * - * @param string $path - * @param bool $withTrailingSeparator + * @param string $path + * @param bool|null $withTrailingSeparator * * @return void * @throws TestFrameworkException * @dataProvider formatExceptionDataProvider */ - public function testFormatWithException(string $path, bool $withTrailingSeparator): void + public function testFormatWithException(string $path, ?bool $withTrailingSeparator): void { $this->expectException(TestFrameworkException::class); $this->expectExceptionMessage("Invalid or non-existing file: $path\n"); + + if ($withTrailingSeparator === null) { + FilePathFormatter::format($path); + return; + } FilePathFormatter::format($path, $withTrailingSeparator); } @@ -63,14 +76,14 @@ public function formatDataProvider(): array $path2 = $path1 . DIRECTORY_SEPARATOR; return [ - [$path1, false, $path1], + [$path1, null, $path2], [$path1, false, $path1], [$path1, true, $path2], - [$path2, false, $path1], + [$path2, null, $path2], [$path2, false, $path1], [$path2, true, $path2], - [__DIR__. DIRECTORY_SEPARATOR . basename(__FILE__), false, __FILE__], - ['', false, null] // Empty string is valid + [__DIR__ . DIRECTORY_SEPARATOR . basename(__FILE__), null, __FILE__ . DIRECTORY_SEPARATOR], + ['', null, null] // Empty string is valid ]; } @@ -82,8 +95,8 @@ public function formatDataProvider(): array public function formatExceptionDataProvider(): array { return [ - ['abc', false], - ['X://some\dir/@', false] + ['abc', null], + ['X://some\dir/@', null] ]; } } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/UrlFormatterTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/UrlFormatterTest.php index dcb076b91..21cfa9daa 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/UrlFormatterTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/UrlFormatterTest.php @@ -17,14 +17,18 @@ class UrlFormatterTest extends MagentoTestCase * Test url format. * * @param string $path - * @param bool $withTrailingSeparator + * @param bool|null $withTrailingSeparator * @param string $expectedPath * * @return void * @dataProvider formatDataProvider */ - public function testFormat(string $path, bool $withTrailingSeparator, string $expectedPath): void + public function testFormat(string $path, ?bool $withTrailingSeparator, string $expectedPath): void { + if ($withTrailingSeparator === null) { + $this->assertEquals($expectedPath, UrlFormatter::format($path)); + return; + } $this->assertEquals($expectedPath, UrlFormatter::format($path, $withTrailingSeparator)); } @@ -32,15 +36,20 @@ public function testFormat(string $path, bool $withTrailingSeparator, string $ex * Test url format with exception. * * @param string $path - * @param bool $withTrailingSeparator + * @param bool|null $withTrailingSeparator * * @return void * @dataProvider formatExceptionDataProvider */ - public function testFormatWithException(string $path, bool $withTrailingSeparator): void + public function testFormatWithException(string $path, ?bool $withTrailingSeparator): void { $this->expectException(TestFrameworkException::class); $this->expectExceptionMessage("Invalid url: $path\n"); + + if ($withTrailingSeparator === null) { + UrlFormatter::format($path); + return; + } UrlFormatter::format($path, $withTrailingSeparator); } @@ -62,16 +71,16 @@ public function formatDataProvider(): array $url9 = 'http://www.google.com'; return [ - [$url1, false, $url1], + [$url1, null, $url2], [$url1, false, $url1], [$url1, true, $url2], - [$url2, false, $url1], + [$url2, null, $url2], [$url2, false, $url1], [$url2, true, $url2], - [$url3, false, $url3], + [$url3, null, $url4], [$url3, false, $url3], [$url3, true, $url4], - [$url4, false, $url3], + [$url4, null, $url4], [$url4, false, $url3], [$url4, true, $url4], [$url5, true, $url6], @@ -91,7 +100,7 @@ public function formatDataProvider(): array public function formatExceptionDataProvider(): array { return [ - ['', false] + ['', null] ]; } } From a08684a1af36903d1ef2ca28cf897d6168502246 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Wed, 18 Aug 2021 09:55:09 -0500 Subject: [PATCH 709/888] MQE-2721: [PHP 8] Remove usage of reserved keyword "match" --- .../FunctionalTestingFramework/Config/Dom/ArrayNodeConfig.php | 4 ++-- .../Config/Dom/NodeMergingConfig.php | 2 +- .../FunctionalTestingFramework/Config/Dom/NodePathMatcher.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Config/Dom/ArrayNodeConfig.php b/src/Magento/FunctionalTestingFramework/Config/Dom/ArrayNodeConfig.php index 5f03450dc..d224bb882 100644 --- a/src/Magento/FunctionalTestingFramework/Config/Dom/ArrayNodeConfig.php +++ b/src/Magento/FunctionalTestingFramework/Config/Dom/ArrayNodeConfig.php @@ -64,7 +64,7 @@ public function __construct( public function isNumericArray($nodeXpath) { foreach ($this->numericArrays as $pathPattern) { - if ($this->nodePathMatcher->match($pathPattern, $nodeXpath)) { + if ($this->nodePathMatcher->pathMatch($pathPattern, $nodeXpath)) { return true; } } @@ -84,7 +84,7 @@ public function getAssocArrayKeyAttribute($nodeXpath) } foreach ($this->assocArrays as $pathPattern => $keyAttribute) { - if ($this->nodePathMatcher->match($pathPattern, $nodeXpath)) { + if ($this->nodePathMatcher->pathMatch($pathPattern, $nodeXpath)) { return $keyAttribute; } } diff --git a/src/Magento/FunctionalTestingFramework/Config/Dom/NodeMergingConfig.php b/src/Magento/FunctionalTestingFramework/Config/Dom/NodeMergingConfig.php index e4231c8ec..f02b1dc5c 100644 --- a/src/Magento/FunctionalTestingFramework/Config/Dom/NodeMergingConfig.php +++ b/src/Magento/FunctionalTestingFramework/Config/Dom/NodeMergingConfig.php @@ -44,7 +44,7 @@ public function __construct(NodePathMatcher $nodePathMatcher, array $idAttribute public function getIdAttribute($nodeXpath) { foreach ($this->idAttributes as $pathPattern => $idAttribute) { - if ($this->nodePathMatcher->match($pathPattern, $nodeXpath)) { + if ($this->nodePathMatcher->pathMatch($pathPattern, $nodeXpath)) { return $idAttribute; } } diff --git a/src/Magento/FunctionalTestingFramework/Config/Dom/NodePathMatcher.php b/src/Magento/FunctionalTestingFramework/Config/Dom/NodePathMatcher.php index 2857bbea6..b7c3f9185 100644 --- a/src/Magento/FunctionalTestingFramework/Config/Dom/NodePathMatcher.php +++ b/src/Magento/FunctionalTestingFramework/Config/Dom/NodePathMatcher.php @@ -17,7 +17,7 @@ class NodePathMatcher * @param string $xpathSubject Example: '/some[@attr="value"]/static/ns:path'. * @return boolean */ - public function match($pathPattern, $xpathSubject) + public function pathMatch($pathPattern, $xpathSubject) { $pathSubject = $this->simplifyXpath($xpathSubject); $pathPattern = '#^' . $pathPattern . '$#'; From c817aeaac98f1a3924ea8f9aa5621386e002344c Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Thu, 19 Aug 2021 15:35:29 +0300 Subject: [PATCH 710/888] MFTF-33780: Changed loose comparisons into strict --- .../NamingConventions/InterfaceNameSniff.php | 6 ++--- .../OperationDataArrayResolverTest.php | 4 ++-- .../Suite/Handlers/SuiteObjectHandlerTest.php | 4 ++-- .../Suite/SuiteGeneratorTest.php | 6 ++--- .../Test/Objects/ActionGroupObjectTest.php | 10 ++++---- dev/tests/unit/Util/SuiteDataArrayBuilder.php | 4 ++-- dev/tests/unit/Util/TestDataArrayBuilder.php | 12 +++++----- dev/tests/unit/Util/TestLoggingUtil.php | 2 +- .../Tests/ResilientGenerationTest.php | 6 ++--- etc/config/command.php | 4 ++-- .../Allure/Adapter/MagentoAllureAdapter.php | 8 +++---- .../Allure/AllureHelper.php | 2 +- .../Codeception/Subscriber/Console.php | 4 ++-- .../Composer/ComposerInstall.php | 4 ++-- .../Composer/ComposerPackage.php | 2 +- .../Config/Converter.php | 10 ++++---- .../Config/Converter/Dom/Flat.php | 8 +++---- .../FunctionalTestingFramework/Config/Dom.php | 4 ++-- .../Config/MftfApplicationConfig.php | 4 ++-- .../Config/Reader/Filesystem.php | 2 +- .../Config/Reader/MftfFilesystem.php | 4 ++-- .../Config/ValidationState.php | 2 +- .../Console/DoctorCommand.php | 2 +- .../Console/GenerateDevUrnCommand.php | 4 ++-- .../Console/GenerateTestsCommand.php | 3 ++- .../Console/RunManifestCommand.php | 2 +- .../Console/RunTestCommand.php | 4 ++-- .../Console/RunTestFailedCommand.php | 6 ++--- .../Console/RunTestGroupCommand.php | 4 ++-- .../Data/Argument/Interpreter/ArrayType.php | 2 +- .../DataGenerator/Config/Dom.php | 2 +- .../Handlers/CredentialStore.php | 8 +++---- .../Handlers/DataObjectHandler.php | 4 ++-- .../Handlers/PersistedObjectHandler.php | 10 ++++---- .../Objects/EntityDataObject.php | 12 +++++----- .../Objects/OperationDefinitionObject.php | 2 +- .../Persist/OperationDataArrayResolver.php | 18 +++++++------- .../DataGenerator/Util/DataExtensionUtil.php | 2 +- .../DataTransport/WebApiExecutor.php | 2 +- .../Extension/TestContextExtension.php | 8 +++---- .../Module/MagentoAssert.php | 2 +- .../Module/MagentoWebDriver.php | 8 +++---- .../ObjectManager/Config/Mapper/Dom.php | 8 +++---- .../ObjectManager/Factory.php | 6 +++-- .../Factory/Dynamic/Developer.php | 3 ++- .../Page/Handlers/PageObjectHandler.php | 2 +- .../Page/Objects/ElementObject.php | 8 +++---- .../StaticCheck/AnnotationsCheck.php | 4 ++-- .../StaticCheck/TestDependencyCheck.php | 4 ++-- .../Suite/Generators/GroupClassGenerator.php | 6 ++--- .../Suite/Handlers/SuiteObjectHandler.php | 2 +- .../Suite/SuiteGenerator.php | 4 ++-- .../Suite/Util/SuiteObjectExtractor.php | 13 +++++----- .../Test/Config/Converter/Dom/Flat.php | 12 +++++----- .../Test/Config/Dom.php | 2 +- .../Handlers/ActionGroupObjectHandler.php | 4 ++-- .../Test/Handlers/TestObjectHandler.php | 8 +++---- .../Test/Objects/ActionGroupObject.php | 4 ++-- .../Test/Objects/ActionObject.php | 24 +++++++++---------- .../Test/Objects/TestObject.php | 2 +- .../Test/Util/ActionMergeUtil.php | 4 ++-- .../Test/Util/ActionObjectExtractor.php | 11 +++++---- .../Test/Util/AnnotationExtractor.php | 12 +++++----- .../Test/Util/ObjectExtensionUtil.php | 4 ++-- .../Upgrade/UpdateAssertionSchema.php | 14 +++++------ .../Util/ComposerModuleResolver.php | 4 ++-- .../Util/ConfigSanitizerUtil.php | 8 +++---- .../Util/Logger/LoggingUtil.php | 2 +- .../Util/ModulePathExtractor.php | 4 ++-- .../Util/ModuleResolver.php | 8 +++---- .../ModuleResolver/ModuleResolverService.php | 4 ++-- .../Util/Script/ScriptUtil.php | 2 +- .../Util/Sorter/ParallelGroupSorter.php | 14 +++++------ .../Util/TestGenerator.php | 22 ++++++++--------- .../DuplicateNodeValidationUtil.php | 4 ++-- .../SingleNodePerFileValidationUtil.php | 2 +- 76 files changed, 229 insertions(+), 223 deletions(-) diff --git a/dev/tests/static/Magento/Sniffs/NamingConventions/InterfaceNameSniff.php b/dev/tests/static/Magento/Sniffs/NamingConventions/InterfaceNameSniff.php index 1618beb66..4c8461bea 100644 --- a/dev/tests/static/Magento/Sniffs/NamingConventions/InterfaceNameSniff.php +++ b/dev/tests/static/Magento/Sniffs/NamingConventions/InterfaceNameSniff.php @@ -29,9 +29,9 @@ public function process(File $sourceFile, $stackPtr) $declarationLine = $tokens[$stackPtr]['line']; $suffixLength = strlen(self::INTERFACE_SUFFIX); // Find first T_STRING after 'interface' keyword in the line and verify it - while ($tokens[$stackPtr]['line'] == $declarationLine) { - if ($tokens[$stackPtr]['type'] == 'T_STRING') { - if (substr($tokens[$stackPtr]['content'], 0 - $suffixLength) != self::INTERFACE_SUFFIX) { + while ($tokens[$stackPtr]['line'] === $declarationLine) { + if ($tokens[$stackPtr]['type'] === 'T_STRING') { + if (substr($tokens[$stackPtr]['content'], 0 - $suffixLength) !== self::INTERFACE_SUFFIX) { $sourceFile->addError( 'Interface should have name that ends with "Interface" suffix.', $stackPtr, diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php index db043f860..ce1911fd0 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php @@ -306,7 +306,7 @@ public function testNestedMetadataArrayOfValue(): void $callback = function ($name) { $entityDataObjectBuilder = new EntityDataObjectBuilder(); - if ($name == 'childObject1') { + if ($name === 'childObject1') { return $entityDataObjectBuilder ->withName('childObject1') ->withType('childType') @@ -314,7 +314,7 @@ public function testNestedMetadataArrayOfValue(): void ->build(); }; - if ($name == 'childObject2') { + if ($name === 'childObject2') { return $entityDataObjectBuilder ->withName('childObject2') ->withType('childType') diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/Handlers/SuiteObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/Handlers/SuiteObjectHandlerTest.php index c672d20b7..373e0d6c1 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/Handlers/SuiteObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/Handlers/SuiteObjectHandlerTest.php @@ -113,11 +113,11 @@ private function setMockTestAndSuiteParserOutput(array $testData, array $suiteDa ->will( $this->returnCallback( function ($clazz) use ($mockDataParser, $mockSuiteDataParser) { - if ($clazz == TestDataParser::class) { + if ($clazz === TestDataParser::class) { return $mockDataParser; } - if ($clazz == SuiteDataParser::class) { + if ($clazz === SuiteDataParser::class) { return $mockSuiteDataParser; } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php index 15d6b4a5f..f6e215a5b 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php @@ -347,13 +347,13 @@ function ( $mockGroupClass, $objectManager ) { - if ($class == TestDataParser::class) { + if ($class === TestDataParser::class) { return $mockDataParser; } - if ($class == SuiteDataParser::class) { + if ($class === SuiteDataParser::class) { return $mockSuiteDataParser; } - if ($class == GroupClassGenerator::class) { + if ($class === GroupClassGenerator::class) { return $mockGroupClass; } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionGroupObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionGroupObjectTest.php index 60e97e79c..a6df01937 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionGroupObjectTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionGroupObjectTest.php @@ -61,7 +61,7 @@ public function testGetStepsWithDefaultCase(): void public function testGetStepsWithCustomArgs(): void { $this->setEntityObjectHandlerReturn(function ($entityName) { - if ($entityName == "data2") { + if ($entityName === 'data2') { return (new EntityDataObjectBuilder())->withDataFields(['field2' => 'testValue2'])->build(); } }); @@ -128,7 +128,7 @@ public function testGetStepsWithPersistedArgs(): void public function testGetStepsWithNoFieldArg(): void { $this->setEntityObjectHandlerReturn(function ($entityName) { - if ($entityName == "data2") { + if ($entityName === 'data2') { return (new EntityDataObjectBuilder())->withDataFields(['field2' => 'testValue2'])->build(); } }); @@ -151,7 +151,7 @@ public function testGetStepsWithNoFieldArg(): void public function testGetStepsWithNoArgs(): void { $this->setEntityObjectHandlerReturn(function ($entityName) { - if ($entityName == "data1") { + if ($entityName === 'data1') { return (new EntityDataObjectBuilder())->withDataFields(['field1' => 'testValue'])->build(); } }); @@ -174,7 +174,7 @@ public function testGetStepsWithParameterizedArg(): void { // Mock Entity Object Handler $this->setEntityObjectHandlerReturn(function ($entityName) { - if ($entityName == "data2") { + if ($entityName === 'data2') { return (new EntityDataObjectBuilder())->withDataFields(['field2' => 'testValue2'])->build(); } }); @@ -216,7 +216,7 @@ public function testGetStepsWithParameterizedSimpleArg(): void { // Mock Entity Object Handler $this->setEntityObjectHandlerReturn(function ($entityName) { - if ($entityName == "data2") { + if ($entityName === 'data2') { return (new EntityDataObjectBuilder())->withDataFields(['field2' => 'testValue2'])->build(); } }); diff --git a/dev/tests/unit/Util/SuiteDataArrayBuilder.php b/dev/tests/unit/Util/SuiteDataArrayBuilder.php index 85411b447..9f937707a 100644 --- a/dev/tests/unit/Util/SuiteDataArrayBuilder.php +++ b/dev/tests/unit/Util/SuiteDataArrayBuilder.php @@ -181,7 +181,7 @@ private function appendEntriesToSuiteContents($currentContents, $type, $contents */ public function withAfterHook($afterHook = null) { - if ($afterHook == null) { + if ($afterHook === null) { $this->afterHook = [$this->testActionAfterName => [ ActionObjectExtractor::NODE_NAME => $this->testActionType, ActionObjectExtractor::TEST_STEP_MERGE_KEY => $this->testActionAfterName @@ -202,7 +202,7 @@ public function withAfterHook($afterHook = null) */ public function withBeforeHook($beforeHook = null) { - if ($beforeHook == null) { + if ($beforeHook === null) { $this->beforeHook = [$this->testActionBeforeName => [ ActionObjectExtractor::NODE_NAME => $this->testActionType, ActionObjectExtractor::TEST_STEP_MERGE_KEY => $this->testActionBeforeName diff --git a/dev/tests/unit/Util/TestDataArrayBuilder.php b/dev/tests/unit/Util/TestDataArrayBuilder.php index e40d80e83..0a9672dd7 100644 --- a/dev/tests/unit/Util/TestDataArrayBuilder.php +++ b/dev/tests/unit/Util/TestDataArrayBuilder.php @@ -109,7 +109,7 @@ public function withName($name) */ public function withAnnotations($annotations = null) { - if ($annotations == null) { + if ($annotations === null) { $this->annotations = ['group' => [['value' => 'test']]]; } else { $this->annotations = $annotations; @@ -126,7 +126,7 @@ public function withAnnotations($annotations = null) */ public function withBeforeHook($beforeHook = null) { - if ($beforeHook == null) { + if ($beforeHook === null) { $this->beforeHook = [$this->testActionBeforeName => [ ActionObjectExtractor::NODE_NAME => $this->testActionType, ActionObjectExtractor::TEST_STEP_MERGE_KEY => $this->testActionBeforeName @@ -146,7 +146,7 @@ public function withBeforeHook($beforeHook = null) */ public function withAfterHook($afterHook = null) { - if ($afterHook == null) { + if ($afterHook === null) { $this->afterHook = [$this->testActionAfterName => [ ActionObjectExtractor::NODE_NAME => $this->testActionType, ActionObjectExtractor::TEST_STEP_MERGE_KEY => $this->testActionAfterName @@ -167,7 +167,7 @@ public function withAfterHook($afterHook = null) */ public function withFailedHook($failedHook = null) { - if ($failedHook == null) { + if ($failedHook === null) { $this->failedHook = [$this->testActionFailedName => [ ActionObjectExtractor::NODE_NAME => $this->testActionType, ActionObjectExtractor::TEST_STEP_MERGE_KEY => $this->testActionFailedName @@ -188,7 +188,7 @@ public function withFailedHook($failedHook = null) */ public function withTestActions($actions = null) { - if ($actions == null) { + if ($actions === null) { $this->testActions = [$this->testTestActionName => [ ActionObjectExtractor::NODE_NAME => $this->testActionType, ActionObjectExtractor::TEST_STEP_MERGE_KEY => $this->testTestActionName @@ -207,7 +207,7 @@ public function withTestActions($actions = null) */ public function withFileName($filename = null) { - if ($filename == null) { + if ($filename === null) { $this->filename = "/magento2-functional-testing-framework/dev/tests/verification/TestModule/Test/BasicFunctionalTest.xml"; } else { diff --git a/dev/tests/unit/Util/TestLoggingUtil.php b/dev/tests/unit/Util/TestLoggingUtil.php index f275a5c97..ed29f091c 100644 --- a/dev/tests/unit/Util/TestLoggingUtil.php +++ b/dev/tests/unit/Util/TestLoggingUtil.php @@ -40,7 +40,7 @@ private function __construct() */ public static function getInstance(): TestLoggingUtil { - if (self::$instance == null) { + if (self::$instance === null) { self::$instance = new TestLoggingUtil(); } return self::$instance; diff --git a/dev/tests/verification/Tests/ResilientGenerationTest.php b/dev/tests/verification/Tests/ResilientGenerationTest.php index bf65094e3..cbd032ed2 100644 --- a/dev/tests/verification/Tests/ResilientGenerationTest.php +++ b/dev/tests/verification/Tests/ResilientGenerationTest.php @@ -123,7 +123,7 @@ public function testGenerateAllSuites() SuiteGenerator::getInstance()->generateAllSuites($testManifest); foreach (SuiteTestReferences::$data as $groupName => $expectedContents) { - if (substr($groupName, 0, 11) != 'NotGenerate') { + if (substr($groupName, 0, 11) !== 'NotGenerate') { // Validate Yaml file updated $yml = Yaml::parse(file_get_contents(self::CONFIG_YML_FILE)); $this->assertArrayHasKey($groupName, $yml['groups']); @@ -175,7 +175,7 @@ function () use ($groupName) { ); } - if (substr($groupName, 0, 11) != 'NotGenerate') { + if (substr($groupName, 0, 11) !== 'NotGenerate') { // Validate Yaml file updated $yml = Yaml::parse(file_get_contents(self::CONFIG_YML_FILE)); $this->assertArrayHasKey($groupName, $yml['groups']); @@ -199,7 +199,7 @@ function () use ($groupName) { } // Validate log message - if (substr($groupName, 0, 11) != 'NotGenerate' + if (substr($groupName, 0, 11) !== 'NotGenerate' && !in_array($groupName, array_keys(self::$exceptionGrpLogs))) { $type = 'info'; $message = '/suite generated/'; diff --git a/etc/config/command.php b/etc/config/command.php index e3b8f1191..72c6f1a42 100644 --- a/etc/config/command.php +++ b/etc/config/command.php @@ -18,7 +18,7 @@ // Token returned will be null if the token we passed in is invalid $tokenFromMagento = $tokenModel->loadByToken($tokenPassedIn)->getToken(); - if (!empty($tokenFromMagento) && ($tokenFromMagento == $tokenPassedIn)) { + if (!empty($tokenFromMagento) && ($tokenFromMagento === $tokenPassedIn)) { $php = PHP_BINDIR ? PHP_BINDIR . '/php' : 'php'; $magentoBinary = $php . ' -f ../../../../bin/magento'; $valid = validateCommand($magentoBinary, $command); @@ -52,7 +52,7 @@ $exitCode = $process->getExitCode(); - if ($exitCode == 0 || $idleTimeout) { + if ($process->isSuccessful() || $idleTimeout) { http_response_code(202); } else { http_response_code(500); diff --git a/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php b/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php index 7d7a7bd44..d5efbbc0f 100644 --- a/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php +++ b/src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php @@ -63,7 +63,7 @@ class MagentoAllureAdapter extends AllureCodeception */ private function getGroup() { - if ($this->options['groups'] != null) { + if ($this->options['groups'] !== null) { return $this->options['groups'][0]; } return null; @@ -79,7 +79,7 @@ public function suiteBefore(SuiteEvent $suiteEvent) { $changeSuiteEvent = $suiteEvent; - if ($this->getGroup() != null) { + if ($this->getGroup() !== null) { $suite = $suiteEvent->getSuite(); $suiteName = ($suite->getName()) . "\\" . $this->sanitizeGroupName($this->getGroup()); @@ -414,8 +414,8 @@ private function removeAttachments($step, $testFailed) private function formatAllureTestClassName($test) { if ($this->getGroup() !== null) { - foreach ($test->getLabels() as $name => $label) { - if ($label->getName() == 'testClass') { + foreach ($test->getLabels() as $label) { + if ($label->getName() === 'testClass') { $originalTestClass = $this->sanitizeTestClassLabel($label->getValue()); call_user_func(\Closure::bind( function () use ($label, $originalTestClass) { diff --git a/src/Magento/FunctionalTestingFramework/Allure/AllureHelper.php b/src/Magento/FunctionalTestingFramework/Allure/AllureHelper.php index 4fbd65eb7..cc0251a48 100644 --- a/src/Magento/FunctionalTestingFramework/Allure/AllureHelper.php +++ b/src/Magento/FunctionalTestingFramework/Allure/AllureHelper.php @@ -50,7 +50,7 @@ public static function addAttachmentToLastStep($data, $caption): void $rootStep = Allure::lifecycle()->getStepStorage()->getLast(); $trueLastStep = array_last($rootStep->getSteps()); - if ($trueLastStep == null) { + if ($trueLastStep === null) { // Nothing to attach to; do not fire off allure event return; } diff --git a/src/Magento/FunctionalTestingFramework/Codeception/Subscriber/Console.php b/src/Magento/FunctionalTestingFramework/Codeception/Subscriber/Console.php index 90f04abae..c6c6a4eec 100644 --- a/src/Magento/FunctionalTestingFramework/Codeception/Subscriber/Console.php +++ b/src/Magento/FunctionalTestingFramework/Codeception/Subscriber/Console.php @@ -119,7 +119,7 @@ public function beforeStep(StepEvent $e) } $metaStep = $e->getStep()->getMetaStep(); - if ($metaStep and $this->metaStep != $metaStep) { + if ($metaStep and $this->metaStep !== $metaStep) { $this->message(' ' . $metaStep->getPrefix()) ->style('bold') ->append($metaStep->__toString()) @@ -158,7 +158,7 @@ public function afterStep(StepEvent $e) */ private function printStepKeys(Step $step) { - if ($step instanceof Comment and $step->__toString() == '') { + if ($step instanceof Comment and $step->__toString() === '') { return; // don't print empty comments } diff --git a/src/Magento/FunctionalTestingFramework/Composer/ComposerInstall.php b/src/Magento/FunctionalTestingFramework/Composer/ComposerInstall.php index f10c0b418..151fdc86e 100644 --- a/src/Magento/FunctionalTestingFramework/Composer/ComposerInstall.php +++ b/src/Magento/FunctionalTestingFramework/Composer/ComposerInstall.php @@ -50,7 +50,7 @@ public function isInstalledPackageOfType($packageName, $packageType) { /** @var CompletePackageInterface $package */ foreach ($this->getLocker()->getLockedRepository()->getPackages() as $package) { - if (($package->getName() == $packageName) && ($package->getType() == $packageType)) { + if (($package->getName() === $packageName) && ($package->getType() === $packageType)) { return true; } } @@ -67,7 +67,7 @@ public function getInstalledTestPackages() $packages = []; /** @var CompletePackageInterface $package */ foreach ($this->getLocker()->getLockedRepository()->getPackages() as $package) { - if ($package->getType() == self::TEST_MODULE_PACKAGE_TYPE) { + if ($package->getType() === self::TEST_MODULE_PACKAGE_TYPE) { $packages[$package->getName()] = [ self::PACKAGE_NAME => $package->getName(), self::PACKAGE_TYPE => $package->getType(), diff --git a/src/Magento/FunctionalTestingFramework/Composer/ComposerPackage.php b/src/Magento/FunctionalTestingFramework/Composer/ComposerPackage.php index 0a6bfdca2..5e2d21c15 100644 --- a/src/Magento/FunctionalTestingFramework/Composer/ComposerPackage.php +++ b/src/Magento/FunctionalTestingFramework/Composer/ComposerPackage.php @@ -116,7 +116,7 @@ public function getSuggestedMagentoModules() */ public function isMftfTestPackage() { - return ($this->getType() == self::TEST_MODULE_PACKAGE_TYPE) ? true : false; + return $this->getType() === self::TEST_MODULE_PACKAGE_TYPE; } /** diff --git a/src/Magento/FunctionalTestingFramework/Config/Converter.php b/src/Magento/FunctionalTestingFramework/Config/Converter.php index cf61805dc..14b96907e 100644 --- a/src/Magento/FunctionalTestingFramework/Config/Converter.php +++ b/src/Magento/FunctionalTestingFramework/Config/Converter.php @@ -91,7 +91,7 @@ protected function convertXml($elements) foreach ($elements as $element) { if ($element instanceof \DOMElement) { - if ($element->getAttribute('remove') == 'true') { + if ($element->getAttribute('remove') === 'true') { // Remove element continue; } @@ -119,7 +119,7 @@ protected function convertXml($elements) } elseif (!empty($elementData)) { $result[$element->nodeName][] = $elementData; } - } elseif ($element->nodeType == XML_TEXT_NODE && trim($element->nodeValue) != '') { + } elseif ($element->nodeType === XML_TEXT_NODE && trim($element->nodeValue) !== '') { return ['value' => $element->nodeValue]; } } @@ -156,9 +156,9 @@ protected function getElementKey(\DOMElement $element) protected function isKeyAttribute(\DOMElement $element, \DOMAttr $attribute) { if (isset($this->idAttributes[$element->nodeName])) { - return $attribute->name == $this->idAttributes[$element->nodeName]; + return $attribute->name === $this->idAttributes[$element->nodeName]; } else { - return $attribute->name == self::NAME_ATTRIBUTE; + return $attribute->name === self::NAME_ATTRIBUTE; } } @@ -174,7 +174,7 @@ protected function getAttributes(\DOMElement $element) if ($element->hasAttributes()) { /** @var \DomAttr $attribute */ foreach ($element->attributes as $attribute) { - if (trim($attribute->nodeValue) != '' && !$this->isKeyAttribute($element, $attribute)) { + if (trim($attribute->nodeValue) !== '' && !$this->isKeyAttribute($element, $attribute)) { $attributes[$attribute->nodeName] = $this->castNumeric($attribute->nodeValue); } } diff --git a/src/Magento/FunctionalTestingFramework/Config/Converter/Dom/Flat.php b/src/Magento/FunctionalTestingFramework/Config/Converter/Dom/Flat.php index 001a811d9..742ef64f3 100644 --- a/src/Magento/FunctionalTestingFramework/Config/Converter/Dom/Flat.php +++ b/src/Magento/FunctionalTestingFramework/Config/Converter/Dom/Flat.php @@ -41,7 +41,7 @@ protected function getNodeAttributes(\DOMNode $node) $attributes = $node->attributes ?: []; /** @var \DOMNode $attribute */ foreach ($attributes as $attribute) { - if ($attribute->nodeType == XML_ATTRIBUTE_NODE) { + if ($attribute->nodeType === XML_ATTRIBUTE_NODE) { $result[$attribute->nodeName] = $attribute->nodeValue; } } @@ -77,7 +77,7 @@ public function convert(\DOMNode $source, $basePath = '') $value = []; /** @var \DOMNode $node */ foreach ($source->childNodes as $node) { - if ($node->nodeType == XML_ELEMENT_NODE) { + if ($node->nodeType === XML_ELEMENT_NODE) { $nodeName = $node->nodeName; $nodePath = $basePath . '/' . $nodeName; @@ -107,8 +107,8 @@ public function convert(\DOMNode $source, $basePath = '') } else { $value[$nodeName] = $nodeData; } - } elseif ($node->nodeType == XML_CDATA_SECTION_NODE - || ($node->nodeType == XML_TEXT_NODE && trim($node->nodeValue) != '') + } elseif ($node->nodeType === XML_CDATA_SECTION_NODE + || ($node->nodeType === XML_TEXT_NODE && trim($node->nodeValue) !== '') ) { $value = $node->nodeValue; break; diff --git a/src/Magento/FunctionalTestingFramework/Config/Dom.php b/src/Magento/FunctionalTestingFramework/Config/Dom.php index 881b677dc..91de64ae1 100644 --- a/src/Magento/FunctionalTestingFramework/Config/Dom.php +++ b/src/Magento/FunctionalTestingFramework/Config/Dom.php @@ -207,7 +207,7 @@ protected function replaceNodeValue($parentPath, \DOMElement $node, \DOMElement */ protected function isTextNode($node) { - return $node->childNodes->length == 1 && $node->childNodes->item(0) instanceof \DOMText; + return $node->childNodes->length === 1 && $node->childNodes->item(0) instanceof \DOMText; } /** @@ -273,7 +273,7 @@ protected function getMatchedNode($nodePath) $node = null; if ($matchedNodes->length > 1) { throw new \Exception("More than one node matching the query: {$nodePath}"); - } elseif ($matchedNodes->length == 1) { + } elseif ($matchedNodes->length === 1) { $node = $matchedNodes->item(0); } return $node; diff --git a/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php b/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php index 3aad73a06..7685ac919 100644 --- a/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php +++ b/src/Magento/FunctionalTestingFramework/Config/MftfApplicationConfig.php @@ -135,7 +135,7 @@ public static function create( $allowSkipped = false, $filters = [] ) { - if (self::$MFTF_APPLICATION_CONTEXT == null) { + if (self::$MFTF_APPLICATION_CONTEXT === null) { self::$MFTF_APPLICATION_CONTEXT = new MftfApplicationConfig( $forceGenerate, @@ -159,7 +159,7 @@ public static function getConfig() // TODO explicitly set this with AcceptanceTester or MagentoWebDriver // during execution we cannot guarantee the use of the robofile so we return the default application config, // we don't want to set the application context in case the user explicitly does so at a later time. - if (self::$MFTF_APPLICATION_CONTEXT == null) { + if (self::$MFTF_APPLICATION_CONTEXT === null) { return new MftfApplicationConfig(); } diff --git a/src/Magento/FunctionalTestingFramework/Config/Reader/Filesystem.php b/src/Magento/FunctionalTestingFramework/Config/Reader/Filesystem.php index edf490669..8e36a63d7 100644 --- a/src/Magento/FunctionalTestingFramework/Config/Reader/Filesystem.php +++ b/src/Magento/FunctionalTestingFramework/Config/Reader/Filesystem.php @@ -159,7 +159,7 @@ protected function readFiles($fileList) } else { $configMerger->merge($content); } - if (strcasecmp($debugLevel, MftfApplicationConfig::LEVEL_DEVELOPER) == 0) { + if (strcasecmp($debugLevel, MftfApplicationConfig::LEVEL_DEVELOPER) === 0) { $this->validateSchema($configMerger, $fileList->getFilename()); } } catch (\Magento\FunctionalTestingFramework\Config\Dom\ValidationException $e) { diff --git a/src/Magento/FunctionalTestingFramework/Config/Reader/MftfFilesystem.php b/src/Magento/FunctionalTestingFramework/Config/Reader/MftfFilesystem.php index 3740d683f..88a176a3c 100644 --- a/src/Magento/FunctionalTestingFramework/Config/Reader/MftfFilesystem.php +++ b/src/Magento/FunctionalTestingFramework/Config/Reader/MftfFilesystem.php @@ -42,7 +42,7 @@ public function readFiles($fileList) $configMerger->merge($content, $fileList->getFilename(), $exceptionCollector); } // run per file validation with generate:tests -d - if (strcasecmp($debugLevel, MftfApplicationConfig::LEVEL_DEVELOPER) == 0) { + if (strcasecmp($debugLevel, MftfApplicationConfig::LEVEL_DEVELOPER) === 0) { $this->validateSchema($configMerger, $fileList->getFilename()); } } catch (\Magento\FunctionalTestingFramework\Config\Dom\ValidationException $e) { @@ -52,7 +52,7 @@ public function readFiles($fileList) $exceptionCollector->throwException(); //run validation on merged file with generate:tests - if (strcasecmp($debugLevel, MftfApplicationConfig::LEVEL_DEFAULT) == 0) { + if (strcasecmp($debugLevel, MftfApplicationConfig::LEVEL_DEFAULT) === 0) { $this->validateSchema($configMerger); } diff --git a/src/Magento/FunctionalTestingFramework/Config/ValidationState.php b/src/Magento/FunctionalTestingFramework/Config/ValidationState.php index f08dc141a..d610f428a 100644 --- a/src/Magento/FunctionalTestingFramework/Config/ValidationState.php +++ b/src/Magento/FunctionalTestingFramework/Config/ValidationState.php @@ -37,6 +37,6 @@ public function __construct($appMode) */ public function isValidationRequired() { - return $this->appMode == 'developer'; // @todo + return $this->appMode === 'developer'; // @todo } } diff --git a/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php b/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php index aa0c81d57..f48da60d3 100644 --- a/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/DoctorCommand.php @@ -190,7 +190,7 @@ private function runMagentoWebDriverDoctor() // Disable MagentoWebDriver to avoid conflicts foreach ($settings['modules']['enabled'] as $index => $module) { - if ($module == $magentoWebDriver) { + if ($module === $magentoWebDriver) { unset($settings['modules']['enabled'][$index]); break; } diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateDevUrnCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateDevUrnCommand.php index bca72421b..034e6f516 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateDevUrnCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateDevUrnCommand.php @@ -61,10 +61,10 @@ protected function execute(InputInterface $input, OutputInterface $output) { $miscXmlFilePath = $input->getArgument(self::IDE_FILE_PATH_ARGUMENT); $miscXmlFile = realpath($miscXmlFilePath); - $force = $input->getOption('force'); + $force = (bool) $input->getOption('force'); if ($miscXmlFile === false) { - if ($force == true) { + if ($force === true) { // create file and refresh realpath $xml = "<project version=\"4\"/>"; file_put_contents($miscXmlFilePath, $xml); diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php index e783415f3..ed3050898 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php @@ -231,7 +231,8 @@ private function createTestConfiguration( $message = "Unable to create test object {$test} from test configuration. " . $e->getMessage(); LoggingUtil::getInstance()->getLogger(self::class)->error($message); if (MftfApplicationConfig::getConfig()->verboseEnabled() - && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { + && MftfApplicationConfig::getConfig()->getPhase() === MftfApplicationConfig::GENERATION_PHASE + ) { print($message); } GenerationErrorHandler::getInstance()->addError('test', $test, $message); diff --git a/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php index 89b184676..fbabc5282 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php @@ -86,7 +86,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int continue; } - if ($line == count($manifestFile) - 1) { + if ($line === count($manifestFile) - 1) { $this->runManifestLine($manifestFile[$line], $output, true); } else { $this->runManifestLine($manifestFile[$line], $output); diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php index fcf04cb3d..096c6794c 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php @@ -156,7 +156,7 @@ private function runTests(array $tests, OutputInterface $output) if ($this->pauseEnabled()) { $fullCommand = $codeceptionCommand . $testsDirectory . $testName . ' --verbose --steps --debug'; - if ($i != count($tests) - 1) { + if ($i !== count($tests) - 1) { $fullCommand .= self::CODECEPT_RUN_OPTION_NO_EXIT; } $this->returnCode = max($this->returnCode, $this->codeceptRunTest($fullCommand, $output)); @@ -195,7 +195,7 @@ private function runTestsInSuite(array $suitesConfig, OutputInterface $output) $index += 1; if ($this->pauseEnabled()) { - if ($index != $count) { + if ($index !== $count) { $fullCommand .= self::CODECEPT_RUN_OPTION_NO_EXIT; } $this->returnCode = max($this->returnCode, $this->codeceptRunTest($fullCommand, $output)); diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php index 1652a896d..695be0695 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php @@ -108,7 +108,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int for ($i = 0; $i < count($testManifestList); $i++) { if ($this->pauseEnabled()) { $codeceptionCommand = self::CODECEPT_RUN_FUNCTIONAL . $testManifestList[$i] . ' --debug '; - if ($i != count($testManifestList) - 1) { + if ($i !== count($testManifestList) - 1) { $codeceptionCommand .= self::CODECEPT_RUN_OPTION_NO_EXIT; } $returnCode = $this->codeceptRunTest($codeceptionCommand, $output); @@ -161,7 +161,7 @@ private function getFailedTestList() $testName = explode(":", $testInfo[count($testInfo) - 1])[1]; $suiteName = $testInfo[count($testInfo) - 2]; - if ($suiteName == self::DEFAULT_TEST_GROUP) { + if ($suiteName === self::DEFAULT_TEST_GROUP) { array_push($failedTestDetails['tests'], $testName); } else { $suiteName = $this->sanitizeSuiteName($suiteName); @@ -195,7 +195,7 @@ private function getFailedTestList() private function sanitizeSuiteName($suiteName) { $suiteNameArray = explode("_", $suiteName); - if (array_pop($suiteNameArray) == 'G') { + if (array_pop($suiteNameArray) === 'G') { if (is_numeric(array_pop($suiteNameArray))) { $suiteName = implode("_", $suiteNameArray); } diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php index a6302dacd..d9a549627 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php @@ -115,7 +115,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $codeceptionCommandString = $commandString . ' -g ' . $groups[$i]; if ($this->pauseEnabled()) { - if ($i != count($groups) - 1) { + if ($i !== count($groups) - 1) { $codeceptionCommandString .= self::CODECEPT_RUN_OPTION_NO_EXIT; } $returnCodes[] = $this->codeceptRunTest($codeceptionCommandString, $output); @@ -139,7 +139,7 @@ function ($type, $buffer) use ($output) { $this->applyAllFailed(); foreach ($returnCodes as $returnCode) { - if ($returnCode != 0) { + if ($returnCode !== 0) { return $returnCode; } $exitCode = 0; diff --git a/src/Magento/FunctionalTestingFramework/Data/Argument/Interpreter/ArrayType.php b/src/Magento/FunctionalTestingFramework/Data/Argument/Interpreter/ArrayType.php index 566c09912..b292236c6 100644 --- a/src/Magento/FunctionalTestingFramework/Data/Argument/Interpreter/ArrayType.php +++ b/src/Magento/FunctionalTestingFramework/Data/Argument/Interpreter/ArrayType.php @@ -98,7 +98,7 @@ private function compareItems($firstItemKey, $secondItemKey, $indexedItems) $secondValue = intval($secondItem['sortOrder']); } - if ($firstValue == $secondValue) { + if ($firstValue === $secondValue) { // These keys reflect initial relative position of items. // Allows stable sort for items with equal 'sortOrder' return $firstItemKey < $secondItemKey ? -1 : 1; diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Config/Dom.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Config/Dom.php index bc19c35aa..830abe6c9 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Config/Dom.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Config/Dom.php @@ -84,7 +84,7 @@ public function initDom($xml, $filename = null) $itemNodes = $dom->getElementsByTagName('item'); /** @var \DOMElement $itemNode */ foreach ($itemNodes as $itemKey => $itemNode) { - if ($itemNode->hasAttribute("name") == false) { + if ($itemNode->hasAttribute("name") === false) { $itemNode->setAttribute("name", (string)$itemKey); } } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php index 36b2daf41..0347ddaa8 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php @@ -58,7 +58,7 @@ class CredentialStore */ public static function getInstance() { - if (self::$INSTANCE == null) { + if (self::$INSTANCE === null) { self::$INSTANCE = new CredentialStore(); } @@ -162,13 +162,13 @@ private function getExceptionContexts() $exceptionMessage = "\n"; foreach ($this->exceptionContexts->getErrors() as $type => $exceptions) { $exceptionMessage .= "\nException from "; - if ($type == self::ARRAY_KEY_FOR_FILE) { + if ($type === self::ARRAY_KEY_FOR_FILE) { $exceptionMessage .= "File Storage: \n"; } - if ($type == self::ARRAY_KEY_FOR_VAULT) { + if ($type === self::ARRAY_KEY_FOR_VAULT) { $exceptionMessage .= "Vault Storage: \n"; } - if ($type == self::ARRAY_KEY_FOR_AWS_SECRETS_MANAGER) { + if ($type === self::ARRAY_KEY_FOR_AWS_SECRETS_MANAGER) { $exceptionMessage .= "AWS Secrets Manager Storage: \n"; } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php index 87dc6a13d..da7888388 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php @@ -319,8 +319,8 @@ private function processVarElements($entityData) */ private function extendDataObject($dataObject) { - if ($dataObject->getParentName() != null) { - if ($dataObject->getParentName() == $dataObject->getName()) { + if ($dataObject->getParentName() !== null) { + if ($dataObject->getParentName() === $dataObject->getName()) { throw new TestFrameworkException("Mftf Data can not extend from itself: " . $dataObject->getName()); } return $this->extendUtil->extendEntity($dataObject); diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php index c1f5d8d85..e9f905a6b 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/PersistedObjectHandler.php @@ -106,9 +106,9 @@ public function createEntity( $persistedObject->createEntity($storeCode); - if ($scope == self::TEST_SCOPE) { + if ($scope === self::TEST_SCOPE) { $this->testObjects[$key] = $persistedObject; - } elseif ($scope == self::HOOK_SCOPE) { + } elseif ($scope === self::HOOK_SCOPE) { $this->hookObjects[$key] = $persistedObject; } else { $this->suiteObjects[$key] = $persistedObject; @@ -170,9 +170,9 @@ public function getEntity($key, $scope, $entity, $dependentObjectKeys = [], $sto ); $persistedObject->getEntity($index, $storeCode); - if ($scope == self::TEST_SCOPE) { + if ($scope === self::TEST_SCOPE) { $this->testObjects[$key] = $persistedObject; - } elseif ($scope == self::HOOK_SCOPE) { + } elseif ($scope === self::HOOK_SCOPE) { $this->hookObjects[$key] = $persistedObject; } else { $this->suiteObjects[$key] = $persistedObject; @@ -214,7 +214,7 @@ private function retrieveEntity($stepKey, $scope) // Assume TEST_SCOPE is default $entityArrays = [$this->testObjects, $this->hookObjects, $this->suiteObjects]; - if ($scope == self::HOOK_SCOPE) { + if ($scope === self::HOOK_SCOPE) { $entityArrays[0] = $this->hookObjects; $entityArrays[1] = $this->testObjects; } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/EntityDataObject.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/EntityDataObject.php index 2204364f5..817fb6ec4 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/EntityDataObject.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/EntityDataObject.php @@ -233,7 +233,7 @@ private function resolveDataReferences($name, $uniquenessFormat) $this->data[$name_lower], $this->name . '.' . $name ); - if (null === $uniquenessData || $uniquenessFormat == self::NO_UNIQUE_PROCESS) { + if (null === $uniquenessData || $uniquenessFormat === self::NO_UNIQUE_PROCESS) { return $this->data[$name_lower]; } return $this->formatUniqueData($name_lower, $uniquenessData, $uniquenessFormat); @@ -276,7 +276,7 @@ private function formatUniqueData($name, $uniqueData, $uniqueDataFormat) switch ($uniqueDataFormat) { case self::SUITE_UNIQUE_VALUE: $this->checkUniquenessFunctionExists(self::SUITE_UNIQUE_FUNCTION, $uniqueDataFormat); - if ($uniqueData == 'prefix') { + if ($uniqueData === 'prefix') { return msqs($this->getName()) . $this->data[$name]; } else { // $uniData == 'suffix' return $this->data[$name] . msqs($this->getName()); @@ -284,21 +284,21 @@ private function formatUniqueData($name, $uniqueData, $uniqueDataFormat) break; case self::CEST_UNIQUE_VALUE: $this->checkUniquenessFunctionExists(self::CEST_UNIQUE_FUNCTION, $uniqueDataFormat); - if ($uniqueData == 'prefix') { + if ($uniqueData === 'prefix') { return msq($this->getName()) . $this->data[$name]; } else { // $uniqueData == 'suffix' return $this->data[$name] . msq($this->getName()); } break; case self::SUITE_UNIQUE_NOTATION: - if ($uniqueData == 'prefix') { + if ($uniqueData === 'prefix') { return self::SUITE_UNIQUE_FUNCTION . '("' . $this->getName() . '")' . $this->data[$name]; } else { // $uniqueData == 'suffix' return $this->data[$name] . self::SUITE_UNIQUE_FUNCTION . '("' . $this->getName() . '")'; } break; case self::CEST_UNIQUE_NOTATION: - if ($uniqueData == 'prefix') { + if ($uniqueData === 'prefix') { return self::CEST_UNIQUE_FUNCTION . '("' . $this->getName() . '")' . $this->data[$name]; } else { // $uniqueData == 'suffix' return $this->data[$name] . self::CEST_UNIQUE_FUNCTION . '("' . $this->getName() . '")'; @@ -358,7 +358,7 @@ public function getLinkedEntitiesOfType($type) $groupedArray = []; foreach ($this->linkedEntities as $entityName => $entityType) { - if ($entityType == $type) { + if ($entityType === $type) { $groupedArray[] = $entityName; } } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/OperationDefinitionObject.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/OperationDefinitionObject.php index ef1a7faa5..ff84c0959 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/OperationDefinitionObject.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Objects/OperationDefinitionObject.php @@ -351,7 +351,7 @@ public function addQueryParams() */ public function logDeprecated() { - if ($this->deprecated != null) { + if ($this->deprecated !== null) { LoggingUtil::getInstance()->getLogger(self::class)->deprecation( $message = "The operation {$this->name} is deprecated.", ["operationType" => $this->operation, "deprecatedMessage" => $this->deprecated], diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/OperationDataArrayResolver.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/OperationDataArrayResolver.php index e4dc5f267..431ab5d4e 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/OperationDataArrayResolver.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/OperationDataArrayResolver.php @@ -78,7 +78,7 @@ public function resolveOperationDataArray($entityObject, $operationMetadata, $op self::incrementSequence($entityObject->getName()); foreach ($operationMetadata as $operationElement) { - if ($operationElement->getType() == OperationElementExtractor::OPERATION_OBJECT_OBJ_NAME) { + if ($operationElement->getType() === OperationElementExtractor::OPERATION_OBJECT_OBJ_NAME) { $entityObj = $this->resolveOperationObjectAndEntityData($entityObject, $operationElement->getValue()); if (null === $entityObj && $operationElement->isRequired()) { throw new \Exception(sprintf( @@ -189,13 +189,13 @@ private function resolvePrimitiveReference($entityObject, $operationKey, $operat EntityDataObject::CEST_UNIQUE_VALUE ); - if ($elementData == null && $entityObject->getVarReference($operationKey) != null) { + if ($elementData === null && $entityObject->getVarReference($operationKey) !== null) { list($type, $field) = explode( DataObjectHandler::_SEPARATOR, $entityObject->getVarReference($operationKey) ); - if ($operationElementType == OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY) { + if ($operationElementType === OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY) { $elementDatas = []; $entities = $this->getDependentEntitiesOfType($type); foreach ($entities as $entity) { @@ -224,7 +224,7 @@ private function getDependentEntitiesOfType($type) $entitiesOfType = []; foreach ($this->dependentEntities as $dependentEntity) { - if ($dependentEntity->getType() == $type) { + if ($dependentEntity->getType() === $type) { $entitiesOfType[] = $dependentEntity; } } @@ -244,7 +244,7 @@ private function getDependentEntitiesOfType($type) */ private function resolveOperationObjectAndEntityData($entityObject, $operationElementValue) { - if ($operationElementValue != $entityObject->getType()) { + if ($operationElementValue !== $entityObject->getType()) { // if we have a mismatch attempt to retrieve linked data and return just the last linkage // this enables overwriting of required entity fields $linkName = $entityObject->getLinkedEntitiesOfType($operationElementValue); @@ -275,7 +275,7 @@ private function resolveNonPrimitiveElement($entityName, $operationElement, $ope // in array case if (!is_array($operationElement->getValue()) && !empty($operationElement->getNestedOperationElement($operationElement->getValue())) - && $operationElement->getType() == OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY + && $operationElement->getType() === OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY ) { $operationSubArray = $this->resolveOperationDataArray( $linkedEntityObj, @@ -403,7 +403,7 @@ private function resolvePrimitiveReferenceElement($entityObject, $operationEleme // If data was defined at all, attempt to put it into operation data array // If data was not defined, and element is required, throw exception // If no data is defined, don't input defaults per primitive into operation data array - if ($elementData != null) { + if ($elementData !== null) { if (array_key_exists($operationElement->getKey(), $entityObject->getUniquenessData())) { $uniqueData = $entityObject->getUniquenessDataByName($operationElement->getKey()); if ($uniqueData === 'suffix') { @@ -449,7 +449,7 @@ private function resolveNonPrimitiveReferenceElement($entityObject, $operation, $entityNamesOfType = $entityObject->getLinkedEntitiesOfType($operationElementType); // If an element is required by metadata, but was not provided in the entity, throw an exception - if ($operationElement->isRequired() && $entityNamesOfType == null) { + if ($operationElement->isRequired() && $entityNamesOfType === null) { throw new \Exception(sprintf( self::EXCEPTION_REQUIRED_DATA, $operationElement->getType(), @@ -476,7 +476,7 @@ private function resolveNonPrimitiveReferenceElement($entityObject, $operation, } } - if ($operationElement->getType() == OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY) { + if ($operationElement->getType() === OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY) { $operationDataArray[$operationElement->getKey()][] = $operationDataSubArray; } else { $operationDataArray[$operationElement->getKey()] = $operationDataSubArray; diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Util/DataExtensionUtil.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Util/DataExtensionUtil.php index 986f087e3..d803be9a2 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Util/DataExtensionUtil.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Util/DataExtensionUtil.php @@ -32,7 +32,7 @@ public function extendEntity($entityObject) { // Check to see if the parent entity exists $parentEntity = DataObjectHandler::getInstance()->getObject($entityObject->getParentName()); - if ($parentEntity == null) { + if ($parentEntity === null) { throw new XmlException( "Parent Entity " . $entityObject->getParentName() . diff --git a/src/Magento/FunctionalTestingFramework/DataTransport/WebApiExecutor.php b/src/Magento/FunctionalTestingFramework/DataTransport/WebApiExecutor.php index 1bf792003..3a4b627bd 100644 --- a/src/Magento/FunctionalTestingFramework/DataTransport/WebApiExecutor.php +++ b/src/Magento/FunctionalTestingFramework/DataTransport/WebApiExecutor.php @@ -135,7 +135,7 @@ public function close() protected function getFormattedUrl($resource) { $urlResult = MftfGlobals::getWebApiBaseUrl(); - if ($this->storeCode != null) { + if ($this->storeCode !== null) { $urlResult .= $this->storeCode . '/'; } $urlResult .= trim($resource, '/'); diff --git a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php index e4f433a2a..4e65e992f 100644 --- a/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php +++ b/src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php @@ -100,7 +100,7 @@ function () use ($cest) { // check for errors in all test hooks and attach in allure if (!empty($testResultObject->errors())) { foreach ($testResultObject->errors() as $error) { - if ($error->failedTest()->getTestMethod() == $cest->getTestMethod()) { + if ($error->failedTest()->getTestMethod() === $cest->getTestMethod()) { $this->attachExceptionToAllure($error->thrownException(), $cest->getTestMethod()); } } @@ -109,7 +109,7 @@ function () use ($cest) { // check for failures in all test hooks and attach in allure if (!empty($testResultObject->failures())) { foreach ($testResultObject->failures() as $failure) { - if ($failure->failedTest()->getTestMethod() == $cest->getTestMethod()) { + if ($failure->failedTest()->getTestMethod() === $cest->getTestMethod()) { $this->attachExceptionToAllure($failure->thrownException(), $cest->getTestMethod()); } } @@ -128,7 +128,7 @@ public function extractContext($trace, $class) { foreach ($trace as $entry) { $traceClass = $entry["class"] ?? null; - if (strpos($traceClass, $class) != 0) { + if (strpos($traceClass, $class) !== 0) { return $entry["function"]; } } @@ -257,7 +257,7 @@ public function saveFailed(\Codeception\Event\PrintResultEvent $e) protected function localizePath($path) { $root = realpath($this->getRootDir()) . DIRECTORY_SEPARATOR; - if (substr($path, 0, strlen($root)) == $root) { + if (substr($path, 0, strlen($root)) === $root) { return substr($path, strlen($root)); } return $path; diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoAssert.php b/src/Magento/FunctionalTestingFramework/Module/MagentoAssert.php index 3c6c08173..78301ad6f 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoAssert.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoAssert.php @@ -36,7 +36,7 @@ public function assertArrayIsSorted(array $data, $sortOrder = "asc") $data = array_map('strtolower', $data); } - if ($sortOrder == "asc") { + if ($sortOrder === 'asc') { for ($i = 1; $i < $elementTotal; $i++) { // $i >= $i-1 $this->assertLessThanOrEqual($data[$i], $data[$i-1], $message); diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 7a3220921..328eb4842 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -222,7 +222,7 @@ public function _getUrl() public function _getCurrentUri() { $url = $this->webDriver->getCurrentURL(); - if ($url == 'about:blank') { + if ($url === 'about:blank') { throw new ModuleException($this, 'Current url is blank, no page was opened'); } @@ -509,7 +509,7 @@ public function parseFloat($floatString) */ public function mSetLocale(int $category, $locale) { - if (self::$localeAll[$category] == $locale) { + if (self::$localeAll[$category] === $locale) { return; } foreach (self::$localeAll as $c => $l) { @@ -849,7 +849,7 @@ public function _failed(TestInterface $test, $fail) } } - if ($this->current_test == null) { + if ($this->current_test === null) { throw new \RuntimeException("Suite condition failure: \n" . $fail->getMessage()); } @@ -869,7 +869,7 @@ public function _failed(TestInterface $test, $fail) public function saveScreenshot() { $testDescription = "unknown." . uniqid(); - if ($this->current_test != null) { + if ($this->current_test !== null) { $testDescription = Descriptor::getTestSignature($this->current_test); } diff --git a/src/Magento/FunctionalTestingFramework/ObjectManager/Config/Mapper/Dom.php b/src/Magento/FunctionalTestingFramework/ObjectManager/Config/Mapper/Dom.php index ba7bc64cd..99912355d 100644 --- a/src/Magento/FunctionalTestingFramework/ObjectManager/Config/Mapper/Dom.php +++ b/src/Magento/FunctionalTestingFramework/ObjectManager/Config/Mapper/Dom.php @@ -54,7 +54,7 @@ public function convert($config) $output = []; /** @var \DOMNode $node */ foreach ($config->documentElement->childNodes as $node) { - if ($node->nodeType != XML_ELEMENT_NODE) { + if ($node->nodeType !== XML_ELEMENT_NODE) { continue; } switch ($node->nodeName) { @@ -73,7 +73,7 @@ public function convert($config) if ($typeNodeShared) { $typeData['shared'] = $this->booleanUtils->toBoolean($typeNodeShared->nodeValue); } - if ($node->nodeName == 'virtualType') { + if ($node->nodeName === 'virtualType') { $attributeType = $typeNodeAttributes->getNamedItem('type'); // attribute type is required for virtual type only in merged configuration if ($attributeType) { @@ -102,14 +102,14 @@ private function setTypeArguments($node) foreach ($node->childNodes as $typeChildNode) { /** @var \DOMNode $typeChildNode */ - if ($typeChildNode->nodeType != XML_ELEMENT_NODE) { + if ($typeChildNode->nodeType !== XML_ELEMENT_NODE) { continue; } switch ($typeChildNode->nodeName) { case 'arguments': /** @var \DOMNode $argumentNode */ foreach ($typeChildNode->childNodes as $argumentNode) { - if ($argumentNode->nodeType != XML_ELEMENT_NODE) { + if ($argumentNode->nodeType !== XML_ELEMENT_NODE) { continue; } $argumentName = $argumentNode->attributes->getNamedItem('name')->nodeValue; diff --git a/src/Magento/FunctionalTestingFramework/ObjectManager/Factory.php b/src/Magento/FunctionalTestingFramework/ObjectManager/Factory.php index c5882d035..922235011 100644 --- a/src/Magento/FunctionalTestingFramework/ObjectManager/Factory.php +++ b/src/Magento/FunctionalTestingFramework/ObjectManager/Factory.php @@ -84,7 +84,8 @@ public function prepareArguments($object, $method, array $arguments = []) { $type = get_class($object); $parameters = $this->classReader->getParameters($type, $method); - if ($parameters == null) { + + if ($parameters === null) { return []; } @@ -227,7 +228,8 @@ public function create($requestedType, array $arguments = []) { $instanceType = $this->config->getInstanceType($requestedType); $parameters = $this->definitions->getParameters($instanceType); - if ($parameters == null) { + + if ($parameters === null) { return new $instanceType(); } if (isset($this->creationStack[$requestedType])) { diff --git a/src/Magento/FunctionalTestingFramework/ObjectManager/Factory/Dynamic/Developer.php b/src/Magento/FunctionalTestingFramework/ObjectManager/Factory/Dynamic/Developer.php index 937be7da6..0d6623d09 100644 --- a/src/Magento/FunctionalTestingFramework/ObjectManager/Factory/Dynamic/Developer.php +++ b/src/Magento/FunctionalTestingFramework/ObjectManager/Factory/Dynamic/Developer.php @@ -178,7 +178,8 @@ public function create($requestedType, array $arguments = []) { $type = $this->config->getInstanceType($requestedType); $parameters = $this->definitions->getParameters($type); - if ($parameters == null) { + + if ($parameters === null) { return new $type(); } if (isset($this->creationStack[$requestedType])) { diff --git a/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php b/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php index 8f4302077..dd723fa1b 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Page/Handlers/PageObjectHandler.php @@ -66,7 +66,7 @@ private function __construct() $area = $pageData[self::AREA] ?? null; $url = $pageData[self::URL] ?? null; - if ($area == 'admin') { + if ($area === 'admin') { $url = ltrim($url, "/"); } diff --git a/src/Magento/FunctionalTestingFramework/Page/Objects/ElementObject.php b/src/Magento/FunctionalTestingFramework/Page/Objects/ElementObject.php index 567872fc7..f00ded056 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Objects/ElementObject.php +++ b/src/Magento/FunctionalTestingFramework/Page/Objects/ElementObject.php @@ -75,9 +75,9 @@ class ElementObject */ public function __construct($name, $type, $selector, $locatorFunction, $timeout, $parameterized, $deprecated = null) { - if ($selector != null && $locatorFunction != null) { + if ($selector !== null && $locatorFunction !== null) { throw new XmlException("Element '{$name}' cannot have both a selector and a locatorFunction."); - } elseif ($selector == null && $locatorFunction == null) { + } elseif ($selector === null && $locatorFunction === null) { throw new XmlException("Element '{$name}' must have either a selector or a locatorFunction.'"); } @@ -160,11 +160,11 @@ public function getPrioritizedSelector() */ public function getTimeout() { - if ($this->timeout == ElementObject::DEFAULT_TIMEOUT_SYMBOL) { + if ($this->timeout === ElementObject::DEFAULT_TIMEOUT_SYMBOL) { return null; } - return (int)$this->timeout; + return (int) $this->timeout; } /** diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php index e7a0b7e54..0b3e6c40d 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/AnnotationsCheck.php @@ -173,8 +173,8 @@ private function validateSkipIssueId($test) $skip = $annotations['skip'] ?? null; if ($skip !== null) { $validateSkipped = true; - if ((!isset($skip[0]) || strlen($skip[0]) == 0) - && (!isset($skip['issueId']) || strlen($skip['issueId']) == 0)) { + if ((!isset($skip[0]) || strlen($skip[0]) === 0) + && (!isset($skip['issueId']) || strlen($skip['issueId']) === 0)) { $this->errors[][] = "Test {$test->getName()} is skipped but the issueId is empty."; } } diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php index 6bfe17219..556d30d28 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php @@ -157,7 +157,7 @@ private function findErrorsInFileSet($files) $this->allEntities = []; $moduleName = $this->getModuleName($filePath); // Not a module, is either dev/tests/acceptance or loose folder with test materials - if ($moduleName == null) { + if ($moduleName === null) { continue; } @@ -219,7 +219,7 @@ private function findViolatingReferences($moduleName) foreach ($modulesReferencedInTest as $entityName => $files) { $valid = false; foreach ($files as $module) { - if (array_key_exists($module, $moduleDependencies) || $module == $currentModule) { + if (array_key_exists($module, $moduleDependencies) || $module === $currentModule) { $valid = true; break; } diff --git a/src/Magento/FunctionalTestingFramework/Suite/Generators/GroupClassGenerator.php b/src/Magento/FunctionalTestingFramework/Suite/Generators/GroupClassGenerator.php index f90a25322..e160c4875 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Generators/GroupClassGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Generators/GroupClassGenerator.php @@ -152,7 +152,7 @@ private function buildHookMustacheArray($hookObj) } // add these as vars to be created a class level in the template - if ($action->getType() == 'createData') { + if ($action->getType() === 'createData') { $mustacheHookArray[self::MUSTACHE_VAR_TAG][] = [self::ENTITY_MERGE_KEY => $action->getStepKey()]; } @@ -213,7 +213,7 @@ private function replaceReservedTesterFunctions($formattedStep, $actionEntries, $formattedStep = rtrim($formattedStep); foreach (self::REPLACEMENT_ACTIONS as $testAction => $replacement) { $testActionCall = "\${$actor}->{$testAction}"; - if (substr($formattedStep, 0, strlen($testActionCall)) == $testActionCall) { + if (substr($formattedStep, 0, strlen($testActionCall)) === $testActionCall) { $resultingStep = str_replace($testActionCall, $replacement, $formattedStep); $actionEntries[] = ['action' => $resultingStep]; } else { @@ -278,7 +278,7 @@ private function buildReqEntitiesMustacheArray($customAttributes) continue; } - if ($attribute[ActionObjectExtractor::NODE_NAME] == 'requiredEntity') { + if ($attribute[ActionObjectExtractor::NODE_NAME] === 'requiredEntity') { $requiredEntities[] = [self::ENTITY_NAME_TAG => $attribute[TestGenerator::REQUIRED_ENTITY_REFERENCE]]; } } diff --git a/src/Magento/FunctionalTestingFramework/Suite/Handlers/SuiteObjectHandler.php b/src/Magento/FunctionalTestingFramework/Suite/Handlers/SuiteObjectHandler.php index f5d9e45dd..7583f2472 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Handlers/SuiteObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Handlers/SuiteObjectHandler.php @@ -62,7 +62,7 @@ private function __clone() */ public static function getInstance(): ObjectHandlerInterface { - if (self::$instance == null) { + if (self::$instance === null) { self::$instance = new SuiteObjectHandler(); self::$instance->initSuiteData(); } diff --git a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php index ced0ac552..44e4e0b45 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php @@ -206,7 +206,7 @@ private function generateSuiteFromTest($suiteName, $tests = [], $originalSuiteNa $this->appendEntriesToConfig($suiteName, $fullPath, $groupNamespace); if (MftfApplicationConfig::getConfig()->verboseEnabled() - && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { + && MftfApplicationConfig::getConfig()->getPhase() === MftfApplicationConfig::GENERATION_PHASE) { print("suite {$suiteName} generated\n"); } LoggingUtil::getInstance()->getLogger(self::class)->info( @@ -304,7 +304,7 @@ private function generateGroupFile($suiteName, $tests, $originalSuiteName) } else { $suiteObject = SuiteObjectHandler::getInstance()->getObject($suiteName); // we have to handle the case when there is a custom configuration for an existing suite. - if (count($suiteObject->getTests()) != count($tests)) { + if (count($suiteObject->getTests()) !== count($tests)) { return $this->generateGroupFile($suiteName, $tests, $suiteName); } } diff --git a/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php index 247286f6d..6af9070ba 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php @@ -92,7 +92,7 @@ public function parseSuiteDataIntoObjects($parsedSuiteData) $includeTests = $include['objects'] ?? []; $stepError = $include['status'] ?? 0; $includeMessage = ''; - if ($stepError != 0) { + if ($stepError !== 0) { $includeMessage = "ERROR: " . strval($stepError) . " test(s) not included for suite " . $parsedSuite[self::NAME]; } @@ -127,7 +127,8 @@ public function parseSuiteDataIntoObjects($parsedSuiteData) if (!empty($includeMessage)) { LoggingUtil::getInstance()->getLogger(self::class)->error($includeMessage); if (MftfApplicationConfig::getConfig()->verboseEnabled() - && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { + && MftfApplicationConfig::getConfig()->getPhase() === MftfApplicationConfig::GENERATION_PHASE + ) { print($includeMessage); } @@ -145,7 +146,7 @@ public function parseSuiteDataIntoObjects($parsedSuiteData) "Unable to parse suite " . $parsedSuite[self::NAME] . "\n" . $e->getMessage() ); if (MftfApplicationConfig::getConfig()->verboseEnabled() - && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { + && MftfApplicationConfig::getConfig()->getPhase() === MftfApplicationConfig::GENERATION_PHASE) { print("ERROR: Unable to parse suite " . $parsedSuite[self::NAME] . "\n"); } @@ -183,7 +184,7 @@ private function validateSuiteName($parsedSuite) { //check if name used is using special char or the "default" reserved name NameValidationUtil::validateName($parsedSuite[self::NAME], 'Suite'); - if ($parsedSuite[self::NAME] == 'default') { + if ($parsedSuite[self::NAME] === 'default') { throw new FastFailException("A Suite can not have the name \"default\""); } @@ -235,7 +236,7 @@ private function parseObjectHooks($parsedSuite) $suiteHooks[TestObjectExtractor::TEST_AFTER_HOOK] = $hookObject; } - if (count($suiteHooks) == 1) { + if (count($suiteHooks) === 1) { throw new XmlException(sprintf( "Suites that contain hooks must contain both a 'before' and an 'after' hook. Suite: \"%s\"", $parsedSuite[self::NAME] @@ -254,7 +255,7 @@ private function parseObjectHooks($parsedSuite) */ private function isSuiteEmpty($suiteHooks, $includeTests, $excludeTests) { - $noHooks = count($suiteHooks) == 0 || + $noHooks = count($suiteHooks) === 0 || ( empty($suiteHooks['before']->getActions()) && empty($suiteHooks['after']->getActions()) diff --git a/src/Magento/FunctionalTestingFramework/Test/Config/Converter/Dom/Flat.php b/src/Magento/FunctionalTestingFramework/Test/Config/Converter/Dom/Flat.php index 0769f5ebf..23d8d5331 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Config/Converter/Dom/Flat.php +++ b/src/Magento/FunctionalTestingFramework/Test/Config/Converter/Dom/Flat.php @@ -77,7 +77,7 @@ public function convertXml(\DOMNode $source, $basePath = '') $value = []; /** @var \DOMNode $node */ foreach ($source->childNodes as $node) { - if ($node->nodeType == XML_ELEMENT_NODE) { + if ($node->nodeType === XML_ELEMENT_NODE) { $nodeName = $node->nodeName; $nodePath = $basePath . '/' . $nodeName; $arrayKeyAttribute = $this->arrayNodeConfig->getAssocArrayKeyAttribute($nodePath); @@ -90,7 +90,7 @@ public function convertXml(\DOMNode $source, $basePath = '') ); } - if ($nodeName == self::REMOVE_ACTION) { + if ($nodeName === self::REMOVE_ACTION) { // Check to see if the test extends for this remove action $parentHookExtends = in_array($node->parentNode->nodeName, self::TEST_HOOKS) && !empty($node->parentNode->parentNode->getAttribute('extends')); @@ -121,12 +121,12 @@ public function convertXml(\DOMNode $source, $basePath = '') } else { $value[$nodeName] = $nodeData; } - } elseif ($node->nodeType == XML_CDATA_SECTION_NODE - || ($node->nodeType == XML_TEXT_NODE && trim($node->nodeValue) != '') + } elseif ($node->nodeType === XML_CDATA_SECTION_NODE + || ($node->nodeType === XML_TEXT_NODE && trim($node->nodeValue) !== '') ) { $value = $node->nodeValue; break; - } elseif ($node->nodeType == XML_COMMENT_NODE && + } elseif ($node->nodeType === XML_COMMENT_NODE && in_array($node->parentNode->nodeName, self::VALID_COMMENT_PARENT)) { $uniqid = uniqid($node->nodeName); $value[$uniqid] = [ @@ -163,7 +163,7 @@ protected function getNodeAttributes(\DOMNode $node) $attributes = $node->attributes ?: []; /** @var \DOMNode $attribute */ foreach ($attributes as $attribute) { - if ($attribute->nodeType == XML_ATTRIBUTE_NODE) { + if ($attribute->nodeType === XML_ATTRIBUTE_NODE) { $result[$attribute->nodeName] = $attribute->nodeValue; } } diff --git a/src/Magento/FunctionalTestingFramework/Test/Config/Dom.php b/src/Magento/FunctionalTestingFramework/Test/Config/Dom.php index 7ded754be..89f779968 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Config/Dom.php +++ b/src/Magento/FunctionalTestingFramework/Test/Config/Dom.php @@ -173,7 +173,7 @@ protected function appendMergePointerToActions($testNode, $insertType, $insertKe $childNodes = $testNode->childNodes; $previousStepKey = $insertKey; $actionInsertType = ActionObject::MERGE_ACTION_ORDER_AFTER; - if ($insertType == self::TEST_MERGE_POINTER_BEFORE) { + if ($insertType === self::TEST_MERGE_POINTER_BEFORE) { $actionInsertType = ActionObject::MERGE_ACTION_ORDER_BEFORE; } for ($i = 0; $i < $childNodes->length; $i++) { diff --git a/src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php b/src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php index 5a87a32f6..fb4dac688 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php @@ -151,9 +151,9 @@ private function initActionGroups() private function extendActionGroup($actionGroupObject): ActionGroupObject { if ($actionGroupObject->getParentName() !== null) { - if ($actionGroupObject->getParentName() == $actionGroupObject->getName()) { + if ($actionGroupObject->getParentName() === $actionGroupObject->getName()) { throw new TestFrameworkException( - "Mftf Action Group can not extend from itself: " . $actionGroupObject->getName() + 'Mftf Action Group can not extend from itself: ' . $actionGroupObject->getName() ); } return $this->extendUtil->extendActionGroup($actionGroupObject); diff --git a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php index 4abc26c36..287e5306e 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php @@ -124,7 +124,7 @@ public function getAllObjects() if ($errCount > 0 && MftfApplicationConfig::getConfig()->verboseEnabled() - && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { + && MftfApplicationConfig::getConfig()->getPhase() === MftfApplicationConfig::GENERATION_PHASE) { print( "ERROR: " . strval($errCount) @@ -173,7 +173,7 @@ public function getTestsByGroup($groupName) if ($errCount > 0 && MftfApplicationConfig::getConfig()->verboseEnabled() - && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { + && MftfApplicationConfig::getConfig()->getPhase() === MftfApplicationConfig::GENERATION_PHASE) { print( "ERROR: " . strval($errCount) @@ -248,7 +248,7 @@ private function initTestData($validateAnnotations = true) "Unable to parse test " . $testName . "\n" . $exception->getMessage() ); if (MftfApplicationConfig::getConfig()->verboseEnabled() - && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { + && MftfApplicationConfig::getConfig()->getPhase() === MftfApplicationConfig::GENERATION_PHASE) { print("ERROR: Unable to parse test " . $testName . "\n"); } GenerationErrorHandler::getInstance()->addError( @@ -276,7 +276,7 @@ private function initTestData($validateAnnotations = true) private function extendTest($testObject) { if ($testObject->getParentName() !== null) { - if ($testObject->getParentName() == $testObject->getName()) { + if ($testObject->getParentName() === $testObject->getName()) { throw new TestFrameworkException( "Mftf Test can not extend from itself: " . $testObject->getName() ); diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php index 74aa414a8..b608a4846 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php @@ -239,7 +239,7 @@ private function getResolvedActionsWithArgs($arguments, $actionReferenceKey) $action->getStepKey() . ucfirst($actionReferenceKey), $action->getType(), array_replace_recursive($resolvedActionAttributes, $newActionAttributes), - $action->getLinkedAction() == null ? null : $action->getLinkedAction() . ucfirst($actionReferenceKey), + $action->getLinkedAction() === null ? null : $action->getLinkedAction() . ucfirst($actionReferenceKey), $orderOffset, [self::ACTION_GROUP_ORIGIN_NAME => $this->name, self::ACTION_GROUP_ORIGIN_TEST_REF => $actionReferenceKey], @@ -531,7 +531,7 @@ private function findArgumentByName($name, $argumentList) $matchedArgument = array_filter( $argumentList, function ($e) use ($name) { - return $e->getName() == $name; + return $e->getName() === $name; } ); if (isset(array_values($matchedArgument)[0])) { diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php index 8e4aa973c..ed5cc0936 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php @@ -290,7 +290,7 @@ public function resolveReferences() $this->resolveUrlReference(); $this->resolveDataInputReferences(); $this->validateTimezoneAttribute(); - if ($this->getType() == "deleteData") { + if ($this->getType() === "deleteData") { $this->validateMutuallyExclusiveAttributes(self::DELETE_DATA_MUTUAL_EXCLUSIVE_ATTRIBUTES); } } @@ -561,24 +561,24 @@ private function findAndReplaceReferences($objectHandler, $inputString) continue; } - if ($obj == null) { + if ($obj === null) { // keep initial values for subsequent logic $replacement = null; $parameterized = false; - } elseif (get_class($obj) == PageObject::class) { + } elseif (get_class($obj) === PageObject::class) { if ($obj->getDeprecated() !== null) { $this->deprecatedUsage[] = "DEPRECATED PAGE in Test: " . $match . ' ' . $obj->getDeprecated(); } $this->validateUrlAreaAgainstActionType($obj); $replacement = $obj->getUrl(); $parameterized = $obj->isParameterized(); - } elseif (get_class($obj) == SectionObject::class) { + } elseif (get_class($obj) === SectionObject::class) { if ($obj->getDeprecated() !== null) { $this->deprecatedUsage[] = "DEPRECATED SECTION in Test: " . $match . ' ' . $obj->getDeprecated(); } list(,$objField) = $this->stripAndSplitReference($match); - if ($obj->getElement($objField) == null) { + if ($obj->getElement($objField) === null) { throw new TestReferenceException( "Could not resolve entity reference \"{$inputString}\" " . "in Action with stepKey \"{$this->getStepKey()}\"", @@ -592,7 +592,7 @@ private function findAndReplaceReferences($objectHandler, $inputString) $this->deprecatedUsage[] = "DEPRECATED ELEMENT in Test: " . $match . ' ' . $obj->getElement($objField)->getDeprecated(); } - } elseif (get_class($obj) == EntityDataObject::class) { + } elseif (get_class($obj) === EntityDataObject::class) { if ($obj->getDeprecated() !== null) { $this->deprecatedUsage[] = "DEPRECATED DATA ENTITY in Test: " . $match . ' ' . $obj->getDeprecated(); @@ -638,7 +638,7 @@ private function validateMutuallyExclusiveAttributes(array $attributes) . implode("', '", $attributes) . "'", ["type" => $this->getType(), "attributes" => $attributes] ); - } elseif (count($matches) == 0) { + } elseif (count($matches) === 0) { throw new TestReferenceException( "Actions of type '{$this->getType()}' must contain at least one attribute of types '" . implode("', '", $attributes) . "'", @@ -656,7 +656,7 @@ private function validateMutuallyExclusiveAttributes(array $attributes) */ private function validateUrlAreaAgainstActionType($obj) { - if ($obj->getArea() == 'external' && + if ($obj->getArea() === 'external' && in_array($this->getType(), self::EXTERNAL_URL_AREA_INVALID_ACTIONS)) { throw new TestReferenceException( "Page of type 'external' is not compatible with action type '{$this->getType()}'", @@ -697,7 +697,7 @@ private function resolveEntityDataObjectReference($obj, $match) { list(,$objField) = $this->stripAndSplitReference($match); - if (strpos($objField, '[') == true) { + if (strpos($objField, '[') === true) { // Access <array>...</array> $parts = explode('[', $objField); $name = $parts[0]; @@ -726,7 +726,7 @@ private function resolveParameterization($isParameterized, $replacement, $match, } else { $resolvedReplacement = $replacement; } - if (get_class($object) == PageObject::class && $object->getArea() == PageObject::ADMIN_AREA) { + if (get_class($object) === PageObject::class && $object->getArea() === PageObject::ADMIN_AREA) { $urlSegments = [ '{{_ENV.MAGENTO_BACKEND_BASE_URL}}', '{{_ENV.MAGENTO_BACKEND_NAME}}', @@ -794,7 +794,7 @@ private function checkParameterCount($matches, $parameters, $reference) if (count($matches) > count($parameters)) { if (is_array($parameters)) { $parametersGiven = implode(",", $parameters); - } elseif ($parameters == null) { + } elseif ($parameters === null) { $parametersGiven = "NONE"; } else { $parametersGiven = $parameters; @@ -810,7 +810,7 @@ private function checkParameterCount($matches, $parameters, $reference) $reference . ". Parameters Given: " . implode(", ", $parameters), ["reference" => $reference, "parametersGiven" => $parameters] ); - } elseif (count($matches) == 0) { + } elseif (count($matches) === 0) { throw new TestReferenceException( "Parameter Resolution Failed: No parameter matches found in parameterized element with selector " . $reference, diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php index 82bb04906..8341fc7b1 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php @@ -174,7 +174,7 @@ public function isSkipped() */ public function getCodeceptionName() { - if (strpos($this->name, 'Cest') && substr($this->name, -4) == 'Cest') { + if (strpos($this->name, 'Cest') && substr($this->name, -4) === 'Cest') { return $this->name; } diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/ActionMergeUtil.php b/src/Magento/FunctionalTestingFramework/Test/Util/ActionMergeUtil.php index 28a7d405d..a601deb24 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/ActionMergeUtil.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/ActionMergeUtil.php @@ -170,10 +170,10 @@ private function resolveActionGroups($mergedSteps) foreach ($mergedSteps as $key => $mergedStep) { /**@var ActionObject $mergedStep**/ - if ($mergedStep->getType() == ActionObjectExtractor::ACTION_GROUP_TAG) { + if ($mergedStep->getType() === ActionObjectExtractor::ACTION_GROUP_TAG) { $actionGroupRef = $mergedStep->getCustomActionAttributes()[ActionObjectExtractor::ACTION_GROUP_REF]; $actionGroup = ActionGroupObjectHandler::getInstance()->getObject($actionGroupRef); - if ($actionGroup == null) { + if ($actionGroup === null) { throw new TestReferenceException("Could not find ActionGroup by ref \"{$actionGroupRef}\""); } $args = $mergedStep->getCustomActionAttributes()[ActionObjectExtractor::ACTION_GROUP_ARGUMENTS] ?? null; diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/ActionObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/ActionObjectExtractor.php index 8fdcf82f6..a9fb0817e 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/ActionObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/ActionObjectExtractor.php @@ -90,7 +90,7 @@ public function extractActions($testActions, $testName = null) $actions = $this->extractFieldActions($actionData, $actions); $actionAttributes = $this->extractFieldReferences($actionData, $actionAttributes); - if ($linkedAction['stepKey'] != null) { + if ($linkedAction['stepKey'] !== null) { $stepKeyRefs[$linkedAction['stepKey']][] = $stepKey; } @@ -157,7 +157,7 @@ private function processActionGroupArgs($actionType, $actionAttributeData) $actionAttributeArgData = []; foreach ($actionAttributeData as $attributeDataKey => $attributeDataValues) { - if ($attributeDataKey == self::ACTION_GROUP_REF) { + if ($attributeDataKey === self::ACTION_GROUP_REF) { $actionAttributeArgData[self::ACTION_GROUP_REF] = $attributeDataValues; continue; } @@ -187,7 +187,7 @@ private function processHelperArgs($actionType, $actionAttributeData) $actionAttributeArgData = []; foreach ($actionAttributeData as $attributeDataKey => $attributeDataValues) { - if (isset($attributeDataValues['nodeName']) && $attributeDataValues['nodeName'] == 'argument') { + if (isset($attributeDataValues['nodeName']) && $attributeDataValues['nodeName'] === 'argument') { if (isset($attributeDataValues['name']) && in_array($attributeDataValues['name'], $reservedHelperVariableNames)) { $message = 'Helper argument names ' . implode(',', $reservedHelperVariableNames); @@ -225,7 +225,7 @@ private function extractFieldActions($actionData, $actions) $fieldActions = []; foreach ($actionData as $type => $data) { // determine if field type is entity passed in - if (!is_array($data) || $data[self::NODE_NAME] != self::DATA_PERSISTENCE_CUSTOM_FIELD) { + if (!is_array($data) || $data[self::NODE_NAME] !== self::DATA_PERSISTENCE_CUSTOM_FIELD) { continue; } @@ -258,7 +258,8 @@ private function extractFieldReferences($actionData, $actionAttributes) $attributes = []; foreach ($actionAttributes as $attributeName => $attributeValue) { - if (!is_array($attributeValue) || $attributeValue[self::NODE_NAME] != self::DATA_PERSISTENCE_CUSTOM_FIELD) { + if (!is_array($attributeValue) || + $attributeValue[self::NODE_NAME] !== self::DATA_PERSISTENCE_CUSTOM_FIELD) { $attributes[$attributeName] = $attributeValue; continue; } diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php index 4afddc769..8710fbb22 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/AnnotationExtractor.php @@ -77,14 +77,14 @@ public function extractAnnotations($testAnnotations, $filename, $validateAnnotat } $annotationValues = []; // Only transform severity annotation - if ($annotationKey == "severity") { + if ($annotationKey === "severity") { $annotationObjects[$annotationKey] = $this->transformAllureSeverityToMagento( trim($annotationData[0][self::ANNOTATION_VALUE]) ); continue; } - if ($annotationKey == "skip") { + if ($annotationKey === "skip") { $annotationData = $annotationData['issueId']; if ($validateAnnotations) { $this->validateSkippedIssues($annotationData, $filename); @@ -182,7 +182,7 @@ private function validateMissingAnnotations($annotationObjects, $filename) */ public function validateStoryTitleUniqueness() { - if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::EXECUTION_PHASE) { + if (MftfApplicationConfig::getConfig()->getPhase() === MftfApplicationConfig::EXECUTION_PHASE) { return; } @@ -197,7 +197,7 @@ public function validateStoryTitleUniqueness() $message = "Story and Title annotation pairs is not unique in Tests {$tests}\n"; LoggingUtil::getInstance()->getLogger(self::class)->error($message); if (MftfApplicationConfig::getConfig()->verboseEnabled() - && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { + && MftfApplicationConfig::getConfig()->getPhase() === MftfApplicationConfig::GENERATION_PHASE) { print('ERROR: ' . $message); } $testArray = explode(',', $tests); @@ -220,7 +220,7 @@ public function validateStoryTitleUniqueness() */ public function validateTestCaseIdTitleUniqueness() { - if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::EXECUTION_PHASE) { + if (MftfApplicationConfig::getConfig()->getPhase() === MftfApplicationConfig::EXECUTION_PHASE) { return; } @@ -235,7 +235,7 @@ public function validateTestCaseIdTitleUniqueness() $message = "TestCaseId and Title pairs is not unique in Tests {$tests}\n"; LoggingUtil::getInstance()->getLogger(self::class)->error($message); if (MftfApplicationConfig::getConfig()->verboseEnabled() - && MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { + && MftfApplicationConfig::getConfig()->getPhase() === MftfApplicationConfig::GENERATION_PHASE) { print('ERROR: ' . $message); } $testArray = explode(',', $tests); diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/ObjectExtensionUtil.php b/src/Magento/FunctionalTestingFramework/Test/Util/ObjectExtensionUtil.php index 1be3c895f..7f6d050fb 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/ObjectExtensionUtil.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/ObjectExtensionUtil.php @@ -98,7 +98,7 @@ public function extendActionGroup($actionGroupObject) { // Check to see if the parent action group exists $parentActionGroup = ActionGroupObjectHandler::getInstance()->getObject($actionGroupObject->getParentName()); - if ($parentActionGroup == null) { + if ($parentActionGroup === null) { throw new XmlException( "Parent Action Group " . $actionGroupObject->getParentName() . @@ -200,7 +200,7 @@ private function processRemoveActions($actions) // remove actions merged that are of type 'remove' foreach ($actions as $actionName => $actionData) { - if ($actionData->getType() != "remove") { + if ($actionData->getType() !== 'remove') { $cleanedActions[$actionName] = $actionData; } } diff --git a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php index 2628be851..3c6825092 100644 --- a/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php +++ b/src/Magento/FunctionalTestingFramework/Upgrade/UpdateAssertionSchema.php @@ -104,9 +104,9 @@ private function convertOldAssertionToNew($assertion) $value = rtrim(ltrim($value, "'"), "'"); } // If value is empty string (" " or ' '), trim again to become empty - if (str_replace(" ", "", $value) == "''") { + if (str_replace(" ", "", $value) === "''") { $value = ""; - } elseif (str_replace(" ", "", $value) == '""') { + } elseif (str_replace(" ", "", $value) === '""') { $value = ""; } @@ -119,20 +119,20 @@ private function convertOldAssertionToNew($assertion) } // Store in subtype for child element creation - if ($type == "actual") { + if ($type === "actual") { $subElements["actual"]["value"] = $value; - } elseif ($type == "actualType") { + } elseif ($type === "actualType") { $subElements["actual"]["type"] = $value; - } elseif ($type == "expected" or $type == "expectedValue") { + } elseif ($type === "expected" or $type === "expectedValue") { $subElements["expected"]["value"] = $value; - } elseif ($type == "expectedType") { + } elseif ($type === "expectedType") { $subElements["expected"]["type"] = $value; } } $newString .= ">\n"; // Assert type is very edge-cased, completely different schema - if ($assertType == 'assertElementContainsAttribute') { + if ($assertType === 'assertElementContainsAttribute') { // assertElementContainsAttribute type defaulted to string if not present if (!isset($subElements["expected"]['type'])) { $subElements["expected"]['type'] = "string"; diff --git a/src/Magento/FunctionalTestingFramework/Util/ComposerModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ComposerModuleResolver.php index 210c10fdd..92d5dc121 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ComposerModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ComposerModuleResolver.php @@ -48,7 +48,7 @@ public function getComposerInstalledTestModules($rootComposerFile) return $this->installedTestModules; } - if (!file_exists($rootComposerFile) || basename($rootComposerFile, '.json') != 'composer') { + if (!file_exists($rootComposerFile) || basename($rootComposerFile, '.json') !== 'composer') { throw new TestFrameworkException("Invalid root composer json file: {$rootComposerFile}"); } @@ -168,7 +168,7 @@ private function findComposerJsonFilesAtDepth($directory, $depth) self::findComposerJsonFilesAtDepth($dir, $depth-1) ); } - } elseif ($depth == 0) { + } elseif ($depth === 0) { $jsonFileList = glob($directory . $jsonPattern); if ($jsonFileList === false) { $jsonFileList = []; diff --git a/src/Magento/FunctionalTestingFramework/Util/ConfigSanitizerUtil.php b/src/Magento/FunctionalTestingFramework/Util/ConfigSanitizerUtil.php index 3b92b48e4..ee4c85018 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ConfigSanitizerUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/ConfigSanitizerUtil.php @@ -43,16 +43,16 @@ public static function sanitizeWebDriverConfig($config, $params = ['url', 'selen */ private static function sanitizeSeleniumEnvs($config) { - if ($config['protocol'] == '%SELENIUM_PROTOCOL%') { + if ($config['protocol'] === '%SELENIUM_PROTOCOL%') { $config['protocol'] = "http"; } - if ($config['host'] == '%SELENIUM_HOST%') { + if ($config['host'] === '%SELENIUM_HOST%') { $config['host'] = "127.0.0.1"; } - if ($config['port'] == '%SELENIUM_PORT%') { + if ($config['port'] === '%SELENIUM_PORT%') { $config['port'] = "4444"; } - if ($config['path'] == '%SELENIUM_PATH%') { + if ($config['path'] === '%SELENIUM_PATH%') { $config['path'] = "/wd/hub"; } return $config; diff --git a/src/Magento/FunctionalTestingFramework/Util/Logger/LoggingUtil.php b/src/Magento/FunctionalTestingFramework/Util/Logger/LoggingUtil.php index 268bc5193..c32348bcc 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Logger/LoggingUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/Logger/LoggingUtil.php @@ -66,7 +66,7 @@ private function __clone() */ public function getLogger($className): MftfLogger { - if ($className == null) { + if ($className === null) { throw new TestFrameworkException("You must pass a class name to receive a logger"); } diff --git a/src/Magento/FunctionalTestingFramework/Util/ModulePathExtractor.php b/src/Magento/FunctionalTestingFramework/Util/ModulePathExtractor.php index b7386a586..a9f51d226 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModulePathExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModulePathExtractor.php @@ -72,7 +72,7 @@ public function getExtensionPath($path) private function splitKeyForParts($key) { $parts = explode(self::SPLIT_DELIMITER, $key); - return count($parts) == 2 ? $parts : []; + return count($parts) === 2 ? $parts : []; } /** @@ -90,7 +90,7 @@ private function extractKeyByPath($path) } foreach ($this->testModulePaths as $key => $value) { - if (substr($path, 0, strlen($value)) == $value) { + if (substr($path, 0, strlen($value)) === $value) { return $key; } } diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index b04168673..434a1cdc3 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -156,7 +156,7 @@ private function __construct() { $objectManager = \Magento\FunctionalTestingFramework\ObjectManagerFactory::getObjectManager(); - if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::UNIT_TEST_PHASE) { + if (MftfApplicationConfig::getConfig()->getPhase() === MftfApplicationConfig::UNIT_TEST_PHASE) { $this->sequenceSorter = $objectManager->get(AlphabeticSequenceSorter::class); } else { $this->sequenceSorter = $objectManager->get(SequenceSorterInterface::class); @@ -175,7 +175,7 @@ public function getEnabledModules() return $this->enabledModules; } - if (MftfApplicationConfig::getConfig()->getPhase() == MftfApplicationConfig::GENERATION_PHASE) { + if (MftfApplicationConfig::getConfig()->getPhase() === MftfApplicationConfig::GENERATION_PHASE) { $this->printMagentoVersionInfo(); } @@ -338,8 +338,8 @@ private function flipAndFilterModulePathsArray($objectArray, $filterArray) // Filter array by enabled modules foreach ($objectArray as $path => $modules) { if (!array_diff($modules, $filterArray) - || (count($modules) == 1 && isset($this->knownDirectories[$modules[0]]))) { - if (count($modules) == 1) { + || (count($modules) === 1 && isset($this->knownDirectories[$modules[0]]))) { + if (count($modules) === 1) { $oneToOneArray[$path] = $modules[0]; } else { $oneToManyArray[$path] = $modules; diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver/ModuleResolverService.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver/ModuleResolverService.php index 015fa4e9f..16d3e7d2b 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver/ModuleResolverService.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver/ModuleResolverService.php @@ -162,11 +162,11 @@ public function globRelevantPaths(string $testPath, string $pattern): array */ private static function globRelevantWrapper(string $testPath, string $pattern): array { - if ($pattern == "") { + if ($pattern === '') { return glob($testPath . '*' . DIRECTORY_SEPARATOR . '*' . $pattern); } - $subDirectory = "*" . DIRECTORY_SEPARATOR; + $subDirectory = '*' . DIRECTORY_SEPARATOR; $directories = glob($testPath . $subDirectory . $pattern, GLOB_ONLYDIR); foreach (glob($testPath . $subDirectory, GLOB_ONLYDIR) as $dir) { diff --git a/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php b/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php index 11afa5cc1..745ab53fe 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php @@ -273,7 +273,7 @@ public function resolveEntityByNames($references) */ public function findEntity($name) { - if ($name == '_ENV' || $name == '_CREDS') { + if ($name === '_ENV' || $name === '_CREDS') { return null; } diff --git a/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php b/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php index 660dafb62..612d32fd6 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php +++ b/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php @@ -37,7 +37,7 @@ public function __construct() public function getTestsGroupedBySize($suiteConfiguration, $testNameToSize, $time) { // we must have the lines argument in order to create the test groups - if ($time == 0) { + if ($time === 0) { throw new FastFailException( "Please provide the argument '--time' to the robo command in order to". " generate grouped tests manifests for a parallel execution" @@ -139,7 +139,7 @@ private function getSuiteGroupCounts($suiteNameToTestSize, $testNameToSize, $gro $ceilSuiteGroupNumber = ceil($maxSuiteTime / $minGroupTime); $ceilSuiteGroupTime = max(ceil($maxSuiteTime / $ceilSuiteGroupNumber), $minGroupTime); $floorSuiteGroupNumber = floor($maxSuiteTime / $minGroupTime); - if ($floorSuiteGroupNumber != 0) { + if ($floorSuiteGroupNumber !== 0) { $floorSuiteGroupTime = max(ceil($maxSuiteTime / $floorSuiteGroupNumber), $minGroupTime); } @@ -148,7 +148,7 @@ private function getSuiteGroupCounts($suiteNameToTestSize, $testNameToSize, $gro $ceilSuiteGroupTotal = array_sum($ceilSuiteNameToGroupCount); $ceilTestGroupTotal = $groupTotal - $ceilSuiteGroupTotal; - if ($ceilTestGroupTotal == 0) { + if ($ceilTestGroupTotal === 0) { $ceilTestGroupTime = 0; } else { $ceilTestGroupTime = ceil(array_sum($testNameToSize) / $ceilTestGroupTotal); @@ -157,7 +157,7 @@ private function getSuiteGroupCounts($suiteNameToTestSize, $testNameToSize, $gro // Set suite group total to ceiling $suiteNameToGroupCount = $ceilSuiteNameToGroupCount; - if (isset($floorSuiteGroupTime) && $ceilSuiteGroupTime != $floorSuiteGroupTime) { + if (isset($floorSuiteGroupTime) && $ceilSuiteGroupTime !== $floorSuiteGroupTime) { // Calculate test group time for floor $floorSuiteNameToGroupCount = $this->getSuiteGroupCountFromGroupTime( $suiteNameToTestSize, @@ -165,7 +165,7 @@ private function getSuiteGroupCounts($suiteNameToTestSize, $testNameToSize, $gro ); $floorSuiteGroupTotal = array_sum($floorSuiteNameToGroupCount); $floorTestGroupTotal = $groupTotal - $floorSuiteGroupTotal; - if ($floorTestGroupTotal == 0) { + if ($floorTestGroupTotal === 0) { $floorTestGroupTime = 0; } else { $floorTestGroupTime = ceil(array_sum($testNameToSize) / $floorTestGroupTotal); @@ -243,7 +243,7 @@ private function splitSuitesIntoGroups($suiteNameToTestSize, $suiteNameToGroupCo $groups = []; foreach ($suiteNameToTestSize as $suiteName => $suiteTests) { $suiteCnt = $suiteNameToGroupCount[$suiteName]; - if ($suiteCnt == 1) { + if ($suiteCnt === 1) { $groups[][$suiteName] = array_sum($suiteTests); $this->addSuiteToConfig($suiteName, null, $suiteTests); } elseif ($suiteCnt > 1) { @@ -457,7 +457,7 @@ private function splitTestSuite($suiteName, $tests, $maxTime) */ private function addSuiteToConfig($originalSuiteName, $newSuiteName, $tests) { - if ($newSuiteName == null) { + if ($newSuiteName === null) { $this->suiteConfig[$originalSuiteName] = array_keys($tests); return; } diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 917b40809..fbf530fd8 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -371,7 +371,7 @@ private function assembleAllTestPhp($testManifest, array $testsToIgnore) $this->debug("<comment>Finish creating test: " . $test->getCodeceptionName() . "</comment>" . PHP_EOL); // Write to manifest here if manifest is not null - if ($testManifest != null) { + if ($testManifest !== null) { $testManifest->addTest($test); } } catch (FastFailException $e) { @@ -460,7 +460,7 @@ private function generateAnnotationsPhp($annotationsObject, $isMethod = false) foreach ($annotationsObject as $annotationType => $annotationName) { //Remove conditional and output useCaseId upon completion of MQE-588 - if ($annotationType == "useCaseId") { + if ($annotationType === 'useCaseId') { continue; } if (!$isMethod) { @@ -752,7 +752,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $time = $time ?? ActionObject::getDefaultWaitTimeout(); } - if (isset($customActionAttributes['parameterArray']) && $actionObject->getType() != 'pressKey') { + if (isset($customActionAttributes['parameterArray']) && $actionObject->getType() !== 'pressKey') { // validate the param array is in the correct format $this->validateParameterArray($customActionAttributes['parameterArray']); @@ -799,7 +799,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $function = trim($function, '"'); } // turn $javaVariable => \$javaVariable but not {$mftfVariable} - if ($actionObject->getType() == "executeJS") { + if ($actionObject->getType() === "executeJS") { $function = preg_replace('/(?<!{)(\$[A-Za-z._]+)(?![A-z.]*+\$)/', '\\\\$1', $function); } } @@ -905,7 +905,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $requiredEntityKeys = []; foreach ($actionObject->getCustomActionAttributes() as $actionAttribute) { - if (is_array($actionAttribute) && $actionAttribute['nodeName'] == 'requiredEntity') { + if (is_array($actionAttribute) && $actionAttribute['nodeName'] === 'requiredEntity') { //append ActionGroup if provided $requiredEntityActionGroup = $actionAttribute['actionGroup'] ?? null; $requiredEntityKeys[] = $actionAttribute['createDataKey'] . $requiredEntityActionGroup; @@ -977,7 +977,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato // Build array of requiredEntities $requiredEntityKeys = []; foreach ($actionObject->getCustomActionAttributes() as $actionAttribute) { - if (is_array($actionAttribute) && $actionAttribute['nodeName'] == 'requiredEntity') { + if (is_array($actionAttribute) && $actionAttribute['nodeName'] === 'requiredEntity') { //append ActionGroup if provided $requiredEntityActionGroup = $actionAttribute['actionGroup'] ?? null; $requiredEntityKeys[] = $actionAttribute['createDataKey'] . $requiredEntityActionGroup; @@ -1012,7 +1012,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato // Build array of requiredEntities $requiredEntityKeys = []; foreach ($actionObject->getCustomActionAttributes() as $actionAttribute) { - if (is_array($actionAttribute) && $actionAttribute['nodeName'] == 'requiredEntity') { + if (is_array($actionAttribute) && $actionAttribute['nodeName'] === 'requiredEntity') { $requiredEntityActionGroup = $actionAttribute['actionGroup'] ?? null; $requiredEntityKeys[] = $actionAttribute['createDataKey'] . $requiredEntityActionGroup; } @@ -1587,7 +1587,7 @@ private function replaceMatchesIntoArg($matches, &$outputArg) $replacement = null; $delimiter = '$'; $variable = $this->stripAndSplitReference($match, $delimiter); - if (count($variable) != 2) { + if (count($variable) !== 2) { throw new \Exception( "Invalid Persisted Entity Reference: {$match}. Test persisted entity references must follow {$delimiter}entityStepKey.field{$delimiter} format." @@ -1639,7 +1639,7 @@ private function processQuoteBreaks($match, $argument, $replacement) */ private function resolveStepKeyReferences($input, $actionGroupOrigin, $matchAll = false) { - if ($actionGroupOrigin == null) { + if ($actionGroupOrigin === null) { return $input; } $output = $input; @@ -1701,7 +1701,7 @@ private function wrapFunctionArgsWithQuotes($functionRegex, $input) foreach ($allArguments as $argument) { $argument = trim($argument); - if ($argument[0] == self::ARRAY_WRAP_OPEN) { + if ($argument[0] === self::ARRAY_WRAP_OPEN) { $replacement = $this->wrapParameterArray($this->addUniquenessToParamArray($argument)); } elseif (is_numeric($argument)) { $replacement = $argument; @@ -1948,7 +1948,7 @@ private function addUniquenessFunctionCall($input, $wrapWithDoubleQuotes = true) */ private function wrapWithDoubleQuotes($input) { - if ($input == null) { + if ($input === null) { return ''; } //Only replace " with \" so that it doesn't break outer string. diff --git a/src/Magento/FunctionalTestingFramework/Util/Validation/DuplicateNodeValidationUtil.php b/src/Magento/FunctionalTestingFramework/Util/Validation/DuplicateNodeValidationUtil.php index 0c323a2dd..2eba2c493 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Validation/DuplicateNodeValidationUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/Validation/DuplicateNodeValidationUtil.php @@ -65,10 +65,10 @@ public function validateChildUniqueness(\DOMElement $parentNode, $filename, $par $withoutDuplicates = array_unique($keyValues); - if (count($withoutDuplicates) != count($keyValues)) { + if (count($withoutDuplicates) !== count($keyValues)) { $duplicates = array_diff_assoc($keyValues, $withoutDuplicates); $keyError = ""; - foreach ($duplicates as $duplicateKey => $duplicateValue) { + foreach ($duplicates as $duplicateValue) { $keyError .= "\t{$this->uniqueKey}: {$duplicateValue} is used more than once."; if ($parentKey !== null) { $keyError .=" (Parent: {$parentKey})"; diff --git a/src/Magento/FunctionalTestingFramework/Util/Validation/SingleNodePerFileValidationUtil.php b/src/Magento/FunctionalTestingFramework/Util/Validation/SingleNodePerFileValidationUtil.php index c560349be..0fd440888 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Validation/SingleNodePerFileValidationUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/Validation/SingleNodePerFileValidationUtil.php @@ -43,7 +43,7 @@ public function validateSingleNodeForTag($dom, $tag, $filename = '') { $tagNodes = $dom->getElementsByTagName($tag); $count = $tagNodes->length; - if ($count == 1) { + if ($count === 1) { return; } From 738b490af5e048eb7cb7ab447e9e712ea0690719 Mon Sep 17 00:00:00 2001 From: bohdan-harniuk <b.harniuk@atwix.com> Date: Thu, 19 Aug 2021 17:00:40 +0300 Subject: [PATCH 711/888] MFTF-33780: Fixed verification tests --- .../FunctionalTestingFramework/Test/Objects/ActionObject.php | 4 ++-- .../Util/Sorter/ParallelGroupSorter.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php index ed5cc0936..aec38c9a5 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php @@ -290,7 +290,7 @@ public function resolveReferences() $this->resolveUrlReference(); $this->resolveDataInputReferences(); $this->validateTimezoneAttribute(); - if ($this->getType() === "deleteData") { + if ($this->getType() === 'deleteData') { $this->validateMutuallyExclusiveAttributes(self::DELETE_DATA_MUTUAL_EXCLUSIVE_ATTRIBUTES); } } @@ -697,7 +697,7 @@ private function resolveEntityDataObjectReference($obj, $match) { list(,$objField) = $this->stripAndSplitReference($match); - if (strpos($objField, '[') === true) { + if (strpos($objField, '[') !== false) { // Access <array>...</array> $parts = explode('[', $objField); $name = $parts[0]; diff --git a/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php b/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php index 612d32fd6..74f5af3ca 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php +++ b/src/Magento/FunctionalTestingFramework/Util/Sorter/ParallelGroupSorter.php @@ -146,7 +146,7 @@ private function getSuiteGroupCounts($suiteNameToTestSize, $testNameToSize, $gro // Calculate test group time for ceiling $ceilSuiteNameToGroupCount = $this->getSuiteGroupCountFromGroupTime($suiteNameToTestSize, $ceilSuiteGroupTime); $ceilSuiteGroupTotal = array_sum($ceilSuiteNameToGroupCount); - $ceilTestGroupTotal = $groupTotal - $ceilSuiteGroupTotal; + $ceilTestGroupTotal = (int) $groupTotal - (int) $ceilSuiteGroupTotal; if ($ceilTestGroupTotal === 0) { $ceilTestGroupTime = 0; From 964981508dd2e9fcb7a9540cfebab6d1d99a2e1f Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Thu, 26 Aug 2021 11:19:01 -0500 Subject: [PATCH 712/888] MQE-2873: allure dependency - repo name change --- composer.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.lock b/composer.lock index 226426ef8..122825b76 100644 --- a/composer.lock +++ b/composer.lock @@ -72,12 +72,12 @@ "version": "1.3.1", "source": { "type": "git", - "url": "https://github.com/allure-framework/allure-php-commons.git", + "url": "https://github.com/allure-framework/allure-php-api.git", "reference": "f64b69afeff472c564a4e2379efb2b69c430ec5a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/allure-framework/allure-php-commons/zipball/f64b69afeff472c564a4e2379efb2b69c430ec5a", + "url": "https://api.github.com/repos/allure-framework/allure-php-api/zipball/f64b69afeff472c564a4e2379efb2b69c430ec5a", "reference": "f64b69afeff472c564a4e2379efb2b69c430ec5a", "shasum": "" }, @@ -120,7 +120,7 @@ ], "support": { "email": "allure@yandex-team.ru", - "issues": "https://github.com/allure-framework/allure-php-commons/issues", + "issues": "https://github.com/allure-framework/allure-php-api/issues", "source": "https://github.com/allure-framework/allure-php-api" }, "time": "2021-03-26T14:32:27+00:00" @@ -8467,5 +8467,5 @@ "ext-openssl": "*" }, "platform-dev": [], - "plugin-api-version": "2.0.0" + "plugin-api-version": "2.1.0" } From 7b246aff9ab20f9f345cdd17945ea9a2564d65ed Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Thu, 26 Aug 2021 13:46:16 -0500 Subject: [PATCH 713/888] MQE-2873: allure dependency - repo name change --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 741a15260..a5dcc7dd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ Magento Functional Testing Framework Changelog ================================================ +3.6.1 +--------- + +### Enhancements + +* Maintainability + * Updated allure dependencies to pull package from new repo `allure-framework/allure-php-api`. + 3.6.0 --------- From a2e2cc716cf8325f8075acac01b263b22d7c8e34 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Thu, 26 Aug 2021 14:00:29 -0500 Subject: [PATCH 714/888] MQE-2873: allure dependency - repo name change --- composer.json | 2 +- composer.lock | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index bdf92ca3d..88029c93d 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "3.6.0", + "version": "3.6.1", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index 122825b76..422d5f39e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "9bec96d8a169a4286803657bbf61004c", + "content-hash": "4827eceed3051f9eb57bfb47aff974dc", "packages": [ { "name": "allure-framework/allure-codeception", @@ -1361,6 +1361,7 @@ "issues": "https://github.com/CSharpRU/vault-php-guzzle6-transport/issues", "source": "https://github.com/CSharpRU/vault-php-guzzle6-transport/tree/master" }, + "abandoned": true, "time": "2019-03-10T06:17:37+00:00" }, { From 1ed0a11aba9866a1908cc14fb0b0e0cb4e0a6f7e Mon Sep 17 00:00:00 2001 From: eduard13 <e.chitoraga@atwix.com> Date: Wed, 1 Sep 2021 12:25:35 +0300 Subject: [PATCH 715/888] Removing the Guzzle6Transport's dependency --- composer.json | 2 +- composer.lock | 101 ++++++++---------- .../Handlers/SecretStorage/VaultStorage.php | 12 ++- 3 files changed, 55 insertions(+), 60 deletions(-) diff --git a/composer.json b/composer.json index 1d9ac37b4..ae040423f 100755 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "codeception/module-webdriver": "^1.0", "composer/composer": "^1.9||^2.0", "csharpru/vault-php": "^4.2.1", - "csharpru/vault-php-guzzle6-transport": "^2.0", + "guzzlehttp/guzzle": "^7.3.0", "hoa/console": "~3.0", "monolog/monolog": "^2.3", "mustache/mustache": "~2.5", diff --git a/composer.lock b/composer.lock index 72c28adbd..b6065e228 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "1a03b6b0a4885e0049c74d187c70836c", + "content-hash": "edfa5cf6f951445f14be6d5deb535db3", "packages": [ { "name": "allure-framework/allure-codeception", @@ -1325,49 +1325,6 @@ }, "time": "2021-05-21T06:39:35+00:00" }, - { - "name": "csharpru/vault-php-guzzle6-transport", - "version": "2.0.4", - "source": { - "type": "git", - "url": "https://github.com/CSharpRU/vault-php-guzzle6-transport.git", - "reference": "33c392120ac9f253b62b034e0e8ffbbdb3513bd8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/CSharpRU/vault-php-guzzle6-transport/zipball/33c392120ac9f253b62b034e0e8ffbbdb3513bd8", - "reference": "33c392120ac9f253b62b034e0e8ffbbdb3513bd8", - "shasum": "" - }, - "require": { - "guzzlehttp/guzzle": "~6.2", - "guzzlehttp/promises": "^1.3", - "guzzlehttp/psr7": "^1.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "VaultTransports\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Yaroslav Lukyanov", - "email": "c_sharp@mail.ru" - } - ], - "description": "Guzzle6 transport for Vault PHP client", - "support": { - "issues": "https://github.com/CSharpRU/vault-php-guzzle6-transport/issues", - "source": "https://github.com/CSharpRU/vault-php-guzzle6-transport/tree/master" - }, - "abandoned": true, - "time": "2019-03-10T06:17:37+00:00" - }, { "name": "doctrine/annotations", "version": "1.13.2", @@ -1591,37 +1548,44 @@ }, { "name": "guzzlehttp/guzzle", - "version": "6.5.5", + "version": "7.3.0", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e" + "reference": "7008573787b430c1c1f650e3722d9bba59967628" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/9d4290de1cfd701f38099ef7e183b64b4b7b0c5e", - "reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/7008573787b430c1c1f650e3722d9bba59967628", + "reference": "7008573787b430c1c1f650e3722d9bba59967628", "shasum": "" }, "require": { "ext-json": "*", - "guzzlehttp/promises": "^1.0", - "guzzlehttp/psr7": "^1.6.1", - "php": ">=5.5", - "symfony/polyfill-intl-idn": "^1.17.0" + "guzzlehttp/promises": "^1.4", + "guzzlehttp/psr7": "^1.7 || ^2.0", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" }, "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", "ext-curl": "*", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", + "php-http/client-integration-tests": "^3.0", + "phpunit/phpunit": "^8.5.5 || ^9.3.5", "psr/log": "^1.1" }, "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", "psr/log": "Required for using the Log middleware" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "6.5-dev" + "dev-master": "7.3-dev" } }, "autoload": { @@ -1641,6 +1605,11 @@ "name": "Michael Dowling", "email": "mtdowling@gmail.com", "homepage": "https://github.com/mtdowling" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" } ], "description": "Guzzle is a PHP HTTP client library", @@ -1651,14 +1620,34 @@ "framework", "http", "http client", + "psr-18", + "psr-7", "rest", "web service" ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/6.5" + "source": "https://github.com/guzzle/guzzle/tree/7.3.0" }, - "time": "2020-06-16T21:01:06+00:00" + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://github.com/alexeyshockov", + "type": "github" + }, + { + "url": "https://github.com/gmponos", + "type": "github" + } + ], + "time": "2021-03-23T11:33:13+00:00" }, { "name": "guzzlehttp/promises", diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/VaultStorage.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/VaultStorage.php index 39839e8f9..cc0b3e7a8 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/VaultStorage.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/VaultStorage.php @@ -6,12 +6,12 @@ namespace Magento\FunctionalTestingFramework\DataGenerator\Handlers\SecretStorage; +use GuzzleHttp\Client as GuzzleClient; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; use Vault\Client; -use VaultTransports\Guzzle6Transport; class VaultStorage extends BaseStorage { @@ -78,8 +78,14 @@ public function __construct($baseUrl, $secretBasePath) { parent::__construct(); if (null === $this->client) { - // Creating the client using Guzzle6 Transport and passing a custom url - $this->client = new Client(new Guzzle6Transport(['base_uri' => $baseUrl])); + // client configuration and override http errors settings + $config = [ + 'timeout' => 15, + 'base_uri' => $baseUrl, + 'http_errors' => false + ]; + + $this->client = new Client(new GuzzleClient($config)); $this->secretBasePath = $secretBasePath; } $this->readVaultTokenFromFileSystem(); From 9110451b88663bdfc6773961c27a4419fea54d36 Mon Sep 17 00:00:00 2001 From: Maksym Aposov <maposov@magento.com> Date: Thu, 9 Sep 2021 12:23:53 -0500 Subject: [PATCH 716/888] AC-1193: Fix broken MFTF tests --- dev/tests/unit/Util/EntityDataObjectBuilder.php | 3 ++- dev/tests/unit/Util/OperationElementBuilder.php | 3 ++- .../DataGenerator/Persist/OperationDataArrayResolver.php | 2 +- src/Magento/FunctionalTestingFramework/Util/TestGenerator.php | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/dev/tests/unit/Util/EntityDataObjectBuilder.php b/dev/tests/unit/Util/EntityDataObjectBuilder.php index dfe7d6836..82496d2ce 100644 --- a/dev/tests/unit/Util/EntityDataObjectBuilder.php +++ b/dev/tests/unit/Util/EntityDataObjectBuilder.php @@ -18,7 +18,8 @@ class EntityDataObjectBuilder "name" => "Hopper", "gpa" => "3.5678", "phone" => "5555555", - "isprimary" => "true" + "isprimary" => "true", + "empty_string" => "" ]; /** diff --git a/dev/tests/unit/Util/OperationElementBuilder.php b/dev/tests/unit/Util/OperationElementBuilder.php index 2c2a4d9da..69e848de1 100644 --- a/dev/tests/unit/Util/OperationElementBuilder.php +++ b/dev/tests/unit/Util/OperationElementBuilder.php @@ -20,7 +20,8 @@ class OperationElementBuilder 'name' => 'string', 'gpa' => 'number', 'phone' => 'integer', - 'isPrimary' => 'boolean' + 'isPrimary' => 'boolean', + 'empty_string' => 'string' ]; /** diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/OperationDataArrayResolver.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/OperationDataArrayResolver.php index 431ab5d4e..3266f5a24 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/OperationDataArrayResolver.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/OperationDataArrayResolver.php @@ -403,7 +403,7 @@ private function resolvePrimitiveReferenceElement($entityObject, $operationEleme // If data was defined at all, attempt to put it into operation data array // If data was not defined, and element is required, throw exception // If no data is defined, don't input defaults per primitive into operation data array - if ($elementData !== null) { + if ($elementData !== null && $elementData !== '') { if (array_key_exists($operationElement->getKey(), $entityObject->getUniquenessData())) { $uniqueData = $entityObject->getUniquenessDataByName($operationElement->getKey()); if ($uniqueData === 'suffix') { diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index fbf530fd8..17c045977 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1948,7 +1948,7 @@ private function addUniquenessFunctionCall($input, $wrapWithDoubleQuotes = true) */ private function wrapWithDoubleQuotes($input) { - if ($input === null) { + if ($input === null || $input === '') { return ''; } //Only replace " with \" so that it doesn't break outer string. From 5ba5c537050813adf266315ac7e3a1183af87e76 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 9 Sep 2021 17:33:48 -0500 Subject: [PATCH 717/888] MQE-2920: mftf 3.7.0 release --- CHANGELOG.md | 34 +++++++++++++++++++++++++++++++++- composer.json | 2 +- composer.lock | 5 +++-- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a5dcc7dd2..25271e6e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,38 @@ Magento Functional Testing Framework Changelog ================================================ -3.6.1 +3.7.0 +--------- + +### GitHub Pull Requests: + +* [#842](https://github.com/magento/magento2-functional-testing-framework/pull/842) -- Eliminated AspectMock from FileStorageTest +* [#843](https://github.com/magento/magento2-functional-testing-framework/pull/843) -- Eliminated AspectMock from ObjectExtensionUtilTest +* [#844](https://github.com/magento/magento2-functional-testing-framework/pull/844) -- Eliminated AspectMock from TestObjectHandlerTest +* [#845](https://github.com/magento/magento2-functional-testing-framework/pull/845) -- Eliminated AspectMock from SuiteObjectHandlerTest +* [#846](https://github.com/magento/magento2-functional-testing-framework/pull/846) -- Eliminated AspectMock from ActionGroupObjectTest +* [#847](https://github.com/magento/magento2-functional-testing-framework/pull/847) -- Removed not used mocked object +* [#848](https://github.com/magento/magento2-functional-testing-framework/pull/848) -- Eliminated AspectMock usage from ActionObjectTest +* [#850](https://github.com/magento/magento2-functional-testing-framework/pull/850) -- Eliminated AspectMock from TestGeneratorTest +* [#852](https://github.com/magento/magento2-functional-testing-framework/pull/852) -- Eliminated AspectMock from ModuleResolverTest +* [#853](https://github.com/magento/magento2-functional-testing-framework/pull/853) -- Eliminated AspectMock from PersistedObjectHandlerTest +* [#855](https://github.com/magento/magento2-functional-testing-framework/pull/855) -- Eliminated AspectMock from OperationDataArrayResolverTest +* [#856](https://github.com/magento/magento2-functional-testing-framework/pull/856) -- Eliminated AspectMock from DataExtensionUtilTest +* [#857](https://github.com/magento/magento2-functional-testing-framework/pull/857) -- Eliminated AspectMock from ParallelGroupSorterTest +* [#859](https://github.com/magento/magento2-functional-testing-framework/pull/859) -- Eliminated AspectMock usage from SuiteGeneratorTest +* [#861](https://github.com/magento/magento2-functional-testing-framework/pull/861) -- Eliminated aspect mock from mock module resolver builder +* [#862](https://github.com/magento/magento2-functional-testing-framework/pull/862) -- Eliminated AspectMock where it was imported but never used +* [#863](https://github.com/magento/magento2-functional-testing-framework/pull/863) -- Eliminated AspectMock from MagentoTestCase +* [#864](https://github.com/magento/magento2-functional-testing-framework/pull/864) -- Eliminated AspectMock usage from TestLoggingUtil +* [#865](https://github.com/magento/magento2-functional-testing-framework/pull/865) -- Eliminated aspect mock from object handler uti +* [#866](https://github.com/magento/magento2-functional-testing-framework/pull/866) -- Added access/secret key config parameters +* [#867](https://github.com/magento/magento2-functional-testing-framework/pull/867) -- Added empty query and fragment testing to the UrlFormatterTest +* [#868](https://github.com/magento/magento2-functional-testing-framework/pull/868) -- PHP 8 support - fix code related to changes in CURL +* [#869](https://github.com/magento/magento2-functional-testing-framework/pull/869) -- The squizlabs/php_codesniffer composer dependency has been updated to version 3.6.0 +* [#870](https://github.com/magento/magento2-functional-testing-framework/pull/870) -- Removing the csharpru/vault-php-guzzle6-transport not needed dependency +* [#871](https://github.com/magento/magento2-functional-testing-framework/pull/871) -- Changed loose comparisons into strict +* [#872](https://github.com/magento/magento2-functional-testing-framework/pull/872) -- Fix broken MFTF tests + + 3.6.1 --------- ### Enhancements diff --git a/composer.json b/composer.json index ae040423f..1550c0298 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "3.6.1", + "version": "3.7.0", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index b6065e228..575d863a7 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "edfa5cf6f951445f14be6d5deb535db3", + "content-hash": "b1921bd26a93634cba6000ef524db2c9", "packages": [ { "name": "allure-framework/allure-codeception", @@ -5317,6 +5317,7 @@ "type": "github" } ], + "abandoned": true, "time": "2020-09-28T06:45:17+00:00" }, { @@ -8288,5 +8289,5 @@ "ext-openssl": "*" }, "platform-dev": [], - "plugin-api-version": "2.1.0" + "plugin-api-version": "2.0.0" } From 829a82534551adec7279dfbbfa3091f480e04c4f Mon Sep 17 00:00:00 2001 From: Karyna <k.tsymbal@atwix.com> Date: Fri, 1 Oct 2021 12:19:16 +0300 Subject: [PATCH 718/888] add check for isBuiltin method --- .../FunctionalTestingFramework/Code/Reader/ClassReader.php | 6 ++++-- .../FunctionalTestingFramework/System/Code/ClassReader.php | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Code/Reader/ClassReader.php b/src/Magento/FunctionalTestingFramework/Code/Reader/ClassReader.php index 3d359a5f2..f3e67e35b 100644 --- a/src/Magento/FunctionalTestingFramework/Code/Reader/ClassReader.php +++ b/src/Magento/FunctionalTestingFramework/Code/Reader/ClassReader.php @@ -13,6 +13,7 @@ class ClassReader implements ClassReaderInterface * @param string $className * @return array|null * @throws \ReflectionException + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function getConstructor($className) { @@ -24,8 +25,9 @@ public function getConstructor($className) /** @var $parameter \ReflectionParameter */ foreach ($constructor->getParameters() as $parameter) { try { - $name = $parameter->getType() && !$parameter->getType()->isBuiltin() - ? new \ReflectionClass($parameter->getType()->getName()) + $paramType = $parameter->getType(); + $name = ($paramType && method_exists($paramType, 'isBuiltin') && !$paramType->isBuiltin()) + ? new \ReflectionClass($paramType->getName()) : null; $result[] = [ $parameter->getName(), diff --git a/src/Magento/FunctionalTestingFramework/System/Code/ClassReader.php b/src/Magento/FunctionalTestingFramework/System/Code/ClassReader.php index 1ccb28cc6..8408f361b 100644 --- a/src/Magento/FunctionalTestingFramework/System/Code/ClassReader.php +++ b/src/Magento/FunctionalTestingFramework/System/Code/ClassReader.php @@ -20,6 +20,7 @@ class ClassReader * @param string $method * @return array|null * @throws \ReflectionException + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function getParameters($className, $method) { @@ -31,8 +32,9 @@ public function getParameters($className, $method) /** @var $parameter \ReflectionParameter */ foreach ($method->getParameters() as $parameter) { try { - $name = $parameter->getType() && !$parameter->getType()->isBuiltin() - ? new \ReflectionClass($parameter->getType()->getName()) + $paramType = $parameter->getType(); + $name = ($paramType && method_exists($paramType, 'isBuiltin') && !$paramType->isBuiltin()) + ? new \ReflectionClass($paramType->getName()) : null; $result[$parameter->getName()] = [ $parameter->getName(), From d691ce4a4813a057cef9127b087a3cb99b8ac2ee Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Thu, 14 Oct 2021 13:19:38 -0500 Subject: [PATCH 719/888] MQE-2978: [MFTF] Investigate removal of hoa/console --- .github/workflows/main.yml | 8 +- composer.json | 1 - composer.lock | 1118 +++++------------ .../Console/Codecept/CodeceptCommandUtil.php | 2 + .../Util/Iterator/AbstractIterator.php | 14 +- .../Util/Iterator/File.php | 2 +- 6 files changed, 322 insertions(+), 823 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index cc7811a75..03bdbff75 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,7 +12,7 @@ jobs: strategy: fail-fast: false matrix: - php-versions: ['7.3', '7.4', '8.0'] + php-versions: ['7.3', '7.4', '8.0', '8.1'] steps: - uses: actions/checkout@v2 @@ -54,7 +54,7 @@ jobs: strategy: fail-fast: false matrix: - php-versions: ['7.3', '7.4', '8.0'] + php-versions: ['7.3', '7.4', '8.0', '8.1'] steps: - uses: actions/checkout@v2 @@ -86,7 +86,7 @@ jobs: strategy: fail-fast: false matrix: - php-versions: ['7.3', '7.4', '8.0'] + php-versions: ['7.3', '7.4', '8.0', '8.1'] steps: - uses: actions/checkout@v2 @@ -118,7 +118,7 @@ jobs: strategy: fail-fast: false matrix: - php-versions: ['7.3', '7.4', '8.0'] + php-versions: ['7.3', '7.4', '8.0', '8.1'] services: chrome: diff --git a/composer.json b/composer.json index 1550c0298..a7502b067 100755 --- a/composer.json +++ b/composer.json @@ -24,7 +24,6 @@ "composer/composer": "^1.9||^2.0", "csharpru/vault-php": "^4.2.1", "guzzlehttp/guzzle": "^7.3.0", - "hoa/console": "~3.0", "monolog/monolog": "^2.3", "mustache/mustache": "~2.5", "nikic/php-parser": "^4.4", diff --git a/composer.lock b/composer.lock index 575d863a7..061c9d862 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b1921bd26a93634cba6000ef524db2c9", + "content-hash": "8dc05529156aa036fdfe184d1b174c49", "packages": [ { "name": "allure-framework/allure-codeception", @@ -125,21 +125,72 @@ }, "time": "2021-03-26T14:32:27+00:00" }, + { + "name": "aws/aws-crt-php", + "version": "v1.0.2", + "source": { + "type": "git", + "url": "https://github.com/awslabs/aws-crt-php.git", + "reference": "3942776a8c99209908ee0b287746263725685732" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/3942776a8c99209908ee0b287746263725685732", + "reference": "3942776a8c99209908ee0b287746263725685732", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35|^5.4.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "AWS SDK Common Runtime Team", + "email": "aws-sdk-common-runtime@amazon.com" + } + ], + "description": "AWS Common Runtime for PHP", + "homepage": "http://aws.amazon.com/sdkforphp", + "keywords": [ + "amazon", + "aws", + "crt", + "sdk" + ], + "support": { + "issues": "https://github.com/awslabs/aws-crt-php/issues", + "source": "https://github.com/awslabs/aws-crt-php/tree/v1.0.2" + }, + "time": "2021-09-03T22:57:30+00:00" + }, { "name": "aws/aws-sdk-php", - "version": "3.191.5", + "version": "3.198.4", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "c003e59f8976f6fe045c27f6afc5d5004317f39b" + "reference": "b0b95cf0fa287e5b5db73ceafaf836950ede76ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/c003e59f8976f6fe045c27f6afc5d5004317f39b", - "reference": "c003e59f8976f6fe045c27f6afc5d5004317f39b", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/b0b95cf0fa287e5b5db73ceafaf836950ede76ff", + "reference": "b0b95cf0fa287e5b5db73ceafaf836950ede76ff", "shasum": "" }, "require": { + "aws/aws-crt-php": "^1.0.2", "ext-json": "*", "ext-pcre": "*", "ext-simplexml": "*", @@ -211,9 +262,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.191.5" + "source": "https://github.com/aws/aws-sdk-php/tree/3.198.4" }, - "time": "2021-08-26T18:16:35+00:00" + "time": "2021-10-13T18:16:14+00:00" }, { "name": "beberlei/assert", @@ -284,25 +335,24 @@ }, { "name": "behat/gherkin", - "version": "v4.8.0", + "version": "v4.9.0", "source": { "type": "git", "url": "https://github.com/Behat/Gherkin.git", - "reference": "2391482cd003dfdc36b679b27e9f5326bd656acd" + "reference": "0bc8d1e30e96183e4f36db9dc79caead300beff4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Behat/Gherkin/zipball/2391482cd003dfdc36b679b27e9f5326bd656acd", - "reference": "2391482cd003dfdc36b679b27e9f5326bd656acd", + "url": "https://api.github.com/repos/Behat/Gherkin/zipball/0bc8d1e30e96183e4f36db9dc79caead300beff4", + "reference": "0bc8d1e30e96183e4f36db9dc79caead300beff4", "shasum": "" }, "require": { "php": "~7.2|~8.0" }, "require-dev": { - "cucumber/cucumber": "dev-gherkin-16.0.0", + "cucumber/cucumber": "dev-gherkin-22.0.0", "phpunit/phpunit": "~8|~9", - "symfony/phpunit-bridge": "~3|~4|~5", "symfony/yaml": "~3|~4|~5" }, "suggest": { @@ -311,7 +361,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.4-dev" + "dev-master": "4.x-dev" } }, "autoload": { @@ -342,9 +392,9 @@ ], "support": { "issues": "https://github.com/Behat/Gherkin/issues", - "source": "https://github.com/Behat/Gherkin/tree/v4.8.0" + "source": "https://github.com/Behat/Gherkin/tree/v4.9.0" }, - "time": "2021-02-04T12:44:21+00:00" + "time": "2021-10-12T13:05:09+00:00" }, { "name": "brick/math", @@ -658,16 +708,16 @@ }, { "name": "codeception/module-webdriver", - "version": "1.3.0", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/Codeception/module-webdriver.git", - "reference": "0b043cedebdb62d6706d9823f1c17bd0f26d831d" + "reference": "baa18b7bf70aa024012f967b5ce5021e1faa9151" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/module-webdriver/zipball/0b043cedebdb62d6706d9823f1c17bd0f26d831d", - "reference": "0b043cedebdb62d6706d9823f1c17bd0f26d831d", + "url": "https://api.github.com/repos/Codeception/module-webdriver/zipball/baa18b7bf70aa024012f967b5ce5021e1faa9151", + "reference": "baa18b7bf70aa024012f967b5ce5021e1faa9151", "shasum": "" }, "require": { @@ -708,9 +758,9 @@ ], "support": { "issues": "https://github.com/Codeception/module-webdriver/issues", - "source": "https://github.com/Codeception/module-webdriver/tree/1.3.0" + "source": "https://github.com/Codeception/module-webdriver/tree/1.4.0" }, - "time": "2021-08-22T07:21:13+00:00" + "time": "2021-09-02T12:01:02+00:00" }, { "name": "codeception/phpunit-wrapper", @@ -797,16 +847,16 @@ }, { "name": "composer/ca-bundle", - "version": "1.2.10", + "version": "1.2.11", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "9fdb22c2e97a614657716178093cd1da90a64aa8" + "reference": "0b072d51c5a9c6f3412f7ea3ab043d6603cb2582" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/9fdb22c2e97a614657716178093cd1da90a64aa8", - "reference": "9fdb22c2e97a614657716178093cd1da90a64aa8", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/0b072d51c5a9c6f3412f7ea3ab043d6603cb2582", + "reference": "0b072d51c5a9c6f3412f7ea3ab043d6603cb2582", "shasum": "" }, "require": { @@ -818,7 +868,7 @@ "phpstan/phpstan": "^0.12.55", "psr/log": "^1.0", "symfony/phpunit-bridge": "^4.2 || ^5", - "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0" + "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0 || ^6.0" }, "type": "library", "extra": { @@ -853,7 +903,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.2.10" + "source": "https://github.com/composer/ca-bundle/tree/1.2.11" }, "funding": [ { @@ -869,20 +919,20 @@ "type": "tidelift" } ], - "time": "2021-06-07T13:58:28+00:00" + "time": "2021-09-25T20:32:43+00:00" }, { "name": "composer/composer", - "version": "2.1.6", + "version": "2.1.9", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "e5cac5f9d2354d08b67f1d21c664ae70d748c603" + "reference": "e558c88f28d102d497adec4852802c0dc14c7077" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/e5cac5f9d2354d08b67f1d21c664ae70d748c603", - "reference": "e5cac5f9d2354d08b67f1d21c664ae70d748c603", + "url": "https://api.github.com/repos/composer/composer/zipball/e558c88f28d102d497adec4852802c0dc14c7077", + "reference": "e558c88f28d102d497adec4852802c0dc14c7077", "shasum": "" }, "require": { @@ -951,7 +1001,7 @@ "support": { "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/composer/issues", - "source": "https://github.com/composer/composer/tree/2.1.6" + "source": "https://github.com/composer/composer/tree/2.1.9" }, "funding": [ { @@ -967,7 +1017,7 @@ "type": "tidelift" } ], - "time": "2021-08-19T15:11:08+00:00" + "time": "2021-10-05T07:47:38+00:00" }, { "name": "composer/metadata-minifier", @@ -1651,16 +1701,16 @@ }, { "name": "guzzlehttp/promises", - "version": "1.4.1", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d" + "reference": "136a635e2b4a49b9d79e9c8fee267ffb257fdba0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/8e7d04f1f6450fef59366c399cfad4b9383aa30d", - "reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d", + "url": "https://api.github.com/repos/guzzle/promises/zipball/136a635e2b4a49b9d79e9c8fee267ffb257fdba0", + "reference": "136a635e2b4a49b9d79e9c8fee267ffb257fdba0", "shasum": "" }, "require": { @@ -1672,7 +1722,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4-dev" + "dev-master": "1.5-dev" } }, "autoload": { @@ -1688,10 +1738,25 @@ "MIT" ], "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, { "name": "Michael Dowling", "email": "mtdowling@gmail.com", "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" } ], "description": "Guzzle promises library", @@ -1700,22 +1765,36 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/1.4.1" + "source": "https://github.com/guzzle/promises/tree/1.5.0" }, - "time": "2021-03-07T09:25:29+00:00" + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2021-10-07T13:05:22+00:00" }, { "name": "guzzlehttp/psr7", - "version": "1.8.2", + "version": "1.8.3", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "dc960a912984efb74d0a90222870c72c87f10c91" + "reference": "1afdd860a2566ed3c2b0b4a3de6e23434a79ec85" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/dc960a912984efb74d0a90222870c72c87f10c91", - "reference": "dc960a912984efb74d0a90222870c72c87f10c91", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/1afdd860a2566ed3c2b0b4a3de6e23434a79ec85", + "reference": "1afdd860a2566ed3c2b0b4a3de6e23434a79ec85", "shasum": "" }, "require": { @@ -1752,13 +1831,34 @@ "MIT" ], "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, { "name": "Michael Dowling", "email": "mtdowling@gmail.com", "homepage": "https://github.com/mtdowling" }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, { "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", "homepage": "https://github.com/Tobion" } ], @@ -1775,630 +1875,23 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/1.8.2" - }, - "time": "2021-04-26T09:17:50+00:00" - }, - { - "name": "hoa/consistency", - "version": "1.17.05.02", - "source": { - "type": "git", - "url": "https://github.com/hoaproject/Consistency.git", - "reference": "fd7d0adc82410507f332516faf655b6ed22e4c2f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hoaproject/Consistency/zipball/fd7d0adc82410507f332516faf655b6ed22e4c2f", - "reference": "fd7d0adc82410507f332516faf655b6ed22e4c2f", - "shasum": "" - }, - "require": { - "hoa/exception": "~1.0", - "php": ">=5.5.0" - }, - "require-dev": { - "hoa/stream": "~1.0", - "hoa/test": "~2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Hoa\\Consistency\\": "." - }, - "files": [ - "Prelude.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Ivan Enderlin", - "email": "ivan.enderlin@hoa-project.net" - }, - { - "name": "Hoa community", - "homepage": "https://hoa-project.net/" - } - ], - "description": "The Hoa\\Consistency library.", - "homepage": "https://hoa-project.net/", - "keywords": [ - "autoloader", - "callable", - "consistency", - "entity", - "flex", - "keyword", - "library" - ], - "support": { - "docs": "https://central.hoa-project.net/Documentation/Library/Consistency", - "email": "support@hoa-project.net", - "forum": "https://users.hoa-project.net/", - "irc": "irc://chat.freenode.net/hoaproject", - "issues": "https://github.com/hoaproject/Consistency/issues", - "source": "https://central.hoa-project.net/Resource/Library/Consistency" - }, - "time": "2017-05-02T12:18:12+00:00" - }, - { - "name": "hoa/console", - "version": "3.17.05.02", - "source": { - "type": "git", - "url": "https://github.com/hoaproject/Console.git", - "reference": "e231fd3ea70e6d773576ae78de0bdc1daf331a66" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hoaproject/Console/zipball/e231fd3ea70e6d773576ae78de0bdc1daf331a66", - "reference": "e231fd3ea70e6d773576ae78de0bdc1daf331a66", - "shasum": "" - }, - "require": { - "hoa/consistency": "~1.0", - "hoa/event": "~1.0", - "hoa/exception": "~1.0", - "hoa/file": "~1.0", - "hoa/protocol": "~1.0", - "hoa/stream": "~1.0", - "hoa/ustring": "~4.0" - }, - "require-dev": { - "hoa/test": "~2.0" - }, - "suggest": { - "ext-pcntl": "To enable hoa://Event/Console/Window:resize.", - "hoa/dispatcher": "To use the console kit.", - "hoa/router": "To use the console kit." - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Hoa\\Console\\": "." - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Ivan Enderlin", - "email": "ivan.enderlin@hoa-project.net" - }, - { - "name": "Hoa community", - "homepage": "https://hoa-project.net/" - } - ], - "description": "The Hoa\\Console library.", - "homepage": "https://hoa-project.net/", - "keywords": [ - "autocompletion", - "chrome", - "cli", - "console", - "cursor", - "getoption", - "library", - "option", - "parser", - "processus", - "readline", - "terminfo", - "tput", - "window" - ], - "support": { - "docs": "https://central.hoa-project.net/Documentation/Library/Console", - "email": "support@hoa-project.net", - "forum": "https://users.hoa-project.net/", - "irc": "irc://chat.freenode.net/hoaproject", - "issues": "https://github.com/hoaproject/Console/issues", - "source": "https://central.hoa-project.net/Resource/Library/Console" - }, - "time": "2017-05-02T12:26:19+00:00" - }, - { - "name": "hoa/event", - "version": "1.17.01.13", - "source": { - "type": "git", - "url": "https://github.com/hoaproject/Event.git", - "reference": "6c0060dced212ffa3af0e34bb46624f990b29c54" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hoaproject/Event/zipball/6c0060dced212ffa3af0e34bb46624f990b29c54", - "reference": "6c0060dced212ffa3af0e34bb46624f990b29c54", - "shasum": "" + "source": "https://github.com/guzzle/psr7/tree/1.8.3" }, - "require": { - "hoa/consistency": "~1.0", - "hoa/exception": "~1.0" - }, - "require-dev": { - "hoa/test": "~2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Hoa\\Event\\": "." - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Ivan Enderlin", - "email": "ivan.enderlin@hoa-project.net" - }, - { - "name": "Hoa community", - "homepage": "https://hoa-project.net/" - } - ], - "description": "The Hoa\\Event library.", - "homepage": "https://hoa-project.net/", - "keywords": [ - "event", - "library", - "listener", - "observer" - ], - "support": { - "docs": "https://central.hoa-project.net/Documentation/Library/Event", - "email": "support@hoa-project.net", - "forum": "https://users.hoa-project.net/", - "irc": "irc://chat.freenode.net/hoaproject", - "issues": "https://github.com/hoaproject/Event/issues", - "source": "https://central.hoa-project.net/Resource/Library/Event" - }, - "time": "2017-01-13T15:30:50+00:00" - }, - { - "name": "hoa/exception", - "version": "1.17.01.16", - "source": { - "type": "git", - "url": "https://github.com/hoaproject/Exception.git", - "reference": "091727d46420a3d7468ef0595651488bfc3a458f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hoaproject/Exception/zipball/091727d46420a3d7468ef0595651488bfc3a458f", - "reference": "091727d46420a3d7468ef0595651488bfc3a458f", - "shasum": "" - }, - "require": { - "hoa/consistency": "~1.0", - "hoa/event": "~1.0" - }, - "require-dev": { - "hoa/test": "~2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Hoa\\Exception\\": "." - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Ivan Enderlin", - "email": "ivan.enderlin@hoa-project.net" - }, - { - "name": "Hoa community", - "homepage": "https://hoa-project.net/" - } - ], - "description": "The Hoa\\Exception library.", - "homepage": "https://hoa-project.net/", - "keywords": [ - "exception", - "library" - ], - "support": { - "docs": "https://central.hoa-project.net/Documentation/Library/Exception", - "email": "support@hoa-project.net", - "forum": "https://users.hoa-project.net/", - "irc": "irc://chat.freenode.net/hoaproject", - "issues": "https://github.com/hoaproject/Exception/issues", - "source": "https://central.hoa-project.net/Resource/Library/Exception" - }, - "time": "2017-01-16T07:53:27+00:00" - }, - { - "name": "hoa/file", - "version": "1.17.07.11", - "source": { - "type": "git", - "url": "https://github.com/hoaproject/File.git", - "reference": "35cb979b779bc54918d2f9a4e02ed6c7a1fa67ca" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hoaproject/File/zipball/35cb979b779bc54918d2f9a4e02ed6c7a1fa67ca", - "reference": "35cb979b779bc54918d2f9a4e02ed6c7a1fa67ca", - "shasum": "" - }, - "require": { - "hoa/consistency": "~1.0", - "hoa/event": "~1.0", - "hoa/exception": "~1.0", - "hoa/iterator": "~2.0", - "hoa/stream": "~1.0" - }, - "require-dev": { - "hoa/test": "~2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Hoa\\File\\": "." - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Ivan Enderlin", - "email": "ivan.enderlin@hoa-project.net" - }, - { - "name": "Hoa community", - "homepage": "https://hoa-project.net/" - } - ], - "description": "The Hoa\\File library.", - "homepage": "https://hoa-project.net/", - "keywords": [ - "Socket", - "directory", - "file", - "finder", - "library", - "link", - "temporary" - ], - "support": { - "docs": "https://central.hoa-project.net/Documentation/Library/File", - "email": "support@hoa-project.net", - "forum": "https://users.hoa-project.net/", - "irc": "irc://chat.freenode.net/hoaproject", - "issues": "https://github.com/hoaproject/File/issues", - "source": "https://central.hoa-project.net/Resource/Library/File" - }, - "time": "2017-07-11T07:42:15+00:00" - }, - { - "name": "hoa/iterator", - "version": "2.17.01.10", - "source": { - "type": "git", - "url": "https://github.com/hoaproject/Iterator.git", - "reference": "d1120ba09cb4ccd049c86d10058ab94af245f0cc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hoaproject/Iterator/zipball/d1120ba09cb4ccd049c86d10058ab94af245f0cc", - "reference": "d1120ba09cb4ccd049c86d10058ab94af245f0cc", - "shasum": "" - }, - "require": { - "hoa/consistency": "~1.0", - "hoa/exception": "~1.0" - }, - "require-dev": { - "hoa/test": "~2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "Hoa\\Iterator\\": "." - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Ivan Enderlin", - "email": "ivan.enderlin@hoa-project.net" - }, - { - "name": "Hoa community", - "homepage": "https://hoa-project.net/" - } - ], - "description": "The Hoa\\Iterator library.", - "homepage": "https://hoa-project.net/", - "keywords": [ - "iterator", - "library" - ], - "support": { - "docs": "https://central.hoa-project.net/Documentation/Library/Iterator", - "email": "support@hoa-project.net", - "forum": "https://users.hoa-project.net/", - "irc": "irc://chat.freenode.net/hoaproject", - "issues": "https://github.com/hoaproject/Iterator/issues", - "source": "https://central.hoa-project.net/Resource/Library/Iterator" - }, - "time": "2017-01-10T10:34:47+00:00" - }, - { - "name": "hoa/protocol", - "version": "1.17.01.14", - "source": { - "type": "git", - "url": "https://github.com/hoaproject/Protocol.git", - "reference": "5c2cf972151c45f373230da170ea015deecf19e2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hoaproject/Protocol/zipball/5c2cf972151c45f373230da170ea015deecf19e2", - "reference": "5c2cf972151c45f373230da170ea015deecf19e2", - "shasum": "" - }, - "require": { - "hoa/consistency": "~1.0", - "hoa/exception": "~1.0" - }, - "require-dev": { - "hoa/test": "~2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Hoa\\Protocol\\": "." - }, - "files": [ - "Wrapper.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Ivan Enderlin", - "email": "ivan.enderlin@hoa-project.net" - }, - { - "name": "Hoa community", - "homepage": "https://hoa-project.net/" - } - ], - "description": "The Hoa\\Protocol library.", - "homepage": "https://hoa-project.net/", - "keywords": [ - "library", - "protocol", - "resource", - "stream", - "wrapper" - ], - "support": { - "docs": "https://central.hoa-project.net/Documentation/Library/Protocol", - "email": "support@hoa-project.net", - "forum": "https://users.hoa-project.net/", - "irc": "irc://chat.freenode.net/hoaproject", - "issues": "https://github.com/hoaproject/Protocol/issues", - "source": "https://central.hoa-project.net/Resource/Library/Protocol" - }, - "time": "2017-01-14T12:26:10+00:00" - }, - { - "name": "hoa/stream", - "version": "1.17.02.21", - "source": { - "type": "git", - "url": "https://github.com/hoaproject/Stream.git", - "reference": "3293cfffca2de10525df51436adf88a559151d82" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hoaproject/Stream/zipball/3293cfffca2de10525df51436adf88a559151d82", - "reference": "3293cfffca2de10525df51436adf88a559151d82", - "shasum": "" - }, - "require": { - "hoa/consistency": "~1.0", - "hoa/event": "~1.0", - "hoa/exception": "~1.0", - "hoa/protocol": "~1.0" - }, - "require-dev": { - "hoa/test": "~2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Hoa\\Stream\\": "." - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ + "funding": [ { - "name": "Ivan Enderlin", - "email": "ivan.enderlin@hoa-project.net" + "url": "https://github.com/GrahamCampbell", + "type": "github" }, { - "name": "Hoa community", - "homepage": "https://hoa-project.net/" - } - ], - "description": "The Hoa\\Stream library.", - "homepage": "https://hoa-project.net/", - "keywords": [ - "Context", - "bucket", - "composite", - "filter", - "in", - "library", - "out", - "protocol", - "stream", - "wrapper" - ], - "support": { - "docs": "https://central.hoa-project.net/Documentation/Library/Stream", - "email": "support@hoa-project.net", - "forum": "https://users.hoa-project.net/", - "irc": "irc://chat.freenode.net/hoaproject", - "issues": "https://github.com/hoaproject/Stream/issues", - "source": "https://central.hoa-project.net/Resource/Library/Stream" - }, - "time": "2017-02-21T16:01:06+00:00" - }, - { - "name": "hoa/ustring", - "version": "4.17.01.16", - "source": { - "type": "git", - "url": "https://github.com/hoaproject/Ustring.git", - "reference": "e6326e2739178799b1fe3fdd92029f9517fa17a0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hoaproject/Ustring/zipball/e6326e2739178799b1fe3fdd92029f9517fa17a0", - "reference": "e6326e2739178799b1fe3fdd92029f9517fa17a0", - "shasum": "" - }, - "require": { - "hoa/consistency": "~1.0", - "hoa/exception": "~1.0" - }, - "require-dev": { - "hoa/test": "~2.0" - }, - "suggest": { - "ext-iconv": "ext/iconv must be present (or a third implementation) to use Hoa\\Ustring::transcode().", - "ext-intl": "To get a better Hoa\\Ustring::toAscii() and Hoa\\Ustring::compareTo()." - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.x-dev" - } - }, - "autoload": { - "psr-4": { - "Hoa\\Ustring\\": "." - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Ivan Enderlin", - "email": "ivan.enderlin@hoa-project.net" + "url": "https://github.com/Nyholm", + "type": "github" }, { - "name": "Hoa community", - "homepage": "https://hoa-project.net/" + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" } ], - "description": "The Hoa\\Ustring library.", - "homepage": "https://hoa-project.net/", - "keywords": [ - "library", - "search", - "string", - "unicode" - ], - "support": { - "docs": "https://central.hoa-project.net/Documentation/Library/Ustring", - "email": "support@hoa-project.net", - "forum": "https://users.hoa-project.net/", - "irc": "irc://chat.freenode.net/hoaproject", - "issues": "https://github.com/hoaproject/Ustring/issues", - "source": "https://central.hoa-project.net/Resource/Library/Ustring" - }, - "time": "2017-01-16T07:08:25+00:00" + "time": "2021-10-05T13:56:00+00:00" }, { "name": "jms/metadata", @@ -2629,24 +2122,24 @@ }, { "name": "monolog/monolog", - "version": "2.3.2", + "version": "2.3.5", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "71312564759a7db5b789296369c1a264efc43aad" + "reference": "fd4380d6fc37626e2f799f29d91195040137eba9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/71312564759a7db5b789296369c1a264efc43aad", - "reference": "71312564759a7db5b789296369c1a264efc43aad", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fd4380d6fc37626e2f799f29d91195040137eba9", + "reference": "fd4380d6fc37626e2f799f29d91195040137eba9", "shasum": "" }, "require": { "php": ">=7.2", - "psr/log": "^1.0.1" + "psr/log": "^1.0.1 || ^2.0 || ^3.0" }, "provide": { - "psr/log-implementation": "1.0.0" + "psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0" }, "require-dev": { "aws/aws-sdk-php": "^2.4.9 || ^3.0", @@ -2654,14 +2147,14 @@ "elasticsearch/elasticsearch": "^7", "graylog2/gelf-php": "^1.4.2", "mongodb/mongodb": "^1.8", - "php-amqplib/php-amqplib": "~2.4", + "php-amqplib/php-amqplib": "~2.4 || ^3", "php-console/php-console": "^3.1.3", "phpspec/prophecy": "^1.6.1", "phpstan/phpstan": "^0.12.91", "phpunit/phpunit": "^8.5", "predis/predis": "^1.1", "rollbar/rollbar": "^1.3", - "ruflin/elastica": ">=0.90 <7.0.1", + "ruflin/elastica": ">=0.90@dev", "swiftmailer/swiftmailer": "^5.3|^6.0" }, "suggest": { @@ -2669,8 +2162,11 @@ "doctrine/couchdb": "Allow sending log messages to a CouchDB server", "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", "ext-mbstring": "Allow to work properly with unicode symbols", "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", + "ext-openssl": "Required to send log messages using SSL", + "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", @@ -2709,7 +2205,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/2.3.2" + "source": "https://github.com/Seldaek/monolog/tree/2.3.5" }, "funding": [ { @@ -2721,7 +2217,7 @@ "type": "tidelift" } ], - "time": "2021-07-23T07:42:52+00:00" + "time": "2021-10-01T21:08:31+00:00" }, { "name": "mtdowling/jmespath.php", @@ -2894,16 +2390,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.12.0", + "version": "v4.13.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "6608f01670c3cc5079e18c1dab1104e002579143" + "reference": "50953a2691a922aa1769461637869a0a2faa3f53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6608f01670c3cc5079e18c1dab1104e002579143", - "reference": "6608f01670c3cc5079e18c1dab1104e002579143", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/50953a2691a922aa1769461637869a0a2faa3f53", + "reference": "50953a2691a922aa1769461637869a0a2faa3f53", "shasum": "" }, "require": { @@ -2944,9 +2440,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.12.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.0" }, - "time": "2021-07-21T10:44:31+00:00" + "time": "2021-09-20T12:20:58+00:00" }, { "name": "paragonie/constant_time_encoding", @@ -3128,16 +2624,16 @@ }, { "name": "php-webdriver/webdriver", - "version": "1.11.1", + "version": "1.12.0", "source": { "type": "git", "url": "https://github.com/php-webdriver/php-webdriver.git", - "reference": "da16e39968f8dd5cfb7d07eef91dc2b731c69880" + "reference": "99d4856ed7dffcdf6a52eccd6551e83d8d557ceb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/da16e39968f8dd5cfb7d07eef91dc2b731c69880", - "reference": "da16e39968f8dd5cfb7d07eef91dc2b731c69880", + "url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/99d4856ed7dffcdf6a52eccd6551e83d8d557ceb", + "reference": "99d4856ed7dffcdf6a52eccd6551e83d8d557ceb", "shasum": "" }, "require": { @@ -3146,20 +2642,19 @@ "ext-zip": "*", "php": "^5.6 || ~7.0 || ^8.0", "symfony/polyfill-mbstring": "^1.12", - "symfony/process": "^2.8 || ^3.1 || ^4.0 || ^5.0" + "symfony/process": "^2.8 || ^3.1 || ^4.0 || ^5.0 || ^6.0" }, "replace": { "facebook/webdriver": "*" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.0", "ondram/ci-detector": "^2.1 || ^3.5 || ^4.0", "php-coveralls/php-coveralls": "^2.4", "php-mock/php-mock-phpunit": "^1.1 || ^2.0", "php-parallel-lint/php-parallel-lint": "^1.2", "phpunit/phpunit": "^5.7 || ^7 || ^8 || ^9", "squizlabs/php_codesniffer": "^3.5", - "symfony/var-dumper": "^3.3 || ^4.0 || ^5.0" + "symfony/var-dumper": "^3.3 || ^4.0 || ^5.0 || ^6.0" }, "suggest": { "ext-SimpleXML": "For Firefox profile creation" @@ -3188,9 +2683,9 @@ ], "support": { "issues": "https://github.com/php-webdriver/php-webdriver/issues", - "source": "https://github.com/php-webdriver/php-webdriver/tree/1.11.1" + "source": "https://github.com/php-webdriver/php-webdriver/tree/1.12.0" }, - "time": "2021-05-21T15:12:49+00:00" + "time": "2021-10-14T09:30:02+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -3303,16 +2798,16 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.4.0", + "version": "1.5.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0" + "reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", - "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/a12f7e301eb7258bb68acd89d4aefa05c2906cae", + "reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae", "shasum": "" }, "require": { @@ -3320,7 +2815,8 @@ "phpdocumentor/reflection-common": "^2.0" }, "require-dev": { - "ext-tokenizer": "*" + "ext-tokenizer": "*", + "psalm/phar": "^4.8" }, "type": "library", "extra": { @@ -3346,39 +2842,39 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.4.0" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.5.1" }, - "time": "2020-09-17T18:55:26+00:00" + "time": "2021-10-02T14:08:47+00:00" }, { "name": "phpspec/prophecy", - "version": "1.13.0", + "version": "1.14.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "be1996ed8adc35c3fd795488a653f4b518be70ea" + "reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/be1996ed8adc35c3fd795488a653f4b518be70ea", - "reference": "be1996ed8adc35c3fd795488a653f4b518be70ea", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e", + "reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e", "shasum": "" }, "require": { "doctrine/instantiator": "^1.2", - "php": "^7.2 || ~8.0, <8.1", + "php": "^7.2 || ~8.0, <8.2", "phpdocumentor/reflection-docblock": "^5.2", "sebastian/comparator": "^3.0 || ^4.0", "sebastian/recursion-context": "^3.0 || ^4.0" }, "require-dev": { - "phpspec/phpspec": "^6.0", + "phpspec/phpspec": "^6.0 || ^7.0", "phpunit/phpunit": "^8.0 || ^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.11.x-dev" + "dev-master": "1.x-dev" } }, "autoload": { @@ -3413,22 +2909,22 @@ ], "support": { "issues": "https://github.com/phpspec/prophecy/issues", - "source": "https://github.com/phpspec/prophecy/tree/1.13.0" + "source": "https://github.com/phpspec/prophecy/tree/1.14.0" }, - "time": "2021-03-17T13:42:18+00:00" + "time": "2021-09-10T09:02:12+00:00" }, { "name": "phpstan/phpdoc-parser", - "version": "0.5.5", + "version": "0.5.7", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "ea0b17460ec38e20d7eb64e7ec49b5d44af5d28c" + "reference": "816e826ce0b7fb32098d8cb6de62511ce6021cea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/ea0b17460ec38e20d7eb64e7ec49b5d44af5d28c", - "reference": "ea0b17460ec38e20d7eb64e7ec49b5d44af5d28c", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/816e826ce0b7fb32098d8cb6de62511ce6021cea", + "reference": "816e826ce0b7fb32098d8cb6de62511ce6021cea", "shasum": "" }, "require": { @@ -3462,29 +2958,29 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/0.5.5" + "source": "https://github.com/phpstan/phpdoc-parser/tree/0.5.7" }, - "time": "2021-06-11T13:24:46+00:00" + "time": "2021-09-12T11:52:00+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.6", + "version": "9.2.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "f6293e1b30a2354e8428e004689671b83871edde" + "reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f6293e1b30a2354e8428e004689671b83871edde", - "reference": "f6293e1b30a2354e8428e004689671b83871edde", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d4c798ed8d51506800b441f7a13ecb0f76f12218", + "reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.10.2", + "nikic/php-parser": "^4.12.0", "php": ">=7.3", "phpunit/php-file-iterator": "^3.0.3", "phpunit/php-text-template": "^2.0.2", @@ -3533,7 +3029,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.6" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.7" }, "funding": [ { @@ -3541,7 +3037,7 @@ "type": "github" } ], - "time": "2021-03-28T07:26:59+00:00" + "time": "2021-09-17T05:39:03+00:00" }, { "name": "phpunit/php-file-iterator", @@ -3786,16 +3282,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.8", + "version": "9.5.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "191768ccd5c85513b4068bdbe99bb6390c7d54fb" + "reference": "c814a05837f2edb0d1471d6e3f4ab3501ca3899a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/191768ccd5c85513b4068bdbe99bb6390c7d54fb", - "reference": "191768ccd5c85513b4068bdbe99bb6390c7d54fb", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c814a05837f2edb0d1471d6e3f4ab3501ca3899a", + "reference": "c814a05837f2edb0d1471d6e3f4ab3501ca3899a", "shasum": "" }, "require": { @@ -3811,7 +3307,7 @@ "phar-io/version": "^3.0.2", "php": ">=7.3", "phpspec/prophecy": "^1.12.1", - "phpunit/php-code-coverage": "^9.2.3", + "phpunit/php-code-coverage": "^9.2.7", "phpunit/php-file-iterator": "^3.0.5", "phpunit/php-invoker": "^3.1.1", "phpunit/php-text-template": "^2.0.3", @@ -3873,7 +3369,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.8" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.10" }, "funding": [ { @@ -3885,7 +3381,7 @@ "type": "github" } ], - "time": "2021-07-31T15:17:34+00:00" + "time": "2021-09-25T07:38:51+00:00" }, { "name": "psr/cache", @@ -4240,16 +3736,16 @@ }, { "name": "ramsey/collection", - "version": "1.2.1", + "version": "1.2.2", "source": { "type": "git", "url": "https://github.com/ramsey/collection.git", - "reference": "eaca1dc1054ddd10cbd83c1461907bee6fb528fa" + "reference": "cccc74ee5e328031b15640b51056ee8d3bb66c0a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/collection/zipball/eaca1dc1054ddd10cbd83c1461907bee6fb528fa", - "reference": "eaca1dc1054ddd10cbd83c1461907bee6fb528fa", + "url": "https://api.github.com/repos/ramsey/collection/zipball/cccc74ee5e328031b15640b51056ee8d3bb66c0a", + "reference": "cccc74ee5e328031b15640b51056ee8d3bb66c0a", "shasum": "" }, "require": { @@ -4303,7 +3799,7 @@ ], "support": { "issues": "https://github.com/ramsey/collection/issues", - "source": "https://github.com/ramsey/collection/tree/1.2.1" + "source": "https://github.com/ramsey/collection/tree/1.2.2" }, "funding": [ { @@ -4315,28 +3811,29 @@ "type": "tidelift" } ], - "time": "2021-08-06T03:41:06+00:00" + "time": "2021-10-10T03:01:02+00:00" }, { "name": "ramsey/uuid", - "version": "4.2.1", + "version": "4.2.3", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "fe665a03df4f056aa65af552a96e1976df8c8dae" + "reference": "fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/fe665a03df4f056aa65af552a96e1976df8c8dae", - "reference": "fe665a03df4f056aa65af552a96e1976df8c8dae", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df", + "reference": "fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df", "shasum": "" }, "require": { "brick/math": "^0.8 || ^0.9", "ext-json": "*", - "php": "^7.2 || ^8", + "php": "^7.2 || ^8.0", "ramsey/collection": "^1.0", - "symfony/polyfill-ctype": "^1.8" + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-php80": "^1.14" }, "replace": { "rhumsaa/uuid": "self.version" @@ -4400,7 +3897,7 @@ ], "support": { "issues": "https://github.com/ramsey/uuid/issues", - "source": "https://github.com/ramsey/uuid/tree/4.2.1" + "source": "https://github.com/ramsey/uuid/tree/4.2.3" }, "funding": [ { @@ -4412,7 +3909,7 @@ "type": "tidelift" } ], - "time": "2021-08-11T01:06:55+00:00" + "time": "2021-09-25T23:10:38+00:00" }, { "name": "react/promise", @@ -5317,7 +4814,6 @@ "type": "github" } ], - "abandoned": true, "time": "2020-09-28T06:45:17+00:00" }, { @@ -5617,16 +5113,16 @@ }, { "name": "symfony/console", - "version": "v4.4.29", + "version": "v4.4.30", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "8baf0bbcfddfde7d7225ae8e04705cfd1081cd7b" + "reference": "a3f7189a0665ee33b50e9e228c46f50f5acbed22" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/8baf0bbcfddfde7d7225ae8e04705cfd1081cd7b", - "reference": "8baf0bbcfddfde7d7225ae8e04705cfd1081cd7b", + "url": "https://api.github.com/repos/symfony/console/zipball/a3f7189a0665ee33b50e9e228c46f50f5acbed22", + "reference": "a3f7189a0665ee33b50e9e228c46f50f5acbed22", "shasum": "" }, "require": { @@ -5687,7 +5183,7 @@ "description": "Eases the creation of beautiful and testable command line interfaces", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/console/tree/v4.4.29" + "source": "https://github.com/symfony/console/tree/v4.4.30" }, "funding": [ { @@ -5703,7 +5199,7 @@ "type": "tidelift" } ], - "time": "2021-07-27T19:04:53+00:00" + "time": "2021-08-25T19:27:26+00:00" }, { "name": "symfony/css-selector", @@ -5840,16 +5336,16 @@ }, { "name": "symfony/event-dispatcher", - "version": "v4.4.27", + "version": "v4.4.30", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "958a128b184fcf0ba45ec90c0e88554c9327c2e9" + "reference": "2fe81680070043c4c80e7cedceb797e34f377bac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/958a128b184fcf0ba45ec90c0e88554c9327c2e9", - "reference": "958a128b184fcf0ba45ec90c0e88554c9327c2e9", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/2fe81680070043c4c80e7cedceb797e34f377bac", + "reference": "2fe81680070043c4c80e7cedceb797e34f377bac", "shasum": "" }, "require": { @@ -5904,7 +5400,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.27" + "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.30" }, "funding": [ { @@ -5920,7 +5416,7 @@ "type": "tidelift" } ], - "time": "2021-07-23T15:41:52+00:00" + "time": "2021-08-04T20:31:23+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -6066,16 +5562,16 @@ }, { "name": "symfony/finder", - "version": "v5.3.4", + "version": "v5.3.7", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "17f50e06018baec41551a71a15731287dbaab186" + "reference": "a10000ada1e600d109a6c7632e9ac42e8bf2fb93" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/17f50e06018baec41551a71a15731287dbaab186", - "reference": "17f50e06018baec41551a71a15731287dbaab186", + "url": "https://api.github.com/repos/symfony/finder/zipball/a10000ada1e600d109a6c7632e9ac42e8bf2fb93", + "reference": "a10000ada1e600d109a6c7632e9ac42e8bf2fb93", "shasum": "" }, "require": { @@ -6108,7 +5604,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.3.4" + "source": "https://github.com/symfony/finder/tree/v5.3.7" }, "funding": [ { @@ -6124,20 +5620,20 @@ "type": "tidelift" } ], - "time": "2021-07-23T15:54:19+00:00" + "time": "2021-08-04T21:20:46+00:00" }, { "name": "symfony/http-foundation", - "version": "v5.3.6", + "version": "v5.3.7", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "a8388f7b7054a7401997008ce9cd8c6b0ab7ac75" + "reference": "e36c8e5502b4f3f0190c675f1c1f1248a64f04e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/a8388f7b7054a7401997008ce9cd8c6b0ab7ac75", - "reference": "a8388f7b7054a7401997008ce9cd8c6b0ab7ac75", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/e36c8e5502b4f3f0190c675f1c1f1248a64f04e5", + "reference": "e36c8e5502b4f3f0190c675f1c1f1248a64f04e5", "shasum": "" }, "require": { @@ -6181,7 +5677,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v5.3.6" + "source": "https://github.com/symfony/http-foundation/tree/v5.3.7" }, "funding": [ { @@ -6197,20 +5693,20 @@ "type": "tidelift" } ], - "time": "2021-07-27T17:08:17+00:00" + "time": "2021-08-27T11:20:35+00:00" }, { "name": "symfony/mime", - "version": "v5.3.4", + "version": "v5.3.8", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "633e4e8afe9e529e5599d71238849a4218dd497b" + "reference": "a756033d0a7e53db389618653ae991eba5a19a11" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/633e4e8afe9e529e5599d71238849a4218dd497b", - "reference": "633e4e8afe9e529e5599d71238849a4218dd497b", + "url": "https://api.github.com/repos/symfony/mime/zipball/a756033d0a7e53db389618653ae991eba5a19a11", + "reference": "a756033d0a7e53db389618653ae991eba5a19a11", "shasum": "" }, "require": { @@ -6264,7 +5760,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v5.3.4" + "source": "https://github.com/symfony/mime/tree/v5.3.8" }, "funding": [ { @@ -6280,7 +5776,7 @@ "type": "tidelift" } ], - "time": "2021-07-21T12:40:44+00:00" + "time": "2021-09-10T12:30:38+00:00" }, { "name": "symfony/polyfill-ctype", @@ -6931,16 +6427,16 @@ }, { "name": "symfony/process", - "version": "v4.4.27", + "version": "v4.4.30", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "0b7dc5599ac4aa6d7b936c8f7d10abae64f6cf7f" + "reference": "13d3161ef63a8ec21eeccaaf9a4d7f784a87a97d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/0b7dc5599ac4aa6d7b936c8f7d10abae64f6cf7f", - "reference": "0b7dc5599ac4aa6d7b936c8f7d10abae64f6cf7f", + "url": "https://api.github.com/repos/symfony/process/zipball/13d3161ef63a8ec21eeccaaf9a4d7f784a87a97d", + "reference": "13d3161ef63a8ec21eeccaaf9a4d7f784a87a97d", "shasum": "" }, "require": { @@ -6973,7 +6469,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v4.4.27" + "source": "https://github.com/symfony/process/tree/v4.4.30" }, "funding": [ { @@ -6989,7 +6485,7 @@ "type": "tidelift" } ], - "time": "2021-07-23T15:41:52+00:00" + "time": "2021-08-04T20:31:23+00:00" }, { "name": "symfony/service-contracts", @@ -7336,16 +6832,16 @@ }, { "name": "vlucas/phpdotenv", - "version": "v2.6.7", + "version": "v2.6.8", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "b786088918a884258c9e3e27405c6a4cf2ee246e" + "reference": "f1e2a35e53abe9322f0ab9ada689967e30055d40" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/b786088918a884258c9e3e27405c6a4cf2ee246e", - "reference": "b786088918a884258c9e3e27405c6a4cf2ee246e", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/f1e2a35e53abe9322f0ab9ada689967e30055d40", + "reference": "f1e2a35e53abe9322f0ab9ada689967e30055d40", "shasum": "" }, "require": { @@ -7355,7 +6851,7 @@ "require-dev": { "ext-filter": "*", "ext-pcre": "*", - "phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20" + "phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.21" }, "suggest": { "ext-filter": "Required to use the boolean validator.", @@ -7379,13 +6875,11 @@ "authors": [ { "name": "Graham Campbell", - "email": "graham@alt-three.com", - "homepage": "https://gjcampbell.co.uk/" + "email": "hello@gjcampbell.co.uk" }, { "name": "Vance Lucas", - "email": "vance@vancelucas.com", - "homepage": "https://vancelucas.com/" + "email": "vance@vancelucas.com" } ], "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", @@ -7396,7 +6890,7 @@ ], "support": { "issues": "https://github.com/vlucas/phpdotenv/issues", - "source": "https://github.com/vlucas/phpdotenv/tree/v2.6.7" + "source": "https://github.com/vlucas/phpdotenv/tree/v2.6.8" }, "funding": [ { @@ -7408,7 +6902,7 @@ "type": "tidelift" } ], - "time": "2021-01-20T14:39:13+00:00" + "time": "2021-10-02T19:02:17+00:00" }, { "name": "webmozart/assert", @@ -7637,27 +7131,27 @@ }, { "name": "gitonomy/gitlib", - "version": "v1.2.3", + "version": "v1.3.2", "source": { "type": "git", "url": "https://github.com/gitonomy/gitlib.git", - "reference": "d22f212b97fdb631ac73dfae65c194dc4cb0d227" + "reference": "e73e439590b194b0b250b516b22a68c7116e2f21" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/gitonomy/gitlib/zipball/d22f212b97fdb631ac73dfae65c194dc4cb0d227", - "reference": "d22f212b97fdb631ac73dfae65c194dc4cb0d227", + "url": "https://api.github.com/repos/gitonomy/gitlib/zipball/e73e439590b194b0b250b516b22a68c7116e2f21", + "reference": "e73e439590b194b0b250b516b22a68c7116e2f21", "shasum": "" }, "require": { "ext-pcre": "*", "php": "^5.6 || ^7.0 || ^8.0", "symfony/polyfill-mbstring": "^1.7", - "symfony/process": "^3.4 || ^4.0 || ^5.0" + "symfony/process": "^3.4 || ^4.4 || ^5.0 || ^6.0" }, "require-dev": { "ext-fileinfo": "*", - "phpunit/phpunit": "^5.7 || ^6.5 || ^7.0 || ^8.0 || ^9.0", + "phpunit/phpunit": "^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.20 || ^9.5.9", "psr/log": "^1.0" }, "suggest": { @@ -7677,7 +7171,7 @@ "authors": [ { "name": "Graham Campbell", - "email": "graham@alt-three.com" + "email": "hello@gjcampbell.co.uk" }, { "name": "Julien Didier", @@ -7695,7 +7189,7 @@ "description": "Library for accessing git", "support": { "issues": "https://github.com/gitonomy/gitlib/issues", - "source": "https://github.com/gitonomy/gitlib/tree/v1.2.3" + "source": "https://github.com/gitonomy/gitlib/tree/v1.3.2" }, "funding": [ { @@ -7703,20 +7197,20 @@ "type": "tidelift" } ], - "time": "2020-12-29T16:48:45+00:00" + "time": "2021-09-06T20:30:10+00:00" }, { "name": "pdepend/pdepend", - "version": "2.10.0", + "version": "2.10.1", "source": { "type": "git", "url": "https://github.com/pdepend/pdepend.git", - "reference": "1fd30f4352b630ad53fec3fd5e8b8ba760f85596" + "reference": "30452fdabb3dfca89f4bf977abc44adc5391e062" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pdepend/pdepend/zipball/1fd30f4352b630ad53fec3fd5e8b8ba760f85596", - "reference": "1fd30f4352b630ad53fec3fd5e8b8ba760f85596", + "url": "https://api.github.com/repos/pdepend/pdepend/zipball/30452fdabb3dfca89f4bf977abc44adc5391e062", + "reference": "30452fdabb3dfca89f4bf977abc44adc5391e062", "shasum": "" }, "require": { @@ -7752,7 +7246,7 @@ "description": "Official version of pdepend to be handled with Composer", "support": { "issues": "https://github.com/pdepend/pdepend/issues", - "source": "https://github.com/pdepend/pdepend/tree/2.10.0" + "source": "https://github.com/pdepend/pdepend/tree/2.10.1" }, "funding": [ { @@ -7760,7 +7254,7 @@ "type": "tidelift" } ], - "time": "2021-07-20T09:56:09+00:00" + "time": "2021-10-11T12:15:18+00:00" }, { "name": "php-coveralls/php-coveralls", @@ -7991,16 +7485,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.6.0", + "version": "3.6.1", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "ffced0d2c8fa8e6cdc4d695a743271fab6c38625" + "reference": "f268ca40d54617c6e06757f83f699775c9b3ff2e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ffced0d2c8fa8e6cdc4d695a743271fab6c38625", - "reference": "ffced0d2c8fa8e6cdc4d695a743271fab6c38625", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/f268ca40d54617c6e06757f83f699775c9b3ff2e", + "reference": "f268ca40d54617c6e06757f83f699775c9b3ff2e", "shasum": "" }, "require": { @@ -8043,7 +7537,7 @@ "source": "https://github.com/squizlabs/PHP_CodeSniffer", "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" }, - "time": "2021-04-09T00:54:41+00:00" + "time": "2021-10-11T04:00:11+00:00" }, { "name": "symfony/config", @@ -8126,16 +7620,16 @@ }, { "name": "symfony/dependency-injection", - "version": "v5.3.4", + "version": "v5.3.8", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "5a825e4b386066167a8b55487091cb62beec74c2" + "reference": "e39c344e06a3ceab531ebeb6c077e6652c4a0829" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/5a825e4b386066167a8b55487091cb62beec74c2", - "reference": "5a825e4b386066167a8b55487091cb62beec74c2", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/e39c344e06a3ceab531ebeb6c077e6652c4a0829", + "reference": "e39c344e06a3ceab531ebeb6c077e6652c4a0829", "shasum": "" }, "require": { @@ -8194,7 +7688,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v5.3.4" + "source": "https://github.com/symfony/dependency-injection/tree/v5.3.8" }, "funding": [ { @@ -8210,7 +7704,7 @@ "type": "tidelift" } ], - "time": "2021-07-23T15:55:36+00:00" + "time": "2021-09-21T20:52:44+00:00" }, { "name": "symfony/stopwatch", @@ -8289,5 +7783,5 @@ "ext-openssl": "*" }, "platform-dev": [], - "plugin-api-version": "2.0.0" + "plugin-api-version": "2.1.0" } diff --git a/src/Magento/FunctionalTestingFramework/Console/Codecept/CodeceptCommandUtil.php b/src/Magento/FunctionalTestingFramework/Console/Codecept/CodeceptCommandUtil.php index 3992aa677..1a469b179 100644 --- a/src/Magento/FunctionalTestingFramework/Console/Codecept/CodeceptCommandUtil.php +++ b/src/Magento/FunctionalTestingFramework/Console/Codecept/CodeceptCommandUtil.php @@ -23,6 +23,7 @@ class CodeceptCommandUtil */ private $cwd = null; + // @codingStandardsIgnoreStart /** * Setup Codeception * @@ -39,6 +40,7 @@ public function setup(InputInterface $input) return $input->setTokens($tokens); }, null, ArgvInput::class); } + // @codingStandardsIgnoreEnd /** * Save Codeception working directory diff --git a/src/Magento/FunctionalTestingFramework/Util/Iterator/AbstractIterator.php b/src/Magento/FunctionalTestingFramework/Util/Iterator/AbstractIterator.php index 69e2527aa..85b5dd411 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Iterator/AbstractIterator.php +++ b/src/Magento/FunctionalTestingFramework/Util/Iterator/AbstractIterator.php @@ -33,6 +33,7 @@ abstract class AbstractIterator implements \Iterator, \Countable * * @return mixed */ + #[\ReturnTypeWillChange] abstract public function current(); // @codingStandardsIgnoreEnd @@ -48,14 +49,14 @@ abstract public function current(); * * @return boolean */ - abstract protected function isValid(); + abstract protected function isValid() : bool; /** * Initialize Data Array * * @return void */ - public function rewind() + public function rewind() : void { reset($this->data); if (!$this->isValid()) { @@ -68,7 +69,7 @@ public function rewind() * * @return void */ - public function next() + public function next() : void { $this->current = next($this->data); @@ -86,7 +87,7 @@ public function next() * * @return boolean */ - public function valid() + public function valid() : bool { $current = current($this->data); if ($current === false || $current === null) { @@ -96,22 +97,25 @@ public function valid() } } + // @codingStandardsIgnoreStart /** * Get data key of the current data element * * @return integer|string */ + #[\ReturnTypeWillChange] public function key() { return key($this->data); } + // @codingStandardsIgnoreEnd /** * To make iterator countable * * @return integer */ - public function count() + public function count() : int { return count($this->data); } diff --git a/src/Magento/FunctionalTestingFramework/Util/Iterator/File.php b/src/Magento/FunctionalTestingFramework/Util/Iterator/File.php index 0186acd11..aafc4e288 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Iterator/File.php +++ b/src/Magento/FunctionalTestingFramework/Util/Iterator/File.php @@ -58,7 +58,7 @@ public function current() * * @return boolean */ - protected function isValid() + protected function isValid() : bool { return true; } From 5ba240026fb01034d64ae268ee2276ad304e7aae Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 18 Oct 2021 10:32:44 -0500 Subject: [PATCH 720/888] MQE-2978: [MFTF] Investigate removal of hoa/console - moving `hoa/console` to suggest section --- composer.json | 3 + composer.lock | 120 +++++++++++------- .../tests/MFTF/DevDocs/Test/DevDocsTest.xml | 1 + docs/interactive-pause.md | 7 +- .../Module/MagentoWebDriver.php | 6 + 5 files changed, 86 insertions(+), 51 deletions(-) diff --git a/composer.json b/composer.json index a7502b067..551bcfb5a 100755 --- a/composer.json +++ b/composer.json @@ -46,6 +46,9 @@ "sebastian/phpcpd": "~6.0.0", "squizlabs/php_codesniffer": "~3.6.0" }, + "suggest": { + "hoa/console": "Enables <pause /> action and interactive console functionality" + }, "autoload": { "files": ["src/Magento/FunctionalTestingFramework/_bootstrap.php"], "psr-4": { diff --git a/composer.lock b/composer.lock index 061c9d862..6042807bb 100644 --- a/composer.lock +++ b/composer.lock @@ -177,16 +177,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.198.4", + "version": "3.198.6", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "b0b95cf0fa287e5b5db73ceafaf836950ede76ff" + "reference": "821b8db50dd39be8ec94f286050a500b5f8a0142" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/b0b95cf0fa287e5b5db73ceafaf836950ede76ff", - "reference": "b0b95cf0fa287e5b5db73ceafaf836950ede76ff", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/821b8db50dd39be8ec94f286050a500b5f8a0142", + "reference": "821b8db50dd39be8ec94f286050a500b5f8a0142", "shasum": "" }, "require": { @@ -262,9 +262,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.198.4" + "source": "https://github.com/aws/aws-sdk-php/tree/3.198.6" }, - "time": "2021-10-13T18:16:14+00:00" + "time": "2021-10-15T18:38:53+00:00" }, { "name": "beberlei/assert", @@ -1598,24 +1598,25 @@ }, { "name": "guzzlehttp/guzzle", - "version": "7.3.0", + "version": "7.4.0", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "7008573787b430c1c1f650e3722d9bba59967628" + "reference": "868b3571a039f0ebc11ac8f344f4080babe2cb94" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/7008573787b430c1c1f650e3722d9bba59967628", - "reference": "7008573787b430c1c1f650e3722d9bba59967628", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/868b3571a039f0ebc11ac8f344f4080babe2cb94", + "reference": "868b3571a039f0ebc11ac8f344f4080babe2cb94", "shasum": "" }, "require": { "ext-json": "*", - "guzzlehttp/promises": "^1.4", - "guzzlehttp/psr7": "^1.7 || ^2.0", + "guzzlehttp/promises": "^1.5", + "guzzlehttp/psr7": "^1.8.3 || ^2.1", "php": "^7.2.5 || ^8.0", - "psr/http-client": "^1.0" + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2" }, "provide": { "psr/http-client-implementation": "1.0" @@ -1625,7 +1626,7 @@ "ext-curl": "*", "php-http/client-integration-tests": "^3.0", "phpunit/phpunit": "^8.5.5 || ^9.3.5", - "psr/log": "^1.1" + "psr/log": "^1.1 || ^2.0 || ^3.0" }, "suggest": { "ext-curl": "Required for CURL handler support", @@ -1635,7 +1636,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "7.3-dev" + "dev-master": "7.4-dev" } }, "autoload": { @@ -1651,19 +1652,43 @@ "MIT" ], "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, { "name": "Michael Dowling", "email": "mtdowling@gmail.com", "homepage": "https://github.com/mtdowling" }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, { "name": "Márk Sági-Kazár", "email": "mark.sagikazar@gmail.com", - "homepage": "https://sagikazarmark.hu" + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" } ], "description": "Guzzle is a PHP HTTP client library", - "homepage": "http://guzzlephp.org/", "keywords": [ "client", "curl", @@ -1677,7 +1702,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.3.0" + "source": "https://github.com/guzzle/guzzle/tree/7.4.0" }, "funding": [ { @@ -1689,15 +1714,11 @@ "type": "github" }, { - "url": "https://github.com/alexeyshockov", - "type": "github" - }, - { - "url": "https://github.com/gmponos", - "type": "github" + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" } ], - "time": "2021-03-23T11:33:13+00:00" + "time": "2021-10-18T09:52:00+00:00" }, { "name": "guzzlehttp/promises", @@ -1959,16 +1980,16 @@ }, { "name": "jms/serializer", - "version": "3.14.0", + "version": "3.15.0", "source": { "type": "git", "url": "https://github.com/schmittjoh/serializer.git", - "reference": "bf371f55d8137fec4ff096bd45ff19e2db02ac4c" + "reference": "9d6d9b81889904603383722ca0cd7f7999baeebc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/bf371f55d8137fec4ff096bd45ff19e2db02ac4c", - "reference": "bf371f55d8137fec4ff096bd45ff19e2db02ac4c", + "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/9d6d9b81889904603383722ca0cd7f7999baeebc", + "reference": "9d6d9b81889904603383722ca0cd7f7999baeebc", "shasum": "" }, "require": { @@ -1977,7 +1998,7 @@ "doctrine/lexer": "^1.1", "jms/metadata": "^2.0", "php": "^7.2||^8.0", - "phpstan/phpdoc-parser": "^0.4 || ^0.5" + "phpstan/phpdoc-parser": "^0.4 || ^0.5 || ^1.0" }, "require-dev": { "doctrine/coding-standard": "^8.1", @@ -1990,13 +2011,13 @@ "phpstan/phpstan": "^0.12.65", "phpunit/phpunit": "^8.0||^9.0", "psr/container": "^1.0", - "symfony/dependency-injection": "^3.0|^4.0|^5.0", - "symfony/expression-language": "^3.0|^4.0|^5.0", - "symfony/filesystem": "^3.0|^4.0|^5.0", - "symfony/form": "^3.0|^4.0|^5.0", - "symfony/translation": "^3.0|^4.0|^5.0", - "symfony/validator": "^3.1.9|^4.0|^5.0", - "symfony/yaml": "^3.3|^4.0|^5.0", + "symfony/dependency-injection": "^3.0|^4.0|^5.0|^6.0", + "symfony/expression-language": "^3.0|^4.0|^5.0|^6.0", + "symfony/filesystem": "^3.0|^4.0|^5.0|^6.0", + "symfony/form": "^3.0|^4.0|^5.0|^6.0", + "symfony/translation": "^3.0|^4.0|^5.0|^6.0", + "symfony/validator": "^3.1.9|^4.0|^5.0|^6.0", + "symfony/yaml": "^3.3|^4.0|^5.0|^6.0", "twig/twig": "~1.34|~2.4|^3.0" }, "suggest": { @@ -2007,7 +2028,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.14-dev" + "dev-master": "3.x-dev" } }, "autoload": { @@ -2040,7 +2061,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/serializer/issues", - "source": "https://github.com/schmittjoh/serializer/tree/3.14.0" + "source": "https://github.com/schmittjoh/serializer/tree/3.15.0" }, "funding": [ { @@ -2048,7 +2069,7 @@ "type": "github" } ], - "time": "2021-08-06T12:10:02+00:00" + "time": "2021-10-14T20:02:48+00:00" }, { "name": "justinrainbow/json-schema", @@ -2915,16 +2936,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "0.5.7", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "816e826ce0b7fb32098d8cb6de62511ce6021cea" + "reference": "dbc093d7af60eff5cd575d2ed761b15ed40bd08e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/816e826ce0b7fb32098d8cb6de62511ce6021cea", - "reference": "816e826ce0b7fb32098d8cb6de62511ce6021cea", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/dbc093d7af60eff5cd575d2ed761b15ed40bd08e", + "reference": "dbc093d7af60eff5cd575d2ed761b15ed40bd08e", "shasum": "" }, "require": { @@ -2933,15 +2954,15 @@ "require-dev": { "php-parallel-lint/php-parallel-lint": "^1.2", "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^0.12.87", - "phpstan/phpstan-strict-rules": "^0.12.5", + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-strict-rules": "^1.0", "phpunit/phpunit": "^9.5", "symfony/process": "^5.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "0.5-dev" + "dev-master": "1.0-dev" } }, "autoload": { @@ -2958,9 +2979,9 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/0.5.7" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.2.0" }, - "time": "2021-09-12T11:52:00+00:00" + "time": "2021-09-16T20:46:02+00:00" }, { "name": "phpunit/php-code-coverage", @@ -4814,6 +4835,7 @@ "type": "github" } ], + "abandoned": true, "time": "2020-09-28T06:45:17+00:00" }, { diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml b/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml index bda1cfb57..bf074d516 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml @@ -51,5 +51,6 @@ <actualResult type="array">{{ExtendedMessageData.numbers}}</actualResult> <expectedResult type="array">["Something New", "0", "1", "2", "3", "TESTING CASE"]</expectedResult> </assertEqualsCanonicalizing> + <pause stepKey="testingPause" /> </test> </tests> diff --git a/docs/interactive-pause.md b/docs/interactive-pause.md index 250f19936..5914c6339 100644 --- a/docs/interactive-pause.md +++ b/docs/interactive-pause.md @@ -10,9 +10,12 @@ Check [pause on codeception.com][] for documentation and a video to see `Interac In short, when a test gets to `$I->pause()` step, it stops and shows a console where you can try all available commands with auto-completion, stash commands, save screenshots, etc. -## MFTF Run Commands +## How to Configure Interactive Pause + +To be able to use Interactive console you need to install `hoa/console` library by running `composer require hoa/console` command in your project. This will allow `<pause />` action to work. +MFTF supports `Interactive Pause` when `ENABLE_PAUSE` is set to `true` in `<project_root>/dev/tests/acceptance/.env` file. -The following MFTF run commands support `Interactive Pause` when `ENABLE_PAUSE` is set to `true`. +## MFTF Run Commands ```bash vendor/bin/mftf run:group diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 328eb4842..7f5c5908f 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -1040,6 +1040,12 @@ public function switchToIFrame($locator = null) */ public function pause($pauseOnFail = false) { + if (\Composer\InstalledVersions::isInstalled('hoa/console') === false) { + $message = "<pause /> action is unavailable." . PHP_EOL; + $message .= "Please install `hoa/console` via \"composer require hoa/console\"" . PHP_EOL; + print($message); + return; + } if (!\Codeception\Util\Debug::isEnabled()) { return; } From 4227efe8894a3bdf8d3b5ac8c5b5ecb0a3ff6775 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Tue, 19 Oct 2021 12:08:50 -0500 Subject: [PATCH 721/888] MQE-2979: [MFTF] Update vlucas/phpdotenv to the latest versions --- composer.json | 2 +- composer.lock | 158 +++++++++--------- dev/tests/functional/standalone_bootstrap.php | 27 +-- .../FunctionalTestingFramework/_bootstrap.php | 28 ++-- 4 files changed, 111 insertions(+), 104 deletions(-) diff --git a/composer.json b/composer.json index 551bcfb5a..a0dc719ad 100755 --- a/composer.json +++ b/composer.json @@ -30,11 +30,11 @@ "php-webdriver/webdriver": "^1.9.0", "spomky-labs/otphp": "^10.0", "symfony/console": "^4.4", + "symfony/dotenv": "^5.3", "symfony/finder": "^5.0", "symfony/http-foundation": "^5.0", "symfony/mime": "^5.0", "symfony/process": "^4.4", - "vlucas/phpdotenv": "^2.4", "weew/helpers-array": "^1.3" }, "require-dev": { diff --git a/composer.lock b/composer.lock index 6042807bb..ca3820871 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "8dc05529156aa036fdfe184d1b174c49", + "content-hash": "eeaac3e027dffc09c8cf5229e9924faa", "packages": [ { "name": "allure-framework/allure-codeception", @@ -177,16 +177,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.198.6", + "version": "3.198.7", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "821b8db50dd39be8ec94f286050a500b5f8a0142" + "reference": "40197a954c9f49557a1b0d49e2a9bd6f7bf6adfc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/821b8db50dd39be8ec94f286050a500b5f8a0142", - "reference": "821b8db50dd39be8ec94f286050a500b5f8a0142", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/40197a954c9f49557a1b0d49e2a9bd6f7bf6adfc", + "reference": "40197a954c9f49557a1b0d49e2a9bd6f7bf6adfc", "shasum": "" }, "require": { @@ -262,9 +262,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.198.6" + "source": "https://github.com/aws/aws-sdk-php/tree/3.198.7" }, - "time": "2021-10-15T18:38:53+00:00" + "time": "2021-10-18T18:17:12+00:00" }, { "name": "beberlei/assert", @@ -5356,6 +5356,76 @@ ], "time": "2021-03-23T23:28:01+00:00" }, + { + "name": "symfony/dotenv", + "version": "v5.3.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/dotenv.git", + "reference": "12888c9c46ac750ec5c1381db5bf3d534e7d70cb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/12888c9c46ac750ec5c1381db5bf3d534e7d70cb", + "reference": "12888c9c46ac750ec5c1381db5bf3d534e7d70cb", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1" + }, + "require-dev": { + "symfony/process": "^4.4|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Dotenv\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Registers environment variables from a .env file", + "homepage": "https://symfony.com", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "source": "https://github.com/symfony/dotenv/tree/v5.3.8" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-07-29T06:18:06+00:00" + }, { "name": "symfony/event-dispatcher", "version": "v4.4.30", @@ -6852,80 +6922,6 @@ ], "time": "2021-07-28T10:34:58+00:00" }, - { - "name": "vlucas/phpdotenv", - "version": "v2.6.8", - "source": { - "type": "git", - "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "f1e2a35e53abe9322f0ab9ada689967e30055d40" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/f1e2a35e53abe9322f0ab9ada689967e30055d40", - "reference": "f1e2a35e53abe9322f0ab9ada689967e30055d40", - "shasum": "" - }, - "require": { - "php": "^5.3.9 || ^7.0 || ^8.0", - "symfony/polyfill-ctype": "^1.17" - }, - "require-dev": { - "ext-filter": "*", - "ext-pcre": "*", - "phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.21" - }, - "suggest": { - "ext-filter": "Required to use the boolean validator.", - "ext-pcre": "Required to use most of the library." - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.6-dev" - } - }, - "autoload": { - "psr-4": { - "Dotenv\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk" - }, - { - "name": "Vance Lucas", - "email": "vance@vancelucas.com" - } - ], - "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", - "keywords": [ - "dotenv", - "env", - "environment" - ], - "support": { - "issues": "https://github.com/vlucas/phpdotenv/issues", - "source": "https://github.com/vlucas/phpdotenv/tree/v2.6.8" - }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", - "type": "tidelift" - } - ], - "time": "2021-10-02T19:02:17+00:00" - }, { "name": "webmozart/assert", "version": "1.10.0", diff --git a/dev/tests/functional/standalone_bootstrap.php b/dev/tests/functional/standalone_bootstrap.php index 5ce6f029a..e048498c3 100755 --- a/dev/tests/functional/standalone_bootstrap.php +++ b/dev/tests/functional/standalone_bootstrap.php @@ -20,8 +20,12 @@ //Load constants from .env file if (file_exists(ENV_FILE_PATH . '.env')) { - $env = new \Dotenv\Loader(ENV_FILE_PATH . '.env'); - $env->load(); + $env = new \Symfony\Component\Dotenv\Dotenv(); + if (function_exists('putenv')) { + $env->usePutenv(); + } + $env->populate($env->parse(file_get_contents(ENV_FILE_PATH . '.env'), ENV_FILE_PATH . '.env'), true); + foreach ($_ENV as $key => $var) { defined($key) || define($key, $var); @@ -42,19 +46,20 @@ 'MAGENTO_CLI_COMMAND_PATH', 'dev/tests/acceptance/utils/command.php' ); - $env->setEnvironmentVariable('MAGENTO_CLI_COMMAND_PATH', MAGENTO_CLI_COMMAND_PATH); - defined('MAGENTO_CLI_COMMAND_PARAMETER') || define('MAGENTO_CLI_COMMAND_PARAMETER', 'command'); - $env->setEnvironmentVariable('MAGENTO_CLI_COMMAND_PARAMETER', MAGENTO_CLI_COMMAND_PARAMETER); - defined('DEFAULT_TIMEZONE') || define('DEFAULT_TIMEZONE', 'America/Los_Angeles'); - $env->setEnvironmentVariable('DEFAULT_TIMEZONE', DEFAULT_TIMEZONE); - defined('WAIT_TIMEOUT') || define('WAIT_TIMEOUT', 30); - $env->setEnvironmentVariable('WAIT_TIMEOUT', WAIT_TIMEOUT); - defined('VERBOSE_ARTIFACTS') || define('VERBOSE_ARTIFACTS', false); - $env->setEnvironmentVariable('VERBOSE_ARTIFACTS', VERBOSE_ARTIFACTS); + $env->populate( + [ + 'MAGENTO_CLI_COMMAND_PATH' => MAGENTO_CLI_COMMAND_PATH, + 'MAGENTO_CLI_COMMAND_PARAMETER' => MAGENTO_CLI_COMMAND_PARAMETER, + 'DEFAULT_TIMEZONE' => DEFAULT_TIMEZONE, + 'WAIT_TIMEOUT' => WAIT_TIMEOUT, + 'VERBOSE_ARTIFACTS' => VERBOSE_ARTIFACTS, + ], + true + ); try { new DateTimeZone(DEFAULT_TIMEZONE); diff --git a/src/Magento/FunctionalTestingFramework/_bootstrap.php b/src/Magento/FunctionalTestingFramework/_bootstrap.php index 9c13eaa54..9b7f7a821 100644 --- a/src/Magento/FunctionalTestingFramework/_bootstrap.php +++ b/src/Magento/FunctionalTestingFramework/_bootstrap.php @@ -6,6 +6,8 @@ */ // define framework basepath for schema pathing +use Symfony\Component\Dotenv\Exception\PathException; + defined('FW_BP') || define('FW_BP', realpath(__DIR__ . '/../../../')); // get the root path of the project $projectRootPath = substr(FW_BP, 0, strpos(FW_BP, DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR)); @@ -21,8 +23,11 @@ //Load constants from .env file if (file_exists(ENV_FILE_PATH . '.env')) { - $env = new \Dotenv\Loader(ENV_FILE_PATH . '.env'); - $env->load(); + $env = new \Symfony\Component\Dotenv\Dotenv(); + if (function_exists('putenv')) { + $env->usePutenv(); + } + $env->populate($env->parse(file_get_contents(ENV_FILE_PATH . '.env'), ENV_FILE_PATH . '.env'), true); if (array_key_exists('TESTS_MODULE_PATH', $_ENV) xor array_key_exists('TESTS_BP', $_ENV)) { throw new Exception( @@ -42,19 +47,20 @@ 'MAGENTO_CLI_COMMAND_PATH', 'dev/tests/acceptance/utils/command.php' ); - $env->setEnvironmentVariable('MAGENTO_CLI_COMMAND_PATH', MAGENTO_CLI_COMMAND_PATH); - defined('MAGENTO_CLI_COMMAND_PARAMETER') || define('MAGENTO_CLI_COMMAND_PARAMETER', 'command'); - $env->setEnvironmentVariable('MAGENTO_CLI_COMMAND_PARAMETER', MAGENTO_CLI_COMMAND_PARAMETER); - defined('DEFAULT_TIMEZONE') || define('DEFAULT_TIMEZONE', 'America/Los_Angeles'); - $env->setEnvironmentVariable('DEFAULT_TIMEZONE', DEFAULT_TIMEZONE); - defined('WAIT_TIMEOUT') || define('WAIT_TIMEOUT', 30); - $env->setEnvironmentVariable('WAIT_TIMEOUT', WAIT_TIMEOUT); - defined('VERBOSE_ARTIFACTS') || define('VERBOSE_ARTIFACTS', false); - $env->setEnvironmentVariable('VERBOSE_ARTIFACTS', VERBOSE_ARTIFACTS); + $env->populate( + [ + 'MAGENTO_CLI_COMMAND_PATH' => MAGENTO_CLI_COMMAND_PATH, + 'MAGENTO_CLI_COMMAND_PARAMETER' => MAGENTO_CLI_COMMAND_PARAMETER, + 'DEFAULT_TIMEZONE' => DEFAULT_TIMEZONE, + 'WAIT_TIMEOUT' => WAIT_TIMEOUT, + 'VERBOSE_ARTIFACTS' => VERBOSE_ARTIFACTS, + ], + true + ); try { new DateTimeZone(DEFAULT_TIMEZONE); From b21a1e08957863ad7ccc9d4442be20c5a8d5dcee Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Wed, 27 Oct 2021 15:10:50 -0500 Subject: [PATCH 722/888] MQE-2967: Magento Quality Engineering Repo Metadata Service Onboarding: Pangolins --- .github/.metadata.json | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 .github/.metadata.json diff --git a/.github/.metadata.json b/.github/.metadata.json new file mode 100644 index 000000000..233f2e623 --- /dev/null +++ b/.github/.metadata.json @@ -0,0 +1,32 @@ +{ + "templateVersion": "0.1", + "product": { + "name": "Magento2 Functional Testing Framework (MFTF)", + "description": "MFTF is a framework to write and execute UI Functional tests for Magento 2 projects" + }, + "contacts": { + "team": { + "name": "Magento Quality Engineering / Pangolin", + "DL": "pangolin@adobe.com", + "slackChannel": "mftf" + } + }, + "ticketTracker": { + "functionalJiraQueue": { + "projectKey": "MQE", + "component": "" + }, + "securityJiraQueue": { + "projectKey": "MAGREQ", + "component": "Test Infrastructure" + } + }, + "staticScan": { + "enable": true, + "frequency": "monthly", + "customName": "", + "branchesToScan": [ + "develop" + ] + } +} From 537fe57eb92106f83dd4e0991711fe99ade40609 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Wed, 27 Oct 2021 15:51:03 -0500 Subject: [PATCH 723/888] MQE-2967: Magento Quality Engineering Repo Metadata Service Onboarding: Pangolins --- .github/.metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/.metadata.json b/.github/.metadata.json index 233f2e623..8e9c6212c 100644 --- a/.github/.metadata.json +++ b/.github/.metadata.json @@ -14,7 +14,7 @@ "ticketTracker": { "functionalJiraQueue": { "projectKey": "MQE", - "component": "" + "component": "Framework - MFTF" }, "securityJiraQueue": { "projectKey": "MAGREQ", From 892fc1ab36422aef970881a412b581d78417e3ee Mon Sep 17 00:00:00 2001 From: Your Name <you@example.com> Date: Fri, 29 Oct 2021 14:57:48 +0530 Subject: [PATCH 724/888] <seeInCurrentUrl> encodes special character which caused test failed --- .../FunctionalTestingFramework/Module/MagentoWebDriver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 7f5c5908f..433841c70 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -340,7 +340,7 @@ public function seeInCurrentUrl($needle) $actualUrl = $this->webDriver->getCurrentURL(); $comparison = "Expected: $needle\nActual: $actualUrl"; AllureHelper::addAttachmentToCurrentStep($comparison, 'Comparison'); - $this->assertStringContainsString($needle, $actualUrl); + $this->assertStringContainsString($needle, urldecode($actualUrl)); } /** From f6e1112d06062b6c5dfd837726b69a930220f798 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 8 Nov 2021 09:27:17 -0600 Subject: [PATCH 725/888] MQE-3006: Repo Metadata - Remove Email/Add DL --- .github/.metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/.metadata.json b/.github/.metadata.json index 8e9c6212c..f07606072 100644 --- a/.github/.metadata.json +++ b/.github/.metadata.json @@ -7,7 +7,7 @@ "contacts": { "team": { "name": "Magento Quality Engineering / Pangolin", - "DL": "pangolin@adobe.com", + "DL": "GRP-Pangolin", "slackChannel": "mftf" } }, From 32d1b2b55f98cf06af3eaec2f07b1e1562ca282d Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 8 Nov 2021 17:25:35 -0600 Subject: [PATCH 726/888] MQE-2677: Add filter for groups --- .../Util/TestGeneratorTest.php | 132 +++++++++++++++++- .../Filter/Test/ExcludeGroup.php | 58 ++++++++ .../Filter/Test/IncludeGroup.php | 58 ++++++++ 3 files changed, 247 insertions(+), 1 deletion(-) create mode 100644 src/Magento/FunctionalTestingFramework/Filter/Test/ExcludeGroup.php create mode 100644 src/Magento/FunctionalTestingFramework/Filter/Test/IncludeGroup.php diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php index 800c506f1..217cf7f09 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php @@ -162,7 +162,7 @@ public function testAllowSkipped(): void * @return void * @throws TestReferenceException */ - public function testFilter(): void + public function testSeverityFilter(): void { $mockConfig = $this->createMock(MftfApplicationConfig::class); $fileList = new FilterList(['severity' => ['CRITICAL']]); @@ -221,6 +221,136 @@ function ($filename) use (&$generatedTests) { $this->assertArrayNotHasKey('test2Cest', $generatedTests); } + /** + * Tests that TestGenerator createAllTestFiles correctly filters based on group. + * + * @return void + * @throws TestReferenceException + */ + public function testIncludeGroupFilter(): void + { + $mockConfig = $this->createMock(MftfApplicationConfig::class); + $fileList = new FilterList(['includeGroup' => ['someGroupValue']]); + $mockConfig + ->method('getFilterList') + ->willReturn($fileList); + + $property = new ReflectionProperty(MftfApplicationConfig::class, 'MFTF_APPLICATION_CONTEXT'); + $property->setAccessible(true); + $property->setValue($mockConfig); + + $actionInput = 'fakeInput'; + $actionObject = new ActionObject('fakeAction', 'comment', [ + 'userInput' => $actionInput + ]); + + $annotation1 = ['group' => ['someGroupValue']]; + $annotation2 = ['group' => ['someOtherGroupValue']]; + $test1 = new TestObject( + 'test1', + ['fakeAction' => $actionObject], + $annotation1, + [], + 'filename' + ); + $test2 = new TestObject( + 'test2', + ['fakeAction' => $actionObject], + $annotation2, + [], + 'filename' + ); + + // Mock createCestFile to return name of tests that testGenerator tried to create + $generatedTests = []; + $cestFileCreatorUtil = $this->createMock(CestFileCreatorUtil::class); + $cestFileCreatorUtil + ->method('create') + ->will( + $this->returnCallback( + function ($filename) use (&$generatedTests) { + $generatedTests[$filename] = true; + } + ) + ); + + $property = new ReflectionProperty(CestFileCreatorUtil::class, 'INSTANCE'); + $property->setAccessible(true); + $property->setValue($cestFileCreatorUtil); + + $testGeneratorObject = TestGenerator::getInstance('', ['sampleTest' => $test1, 'test2' => $test2]); + $testGeneratorObject->createAllTestFiles(); + + // Ensure Test1 was Generated but not Test 2 + $this->assertArrayHasKey('test1Cest', $generatedTests); + $this->assertArrayNotHasKey('test2Cest', $generatedTests); + } + + /** + * Tests that TestGenerator createAllTestFiles correctly filters based on group not included. + * + * @return void + * @throws TestReferenceException + */ + public function testExcludeGroupFilter(): void + { + $mockConfig = $this->createMock(MftfApplicationConfig::class); + $fileList = new FilterList(['excludeGroup' => ['someGroupValue']]); + $mockConfig + ->method('getFilterList') + ->willReturn($fileList); + + $property = new ReflectionProperty(MftfApplicationConfig::class, 'MFTF_APPLICATION_CONTEXT'); + $property->setAccessible(true); + $property->setValue($mockConfig); + + $actionInput = 'fakeInput'; + $actionObject = new ActionObject('fakeAction', 'comment', [ + 'userInput' => $actionInput + ]); + + $annotation1 = ['group' => ['someGroupValue']]; + $annotation2 = ['group' => ['someOtherGroupValue']]; + $test1 = new TestObject( + 'test1', + ['fakeAction' => $actionObject], + $annotation1, + [], + 'filename' + ); + $test2 = new TestObject( + 'test2', + ['fakeAction' => $actionObject], + $annotation2, + [], + 'filename' + ); + + // Mock createCestFile to return name of tests that testGenerator tried to create + $generatedTests = []; + $cestFileCreatorUtil = $this->createMock(CestFileCreatorUtil::class); + $cestFileCreatorUtil + ->method('create') + ->will( + $this->returnCallback( + function ($filename) use (&$generatedTests) { + $generatedTests[$filename] = true; + } + ) + ); + + $property = new ReflectionProperty(CestFileCreatorUtil::class, 'INSTANCE'); + $property->setAccessible(true); + $property->setValue($cestFileCreatorUtil); + + $testGeneratorObject = TestGenerator::getInstance('', ['sampleTest' => $test1, 'test2' => $test2]); + $testGeneratorObject->createAllTestFiles(); + + // Ensure Test2 was Generated but not Test 1 + $this->assertArrayNotHasKey('test1Cest', $generatedTests); + $this->assertArrayHasKey('test2Cest', $generatedTests); + } + /** * @inheritDoc */ diff --git a/src/Magento/FunctionalTestingFramework/Filter/Test/ExcludeGroup.php b/src/Magento/FunctionalTestingFramework/Filter/Test/ExcludeGroup.php new file mode 100644 index 000000000..38a3bf8f2 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Filter/Test/ExcludeGroup.php @@ -0,0 +1,58 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\FunctionalTestingFramework\Filter\Test; + +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Filter\FilterInterface; +use Magento\FunctionalTestingFramework\Test\Objects\TestObject; + +/** + * Class ExcludeGroup + */ +class ExcludeGroup implements FilterInterface +{ + const ANNOTATION_TAG = 'group'; + + /** + * @var array + */ + private $filterValues = []; + + /** + * Group constructor. + * + * @param array $filterValues + * @throws TestFrameworkException + */ + public function __construct(array $filterValues = []) + { + $this->filterValues = $filterValues; + } + + /** + * Filter tests by group. + * + * @param TestObject[] $tests + * @return void + */ + public function filter(array &$tests) + { + if ($this->filterValues === []) { + return; + } + /** @var TestObject $test */ + foreach ($tests as $testName => $test) { + $groups = $test->getAnnotationByName(self::ANNOTATION_TAG); + $testExcludeGroup = !empty(array_intersect($groups, $this->filterValues)); + if ($testExcludeGroup) { + unset($tests[$testName]); + } + } + } +} diff --git a/src/Magento/FunctionalTestingFramework/Filter/Test/IncludeGroup.php b/src/Magento/FunctionalTestingFramework/Filter/Test/IncludeGroup.php new file mode 100644 index 000000000..b84a48e55 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Filter/Test/IncludeGroup.php @@ -0,0 +1,58 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\FunctionalTestingFramework\Filter\Test; + +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Filter\FilterInterface; +use Magento\FunctionalTestingFramework\Test\Objects\TestObject; + +/** + * Class IncludeGroup + */ +class IncludeGroup implements FilterInterface +{ + const ANNOTATION_TAG = 'group'; + + /** + * @var array + */ + private $filterValues = []; + + /** + * Group constructor. + * + * @param array $filterValues + * @throws TestFrameworkException + */ + public function __construct(array $filterValues = []) + { + $this->filterValues = $filterValues; + } + + /** + * Filter tests by group. + * + * @param TestObject[] $tests + * @return void + */ + public function filter(array &$tests) + { + if ($this->filterValues === []) { + return; + } + /** @var TestObject $test */ + foreach ($tests as $testName => $test) { + $groups = $test->getAnnotationByName(self::ANNOTATION_TAG); + $testIncludeGroup = empty(array_intersect($groups, $this->filterValues)); + if ($testIncludeGroup) { + unset($tests[$testName]); + } + } + } +} From a8e52a26e5b6e9acc997acaa64ea0fdc15486d9f Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Tue, 9 Nov 2021 10:02:55 -0600 Subject: [PATCH 727/888] MQE-2677: Add filter for groups --- docs/commands/mftf.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 6ed472d47..6e1b2f713 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -160,7 +160,7 @@ vendor/bin/mftf generate:tests [option] [<test name>] [<test name>] [--remove] | Option | Description| | ---| --- | | `--config=[<default> or <singleRun> or <parallel>]` | Creates a single manifest file with a list of all tests. The default location is `tests/functional/Magento/FunctionalTest/_generated/testManifest.txt`.<br/> You can split the list into multiple groups using `--config=parallel`; the groups will be generated in `_generated/groups/` like `_generated/groups/group1.txt, group2.txt, ...`.<br/> Available values: `default` (default), `singleRun`(same as `default`), and `parallel`.<br/> Example: `generate:tests --config=parallel`. | -| `--filter` | Option to filter tests to be generated.<br/>Template: '<filterName>:<filterValue>'.<br/>Existing filter types: severity.<br/>Existing severity values: BLOCKER, CRITICAL, MAJOR, AVERAGE, MINOR.<br/>Example: `--filter=severity:CRITICAL`| +| `--filter` | Option to filter tests to be generated.<br/>Template: '<filterName>:<filterValue>'.<br/>Existing filter types: severity, includeGroup, excludeGroup.<br/>Existing severity values: BLOCKER, CRITICAL, MAJOR, AVERAGE, MINOR.<br/>Example: `--filter=severity:CRITICAL`, `--filter=includeGroup:customer`| | `--force` | Forces test generation, regardless of the module merge order defined in the Magento instance. Example: `generate:tests --force`. | | `-i,--time` | Set time in minutes to determine the group size when `--config=parallel` is used. <br/>Example: `generate:tests --config=parallel --time=15` <br/>Option `--time` will be the default and the __default value__ is `10` when neither `--time` nor `--groups` is specified. <br/>Example: `generate:tests --config=parallel`| | `-g,--groups` | Set number of groups to be split into when `--config=parallel` is used. <br>Example: `generate:tests --config=parallel --groups=300` <br/>Options `--time` and `--groups` are mutually exclusive and only one should be used.| From b500d4de3e0c71543512507343684d7f04626dc2 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Wed, 10 Nov 2021 10:26:33 -0600 Subject: [PATCH 728/888] MQE-2677: Add filter for groups --- docs/commands/mftf.md | 2 +- .../Console/GenerateTestsCommand.php | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 6e1b2f713..4abd0dace 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -160,7 +160,7 @@ vendor/bin/mftf generate:tests [option] [<test name>] [<test name>] [--remove] | Option | Description| | ---| --- | | `--config=[<default> or <singleRun> or <parallel>]` | Creates a single manifest file with a list of all tests. The default location is `tests/functional/Magento/FunctionalTest/_generated/testManifest.txt`.<br/> You can split the list into multiple groups using `--config=parallel`; the groups will be generated in `_generated/groups/` like `_generated/groups/group1.txt, group2.txt, ...`.<br/> Available values: `default` (default), `singleRun`(same as `default`), and `parallel`.<br/> Example: `generate:tests --config=parallel`. | -| `--filter` | Option to filter tests to be generated.<br/>Template: '<filterName>:<filterValue>'.<br/>Existing filter types: severity, includeGroup, excludeGroup.<br/>Existing severity values: BLOCKER, CRITICAL, MAJOR, AVERAGE, MINOR.<br/>Example: `--filter=severity:CRITICAL`, `--filter=includeGroup:customer`| +| `--filter` | Option to filter tests to be generated.<br/>Template: '<filterName>:<filterValue>'.<br/>Existing filter types: severity, includeGroup, excludeGroup.<br/>Existing severity values: BLOCKER, CRITICAL, MAJOR, AVERAGE, MINOR.<br/>Example: `vendor/bin/mftf generate:tests --filter=severity:CRITICAL --filter=severity:BLOCKER --filter=includeGroup:customer`| | `--force` | Forces test generation, regardless of the module merge order defined in the Magento instance. Example: `generate:tests --force`. | | `-i,--time` | Set time in minutes to determine the group size when `--config=parallel` is used. <br/>Example: `generate:tests --config=parallel --time=15` <br/>Option `--time` will be the default and the __default value__ is `10` when neither `--time` nor `--groups` is specified. <br/>Example: `generate:tests --config=parallel`| | `-g,--groups` | Set number of groups to be split into when `--config=parallel` is used. <br>Example: `generate:tests --config=parallel --groups=300` <br/>Options `--time` and `--groups` are mutually exclusive and only one should be used.| diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php index ed3050898..b277f9c4e 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php @@ -78,7 +78,8 @@ protected function configure() . '<info>Template:</info> <filterName>:<filterValue>' . PHP_EOL . '<info>Existing filter types:</info> severity.' . PHP_EOL . '<info>Existing severity values:</info> BLOCKER, CRITICAL, MAJOR, AVERAGE, MINOR.' . PHP_EOL - . '<info>Example:</info> --filter=severity:CRITICAL' . PHP_EOL + . '<info>Example:</info> --filter=severity:CRITICAL' + . ' --filter=includeGroup:customer --filter=excludeGroup:customerAnalytics' . PHP_EOL ); parent::configure(); From 4d745cca8c6702d127f5e9011f41ed314a480f63 Mon Sep 17 00:00:00 2001 From: "Shashik.K.Singh" <shashik.k.singh@ip-192-168-1-7.ec2.internal> Date: Thu, 11 Nov 2021 15:20:10 +0530 Subject: [PATCH 729/888] MQE-2669 seprated a run:failed command to generate:failed and run:failed --- .gitignore | 1 + .../Console/CommandList.php | 1 + .../Console/GenerateTestFailedCommand.php | 189 ++++++++++++++++++ .../Console/RunTestFailedCommand.php | 100 --------- 4 files changed, 191 insertions(+), 100 deletions(-) create mode 100644 src/Magento/FunctionalTestingFramework/Console/GenerateTestFailedCommand.php diff --git a/.gitignore b/.gitignore index 3166f9529..51e1b71d5 100755 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ dev/tests/docs/* dev/tests/_output dev/tests/functional.suite.yml /v2/ +dev/.credentials.example \ No newline at end of file diff --git a/src/Magento/FunctionalTestingFramework/Console/CommandList.php b/src/Magento/FunctionalTestingFramework/Console/CommandList.php index 840e7dd86..a31ebe175 100644 --- a/src/Magento/FunctionalTestingFramework/Console/CommandList.php +++ b/src/Magento/FunctionalTestingFramework/Console/CommandList.php @@ -36,6 +36,7 @@ public function __construct(array $commands = []) 'generate:tests' => new GenerateTestsCommand(), 'generate:urn-catalog' => new GenerateDevUrnCommand(), 'reset' => new CleanProjectCommand(), + 'generate:failed' => new GenerateTestFailedCommand(), 'run:failed' => new RunTestFailedCommand(), 'run:group' => new RunTestGroupCommand(), 'run:manifest' => new RunManifestCommand(), diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestFailedCommand.php new file mode 100644 index 000000000..9db7769c8 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestFailedCommand.php @@ -0,0 +1,189 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types = 1); + +namespace Magento\FunctionalTestingFramework\Console; + +use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Process\Process; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Symfony\Component\Console\Input\InputOption; + +class GenerateTestFailedCommand extends BaseGenerateCommand +{ + /** + * Default Test group to signify not in suite + */ + const DEFAULT_TEST_GROUP = 'default'; + + /** + * @var string + */ + private $testsReRunFile; + + /** + * @var array + */ + private $failedList = []; + + /** + * Configures the current command. + * + * @return void + */ + protected function configure() + { + $this->setName('generate:failed') + ->setDescription('Generate a set of tests failed'); + + parent::configure(); + } + + /** + * Executes the current command. + * + * @param InputInterface $input + * @param OutputInterface $output + * @return integer + * @throws \Exception + * + * @SuppressWarnings(PHPMD.UnusedLocalVariable) + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + protected function execute(InputInterface $input, OutputInterface $output): int + { + $this->testsFailedFile = $this->getTestsOutputDir() . self::FAILED_FILE; + $this->testsReRunFile = $this->getTestsOutputDir() . "rerun_tests"; + + $force = $input->getOption('force'); + $debug = $input->getOption('debug') ?? MftfApplicationConfig::LEVEL_DEVELOPER; // for backward compatibility + $allowSkipped = $input->getOption('allow-skipped'); + $verbose = $output->isVerbose(); + + // Create Mftf Configuration + MftfApplicationConfig::create( + $force, + MftfApplicationConfig::EXECUTION_PHASE, + $verbose, + $debug, + $allowSkipped + ); + + $testConfiguration = $this->getFailedTestList(); + + if ($testConfiguration === null) { + // no failed tests found, run is a success + return 0; + } + + $command = $this->getApplication()->find('generate:tests'); + $args = [ + '--tests' => $testConfiguration, + '--force' => $force, + '--remove' => true, + '--debug' => $debug, + '--allow-skipped' => $allowSkipped, + '-v' => $verbose + ]; + $command->run(new ArrayInput($args), $output); + $output->writeln("Test Failed Generated, now run:failed command"); + return 1; + } + + /** + * Returns a json string of tests that failed on the last run + * + * @return string + */ + private function getFailedTestList() + { + $failedTestDetails = ['tests' => [], 'suites' => []]; + + if (realpath($this->testsFailedFile)) { + $testList = $this->readFailedTestFile($this->testsFailedFile); + + foreach ($testList as $test) { + if (!empty($test)) { + $this->writeFailedTestToFile($test, $this->testsReRunFile); + $testInfo = explode(DIRECTORY_SEPARATOR, $test); + $testName = explode(":", $testInfo[count($testInfo) - 1])[1]; + $suiteName = $testInfo[count($testInfo) - 2]; + + if ($suiteName === self::DEFAULT_TEST_GROUP) { + array_push($failedTestDetails['tests'], $testName); + } else { + $suiteName = $this->sanitizeSuiteName($suiteName); + $failedTestDetails['suites'] = array_merge_recursive( + $failedTestDetails['suites'], + [$suiteName => [$testName]] + ); + } + } + } + } + if (empty($failedTestDetails['tests']) & empty($failedTestDetails['suites'])) { + return null; + } + if (empty($failedTestDetails['tests'])) { + $failedTestDetails['tests'] = null; + } + if (empty($failedTestDetails['suites'])) { + $failedTestDetails['suites'] = null; + } + $testConfigurationJson = json_encode($failedTestDetails); + return $testConfigurationJson; + } + + /** + * Trim potential suite_parallel_0_G to suite_parallel + * + * @param string $suiteName + * @return string + */ + private function sanitizeSuiteName($suiteName) + { + $suiteNameArray = explode("_", $suiteName); + if (array_pop($suiteNameArray) === 'G') { + if (is_numeric(array_pop($suiteNameArray))) { + $suiteName = implode("_", $suiteNameArray); + } + } + return $suiteName; + } + + /** + * Returns an array of tests read from the failed test file in _output + * + * @param string $filePath + * @return array|boolean + */ + private function readFailedTestFile($filePath) + { + return file($filePath, FILE_IGNORE_NEW_LINES); + } + + /** + * Writes the test name to a file if it does not already exist + * + * @param string $test + * @param string $filePath + * @return void + */ + private function writeFailedTestToFile($test, $filePath) + { + if (file_exists($filePath)) { + if (strpos(file_get_contents($filePath), $test) === false) { + file_put_contents($filePath, "\n" . $test, FILE_APPEND); + } + } else { + file_put_contents($filePath, $test . "\n"); + } + } +} diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php index 695be0695..d9109d8e0 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php @@ -23,11 +23,6 @@ class RunTestFailedCommand extends BaseGenerateCommand */ const DEFAULT_TEST_GROUP = 'default'; - /** - * @var string - */ - private $testsReRunFile; - /** * @var string */ @@ -64,45 +59,11 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output): int { - $this->testsFailedFile = $this->getTestsOutputDir() . self::FAILED_FILE; - $this->testsReRunFile = $this->getTestsOutputDir() . "rerun_tests"; $this->testsManifestFile= FilePathFormatter::format(TESTS_MODULE_PATH) . "_generated" . DIRECTORY_SEPARATOR . "testManifest.txt"; - $force = $input->getOption('force'); - $debug = $input->getOption('debug') ?? MftfApplicationConfig::LEVEL_DEVELOPER; // for backward compatibility - $allowSkipped = $input->getOption('allow-skipped'); - $verbose = $output->isVerbose(); - - // Create Mftf Configuration - MftfApplicationConfig::create( - $force, - MftfApplicationConfig::EXECUTION_PHASE, - $verbose, - $debug, - $allowSkipped - ); - - $testConfiguration = $this->getFailedTestList(); - - if ($testConfiguration === null) { - // no failed tests found, run is a success - return 0; - } - - $command = $this->getApplication()->find('generate:tests'); - $args = [ - '--tests' => $testConfiguration, - '--force' => $force, - '--remove' => true, - '--debug' => $debug, - '--allow-skipped' => $allowSkipped, - '-v' => $verbose - ]; - $command->run(new ArrayInput($args), $output); - $testManifestList = $this->readTestManifestFile(); $returnCode = 0; for ($i = 0; $i < count($testManifestList); $i++) { @@ -142,67 +103,6 @@ function ($type, $buffer) use ($output) { return $returnCode; } - /** - * Returns a json string of tests that failed on the last run - * - * @return string - */ - private function getFailedTestList() - { - $failedTestDetails = ['tests' => [], 'suites' => []]; - - if (realpath($this->testsFailedFile)) { - $testList = $this->readFailedTestFile($this->testsFailedFile); - - foreach ($testList as $test) { - if (!empty($test)) { - $this->writeFailedTestToFile($test, $this->testsReRunFile); - $testInfo = explode(DIRECTORY_SEPARATOR, $test); - $testName = explode(":", $testInfo[count($testInfo) - 1])[1]; - $suiteName = $testInfo[count($testInfo) - 2]; - - if ($suiteName === self::DEFAULT_TEST_GROUP) { - array_push($failedTestDetails['tests'], $testName); - } else { - $suiteName = $this->sanitizeSuiteName($suiteName); - $failedTestDetails['suites'] = array_merge_recursive( - $failedTestDetails['suites'], - [$suiteName => [$testName]] - ); - } - } - } - } - if (empty($failedTestDetails['tests']) & empty($failedTestDetails['suites'])) { - return null; - } - if (empty($failedTestDetails['tests'])) { - $failedTestDetails['tests'] = null; - } - if (empty($failedTestDetails['suites'])) { - $failedTestDetails['suites'] = null; - } - $testConfigurationJson = json_encode($failedTestDetails); - return $testConfigurationJson; - } - - /** - * Trim potential suite_parallel_0_G to suite_parallel - * - * @param string $suiteName - * @return string - */ - private function sanitizeSuiteName($suiteName) - { - $suiteNameArray = explode("_", $suiteName); - if (array_pop($suiteNameArray) === 'G') { - if (is_numeric(array_pop($suiteNameArray))) { - $suiteName = implode("_", $suiteNameArray); - } - } - return $suiteName; - } - /** * Returns an array of run commands read from the manifest file created post generation * From 59fe93dd2792b0a1392868d0085e752e75cb7397 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@ip-192-168-29-250.ec2.internal> Date: Thu, 11 Nov 2021 15:37:52 +0530 Subject: [PATCH 730/888] MQE-2290 Deleting MagentoPwaWebDriver file and moving it to Pwa_tests repo --- .../Module/MagentoPwaWebDriver.php | 100 ------------------ 1 file changed, 100 deletions(-) delete mode 100644 src/Magento/FunctionalTestingFramework/Module/MagentoPwaWebDriver.php diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoPwaWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoPwaWebDriver.php deleted file mode 100644 index f2f818bd4..000000000 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoPwaWebDriver.php +++ /dev/null @@ -1,100 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\FunctionalTestingFramework\Module; - -use Codeception\Module\WebDriver; - -/** - * Class MagentoPwaActions - * - * Contains all custom PWA action functions to be used in PWA tests. - * - * @package Magento\FunctionalTestingFramework\Module - */ -class MagentoPwaWebDriver extends MagentoWebDriver -{ - /** - * List of known PWA loading masks by selector - * - * Overriding the MagentoWebDriver array to contain applicable PWA locators. - * - * @var array - */ - protected $loadingMasksLocators = [ - '//div[contains(@class, "indicator-global-")]', - '//div[contains(@class, "indicator-root-")]', - '//img[contains(@class, "indicator-indicator-")]', - '//span[contains(@class, "indicator-message-")]' - ]; - - /** - * Go to the page. - * - * Overriding the MagentoWebDriver version because it contains 'waitForPageLoad'. - * The AJAX check in 'waitForPageLoad' does NOT work with a PWA. - * - * @param string $page - * @param integer $timeout - * @throws \Exception - * @return void - */ - public function amOnPage($page, $timeout = null) - { - WebDriver::amOnPage($page); - $this->waitForLoadingMaskToDisappear($timeout); - } - - /** - * Wait for a PWA Element to NOT be visible using JavaScript. - * Add the WAIT_TIMEOUT variable to your .env file for this action. - * - * @param string $selector - * @param integer $timeout - * @throws \Exception - * @return void - */ - public function waitForPwaElementNotVisible($selector, $timeout = null) - { - $timeout = $timeout ?? $this->_getConfig()['pageload_timeout']; - - // Determine what type of Selector is used. - // Then use the correct JavaScript to locate the Element. - if (\Codeception\Util\Locator::isCss($selector)) { - $this->waitForLoadingMaskToDisappear($timeout); - $this->waitForJS("return !document.querySelector(`$selector`);", $timeout); - } else { - $this->waitForLoadingMaskToDisappear($timeout); - $this->waitForJS("return !document.evaluate(`$selector`, document, null, - XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;", $timeout); - } - } - - /** - * Wait for a PWA Element to be visible using JavaScript. - * Add the WAIT_TIMEOUT variable to your .env file for this action. - * - * @param string $selector - * @param integer $timeout - * @throws \Exception - * @return void - */ - public function waitForPwaElementVisible($selector, $timeout = null) - { - $timeout = $timeout ?? $this->_getConfig()['pageload_timeout']; - - // Determine what type of Selector is used. - // Then use the correct JavaScript to locate the Element. - if (\Codeception\Util\Locator::isCss($selector)) { - $this->waitForLoadingMaskToDisappear($timeout); - $this->waitForJS("return !!document && !!document.querySelector(`$selector`);", $timeout); - } else { - $this->waitForLoadingMaskToDisappear($timeout); - $this->waitForJS("return !!document && !!document.evaluate(`$selector`, document, null, - XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;", $timeout); - } - } -} From ba201f11962217c1735892e38460b5f37c0f3ca1 Mon Sep 17 00:00:00 2001 From: "Shashik.K.Singh" <shashik.k.singh@BLR1-LMC-N71386.local> Date: Thu, 11 Nov 2021 22:25:06 +0530 Subject: [PATCH 731/888] MQE-2669 seprated a run:failed command to generate:failed and run:failed --- .gitignore | 4 +++- .../Console/GenerateTestFailedCommand.php | 5 ----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 51e1b71d5..1ab55a2ff 100755 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,6 @@ dev/tests/docs/* dev/tests/_output dev/tests/functional.suite.yml /v2/ -dev/.credentials.example \ No newline at end of file +dev/.credentials.example +dev/tests/.phpunit.result.cache +dev/tests/verification/TestModule/Test/testFile.xml \ No newline at end of file diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestFailedCommand.php index 9db7769c8..a9308b473 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestFailedCommand.php @@ -28,11 +28,6 @@ class GenerateTestFailedCommand extends BaseGenerateCommand */ private $testsReRunFile; - /** - * @var array - */ - private $failedList = []; - /** * Configures the current command. * From 908c2e33c52fc6dc00a0d4b0388fadf0dc9e79d5 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Wed, 17 Nov 2021 12:54:12 -0600 Subject: [PATCH 732/888] MQE-1766 --- .github/workflows/main.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 03bdbff75..4a567c7c4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -39,14 +39,14 @@ jobs: - name: Run tests run: vendor/bin/phpunit --configuration dev/tests/phpunit.xml --testsuite unit --coverage-clover clover.xml - - name: Monitor coverage - if: github.event_name == 'pull_request' - uses: slavcodev/coverage-monitor-action@1.2.0 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - clover_file: "clover.xml" - threshold_alert: 10 - threshold_warning: 20 +# - name: Monitor coverage +# if: github.event_name == 'pull_request' +# uses: slavcodev/coverage-monitor-action@1.2.0 +# with: +# github_token: ${{ secrets.GITHUB_TOKEN }} +# clover_file: "clover.xml" +# threshold_alert: 10 +# threshold_warning: 20 verification-tests: name: Verification Tests From 6e7bb98fb2cede7bb52a65910507a593613ec1f7 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Wed, 17 Nov 2021 14:22:24 -0600 Subject: [PATCH 733/888] MQE-2669: bin/mftf run:failed process used a lot of RAM during MTSv1 build --- .../Console/RunTestFailedCommand.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php index d9109d8e0..7a3f9697e 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php @@ -59,6 +59,10 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output): int { + $this->testsFailedFile = $this->getTestsOutputDir() . self::FAILED_FILE; + $this->testsReRunFile = $this->getTestsOutputDir() . "rerun_tests"; + $failedTestList = $this->readFailedTestFile($this->testsFailedFile); + $this->testsManifestFile= FilePathFormatter::format(TESTS_MODULE_PATH) . "_generated" . DIRECTORY_SEPARATOR . @@ -67,6 +71,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int $testManifestList = $this->readTestManifestFile(); $returnCode = 0; for ($i = 0; $i < count($testManifestList); $i++) { + if (in_array($testManifestList[$i], $failedTestList) === false) { + continue; + } if ($this->pauseEnabled()) { $codeceptionCommand = self::CODECEPT_RUN_FUNCTIONAL . $testManifestList[$i] . ' --debug '; if ($i !== count($testManifestList) - 1) { @@ -86,6 +93,7 @@ function ($type, $buffer) use ($output) { $output->write($buffer); } )); + $process->__destruct(); } if (file_exists($this->testsFailedFile)) { @@ -121,7 +129,14 @@ private function readTestManifestFile() */ private function readFailedTestFile($filePath) { - return file($filePath, FILE_IGNORE_NEW_LINES); + $failedTests = file($filePath, FILE_IGNORE_NEW_LINES); + if ($failedTests !== false) { + foreach ($failedTests as $key => $failedTest) { + list($filePath) = explode(":", $failedTest); + $failedTests[$key] = $filePath; + } + } + return $failedTests; } /** From f5d5360489249198edda00fec1970c76eefef8f2 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@magento.com> Date: Thu, 18 Nov 2021 10:11:48 -0600 Subject: [PATCH 734/888] MQE-1766 --- .../FunctionalTestingFramework/Module/MagentoWebDriver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 433841c70..b7a9f1bdc 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -340,7 +340,7 @@ public function seeInCurrentUrl($needle) $actualUrl = $this->webDriver->getCurrentURL(); $comparison = "Expected: $needle\nActual: $actualUrl"; AllureHelper::addAttachmentToCurrentStep($comparison, 'Comparison'); - $this->assertStringContainsString($needle, urldecode($actualUrl)); + $this->assertStringContainsString(urldecode($needle), urldecode($actualUrl)); } /** From 6b27aae83244f9a22978423f50864db437ac4869 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Thu, 18 Nov 2021 10:52:14 -0600 Subject: [PATCH 735/888] MQE-2669: bin/mftf run:failed process used a lot of RAM during MTSv1 build --- .../Console/GenerateTestFailedCommand.php | 4 ++-- .../Console/RunTestFailedCommand.php | 18 +----------------- 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestFailedCommand.php index a9308b473..162760659 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestFailedCommand.php @@ -74,7 +74,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $testConfiguration = $this->getFailedTestList(); if ($testConfiguration === null) { - // no failed tests found, run is a success + // No failed tests found, no tests generated return 0; } @@ -89,7 +89,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int ]; $command->run(new ArrayInput($args), $output); $output->writeln("Test Failed Generated, now run:failed command"); - return 1; + return 0; } /** diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php index 7a3f9697e..97180908e 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php @@ -18,11 +18,6 @@ class RunTestFailedCommand extends BaseGenerateCommand { - /** - * Default Test group to signify not in suite - */ - const DEFAULT_TEST_GROUP = 'default'; - /** * @var string */ @@ -61,7 +56,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int { $this->testsFailedFile = $this->getTestsOutputDir() . self::FAILED_FILE; $this->testsReRunFile = $this->getTestsOutputDir() . "rerun_tests"; - $failedTestList = $this->readFailedTestFile($this->testsFailedFile); $this->testsManifestFile= FilePathFormatter::format(TESTS_MODULE_PATH) . "_generated" . @@ -71,9 +65,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int $testManifestList = $this->readTestManifestFile(); $returnCode = 0; for ($i = 0; $i < count($testManifestList); $i++) { - if (in_array($testManifestList[$i], $failedTestList) === false) { - continue; - } if ($this->pauseEnabled()) { $codeceptionCommand = self::CODECEPT_RUN_FUNCTIONAL . $testManifestList[$i] . ' --debug '; if ($i !== count($testManifestList) - 1) { @@ -129,14 +120,7 @@ private function readTestManifestFile() */ private function readFailedTestFile($filePath) { - $failedTests = file($filePath, FILE_IGNORE_NEW_LINES); - if ($failedTests !== false) { - foreach ($failedTests as $key => $failedTest) { - list($filePath) = explode(":", $failedTest); - $failedTests[$key] = $filePath; - } - } - return $failedTests; + return file($filePath, FILE_IGNORE_NEW_LINES); } /** From 962d1caf63e1df41a3e1a7c5ee174729acf97c82 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@adobe.com> Date: Wed, 17 Nov 2021 12:54:12 -0600 Subject: [PATCH 736/888] MQE-1766 --- .github/workflows/main.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 03bdbff75..4a567c7c4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -39,14 +39,14 @@ jobs: - name: Run tests run: vendor/bin/phpunit --configuration dev/tests/phpunit.xml --testsuite unit --coverage-clover clover.xml - - name: Monitor coverage - if: github.event_name == 'pull_request' - uses: slavcodev/coverage-monitor-action@1.2.0 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - clover_file: "clover.xml" - threshold_alert: 10 - threshold_warning: 20 +# - name: Monitor coverage +# if: github.event_name == 'pull_request' +# uses: slavcodev/coverage-monitor-action@1.2.0 +# with: +# github_token: ${{ secrets.GITHUB_TOKEN }} +# clover_file: "clover.xml" +# threshold_alert: 10 +# threshold_warning: 20 verification-tests: name: Verification Tests From 22a941ae08290e1c84ca1fc52f153b54678d0085 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Thu, 18 Nov 2021 19:08:26 -0600 Subject: [PATCH 737/888] MQE-2669: bin/mftf run:failed process used a lot of RAM during MTSv1 build --- .../Console/RunTestFailedCommand.php | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php index 97180908e..daf0f62e7 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php @@ -54,6 +54,11 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output): int { + $returnCode = $this->executeGenerateFailed($input, $output); + if ($returnCode !== 0) { + return $returnCode; + } + $this->testsFailedFile = $this->getTestsOutputDir() . self::FAILED_FILE; $this->testsReRunFile = $this->getTestsOutputDir() . "rerun_tests"; @@ -85,6 +90,7 @@ function ($type, $buffer) use ($output) { } )); $process->__destruct(); + unset($process); } if (file_exists($this->testsFailedFile)) { @@ -102,6 +108,35 @@ function ($type, $buffer) use ($output) { return $returnCode; } + /** + * @param OutputInterface $output + * @return mixed + */ + private function executeGenerateFailed(InputInterface $input, OutputInterface $output) + { + $returnCode = 0; + $binMftf = PROJECT_ROOT . '/vendor/bin/mftf'; + if (file_exists($binMftf) === false) { + $binMftf = PROJECT_ROOT . '/bin/mftf'; + } + $forceGenerate = $input->getOption('force') ? ' -f' : ''; + $mftfCommand = realpath($binMftf) . ' generate:failed' . $forceGenerate; + + $process = new Process($mftfCommand); + $process->setWorkingDirectory(TESTS_BP); + $process->setIdleTimeout(600); + $process->setTimeout(0); + $returnCode = max($returnCode, $process->run( + function ($type, $buffer) use ($output) { + $output->write($buffer); + } + )); + $process->__destruct(); + unset($process); + + return $returnCode; + } + /** * Returns an array of run commands read from the manifest file created post generation * From a5a73af19c5e37ddf3672379919a14c6db591283 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Thu, 18 Nov 2021 19:17:45 -0600 Subject: [PATCH 738/888] MQE-2669: bin/mftf run:failed process used a lot of RAM during MTSv1 build --- .../Console/RunTestFailedCommand.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php index daf0f62e7..01d800286 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php @@ -109,8 +109,14 @@ function ($type, $buffer) use ($output) { } /** + * Execute generate failed tests command as a separate process, so that we can kill it and avoid high memory usage. + * + * @param InputInterface $input * @param OutputInterface $output - * @return mixed + * @return integer + * + * @SuppressWarnings(PHPMD.UnusedLocalVariable) + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ private function executeGenerateFailed(InputInterface $input, OutputInterface $output) { From dccf3882b819453d6229fbd0fecb535784cbf917 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Fri, 19 Nov 2021 09:40:52 -0600 Subject: [PATCH 739/888] MQE-2669: bin/mftf run:failed process used a lot of RAM during MTSv1 build --- .../Console/GenerateTestFailedCommand.php | 1 + .../Console/RunTestFailedCommand.php | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestFailedCommand.php index 162760659..8b21adefc 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestFailedCommand.php @@ -75,6 +75,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int if ($testConfiguration === null) { // No failed tests found, no tests generated + $this->removeGeneratedDirectory($output, $verbose); return 0; } diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php index 01d800286..ac850607c 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php @@ -68,6 +68,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int "testManifest.txt"; $testManifestList = $this->readTestManifestFile(); + if ($testManifestList === false) { + // If there is no test manifest file then we have nothing to execute. + return 0; + } $returnCode = 0; for ($i = 0; $i < count($testManifestList); $i++) { if ($this->pauseEnabled()) { @@ -150,7 +154,10 @@ function ($type, $buffer) use ($output) { */ private function readTestManifestFile() { - return file($this->testsManifestFile, FILE_IGNORE_NEW_LINES); + if (file_exists($this->testsManifestFile)) { + return file($this->testsManifestFile, FILE_IGNORE_NEW_LINES); + } + return false; } /** From 8a535f64a67002f117e1e418f353c335795a42e0 Mon Sep 17 00:00:00 2001 From: Kevin Kozan <kkozan@magento.com> Date: Fri, 19 Nov 2021 11:44:06 -0600 Subject: [PATCH 740/888] MQE-2669: bin/mftf run:failed process used a lot of RAM - Added simple unit test to test configuration generator --- .../Console/GenerateTestFailedCommandTest.php | 41 +++++++++++++++++++ .../Console/GenerateTestFailedCommand.php | 29 ++++++------- 2 files changed, 54 insertions(+), 16 deletions(-) create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/Console/GenerateTestFailedCommandTest.php diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Console/GenerateTestFailedCommandTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Console/GenerateTestFailedCommandTest.php new file mode 100644 index 000000000..a127ea313 --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Console/GenerateTestFailedCommandTest.php @@ -0,0 +1,41 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace tests\unit\Magento\FunctionalTestFramework\Console; + +use Magento\FunctionalTestingFramework\Console\GenerateTestFailedCommand; +use Magento\FunctionalTestingFramework\Test\Objects\TestObject; +use PHPUnit\Framework\MockObject\MockBuilder; +use PHPUnit\Framework\TestCase; +use Magento\FunctionalTestingFramework\Exceptions\FastFailException; +use Magento\FunctionalTestingFramework\Console\GenerateTestsCommand; +use ReflectionClass; + +class GenerateTestFailedCommandTest extends BaseGenerateCommandTest +{ + public function testSingleTestNoSuite(): void + { + $testFileReturn = [ + "tests/functional/tests/MFTF/_generated/default/SingleTestNoSuiteTest.php:SingleTestNoSuiteTest" + ]; + $expectedConfiguration = '{"tests":["SingleTestNoSuiteTest"],"suites":null}'; + + // Create a stub for the SomeClass class. + $stub = $this->getMockBuilder(GenerateTestFailedCommand::class) + ->onlyMethods(["readFailedTestFile", "writeFailedTestToFile"]) + ->getMock(); + // Configure the stub. + $stub + ->method('readFailedTestFile') + ->willReturn($testFileReturn); + $stub + ->method('writeFailedTestToFile') + ->willReturn(null); + + // Run the real code + $configuration = $stub->getFailedTestList("", ""); + $this->assertEquals($expectedConfiguration, $configuration); + } +} diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestFailedCommand.php index 8b21adefc..7b6208bd4 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestFailedCommand.php @@ -23,11 +23,6 @@ class GenerateTestFailedCommand extends BaseGenerateCommand */ const DEFAULT_TEST_GROUP = 'default'; - /** - * @var string - */ - private $testsReRunFile; - /** * Configures the current command. * @@ -54,9 +49,6 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output): int { - $this->testsFailedFile = $this->getTestsOutputDir() . self::FAILED_FILE; - $this->testsReRunFile = $this->getTestsOutputDir() . "rerun_tests"; - $force = $input->getOption('force'); $debug = $input->getOption('debug') ?? MftfApplicationConfig::LEVEL_DEVELOPER; // for backward compatibility $allowSkipped = $input->getOption('allow-skipped'); @@ -71,7 +63,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int $allowSkipped ); - $testConfiguration = $this->getFailedTestList(); + $testsFailedFile = $this->getTestsOutputDir() . self::FAILED_FILE; + $testsReRunFile = $this->getTestsOutputDir() . "rerun_tests"; + $testConfiguration = $this->getFailedTestList($testsFailedFile, $testsReRunFile); if ($testConfiguration === null) { // No failed tests found, no tests generated @@ -98,16 +92,16 @@ protected function execute(InputInterface $input, OutputInterface $output): int * * @return string */ - private function getFailedTestList() + public function getFailedTestList($testsFailedFile, $testsReRunFile) { $failedTestDetails = ['tests' => [], 'suites' => []]; - if (realpath($this->testsFailedFile)) { - $testList = $this->readFailedTestFile($this->testsFailedFile); + $testList = $this->readFailedTestFile($testsFailedFile); + if (!empty($testList)) { foreach ($testList as $test) { if (!empty($test)) { - $this->writeFailedTestToFile($test, $this->testsReRunFile); + $this->writeFailedTestToFile($test, $testsReRunFile); $testInfo = explode(DIRECTORY_SEPARATOR, $test); $testName = explode(":", $testInfo[count($testInfo) - 1])[1]; $suiteName = $testInfo[count($testInfo) - 2]; @@ -160,9 +154,12 @@ private function sanitizeSuiteName($suiteName) * @param string $filePath * @return array|boolean */ - private function readFailedTestFile($filePath) + public function readFailedTestFile($filePath) { - return file($filePath, FILE_IGNORE_NEW_LINES); + if (realpath($filePath)) { + return file($filePath, FILE_IGNORE_NEW_LINES); + } + return ""; } /** @@ -172,7 +169,7 @@ private function readFailedTestFile($filePath) * @param string $filePath * @return void */ - private function writeFailedTestToFile($test, $filePath) + public function writeFailedTestToFile($test, $filePath) { if (file_exists($filePath)) { if (strpos(file_get_contents($filePath), $test) === false) { From c8ac8bfb435a298ba5bc5f42c874b102a7eb41a2 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 22 Nov 2021 19:15:08 -0600 Subject: [PATCH 741/888] MQE-2669: Seprated a run:failed command to generate:failed and run:failed --- .../Console/RunTestFailedCommand.php | 80 +++++++------------ .../Suite/views/SuiteClass.mustache | 18 +++++ .../Util/TestGenerator.php | 10 ++- 3 files changed, 54 insertions(+), 54 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php index ac850607c..16e621dfb 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php @@ -18,10 +18,12 @@ class RunTestFailedCommand extends BaseGenerateCommand { + const DEFAULT_TEST_GROUP = 'default'; + /** * @var string */ - private $testsManifestFile; + private $testsReRunFile = ""; /** * @var array @@ -54,22 +56,14 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output): int { - $returnCode = $this->executeGenerateFailed($input, $output); - if ($returnCode !== 0) { - return $returnCode; - } - $this->testsFailedFile = $this->getTestsOutputDir() . self::FAILED_FILE; $this->testsReRunFile = $this->getTestsOutputDir() . "rerun_tests"; - $this->testsManifestFile= FilePathFormatter::format(TESTS_MODULE_PATH) . - "_generated" . - DIRECTORY_SEPARATOR . - "testManifest.txt"; + $failedTests = $this->readFailedTestFile($this->testsFailedFile); + $testManifestList = $this->filterTestsForExecution($failedTests); - $testManifestList = $this->readTestManifestFile(); - if ($testManifestList === false) { - // If there is no test manifest file then we have nothing to execute. + if (empty($testManifestList)) { + // If there is no tests in manifest then we have nothing to execute. return 0; } $returnCode = 0; @@ -113,51 +107,31 @@ function ($type, $buffer) use ($output) { } /** - * Execute generate failed tests command as a separate process, so that we can kill it and avoid high memory usage. + * Returns a list of tests/suites which should have an additional run. * - * @param InputInterface $input - * @param OutputInterface $output - * @return integer - * - * @SuppressWarnings(PHPMD.UnusedLocalVariable) - * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @param $failedTests + * @return array */ - private function executeGenerateFailed(InputInterface $input, OutputInterface $output) + private function filterTestsForExecution($failedTests): array { - $returnCode = 0; - $binMftf = PROJECT_ROOT . '/vendor/bin/mftf'; - if (file_exists($binMftf) === false) { - $binMftf = PROJECT_ROOT . '/bin/mftf'; - } - $forceGenerate = $input->getOption('force') ? ' -f' : ''; - $mftfCommand = realpath($binMftf) . ' generate:failed' . $forceGenerate; - - $process = new Process($mftfCommand); - $process->setWorkingDirectory(TESTS_BP); - $process->setIdleTimeout(600); - $process->setTimeout(0); - $returnCode = max($returnCode, $process->run( - function ($type, $buffer) use ($output) { - $output->write($buffer); + $testsOrGroupsToRerun = []; + + foreach ($failedTests as $test) { + if (!empty($test)) { + $this->writeFailedTestToFile($test, $this->testsReRunFile); + $testInfo = explode(DIRECTORY_SEPARATOR, $test); + $suiteName = $testInfo[count($testInfo) - 2]; + list($testPath) = explode(":", $test); + + if ($suiteName === self::DEFAULT_TEST_GROUP) { + $testsOrGroupsToRerun[] = $testPath; + } else { + $testsOrGroupsToRerun[] = "-g " . $suiteName; + } } - )); - $process->__destruct(); - unset($process); - - return $returnCode; - } - - /** - * Returns an array of run commands read from the manifest file created post generation - * - * @return array|boolean - */ - private function readTestManifestFile() - { - if (file_exists($this->testsManifestFile)) { - return file($this->testsManifestFile, FILE_IGNORE_NEW_LINES); } - return false; + + return $testsOrGroupsToRerun; } /** diff --git a/src/Magento/FunctionalTestingFramework/Suite/views/SuiteClass.mustache b/src/Magento/FunctionalTestingFramework/Suite/views/SuiteClass.mustache index dc2fde915..1a4dde251 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/views/SuiteClass.mustache +++ b/src/Magento/FunctionalTestingFramework/Suite/views/SuiteClass.mustache @@ -43,6 +43,7 @@ class {{suiteName}} extends \Codeception\GroupObject {{#before}} public function _before(\Codeception\Event\TestEvent $e) { + $this->testCount = $this->getTestCount(); $this->webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); $this->moduleContainer = $this->webDriver->getModuleContainer(); {{#helpers}} @@ -171,4 +172,21 @@ class {{suiteName}} extends \Codeception\GroupObject } return $module; } + + /** + * Counts how many tests in group. + * + * @return integer + */ + private function getTestCount() + { + $config = $this->getGlobalConfig(); + if (empty($config['groups']) && empty($config['groups'][self::$group])) { + return $this->testCount; + } + $pathToGroupDir = TESTS_BP . DIRECTORY_SEPARATOR . array_first($config['groups'][self::$group]); + $pathToGroupCests = $pathToGroupDir . DIRECTORY_SEPARATOR . "*Cest.php"; + + return count(glob($pathToGroupCests)); + } } diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 17c045977..b1638a548 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1801,7 +1801,8 @@ private function generateTestPhp($test) } else { $skipString .= "No issues have been specified."; } - $steps = "\t\t" . '$scenario->skip("' . $skipString . '");' . "\n"; + $steps = "\t\t" . 'unlink(__FILE__);' . "\n"; + $steps .= "\t\t" . '$scenario->skip("' . $skipString . '");' . "\n"; $dependencies .= ', \Codeception\Scenario $scenario'; } @@ -1811,6 +1812,13 @@ private function generateTestPhp($test) $testPhp .= $steps; $testPhp .= "\t}\n"; + $testPhp .= PHP_EOL; + $testPhp .= sprintf("\tpublic function _passed(%s)\n", $dependencies); + $testPhp .= "\t{\n"; + $testPhp .= "\t\t// Deleting itself so that we can rerun only failed tests." . PHP_EOL; + $testPhp .= "\t\tunlink(__FILE__);" . PHP_EOL; + $testPhp .= "\t}\n"; + return $testPhp; } From 1d57cc3a86df5f015d66bfb2a648540a613685db Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 22 Nov 2021 19:37:01 -0600 Subject: [PATCH 742/888] MQE-2669: Seprated a run:failed command to generate:failed and run:failed - update tests --- .../ActionGroupContainsStepKeyInArgText.txt | 6 ++++++ .../ActionGroupMergedViaInsertAfter.txt | 6 ++++++ .../ActionGroupMergedViaInsertBefore.txt | 6 ++++++ .../ActionGroupReturningValueTest.txt | 6 ++++++ .../Resources/ActionGroupToExtend.txt | 6 ++++++ .../Resources/ActionGroupUsingCreateData.txt | 6 ++++++ .../ActionGroupUsingNestedArgument.txt | 6 ++++++ .../ActionGroupWithDataOverrideTest.txt | 6 ++++++ .../Resources/ActionGroupWithDataTest.txt | 6 ++++++ ...thDefaultArgumentAndStringSelectorParam.txt | 6 ++++++ ...leParameterSelectorsFromDefaultArgument.txt | 6 ++++++ .../Resources/ActionGroupWithNoArguments.txt | 6 ++++++ .../Resources/ActionGroupWithNoDefaultTest.txt | 6 ++++++ ...GroupWithParameterizedElementWithHyphen.txt | 6 ++++++ ...ameterizedElementsWithStepKeyReferences.txt | 6 ++++++ ...ithPassedArgumentAndStringSelectorParam.txt | 6 ++++++ .../Resources/ActionGroupWithPersistedData.txt | 6 ++++++ ...ctionGroupWithSectionAndDataAsArguments.txt | 6 ++++++ ...pWithSimpleDataUsageFromDefaultArgument.txt | 6 ++++++ ...upWithSimpleDataUsageFromPassedArgument.txt | 6 ++++++ ...gleParameterSelectorFromDefaultArgument.txt | 6 ++++++ ...ngleParameterSelectorFromPassedArgument.txt | 6 ++++++ .../ActionGroupWithStepKeyReferences.txt | 6 ++++++ .../ActionGroupWithTopLevelPersistedData.txt | 6 ++++++ .../ActionsInDifferentModulesSuite.txt | 18 ++++++++++++++++++ .../ArgumentWithSameNameAsElement.txt | 6 ++++++ .../verification/Resources/AssertTest.txt | 6 ++++++ .../Resources/BasicActionGroupTest.txt | 6 ++++++ .../Resources/BasicFunctionalTest.txt | 6 ++++++ .../verification/Resources/BasicMergeTest.txt | 6 ++++++ .../Resources/CharacterReplacementTest.txt | 6 ++++++ .../Resources/ChildExtendedTestAddHooks.txt | 6 ++++++ .../Resources/ChildExtendedTestMerging.txt | 6 ++++++ .../Resources/ChildExtendedTestNoParent.txt | 6 ++++++ .../ChildExtendedTestRemoveAction.txt | 6 ++++++ .../ChildExtendedTestRemoveHookAction.txt | 6 ++++++ .../Resources/ChildExtendedTestReplace.txt | 6 ++++++ .../Resources/ChildExtendedTestReplaceHook.txt | 6 ++++++ .../verification/Resources/DataActionsTest.txt | 6 ++++++ .../Resources/DataReplacementTest.txt | 6 ++++++ .../Resources/DeprecatedEntitiesTest.txt | 6 ++++++ .../verification/Resources/DeprecatedTest.txt | 6 ++++++ .../Resources/ExecuteInSeleniumTest.txt | 0 .../Resources/ExecuteJsEscapingTest.txt | 6 ++++++ .../Resources/ExtendParentDataTest.txt | 6 ++++++ .../Resources/ExtendedActionGroup.txt | 6 ++++++ .../ExtendedActionGroupReturningValueTest.txt | 6 ++++++ ...endedChildActionGroupReturningValueTest.txt | 6 ++++++ .../Resources/ExtendedChildTestInSuiteCest.txt | 6 ++++++ .../Resources/ExtendedChildTestNotInSuite.txt | 6 ++++++ .../Resources/ExtendedParameterArrayTest.txt | 6 ++++++ .../Resources/ExtendedRemoveActionGroup.txt | 6 ++++++ .../Resources/ExtendingSkippedTest.txt | 6 ++++++ .../Resources/GroupSkipGenerationTest.txt | 6 ++++++ .../verification/Resources/HookActionsTest.txt | 6 ++++++ .../Resources/LocatorFunctionTest.txt | 6 ++++++ .../Resources/MergeMassViaInsertAfter.txt | 6 ++++++ .../Resources/MergeMassViaInsertBefore.txt | 6 ++++++ dev/tests/verification/Resources/MergeSkip.txt | 6 ++++++ .../MergedActionGroupReturningValueTest.txt | 6 ++++++ .../Resources/MergedActionGroupTest.txt | 6 ++++++ .../Resources/MergedReferencesTest.txt | 6 ++++++ .../Resources/MultipleActionGroupsTest.txt | 6 ++++++ .../Resources/PageReplacementTest.txt | 6 ++++++ .../Resources/ParameterArrayTest.txt | 6 ++++++ .../Resources/ParentExtendedTest.txt | 6 ++++++ .../PersistedAndXmlEntityArguments.txt | 6 ++++++ .../Resources/PersistedReplacementTest.txt | 6 ++++++ .../PersistenceActionGroupAppendingTest.txt | 6 ++++++ .../Resources/PersistenceCustomFieldsTest.txt | 6 ++++++ .../Resources/SectionReplacementTest.txt | 6 ++++++ .../verification/Resources/SkippedTest.txt | 6 ++++++ .../Resources/SkippedTestTwoIssues.txt | 6 ++++++ .../Resources/SkippedTestWithHooks.txt | 6 ++++++ .../Resources/XmlCommentedActionGroupTest.txt | 6 ++++++ .../Resources/XmlCommentedTest.txt | 6 ++++++ .../Resources/functionalSuiteHooks.txt | 18 ++++++++++++++++++ .../Resources/functionalSuiteWithComments.txt | 18 ++++++++++++++++++ .../Console/RunTestFailedCommand.php | 4 ++-- 79 files changed, 500 insertions(+), 2 deletions(-) delete mode 100644 dev/tests/verification/Resources/ExecuteInSeleniumTest.txt diff --git a/dev/tests/verification/Resources/ActionGroupContainsStepKeyInArgText.txt b/dev/tests/verification/Resources/ActionGroupContainsStepKeyInArgText.txt index d6640846f..ad906d4ea 100644 --- a/dev/tests/verification/Resources/ActionGroupContainsStepKeyInArgText.txt +++ b/dev/tests/verification/Resources/ActionGroupContainsStepKeyInArgText.txt @@ -41,4 +41,10 @@ class ActionGroupContainsStepKeyInArgTextCest $I->see("arg1", ".selector"); // stepKey: arg1ActionGroup $I->comment("Exiting Action Group [actionGroup] actionGroupContainsStepKeyInArgValue"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ActionGroupMergedViaInsertAfter.txt b/dev/tests/verification/Resources/ActionGroupMergedViaInsertAfter.txt index 352af3a2b..a69b8d212 100644 --- a/dev/tests/verification/Resources/ActionGroupMergedViaInsertAfter.txt +++ b/dev/tests/verification/Resources/ActionGroupMergedViaInsertAfter.txt @@ -35,4 +35,10 @@ class ActionGroupMergedViaInsertAfterCest $I->fillField("#baz", "baz"); // stepKey: fillField3Keyone $I->comment("Exiting Action Group [keyone] FunctionalActionGroupForMassMergeAfter"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ActionGroupMergedViaInsertBefore.txt b/dev/tests/verification/Resources/ActionGroupMergedViaInsertBefore.txt index 009109146..45d5188d4 100644 --- a/dev/tests/verification/Resources/ActionGroupMergedViaInsertBefore.txt +++ b/dev/tests/verification/Resources/ActionGroupMergedViaInsertBefore.txt @@ -35,4 +35,10 @@ class ActionGroupMergedViaInsertBeforeCest $I->fillField("#baz", "baz"); // stepKey: fillField3Keyone $I->comment("Exiting Action Group [keyone] FunctionalActionGroupForMassMergeBefore"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ActionGroupReturningValueTest.txt b/dev/tests/verification/Resources/ActionGroupReturningValueTest.txt index 08e0b44f8..2d0220e65 100644 --- a/dev/tests/verification/Resources/ActionGroupReturningValueTest.txt +++ b/dev/tests/verification/Resources/ActionGroupReturningValueTest.txt @@ -72,4 +72,10 @@ class ActionGroupReturningValueTestCest $I->see($actionGroupWithReturnValue1, "#element .{$actionGroupWithReturnValue1}"); // stepKey: see1ActionGroupWithStringUsage1 $I->comment("Exiting Action Group [actionGroupWithStringUsage1] actionGroupWithStringUsage"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ActionGroupToExtend.txt b/dev/tests/verification/Resources/ActionGroupToExtend.txt index bbb9efa0f..14ef8a29a 100644 --- a/dev/tests/verification/Resources/ActionGroupToExtend.txt +++ b/dev/tests/verification/Resources/ActionGroupToExtend.txt @@ -31,4 +31,10 @@ class ActionGroupToExtendCest $I->assertCount(99, $grabProductsActionGroup); // stepKey: assertCountActionGroup $I->comment("Exiting Action Group [actionGroup] ActionGroupToExtend"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt b/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt index cbddc5f4d..8afc91f6f 100644 --- a/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt +++ b/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt @@ -39,4 +39,10 @@ class ActionGroupUsingCreateDataCest public function ActionGroupUsingCreateData(AcceptanceTester $I) { } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ActionGroupUsingNestedArgument.txt b/dev/tests/verification/Resources/ActionGroupUsingNestedArgument.txt index 0cfd7f84d..657046cd5 100644 --- a/dev/tests/verification/Resources/ActionGroupUsingNestedArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupUsingNestedArgument.txt @@ -31,4 +31,10 @@ class ActionGroupUsingNestedArgumentCest $I->assertCount(99, $grabProductsActionGroup); // stepKey: assertCountActionGroup $I->comment("Exiting Action Group [actionGroup] ActionGroupToExtend"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt b/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt index b60a4da5f..bf430a668 100644 --- a/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt +++ b/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt @@ -73,4 +73,10 @@ class ActionGroupWithDataOverrideTestCest $I->comment("Exiting Action Group [actionGroupWithDataOverride1] FunctionalActionGroupWithData"); $I->click("loginButton"); // stepKey: step6 } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ActionGroupWithDataTest.txt b/dev/tests/verification/Resources/ActionGroupWithDataTest.txt index 5f19cdc37..0de660c0e 100644 --- a/dev/tests/verification/Resources/ActionGroupWithDataTest.txt +++ b/dev/tests/verification/Resources/ActionGroupWithDataTest.txt @@ -73,4 +73,10 @@ class ActionGroupWithDataTestCest $I->comment("Exiting Action Group [actionGroupWithData1] FunctionalActionGroupWithData"); $I->click("loginButton"); // stepKey: step6 } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ActionGroupWithDefaultArgumentAndStringSelectorParam.txt b/dev/tests/verification/Resources/ActionGroupWithDefaultArgumentAndStringSelectorParam.txt index 65339e970..21f54d3ed 100644 --- a/dev/tests/verification/Resources/ActionGroupWithDefaultArgumentAndStringSelectorParam.txt +++ b/dev/tests/verification/Resources/ActionGroupWithDefaultArgumentAndStringSelectorParam.txt @@ -32,4 +32,10 @@ class ActionGroupWithDefaultArgumentAndStringSelectorParamCest $I->see("John", "#element .test1"); // stepKey: seeFirstNameActionGroup $I->comment("Exiting Action Group [actionGroup] actionGroupWithDefaultArgumentAndStringSelectorParam"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.txt b/dev/tests/verification/Resources/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.txt index e8cedee97..b24fac754 100644 --- a/dev/tests/verification/Resources/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.txt @@ -32,4 +32,10 @@ class ActionGroupWithMultipleParameterSelectorsFromDefaultArgumentCest $I->see("Doe", "#John-Doe .test"); // stepKey: seeLastNameActionGroup $I->comment("Exiting Action Group [actionGroup] actionGroupWithMultipleParameterSelectorsFromArgument"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ActionGroupWithNoArguments.txt b/dev/tests/verification/Resources/ActionGroupWithNoArguments.txt index e5b9717c2..383164241 100644 --- a/dev/tests/verification/Resources/ActionGroupWithNoArguments.txt +++ b/dev/tests/verification/Resources/ActionGroupWithNoArguments.txt @@ -32,4 +32,10 @@ class ActionGroupWithNoArgumentsCest $I->wait(1); // stepKey: waitForNothingActionGroup $I->comment("Exiting Action Group [actionGroup] actionGroupWithoutArguments"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt b/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt index c0bde006d..97a060d1c 100644 --- a/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt +++ b/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt @@ -71,4 +71,10 @@ class ActionGroupWithNoDefaultTestCest $I->comment("Exiting Action Group [actionGroupWithDataOverride1] FunctionalActionGroupNoDefault"); $I->click("loginButton"); // stepKey: step6 } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ActionGroupWithParameterizedElementWithHyphen.txt b/dev/tests/verification/Resources/ActionGroupWithParameterizedElementWithHyphen.txt index 812285111..53657a2ae 100644 --- a/dev/tests/verification/Resources/ActionGroupWithParameterizedElementWithHyphen.txt +++ b/dev/tests/verification/Resources/ActionGroupWithParameterizedElementWithHyphen.txt @@ -30,4 +30,10 @@ class ActionGroupWithParameterizedElementWithHyphenCest $keyoneActionGroup = $I->executeJS("#element .full-width"); // stepKey: keyoneActionGroup $I->comment("Exiting Action Group [actionGroup] SectionArgumentWithParameterizedSelector"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ActionGroupWithParameterizedElementsWithStepKeyReferences.txt b/dev/tests/verification/Resources/ActionGroupWithParameterizedElementsWithStepKeyReferences.txt index 6c0c3fd0f..47d0566eb 100644 --- a/dev/tests/verification/Resources/ActionGroupWithParameterizedElementsWithStepKeyReferences.txt +++ b/dev/tests/verification/Resources/ActionGroupWithParameterizedElementsWithStepKeyReferences.txt @@ -35,4 +35,10 @@ class ActionGroupWithParameterizedElementsWithStepKeyReferencesCest $I->seeElement("//div[@name='Tiberius'][@class={$testVariableActionGroup}][@data-element='{$testVariable2ActionGroup}'][" . $I->retrieveEntityField('createSimpleData', 'name', 'test') . "]"); // stepKey: see1ActionGroup $I->comment("Exiting Action Group [actionGroup] actionGroupWithParametrizedSelectors"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ActionGroupWithPassedArgumentAndStringSelectorParam.txt b/dev/tests/verification/Resources/ActionGroupWithPassedArgumentAndStringSelectorParam.txt index 6614a320d..31771d938 100644 --- a/dev/tests/verification/Resources/ActionGroupWithPassedArgumentAndStringSelectorParam.txt +++ b/dev/tests/verification/Resources/ActionGroupWithPassedArgumentAndStringSelectorParam.txt @@ -32,4 +32,10 @@ class ActionGroupWithPassedArgumentAndStringSelectorParamCest $I->see("John" . msq("UniquePerson"), "#element .test1"); // stepKey: seeFirstNameActionGroup $I->comment("Exiting Action Group [actionGroup] actionGroupWithDefaultArgumentAndStringSelectorParam"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt b/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt index c1905ff39..3943f1271 100644 --- a/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt +++ b/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt @@ -72,4 +72,10 @@ class ActionGroupWithPersistedDataCest $I->see("#element ." . $I->retrieveEntityField('createPerson', 'firstname', 'test')); // stepKey: see1ActionGroupWithPersistedData1 $I->comment("Exiting Action Group [actionGroupWithPersistedData1] FunctionalActionGroupWithData"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ActionGroupWithSectionAndDataAsArguments.txt b/dev/tests/verification/Resources/ActionGroupWithSectionAndDataAsArguments.txt index b3dcc585f..71519b234 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSectionAndDataAsArguments.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSectionAndDataAsArguments.txt @@ -30,4 +30,10 @@ class ActionGroupWithSectionAndDataAsArgumentsCest $I->waitForElementVisible("#element .John", 10); // stepKey: arg1ActionGroup $I->comment("Exiting Action Group [actionGroup] actionGroupWithSectionAndData"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromDefaultArgument.txt b/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromDefaultArgument.txt index 6d540cb95..72ade673a 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromDefaultArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromDefaultArgument.txt @@ -32,4 +32,10 @@ class ActionGroupWithSimpleDataUsageFromDefaultArgumentCest $I->see("stringLiteral", "#element .stringLiteral"); // stepKey: see1ActionGroup $I->comment("Exiting Action Group [actionGroup] actionGroupWithStringUsage"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromPassedArgument.txt b/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromPassedArgument.txt index 826671a63..b19c6b20f 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromPassedArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromPassedArgument.txt @@ -59,4 +59,10 @@ class ActionGroupWithSimpleDataUsageFromPassedArgumentCest $I->see($I->retrieveEntityField('simpleData', 'firstname[data_index]', 'test'), "#element ." . $I->retrieveEntityField('simpleData', 'firstname[data_index]', 'test')); // stepKey: see1ActionGroup7 $I->comment("Exiting Action Group [actionGroup7] actionGroupWithEntityUsage"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromDefaultArgument.txt b/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromDefaultArgument.txt index 5e64aded3..81712b6fe 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromDefaultArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromDefaultArgument.txt @@ -32,4 +32,10 @@ class ActionGroupWithSingleParameterSelectorFromDefaultArgumentCest $I->see("Doe", "#element .John"); // stepKey: seeLastNameActionGroup $I->comment("Exiting Action Group [actionGroup] actionGroupWithSingleParameterSelectorFromArgument"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromPassedArgument.txt b/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromPassedArgument.txt index e71a8a716..eeb346b60 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromPassedArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromPassedArgument.txt @@ -32,4 +32,10 @@ class ActionGroupWithSingleParameterSelectorFromPassedArgumentCest $I->see("Doe", "#element .John" . msq("UniquePerson")); // stepKey: seeLastNameActionGroup $I->comment("Exiting Action Group [actionGroup] actionGroupWithSingleParameterSelectorFromArgument"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt b/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt index 7d8fae946..ef20ee94b 100644 --- a/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt +++ b/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt @@ -55,4 +55,10 @@ class ActionGroupWithStepKeyReferencesCest $action16ActionGroup = $I->grabValueFrom($action16ActionGroup); // stepKey: action16ActionGroup $I->comment("Exiting Action Group [actionGroup] FunctionActionGroupWithStepKeyReferences"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt b/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt index 18a205544..daba0ab12 100644 --- a/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt +++ b/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt @@ -71,4 +71,10 @@ class ActionGroupWithTopLevelPersistedDataCest $I->see("#element ." . $I->retrieveEntityField('createPersonParam', 'firstname', 'test')); // stepKey: see1ActionGroupWithPersistedData1 $I->comment("Exiting Action Group [actionGroupWithPersistedData1] FunctionalActionGroupWithData"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ActionsInDifferentModulesSuite.txt b/dev/tests/verification/Resources/ActionsInDifferentModulesSuite.txt index d4e1b6eb3..20bf7610f 100644 --- a/dev/tests/verification/Resources/ActionsInDifferentModulesSuite.txt +++ b/dev/tests/verification/Resources/ActionsInDifferentModulesSuite.txt @@ -36,6 +36,7 @@ class ActionsInDifferentModulesSuite extends \Codeception\GroupObject public function _before(\Codeception\Event\TestEvent $e) { + $this->testCount = $this->getTestCount(); $this->webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); $this->moduleContainer = $this->webDriver->getModuleContainer(); // increment test count per execution @@ -215,4 +216,21 @@ class ActionsInDifferentModulesSuite extends \Codeception\GroupObject } return $module; } + + /** + * Counts how many tests in group. + * + * @return integer + */ + private function getTestCount() + { + $config = $this->getGlobalConfig(); + if (empty($config['groups']) && empty($config['groups'][self::$group])) { + return $this->testCount; + } + $pathToGroupDir = TESTS_BP . DIRECTORY_SEPARATOR . array_first($config['groups'][self::$group]); + $pathToGroupCests = $pathToGroupDir . DIRECTORY_SEPARATOR . "*Cest.php"; + + return count(glob($pathToGroupCests)); + } } diff --git a/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt b/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt index 4bf9332b7..2ea282f07 100644 --- a/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt +++ b/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt @@ -68,4 +68,10 @@ class ArgumentWithSameNameAsElementCest $I->seeElement("#element .John"); // stepKey: see2ActionGroup1 $I->comment("Exiting Action Group [actionGroup1] FunctionalActionGroupWithTrickyArgument"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/AssertTest.txt b/dev/tests/verification/Resources/AssertTest.txt index c8435675b..c4fe946e4 100644 --- a/dev/tests/verification/Resources/AssertTest.txt +++ b/dev/tests/verification/Resources/AssertTest.txt @@ -160,4 +160,10 @@ class AssertTestCest $I->assertNotRegExp('/placeholder\/thumbnail\.jpg/', $getSimpleProductThumbnail); // stepKey: simpleThumbnailIsNotDefault $I->assertRegExp("#var\s+adminAnalyticsMetadata\s+=\s+{\s+(\"[\w_]+\":\s+\"[^\"]*?\",\s+)*?(\"[\w_]+\":\s+\"[^\"]*?\"\s+)};#s", $pageSource, "adminAnalyticsMetadata object is invalid"); // stepKey: validateadminAnalyticsMetadata } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/BasicActionGroupTest.txt b/dev/tests/verification/Resources/BasicActionGroupTest.txt index 95c31b813..e2bfdae7e 100644 --- a/dev/tests/verification/Resources/BasicActionGroupTest.txt +++ b/dev/tests/verification/Resources/BasicActionGroupTest.txt @@ -49,4 +49,10 @@ class BasicActionGroupTestCest $I->comment("Exiting Action Group [actionGroup1] FunctionalActionGroup"); $I->click("loginButton"); // stepKey: step6 } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/BasicFunctionalTest.txt b/dev/tests/verification/Resources/BasicFunctionalTest.txt index 29cfd9baf..e6ac37f12 100644 --- a/dev/tests/verification/Resources/BasicFunctionalTest.txt +++ b/dev/tests/verification/Resources/BasicFunctionalTest.txt @@ -185,4 +185,10 @@ class BasicFunctionalTestCest $I->waitForJS("someJsFunction", 30); // stepKey: waitForJSKey1 $I->waitForText("someInput", 30, ".functionalTestSelector"); // stepKey: waitForText1 } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/BasicMergeTest.txt b/dev/tests/verification/Resources/BasicMergeTest.txt index 8842d3d99..a32d6b50e 100644 --- a/dev/tests/verification/Resources/BasicMergeTest.txt +++ b/dev/tests/verification/Resources/BasicMergeTest.txt @@ -75,4 +75,10 @@ class BasicMergeTestCest $I->comment("Exiting Action Group [step8Merge] FunctionalActionGroupWithData"); $I->click("#step10MergedInResult"); // stepKey: step10 } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/CharacterReplacementTest.txt b/dev/tests/verification/Resources/CharacterReplacementTest.txt index 24d8e2ab1..3cdccd7e6 100644 --- a/dev/tests/verification/Resources/CharacterReplacementTest.txt +++ b/dev/tests/verification/Resources/CharacterReplacementTest.txt @@ -35,4 +35,10 @@ class CharacterReplacementTestCest $I->click("#`~!@#$%^&*()-_=+{}[]|\;:\".,></?() .`~!@#$%^&*()-_=+{}[]|\;:\".,></?()"); // stepKey: allChars5 $I->click("#words, and, commas, and, spaces .words, and, commas, and, spaces"); // stepKey: allChars6 } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt b/dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt index 72e924954..782eec26f 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt @@ -58,4 +58,10 @@ class ChildExtendedTestAddHooksCest public function ChildExtendedTestAddHooks(AcceptanceTester $I) { } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ChildExtendedTestMerging.txt b/dev/tests/verification/Resources/ChildExtendedTestMerging.txt index 7900ca9a0..dd8fba438 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestMerging.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestMerging.txt @@ -64,4 +64,10 @@ class ChildExtendedTestMergingCest $I->comment("After Comment"); $I->comment("Last Comment"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ChildExtendedTestNoParent.txt b/dev/tests/verification/Resources/ChildExtendedTestNoParent.txt index be775aba9..99695167c 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestNoParent.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestNoParent.txt @@ -33,4 +33,10 @@ class ChildExtendedTestNoParentCest { $scenario->skip("This test is skipped due to the following issues:No issues have been specified."); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ChildExtendedTestRemoveAction.txt b/dev/tests/verification/Resources/ChildExtendedTestRemoveAction.txt index d3017e010..2a0eddf57 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestRemoveAction.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestRemoveAction.txt @@ -58,4 +58,10 @@ class ChildExtendedTestRemoveActionCest public function ChildExtendedTestRemoveAction(AcceptanceTester $I) { } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ChildExtendedTestRemoveHookAction.txt b/dev/tests/verification/Resources/ChildExtendedTestRemoveHookAction.txt index 0988e5d71..2ab9eaf11 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestRemoveHookAction.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestRemoveHookAction.txt @@ -58,4 +58,10 @@ class ChildExtendedTestRemoveHookActionCest { $I->comment("Parent Comment"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ChildExtendedTestReplace.txt b/dev/tests/verification/Resources/ChildExtendedTestReplace.txt index 9d0a65a3b..daf1bfe2f 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestReplace.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestReplace.txt @@ -59,4 +59,10 @@ class ChildExtendedTestReplaceCest { $I->comment("Different Input"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ChildExtendedTestReplaceHook.txt b/dev/tests/verification/Resources/ChildExtendedTestReplaceHook.txt index c40b46fa0..67ef1b40e 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestReplaceHook.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestReplaceHook.txt @@ -59,4 +59,10 @@ class ChildExtendedTestReplaceHookCest { $I->comment("Parent Comment"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/DataActionsTest.txt b/dev/tests/verification/Resources/DataActionsTest.txt index 84a94174a..2c735ed35 100644 --- a/dev/tests/verification/Resources/DataActionsTest.txt +++ b/dev/tests/verification/Resources/DataActionsTest.txt @@ -43,4 +43,10 @@ class DataActionsTestCest $I->updateEntity("createdInBefore", "test", "entity",[]); // stepKey: updatedDataOutOfScope $I->deleteEntity("createdInBefore", "test"); // stepKey: deleteDataOutOfScope } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/DataReplacementTest.txt b/dev/tests/verification/Resources/DataReplacementTest.txt index b75d93f0d..f1d405750 100644 --- a/dev/tests/verification/Resources/DataReplacementTest.txt +++ b/dev/tests/verification/Resources/DataReplacementTest.txt @@ -89,4 +89,10 @@ class DataReplacementTestCest $I->dontSeeInSource("#element"); // stepKey: htmlReplace35 $I->dontSeeInSource("StringBefore #element StringAfter"); // stepKey: htmlReplace36 } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/DeprecatedEntitiesTest.txt b/dev/tests/verification/Resources/DeprecatedEntitiesTest.txt index 489cb66ea..4d0652bb3 100644 --- a/dev/tests/verification/Resources/DeprecatedEntitiesTest.txt +++ b/dev/tests/verification/Resources/DeprecatedEntitiesTest.txt @@ -31,4 +31,10 @@ class DeprecatedEntitiesTestCest $I->comment("Exiting Action Group [deprecatedActionGroup] DeprecatedActionGroup"); $I->amOnPage("/test.html"); // stepKey: amOnPage } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/DeprecatedTest.txt b/dev/tests/verification/Resources/DeprecatedTest.txt index 845d13912..71fc1de4d 100644 --- a/dev/tests/verification/Resources/DeprecatedTest.txt +++ b/dev/tests/verification/Resources/DeprecatedTest.txt @@ -31,4 +31,10 @@ class DeprecatedTestCest $I->comment("Exiting Action Group [deprecatedActionGroup] DeprecatedActionGroup"); $I->amOnPage("/test.html"); // stepKey: amOnPage } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ExecuteInSeleniumTest.txt b/dev/tests/verification/Resources/ExecuteInSeleniumTest.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/dev/tests/verification/Resources/ExecuteJsEscapingTest.txt b/dev/tests/verification/Resources/ExecuteJsEscapingTest.txt index ad3696e00..6d4de9ad1 100644 --- a/dev/tests/verification/Resources/ExecuteJsEscapingTest.txt +++ b/dev/tests/verification/Resources/ExecuteJsEscapingTest.txt @@ -32,4 +32,10 @@ class ExecuteJsEscapingTestCest $hookPersistedDataNotEscaped = $I->executeJS("return " . $I->retrieveEntityField('persisted', 'data', 'test')); // stepKey: hookPersistedDataNotEscaped $addNewAttributeForRule = $I->executeJS("document.querySelector('entity option[value=" . $I->retrieveEntityField('productAttribute', 'attribute_code', 'test') . "]').setAttribute('selected', 'selected')"); // stepKey: addNewAttributeForRule } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ExtendParentDataTest.txt b/dev/tests/verification/Resources/ExtendParentDataTest.txt index 70cb6b70b..7e97473bd 100644 --- a/dev/tests/verification/Resources/ExtendParentDataTest.txt +++ b/dev/tests/verification/Resources/ExtendParentDataTest.txt @@ -33,4 +33,10 @@ class ExtendParentDataTestCest $I->searchAndMultiSelectOption("#selector", [msq("extendParentData") . "prename"]); // stepKey: originalPre $I->searchAndMultiSelectOption("#selector", ["postnameExtend" . msq("extendParentData")]); // stepKey: secondUniquePre } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ExtendedActionGroup.txt b/dev/tests/verification/Resources/ExtendedActionGroup.txt index 9ed588df4..71e9121fa 100644 --- a/dev/tests/verification/Resources/ExtendedActionGroup.txt +++ b/dev/tests/verification/Resources/ExtendedActionGroup.txt @@ -34,4 +34,10 @@ class ExtendedActionGroupCest $I->assertCount(8000, $grabProductsActionGroup); // stepKey: assertSecondCountActionGroup $I->comment("Exiting Action Group [actionGroup] extendTestActionGroup"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ExtendedActionGroupReturningValueTest.txt b/dev/tests/verification/Resources/ExtendedActionGroupReturningValueTest.txt index 2f26a6463..9b89b3825 100644 --- a/dev/tests/verification/Resources/ExtendedActionGroupReturningValueTest.txt +++ b/dev/tests/verification/Resources/ExtendedActionGroupReturningValueTest.txt @@ -37,4 +37,10 @@ class ExtendedActionGroupReturningValueTestCest $I->see($actionGroupReturningValue, "#element .{$actionGroupReturningValue}"); // stepKey: see1ActionGroupWithStringUsage1 $I->comment("Exiting Action Group [actionGroupWithStringUsage1] actionGroupWithStringUsage"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ExtendedChildActionGroupReturningValueTest.txt b/dev/tests/verification/Resources/ExtendedChildActionGroupReturningValueTest.txt index d043a5c04..e0d9e29f6 100644 --- a/dev/tests/verification/Resources/ExtendedChildActionGroupReturningValueTest.txt +++ b/dev/tests/verification/Resources/ExtendedChildActionGroupReturningValueTest.txt @@ -40,4 +40,10 @@ class ExtendedChildActionGroupReturningValueTestCest $I->see($extendedActionGroupReturningValue, "#element .{$extendedActionGroupReturningValue}"); // stepKey: see1ActionGroupWithStringUsage1 $I->comment("Exiting Action Group [actionGroupWithStringUsage1] actionGroupWithStringUsage"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ExtendedChildTestInSuiteCest.txt b/dev/tests/verification/Resources/ExtendedChildTestInSuiteCest.txt index d1f74abe1..2d1c91630 100644 --- a/dev/tests/verification/Resources/ExtendedChildTestInSuiteCest.txt +++ b/dev/tests/verification/Resources/ExtendedChildTestInSuiteCest.txt @@ -59,4 +59,10 @@ class ExtendedChildTestInSuiteCest { $I->comment("Different Input"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt b/dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt index d9f8a72e6..30d188c9d 100644 --- a/dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt +++ b/dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt @@ -58,4 +58,10 @@ class ExtendedChildTestNotInSuiteCest { $I->comment("Different Input"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ExtendedParameterArrayTest.txt b/dev/tests/verification/Resources/ExtendedParameterArrayTest.txt index d09e9a0b6..306f10fee 100644 --- a/dev/tests/verification/Resources/ExtendedParameterArrayTest.txt +++ b/dev/tests/verification/Resources/ExtendedParameterArrayTest.txt @@ -32,4 +32,10 @@ class ExtendParentDataTestCest $I->searchAndMultiSelectOption("#selector", [msq("extendParentData") . "prename"]); $I->searchAndMultiSelectOption("#selector", ["postnameExtend" . msq("extendParentData")]); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ExtendedRemoveActionGroup.txt b/dev/tests/verification/Resources/ExtendedRemoveActionGroup.txt index b593a9231..792a4ac4f 100644 --- a/dev/tests/verification/Resources/ExtendedRemoveActionGroup.txt +++ b/dev/tests/verification/Resources/ExtendedRemoveActionGroup.txt @@ -29,4 +29,10 @@ class ExtendedRemoveActionGroupCest $I->comment("Entering Action Group [actionGroup] extendRemoveTestActionGroup"); $I->comment("Exiting Action Group [actionGroup] extendRemoveTestActionGroup"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ExtendingSkippedTest.txt b/dev/tests/verification/Resources/ExtendingSkippedTest.txt index 0202f6d4f..5f1bfefe4 100644 --- a/dev/tests/verification/Resources/ExtendingSkippedTest.txt +++ b/dev/tests/verification/Resources/ExtendingSkippedTest.txt @@ -32,4 +32,10 @@ class ExtendingSkippedTestCest { $scenario->skip("This test is skipped due to the following issues:\nParentTestIsSkipped"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/GroupSkipGenerationTest.txt b/dev/tests/verification/Resources/GroupSkipGenerationTest.txt index 89884df82..1a6156cac 100644 --- a/dev/tests/verification/Resources/GroupSkipGenerationTest.txt +++ b/dev/tests/verification/Resources/GroupSkipGenerationTest.txt @@ -31,4 +31,10 @@ class GroupSkipGenerationTestCest public function GroupSkipGenerationTest(AcceptanceTester $I) { } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/HookActionsTest.txt b/dev/tests/verification/Resources/HookActionsTest.txt index 0b77325c1..0ffabfd9e 100644 --- a/dev/tests/verification/Resources/HookActionsTest.txt +++ b/dev/tests/verification/Resources/HookActionsTest.txt @@ -57,4 +57,10 @@ class HookActionsTestCest public function HookActionsTest(AcceptanceTester $I) { } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/LocatorFunctionTest.txt b/dev/tests/verification/Resources/LocatorFunctionTest.txt index 76c48a921..deffe887b 100644 --- a/dev/tests/verification/Resources/LocatorFunctionTest.txt +++ b/dev/tests/verification/Resources/LocatorFunctionTest.txt @@ -40,4 +40,10 @@ class LocatorFunctionTestCest $I->click(Locator::contains("string1", $I->retrieveEntityField('data', 'key1', 'test'))); // stepKey: TwoParamMix2 $I->click(Locator::contains("John", $I->retrieveEntityField('data', 'key1', 'test'))); // stepKey: TwoParamMix3 } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/MergeMassViaInsertAfter.txt b/dev/tests/verification/Resources/MergeMassViaInsertAfter.txt index 1a94b90a6..250cb8b18 100644 --- a/dev/tests/verification/Resources/MergeMassViaInsertAfter.txt +++ b/dev/tests/verification/Resources/MergeMassViaInsertAfter.txt @@ -33,4 +33,10 @@ class MergeMassViaInsertAfterCest $I->click("#mergeThree"); // stepKey: clickThree $I->fillField("#baz", "baz"); // stepKey: fillField3 } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/MergeMassViaInsertBefore.txt b/dev/tests/verification/Resources/MergeMassViaInsertBefore.txt index 12b073bfb..2e14981b0 100644 --- a/dev/tests/verification/Resources/MergeMassViaInsertBefore.txt +++ b/dev/tests/verification/Resources/MergeMassViaInsertBefore.txt @@ -33,4 +33,10 @@ class MergeMassViaInsertBeforeCest $I->fillField("#bar", "bar"); // stepKey: fillField2 $I->fillField("#baz", "baz"); // stepKey: fillField3 } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/MergeSkip.txt b/dev/tests/verification/Resources/MergeSkip.txt index d08f52b56..122809112 100644 --- a/dev/tests/verification/Resources/MergeSkip.txt +++ b/dev/tests/verification/Resources/MergeSkip.txt @@ -28,4 +28,10 @@ class MergeSkipCest { $scenario->skip("This test is skipped due to the following issues:\nIssue5"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/MergedActionGroupReturningValueTest.txt b/dev/tests/verification/Resources/MergedActionGroupReturningValueTest.txt index a4689779b..ef7960d21 100644 --- a/dev/tests/verification/Resources/MergedActionGroupReturningValueTest.txt +++ b/dev/tests/verification/Resources/MergedActionGroupReturningValueTest.txt @@ -74,4 +74,10 @@ class MergedActionGroupReturningValueTestCest $I->see($actionGroupWithReturnValue1, "#element .{$actionGroupWithReturnValue1}"); // stepKey: see1ActionGroupWithStringUsage1 $I->comment("Exiting Action Group [actionGroupWithStringUsage1] actionGroupWithStringUsage"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/MergedActionGroupTest.txt b/dev/tests/verification/Resources/MergedActionGroupTest.txt index c8401874d..f592a9806 100644 --- a/dev/tests/verification/Resources/MergedActionGroupTest.txt +++ b/dev/tests/verification/Resources/MergedActionGroupTest.txt @@ -70,4 +70,10 @@ class MergedActionGroupTestCest $I->click(".merge .Dane"); // stepKey: myMergedClickActionGroupForMerge $I->comment("Exiting Action Group [actionGroupForMerge] FunctionalActionGroupForMerge"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/MergedReferencesTest.txt b/dev/tests/verification/Resources/MergedReferencesTest.txt index 74f780aac..678ae79fe 100644 --- a/dev/tests/verification/Resources/MergedReferencesTest.txt +++ b/dev/tests/verification/Resources/MergedReferencesTest.txt @@ -60,4 +60,10 @@ class MergedReferencesTestCest $I->fillField("#merge", "merged"); // stepKey: fillField1 $I->fillField("#newElement", "newField"); // stepKey: fillField2 } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/MultipleActionGroupsTest.txt b/dev/tests/verification/Resources/MultipleActionGroupsTest.txt index 46673f473..6a387eb76 100644 --- a/dev/tests/verification/Resources/MultipleActionGroupsTest.txt +++ b/dev/tests/verification/Resources/MultipleActionGroupsTest.txt @@ -80,4 +80,10 @@ class MultipleActionGroupsTestCest $I->see("#element .John"); // stepKey: see1ActionGroupWithDataOverride2 $I->comment("Exiting Action Group [actionGroupWithDataOverride2] FunctionalActionGroupWithData"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/PageReplacementTest.txt b/dev/tests/verification/Resources/PageReplacementTest.txt index 6f75ee096..a83a8ac02 100644 --- a/dev/tests/verification/Resources/PageReplacementTest.txt +++ b/dev/tests/verification/Resources/PageReplacementTest.txt @@ -39,4 +39,10 @@ class PageReplacementTestCest $I->amOnPage((getenv("MAGENTO_BACKEND_BASE_URL") ? rtrim(getenv("MAGENTO_BACKEND_BASE_URL"), "/") : "") . "/" . getenv("MAGENTO_BACKEND_NAME") . "/StringLiteral/page.html"); // stepKey: oneParamAdminPageString $I->amOnUrl("http://myFullUrl.com/"); // stepKey: onExternalPage } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ParameterArrayTest.txt b/dev/tests/verification/Resources/ParameterArrayTest.txt index 8918bb619..b6ed5ac8c 100644 --- a/dev/tests/verification/Resources/ParameterArrayTest.txt +++ b/dev/tests/verification/Resources/ParameterArrayTest.txt @@ -50,4 +50,10 @@ class ParameterArrayTestCest $I->pressKey("#selector", ['ctrl', 'a'],'new', 1, ['ctrl'], ['shift', 'ctrl', 'del'], 0, [$I->retrieveEntityField('simpleDataKey', 'name', 'test'), $I->retrieveEntityField('simpleDataKey', 'name', 'test')]); // stepKey: pressKey005 $I->pressKey("#selector", ['ctrl', 'a'],'new', 1, ['ctrl'], ['shift', 'ctrl', 'del'], [msq("simpleParamData") . "prename", "postname" . msq("simpleParamData")]); // stepKey: pressKey006 } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/ParentExtendedTest.txt b/dev/tests/verification/Resources/ParentExtendedTest.txt index 5606b2ac3..3a035ede7 100644 --- a/dev/tests/verification/Resources/ParentExtendedTest.txt +++ b/dev/tests/verification/Resources/ParentExtendedTest.txt @@ -59,4 +59,10 @@ class ParentExtendedTestCest { $I->comment("Parent Comment"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/PersistedAndXmlEntityArguments.txt b/dev/tests/verification/Resources/PersistedAndXmlEntityArguments.txt index d49b99306..9e991362a 100644 --- a/dev/tests/verification/Resources/PersistedAndXmlEntityArguments.txt +++ b/dev/tests/verification/Resources/PersistedAndXmlEntityArguments.txt @@ -30,4 +30,10 @@ class PersistedAndXmlEntityArgumentsCest $I->seeInCurrentUrl("/" . $I->retrieveEntityField('persistedInTest', 'urlKey', 'test') . ".html?___store=" . msq("uniqueData") . "John"); // stepKey: checkUrlAfterGroup $I->comment("Exiting Action Group [afterGroup] FunctionalActionGroupWithXmlAndPersistedData"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/PersistedReplacementTest.txt b/dev/tests/verification/Resources/PersistedReplacementTest.txt index eb1c9995d..f0609e4a8 100644 --- a/dev/tests/verification/Resources/PersistedReplacementTest.txt +++ b/dev/tests/verification/Resources/PersistedReplacementTest.txt @@ -59,4 +59,10 @@ class PersistedReplacementTestCest $I->dontSeeInSource("StringBefore " . $I->retrieveEntityField('createData1', 'firstname', 'test') . " StringAfter"); // stepKey: htmlReplace11 $I->dontSeeInSource("#" . getenv("MAGENTO_BASE_URL") . "#" . $I->retrieveEntityField('createdData', 'firstname', 'test')); // stepKey: htmlReplace12 } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt b/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt index 426003bc2..b966d7ca6 100644 --- a/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt +++ b/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt @@ -49,4 +49,10 @@ class PersistenceActionGroupAppendingTestCest $I->comment($I->retrieveEntityField('createDataACTIONGROUP', 'field', 'test')); $I->comment("Exiting Action Group [ACTIONGROUP] DataPersistenceAppendingActionGroup"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt b/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt index 41251d2fb..34409d108 100644 --- a/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt +++ b/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt @@ -61,4 +61,10 @@ class PersistenceCustomFieldsTestCest $I->createEntity("createData3AGKEY", "test", "entity3", [], $createData3AGKEYFields); // stepKey: createData3AGKEY $I->comment("Exiting Action Group [AGKEY] DataPersistenceSelfReferenceActionGroup"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/SectionReplacementTest.txt b/dev/tests/verification/Resources/SectionReplacementTest.txt index 109c198eb..8b3eadc1b 100644 --- a/dev/tests/verification/Resources/SectionReplacementTest.txt +++ b/dev/tests/verification/Resources/SectionReplacementTest.txt @@ -63,4 +63,10 @@ class SectionReplacementTestCest $I->click("(//div[@data-role='slide'])[1]/a[@data-element='link'][contains(@href,'')]"); // stepKey: selectorParamWithEmptyString $I->click("(//div[@data-role='slide'])[1]/a[@data-element='link'][contains(@href,' ')]"); // stepKey: selectorParamWithASpace } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/SkippedTest.txt b/dev/tests/verification/Resources/SkippedTest.txt index 7dd9ba280..fdeadf256 100644 --- a/dev/tests/verification/Resources/SkippedTest.txt +++ b/dev/tests/verification/Resources/SkippedTest.txt @@ -31,4 +31,10 @@ class SkippedTestCest { $scenario->skip("This test is skipped due to the following issues:\nSkippedValue"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/SkippedTestTwoIssues.txt b/dev/tests/verification/Resources/SkippedTestTwoIssues.txt index 0087ba92d..0eeebd4fd 100644 --- a/dev/tests/verification/Resources/SkippedTestTwoIssues.txt +++ b/dev/tests/verification/Resources/SkippedTestTwoIssues.txt @@ -31,4 +31,10 @@ class SkippedTestTwoIssuesCest { $scenario->skip("This test is skipped due to the following issues:\nSkippedValue\nSecondSkippedValue"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/SkippedTestWithHooks.txt b/dev/tests/verification/Resources/SkippedTestWithHooks.txt index 6b2682c49..a33f64108 100644 --- a/dev/tests/verification/Resources/SkippedTestWithHooks.txt +++ b/dev/tests/verification/Resources/SkippedTestWithHooks.txt @@ -31,4 +31,10 @@ class SkippedTestWithHooksCest { $scenario->skip("This test is skipped due to the following issues:\nSkippedValue"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/XmlCommentedActionGroupTest.txt b/dev/tests/verification/Resources/XmlCommentedActionGroupTest.txt index 0eb546335..5765aab13 100644 --- a/dev/tests/verification/Resources/XmlCommentedActionGroupTest.txt +++ b/dev/tests/verification/Resources/XmlCommentedActionGroupTest.txt @@ -33,4 +33,10 @@ class XmlCommentedActionGroupTestCest $I->see("John", "#element .test1"); // stepKey: seeFirstNameActionGroup $I->comment("Exiting Action Group [actionGroup] XmlCommentedActionGroup"); } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/XmlCommentedTest.txt b/dev/tests/verification/Resources/XmlCommentedTest.txt index 47d984d9e..663732493 100644 --- a/dev/tests/verification/Resources/XmlCommentedTest.txt +++ b/dev/tests/verification/Resources/XmlCommentedTest.txt @@ -70,4 +70,10 @@ class XmlCommentedTestCest $I->comment("<cancelPopup stepKey=\"cancelPopupKey1\"/>"); $I->checkOption(".functionalTestSelector"); // stepKey: checkOptionKey1 } + + public function _passed(AcceptanceTester $I) + { + // Deleting itself so that we can rerun only failed tests. + unlink(__FILE__); + } } diff --git a/dev/tests/verification/Resources/functionalSuiteHooks.txt b/dev/tests/verification/Resources/functionalSuiteHooks.txt index 3156a59dd..416678b68 100644 --- a/dev/tests/verification/Resources/functionalSuiteHooks.txt +++ b/dev/tests/verification/Resources/functionalSuiteHooks.txt @@ -36,6 +36,7 @@ class functionalSuiteHooks extends \Codeception\GroupObject public function _before(\Codeception\Event\TestEvent $e) { + $this->testCount = $this->getTestCount(); $this->webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); $this->moduleContainer = $this->webDriver->getModuleContainer(); // increment test count per execution @@ -198,4 +199,21 @@ class functionalSuiteHooks extends \Codeception\GroupObject } return $module; } + + /** + * Counts how many tests in group. + * + * @return integer + */ + private function getTestCount() + { + $config = $this->getGlobalConfig(); + if (empty($config['groups']) && empty($config['groups'][self::$group])) { + return $this->testCount; + } + $pathToGroupDir = TESTS_BP . DIRECTORY_SEPARATOR . array_first($config['groups'][self::$group]); + $pathToGroupCests = $pathToGroupDir . DIRECTORY_SEPARATOR . "*Cest.php"; + + return count(glob($pathToGroupCests)); + } } diff --git a/dev/tests/verification/Resources/functionalSuiteWithComments.txt b/dev/tests/verification/Resources/functionalSuiteWithComments.txt index 02b50f092..7d5f827a4 100644 --- a/dev/tests/verification/Resources/functionalSuiteWithComments.txt +++ b/dev/tests/verification/Resources/functionalSuiteWithComments.txt @@ -36,6 +36,7 @@ class functionalSuiteWithComments extends \Codeception\GroupObject public function _before(\Codeception\Event\TestEvent $e) { + $this->testCount = $this->getTestCount(); $this->webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); $this->moduleContainer = $this->webDriver->getModuleContainer(); // increment test count per execution @@ -178,4 +179,21 @@ class functionalSuiteWithComments extends \Codeception\GroupObject } return $module; } + + /** + * Counts how many tests in group. + * + * @return integer + */ + private function getTestCount() + { + $config = $this->getGlobalConfig(); + if (empty($config['groups']) && empty($config['groups'][self::$group])) { + return $this->testCount; + } + $pathToGroupDir = TESTS_BP . DIRECTORY_SEPARATOR . array_first($config['groups'][self::$group]); + $pathToGroupCests = $pathToGroupDir . DIRECTORY_SEPARATOR . "*Cest.php"; + + return count(glob($pathToGroupCests)); + } } diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php index 16e621dfb..a8a44337d 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php @@ -109,10 +109,10 @@ function ($type, $buffer) use ($output) { /** * Returns a list of tests/suites which should have an additional run. * - * @param $failedTests + * @param string $failedTests * @return array */ - private function filterTestsForExecution($failedTests): array + private function filterTestsForExecution(string $failedTests): array { $testsOrGroupsToRerun = []; From dd29a86a23220921d837570c6febfbce7d855db5 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 22 Nov 2021 19:44:57 -0600 Subject: [PATCH 743/888] MQE-2669: Seprated a run:failed command to generate:failed and run:failed - update tests --- .../Resources/ChildExtendedTestNoParent.txt | 7 +------ .../Resources/ExtendingSkippedTest.txt | 7 +------ dev/tests/verification/Resources/MergeSkip.txt | 7 +------ dev/tests/verification/Resources/SkippedTest.txt | 7 +------ .../Resources/SkippedTestTwoIssues.txt | 7 +------ .../Resources/SkippedTestWithHooks.txt | 7 +------ .../Util/TestGenerator.php | 14 ++++++++------ 7 files changed, 14 insertions(+), 42 deletions(-) diff --git a/dev/tests/verification/Resources/ChildExtendedTestNoParent.txt b/dev/tests/verification/Resources/ChildExtendedTestNoParent.txt index 99695167c..779f89c7e 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestNoParent.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestNoParent.txt @@ -31,12 +31,7 @@ class ChildExtendedTestNoParentCest */ public function ChildExtendedTestNoParent(AcceptanceTester $I, \Codeception\Scenario $scenario) { - $scenario->skip("This test is skipped due to the following issues:No issues have been specified."); - } - - public function _passed(AcceptanceTester $I) - { - // Deleting itself so that we can rerun only failed tests. unlink(__FILE__); + $scenario->skip("This test is skipped due to the following issues:No issues have been specified."); } } diff --git a/dev/tests/verification/Resources/ExtendingSkippedTest.txt b/dev/tests/verification/Resources/ExtendingSkippedTest.txt index 5f1bfefe4..45b8614e4 100644 --- a/dev/tests/verification/Resources/ExtendingSkippedTest.txt +++ b/dev/tests/verification/Resources/ExtendingSkippedTest.txt @@ -30,12 +30,7 @@ class ExtendingSkippedTestCest */ public function ExtendingSkippedTest(AcceptanceTester $I, \Codeception\Scenario $scenario) { - $scenario->skip("This test is skipped due to the following issues:\nParentTestIsSkipped"); - } - - public function _passed(AcceptanceTester $I) - { - // Deleting itself so that we can rerun only failed tests. unlink(__FILE__); + $scenario->skip("This test is skipped due to the following issues:\nParentTestIsSkipped"); } } diff --git a/dev/tests/verification/Resources/MergeSkip.txt b/dev/tests/verification/Resources/MergeSkip.txt index 122809112..885d622ac 100644 --- a/dev/tests/verification/Resources/MergeSkip.txt +++ b/dev/tests/verification/Resources/MergeSkip.txt @@ -26,12 +26,7 @@ class MergeSkipCest */ public function MergeSkip(AcceptanceTester $I, \Codeception\Scenario $scenario) { - $scenario->skip("This test is skipped due to the following issues:\nIssue5"); - } - - public function _passed(AcceptanceTester $I) - { - // Deleting itself so that we can rerun only failed tests. unlink(__FILE__); + $scenario->skip("This test is skipped due to the following issues:\nIssue5"); } } diff --git a/dev/tests/verification/Resources/SkippedTest.txt b/dev/tests/verification/Resources/SkippedTest.txt index fdeadf256..b50145c0e 100644 --- a/dev/tests/verification/Resources/SkippedTest.txt +++ b/dev/tests/verification/Resources/SkippedTest.txt @@ -29,12 +29,7 @@ class SkippedTestCest */ public function SkippedTest(AcceptanceTester $I, \Codeception\Scenario $scenario) { - $scenario->skip("This test is skipped due to the following issues:\nSkippedValue"); - } - - public function _passed(AcceptanceTester $I) - { - // Deleting itself so that we can rerun only failed tests. unlink(__FILE__); + $scenario->skip("This test is skipped due to the following issues:\nSkippedValue"); } } diff --git a/dev/tests/verification/Resources/SkippedTestTwoIssues.txt b/dev/tests/verification/Resources/SkippedTestTwoIssues.txt index 0eeebd4fd..a494328ba 100644 --- a/dev/tests/verification/Resources/SkippedTestTwoIssues.txt +++ b/dev/tests/verification/Resources/SkippedTestTwoIssues.txt @@ -29,12 +29,7 @@ class SkippedTestTwoIssuesCest */ public function SkippedTestTwoIssues(AcceptanceTester $I, \Codeception\Scenario $scenario) { - $scenario->skip("This test is skipped due to the following issues:\nSkippedValue\nSecondSkippedValue"); - } - - public function _passed(AcceptanceTester $I) - { - // Deleting itself so that we can rerun only failed tests. unlink(__FILE__); + $scenario->skip("This test is skipped due to the following issues:\nSkippedValue\nSecondSkippedValue"); } } diff --git a/dev/tests/verification/Resources/SkippedTestWithHooks.txt b/dev/tests/verification/Resources/SkippedTestWithHooks.txt index a33f64108..15936c463 100644 --- a/dev/tests/verification/Resources/SkippedTestWithHooks.txt +++ b/dev/tests/verification/Resources/SkippedTestWithHooks.txt @@ -29,12 +29,7 @@ class SkippedTestWithHooksCest */ public function SkippedTestWithHooks(AcceptanceTester $I, \Codeception\Scenario $scenario) { - $scenario->skip("This test is skipped due to the following issues:\nSkippedValue"); - } - - public function _passed(AcceptanceTester $I) - { - // Deleting itself so that we can rerun only failed tests. unlink(__FILE__); + $scenario->skip("This test is skipped due to the following issues:\nSkippedValue"); } } diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index b1638a548..8ea831963 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1812,12 +1812,14 @@ private function generateTestPhp($test) $testPhp .= $steps; $testPhp .= "\t}\n"; - $testPhp .= PHP_EOL; - $testPhp .= sprintf("\tpublic function _passed(%s)\n", $dependencies); - $testPhp .= "\t{\n"; - $testPhp .= "\t\t// Deleting itself so that we can rerun only failed tests." . PHP_EOL; - $testPhp .= "\t\tunlink(__FILE__);" . PHP_EOL; - $testPhp .= "\t}\n"; + if (!isset($skipString)) { + $testPhp .= PHP_EOL; + $testPhp .= sprintf("\tpublic function _passed(%s)\n", $dependencies); + $testPhp .= "\t{\n"; + $testPhp .= "\t\t// Deleting itself so that we can rerun only failed tests." . PHP_EOL; + $testPhp .= "\t\tunlink(__FILE__);" . PHP_EOL; + $testPhp .= "\t}\n"; + } return $testPhp; } From 41c14d4596a135a63507a5d1473c8b90edc9426b Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Tue, 23 Nov 2021 12:24:11 -0600 Subject: [PATCH 744/888] MQE-2669: Seprated a run:failed command to generate:failed and run:failed - fix a bug --- .../Console/RunTestFailedCommand.php | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php index a8a44337d..1614fc84c 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php @@ -109,10 +109,10 @@ function ($type, $buffer) use ($output) { /** * Returns a list of tests/suites which should have an additional run. * - * @param string $failedTests + * @param array $failedTests * @return array */ - private function filterTestsForExecution(string $failedTests): array + private function filterTestsForExecution(array $failedTests): array { $testsOrGroupsToRerun = []; @@ -126,7 +126,10 @@ private function filterTestsForExecution(string $failedTests): array if ($suiteName === self::DEFAULT_TEST_GROUP) { $testsOrGroupsToRerun[] = $testPath; } else { - $testsOrGroupsToRerun[] = "-g " . $suiteName; + $group = "-g " . $suiteName; + if (!in_array($group, $testsOrGroupsToRerun)) { + $testsOrGroupsToRerun[] = $group; + } } } } @@ -138,11 +141,16 @@ private function filterTestsForExecution(string $failedTests): array * Returns an array of tests read from the failed test file in _output * * @param string $filePath - * @return array|boolean + * @return array */ - private function readFailedTestFile($filePath) + private function readFailedTestFile(string $filePath): array { - return file($filePath, FILE_IGNORE_NEW_LINES); + $data = []; + if (file_exists($filePath)) { + $file = file($filePath, FILE_IGNORE_NEW_LINES); + $data = $file === false ? [] : $file; + } + return $data; } /** From 3e0def302cc27b0abccfef3c164103b83cbc4ec4 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Tue, 23 Nov 2021 13:22:06 -0600 Subject: [PATCH 745/888] MQE-2669: Seprated a run:failed command to generate:failed and run:failed - fix a bug --- .../Suite/views/SuiteClass.mustache | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Suite/views/SuiteClass.mustache b/src/Magento/FunctionalTestingFramework/Suite/views/SuiteClass.mustache index 1a4dde251..83fed59d9 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/views/SuiteClass.mustache +++ b/src/Magento/FunctionalTestingFramework/Suite/views/SuiteClass.mustache @@ -181,12 +181,17 @@ class {{suiteName}} extends \Codeception\GroupObject private function getTestCount() { $config = $this->getGlobalConfig(); - if (empty($config['groups']) && empty($config['groups'][self::$group])) { + if (empty($config['groups']) || empty($config['groups'][self::$group])) { return $this->testCount; } $pathToGroupDir = TESTS_BP . DIRECTORY_SEPARATOR . array_first($config['groups'][self::$group]); - $pathToGroupCests = $pathToGroupDir . DIRECTORY_SEPARATOR . "*Cest.php"; + $pathToGroupCests = $pathToGroupDir . "*Cest.php"; - return count(glob($pathToGroupCests)); + $files = glob($pathToGroupCests); + if (is_array($files)) { + return count($files); + } + + return $this->testCount; } } From 8294c568b5158e6432acc16d2a255e1c28267cda Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Tue, 23 Nov 2021 13:23:21 -0600 Subject: [PATCH 746/888] MQE-2669: Seprated a run:failed command to generate:failed and run:failed - fix a bug --- .../Resources/ActionsInDifferentModulesSuite.txt | 11 ++++++++--- .../verification/Resources/functionalSuiteHooks.txt | 11 ++++++++--- .../Resources/functionalSuiteWithComments.txt | 11 ++++++++--- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/dev/tests/verification/Resources/ActionsInDifferentModulesSuite.txt b/dev/tests/verification/Resources/ActionsInDifferentModulesSuite.txt index 20bf7610f..35d04d385 100644 --- a/dev/tests/verification/Resources/ActionsInDifferentModulesSuite.txt +++ b/dev/tests/verification/Resources/ActionsInDifferentModulesSuite.txt @@ -225,12 +225,17 @@ class ActionsInDifferentModulesSuite extends \Codeception\GroupObject private function getTestCount() { $config = $this->getGlobalConfig(); - if (empty($config['groups']) && empty($config['groups'][self::$group])) { + if (empty($config['groups']) || empty($config['groups'][self::$group])) { return $this->testCount; } $pathToGroupDir = TESTS_BP . DIRECTORY_SEPARATOR . array_first($config['groups'][self::$group]); - $pathToGroupCests = $pathToGroupDir . DIRECTORY_SEPARATOR . "*Cest.php"; + $pathToGroupCests = $pathToGroupDir . "*Cest.php"; - return count(glob($pathToGroupCests)); + $files = glob($pathToGroupCests); + if (is_array($files)) { + return count($files); + } + + return $this->testCount; } } diff --git a/dev/tests/verification/Resources/functionalSuiteHooks.txt b/dev/tests/verification/Resources/functionalSuiteHooks.txt index 416678b68..7f00b67a8 100644 --- a/dev/tests/verification/Resources/functionalSuiteHooks.txt +++ b/dev/tests/verification/Resources/functionalSuiteHooks.txt @@ -208,12 +208,17 @@ class functionalSuiteHooks extends \Codeception\GroupObject private function getTestCount() { $config = $this->getGlobalConfig(); - if (empty($config['groups']) && empty($config['groups'][self::$group])) { + if (empty($config['groups']) || empty($config['groups'][self::$group])) { return $this->testCount; } $pathToGroupDir = TESTS_BP . DIRECTORY_SEPARATOR . array_first($config['groups'][self::$group]); - $pathToGroupCests = $pathToGroupDir . DIRECTORY_SEPARATOR . "*Cest.php"; + $pathToGroupCests = $pathToGroupDir . "*Cest.php"; - return count(glob($pathToGroupCests)); + $files = glob($pathToGroupCests); + if (is_array($files)) { + return count($files); + } + + return $this->testCount; } } diff --git a/dev/tests/verification/Resources/functionalSuiteWithComments.txt b/dev/tests/verification/Resources/functionalSuiteWithComments.txt index 7d5f827a4..0af9f2bee 100644 --- a/dev/tests/verification/Resources/functionalSuiteWithComments.txt +++ b/dev/tests/verification/Resources/functionalSuiteWithComments.txt @@ -188,12 +188,17 @@ class functionalSuiteWithComments extends \Codeception\GroupObject private function getTestCount() { $config = $this->getGlobalConfig(); - if (empty($config['groups']) && empty($config['groups'][self::$group])) { + if (empty($config['groups']) || empty($config['groups'][self::$group])) { return $this->testCount; } $pathToGroupDir = TESTS_BP . DIRECTORY_SEPARATOR . array_first($config['groups'][self::$group]); - $pathToGroupCests = $pathToGroupDir . DIRECTORY_SEPARATOR . "*Cest.php"; + $pathToGroupCests = $pathToGroupDir . "*Cest.php"; - return count(glob($pathToGroupCests)); + $files = glob($pathToGroupCests); + if (is_array($files)) { + return count($files); + } + + return $this->testCount; } } From a3274a32306b172d63682f42604f02d5ac59ac1d Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Tue, 23 Nov 2021 13:37:55 -0600 Subject: [PATCH 747/888] MQE-2669: Seprated a run:failed command to generate:failed and run:failed - fix a bug --- .../Resources/ActionsInDifferentModulesSuite.txt | 7 +++++-- dev/tests/verification/Resources/functionalSuiteHooks.txt | 7 +++++-- .../verification/Resources/functionalSuiteWithComments.txt | 7 +++++-- .../Suite/views/SuiteClass.mustache | 7 +++++-- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/dev/tests/verification/Resources/ActionsInDifferentModulesSuite.txt b/dev/tests/verification/Resources/ActionsInDifferentModulesSuite.txt index 35d04d385..116eff358 100644 --- a/dev/tests/verification/Resources/ActionsInDifferentModulesSuite.txt +++ b/dev/tests/verification/Resources/ActionsInDifferentModulesSuite.txt @@ -36,7 +36,6 @@ class ActionsInDifferentModulesSuite extends \Codeception\GroupObject public function _before(\Codeception\Event\TestEvent $e) { - $this->testCount = $this->getTestCount(); $this->webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); $this->moduleContainer = $this->webDriver->getModuleContainer(); // increment test count per execution @@ -52,6 +51,8 @@ class ActionsInDifferentModulesSuite extends \Codeception\GroupObject private function executePreConditions() { if ($this->currentTestRun == 1) { + $this->testCount = $this->getTestCount(); + print sprintf(self::$HOOK_EXECUTION_INIT, "before"); try { @@ -233,7 +234,9 @@ class ActionsInDifferentModulesSuite extends \Codeception\GroupObject $files = glob($pathToGroupCests); if (is_array($files)) { - return count($files); + $qty = count($files); + print('In a group "' . self::$group . '" suite executor found ' . $qty . ' tests.' . PHP_EOL); + return $qty; } return $this->testCount; diff --git a/dev/tests/verification/Resources/functionalSuiteHooks.txt b/dev/tests/verification/Resources/functionalSuiteHooks.txt index 7f00b67a8..243b7fecf 100644 --- a/dev/tests/verification/Resources/functionalSuiteHooks.txt +++ b/dev/tests/verification/Resources/functionalSuiteHooks.txt @@ -36,7 +36,6 @@ class functionalSuiteHooks extends \Codeception\GroupObject public function _before(\Codeception\Event\TestEvent $e) { - $this->testCount = $this->getTestCount(); $this->webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); $this->moduleContainer = $this->webDriver->getModuleContainer(); // increment test count per execution @@ -52,6 +51,8 @@ class functionalSuiteHooks extends \Codeception\GroupObject private function executePreConditions() { if ($this->currentTestRun == 1) { + $this->testCount = $this->getTestCount(); + print sprintf(self::$HOOK_EXECUTION_INIT, "before"); try { @@ -216,7 +217,9 @@ class functionalSuiteHooks extends \Codeception\GroupObject $files = glob($pathToGroupCests); if (is_array($files)) { - return count($files); + $qty = count($files); + print('In a group "' . self::$group . '" suite executor found ' . $qty . ' tests.' . PHP_EOL); + return $qty; } return $this->testCount; diff --git a/dev/tests/verification/Resources/functionalSuiteWithComments.txt b/dev/tests/verification/Resources/functionalSuiteWithComments.txt index 0af9f2bee..186a2ae63 100644 --- a/dev/tests/verification/Resources/functionalSuiteWithComments.txt +++ b/dev/tests/verification/Resources/functionalSuiteWithComments.txt @@ -36,7 +36,6 @@ class functionalSuiteWithComments extends \Codeception\GroupObject public function _before(\Codeception\Event\TestEvent $e) { - $this->testCount = $this->getTestCount(); $this->webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); $this->moduleContainer = $this->webDriver->getModuleContainer(); // increment test count per execution @@ -52,6 +51,8 @@ class functionalSuiteWithComments extends \Codeception\GroupObject private function executePreConditions() { if ($this->currentTestRun == 1) { + $this->testCount = $this->getTestCount(); + print sprintf(self::$HOOK_EXECUTION_INIT, "before"); try { @@ -196,7 +197,9 @@ class functionalSuiteWithComments extends \Codeception\GroupObject $files = glob($pathToGroupCests); if (is_array($files)) { - return count($files); + $qty = count($files); + print('In a group "' . self::$group . '" suite executor found ' . $qty . ' tests.' . PHP_EOL); + return $qty; } return $this->testCount; diff --git a/src/Magento/FunctionalTestingFramework/Suite/views/SuiteClass.mustache b/src/Magento/FunctionalTestingFramework/Suite/views/SuiteClass.mustache index 83fed59d9..cf8fdd917 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/views/SuiteClass.mustache +++ b/src/Magento/FunctionalTestingFramework/Suite/views/SuiteClass.mustache @@ -43,7 +43,6 @@ class {{suiteName}} extends \Codeception\GroupObject {{#before}} public function _before(\Codeception\Event\TestEvent $e) { - $this->testCount = $this->getTestCount(); $this->webDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); $this->moduleContainer = $this->webDriver->getModuleContainer(); {{#helpers}} @@ -66,6 +65,8 @@ class {{suiteName}} extends \Codeception\GroupObject private function executePreConditions() { if ($this->currentTestRun == 1) { + $this->testCount = $this->getTestCount(); + print sprintf(self::$HOOK_EXECUTION_INIT, "before"); try { @@ -189,7 +190,9 @@ class {{suiteName}} extends \Codeception\GroupObject $files = glob($pathToGroupCests); if (is_array($files)) { - return count($files); + $qty = count($files); + print('In a group "' . self::$group . '" suite executor found ' . $qty . ' tests.' . PHP_EOL); + return $qty; } return $this->testCount; From 68e0ee814ceda9697ab1e43d3483eb0592d85147 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Tue, 23 Nov 2021 16:46:38 -0600 Subject: [PATCH 748/888] MQE-2669: Seprated a run:failed command to generate:failed and run:failed - add a simple unit test --- .../Console/RunTestFailedCommandTest.php | 53 +++++++++++++++++++ .../Console/RunTestFailedCommand.php | 2 +- 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/Console/RunTestFailedCommandTest.php diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Console/RunTestFailedCommandTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Console/RunTestFailedCommandTest.php new file mode 100644 index 000000000..5bba89de1 --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Console/RunTestFailedCommandTest.php @@ -0,0 +1,53 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace tests\unit\Magento\FunctionalTestFramework\Console; + +use Magento\FunctionalTestingFramework\Console\RunTestFailedCommand; + +class RunTestFailedCommandTest extends BaseGenerateCommandTest +{ + /** + * @throws \ReflectionException + */ + public function testMultipleTests(): void + { + $testFailedFile = [ + "tests/functional/tests/MFTF/_generated/default/SingleTestNoSuiteTest.php:SingleTestNoSuiteTest", + "tests/functional/tests/MFTF/_generated/SomeSpecificSuite/FirstTestSuiteTest.php:SingleTestSuiteTest", + "tests/functional/tests/MFTF/_generated/SomeSpecificSuite/SecondTestNoSuiteTest.php:SingleTestNoSuiteTest", + "tests/functional/tests/MFTF/_generated/SomeOtherSuite/SecondTestNoSuiteTest.php:SingleTestNoSuiteTest", + ]; + + $expectedResult = [ + "tests/functional/tests/MFTF/_generated/default/SingleTestNoSuiteTest.php", + "-g SomeSpecificSuite", + "-g SomeOtherSuite", + ]; + + $runFailed = new RunTestFailedCommand('run:failed'); + $filter = $this->invokePrivateMethod($runFailed, 'filterTestsForExecution', [$testFailedFile]); + $this->assertEquals($expectedResult, $filter); + } + + /** + * Invoking private method to be able to test it. + * NOTE: Bad practice don't repeat it. + * + * @param $object + * @param $methodName + * @param array $parameters + * @return mixed + * @throws \ReflectionException + */ + private function invokePrivateMethod(&$object, $methodName, array $parameters = []) + { + $reflection = new \ReflectionClass(get_class($object)); + $method = $reflection->getMethod($methodName); + $method->setAccessible(true); + return $method->invokeArgs($object, $parameters); + } +} diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php index 1614fc84c..96b376247 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php @@ -23,7 +23,7 @@ class RunTestFailedCommand extends BaseGenerateCommand /** * @var string */ - private $testsReRunFile = ""; + private $testsReRunFile = "rerun_tests"; /** * @var array From ed63e22ecc8cd2a5c0d79342f82f661449edbd4b Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Tue, 30 Nov 2021 11:14:32 -0600 Subject: [PATCH 749/888] MQE-3097: Release MFTF 3.7.1 --- CHANGELOG.md | 16 ++++++++++++++++ composer.json | 2 +- composer.lock | 3 +-- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25271e6e4..eaa96a63e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ Magento Functional Testing Framework Changelog ================================================ +3.7.1 +--------- + +### GitHub Pull Requests: +* [#873](https://github.com/magento/magento2-functional-testing-framework/pull/873) -- Add check for isBuiltin method (for PHP 8 compatibility) by @karyna-tsymbal-atwix + +### Updates +* Moved `hoa/console` to suggest section to avoid issues with PHP8.0 +* Update `vlucas/phpdotenv` to the latest versions +* `<seeInCurrentUrl />` encodes special character which caused test failed +* Add filter for groups, now we can generate tests with specific group annotation +* Seprated a `run:failed` command to `generate:failed` and `run:failed` + * `run:failed` command can execute failed tests without need to regenerate failed tests +* Deleting MagentoPwaWebDriver file and moving it to Pwa_tests repo + + 3.7.0 --------- diff --git a/composer.json b/composer.json index a0dc719ad..61ff7b158 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "3.7.0", + "version": "3.7.1", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index ca3820871..7c4e8d9c9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "eeaac3e027dffc09c8cf5229e9924faa", + "content-hash": "f74783e12acad4c892369ccf2820dff5", "packages": [ { "name": "allure-framework/allure-codeception", @@ -4835,7 +4835,6 @@ "type": "github" } ], - "abandoned": true, "time": "2020-09-28T06:45:17+00:00" }, { From d0d55e6f201e298e1fbd66498209da8b112b9bbd Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Tue, 30 Nov 2021 14:49:27 -0600 Subject: [PATCH 750/888] MQE-3097: Release MFTF 3.7.1 - update docs --- docs/commands/mftf.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 4abd0dace..67fc61e02 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -80,13 +80,22 @@ vendor/bin/mftf run:manifest path/to/your/testManifest.txt This command runs all tests specified in a `testManifest.txt` file. When you generate tests, a `testManifest.txt` file is also generated for you. You can pass this file directly to the `run:manifest` command and it will execute all listed tests. You can also create your own file in the same format to execute a subset of tests. Note: This command does not generate tests. -### Generate and run previously failed tests +### Generate previously failed tests + +```bash +vendor/bin/mftf generate:failed +``` + +This command cleans up the previously generated tests; generates the tests listed in `dev/tests/acceptance/tests/_output/failed`. +For more details about `failed`, refer to [Reporting][]. + +### Run previously failed tests ```bash vendor/bin/mftf run:failed ``` -This command cleans up the previously generated tests; generates and runs the tests listed in `dev/tests/acceptance/tests/_output/failed`. +This command runs the tests listed in `dev/tests/acceptance/tests/_output/failed`. For more details about `failed`, refer to [Reporting][]. ## Error tolerance during generation From 6868d79d423139d2d73f9b7edc3e66bd0dca5d4d Mon Sep 17 00:00:00 2001 From: Oleksandr Shmyheliuk <shmyheli@adobe.com> Date: Mon, 6 Dec 2021 15:30:50 -0600 Subject: [PATCH 751/888] Fix encoding issue when secret key contains plus sign --- .../FunctionalTestingFramework/Module/MagentoWebDriver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 00e295606..dcf07da78 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -571,7 +571,7 @@ public function magentoCLI($command, $timeout = null, $arguments = null) $apiURL, [ 'token' => WebApiAuth::getAdminToken(), - getenv('MAGENTO_CLI_COMMAND_PARAMETER') => $command, + getenv('MAGENTO_CLI_COMMAND_PARAMETER') => urlencode($command), 'arguments' => $arguments, 'timeout' => $timeout, ], From 95708308239091419a971866ab63d0da1c8de68f Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 6 Dec 2021 16:14:15 -0600 Subject: [PATCH 752/888] MQE-3122: Logging of failed test is not working when test fails in `after` section --- .../ActionGroupContainsStepKeyInArgText.txt | 20 +++++++++++++++++-- .../ActionGroupMergedViaInsertAfter.txt | 20 +++++++++++++++++-- .../ActionGroupMergedViaInsertBefore.txt | 20 +++++++++++++++++-- .../ActionGroupReturningValueTest.txt | 12 +++++++++-- .../Resources/ActionGroupToExtend.txt | 20 +++++++++++++++++-- .../Resources/ActionGroupUsingCreateData.txt | 20 +++++++++++++++++-- .../ActionGroupUsingNestedArgument.txt | 20 +++++++++++++++++-- .../ActionGroupWithDataOverrideTest.txt | 12 +++++++++-- .../Resources/ActionGroupWithDataTest.txt | 20 +++++++++++++++++-- ...hDefaultArgumentAndStringSelectorParam.txt | 20 +++++++++++++++++-- ...eParameterSelectorsFromDefaultArgument.txt | 20 +++++++++++++++++-- .../Resources/ActionGroupWithNoArguments.txt | 20 +++++++++++++++++-- .../ActionGroupWithNoDefaultTest.txt | 12 +++++++++-- ...roupWithParameterizedElementWithHyphen.txt | 20 +++++++++++++++++-- ...meterizedElementsWithStepKeyReferences.txt | 20 +++++++++++++++++-- ...thPassedArgumentAndStringSelectorParam.txt | 20 +++++++++++++++++-- .../ActionGroupWithPersistedData.txt | 12 +++++++++-- ...tionGroupWithSectionAndDataAsArguments.txt | 20 +++++++++++++++++-- ...WithSimpleDataUsageFromDefaultArgument.txt | 20 +++++++++++++++++-- ...pWithSimpleDataUsageFromPassedArgument.txt | 20 +++++++++++++++++-- ...leParameterSelectorFromDefaultArgument.txt | 20 +++++++++++++++++-- ...gleParameterSelectorFromPassedArgument.txt | 20 +++++++++++++++++-- .../ActionGroupWithStepKeyReferences.txt | 20 +++++++++++++++++-- .../ActionGroupWithTopLevelPersistedData.txt | 12 +++++++++-- .../ArgumentWithSameNameAsElement.txt | 12 +++++++++-- .../verification/Resources/AssertTest.txt | 20 +++++++++++++++++-- .../Resources/BasicActionGroupTest.txt | 20 +++++++++++++++++-- .../Resources/BasicFunctionalTest.txt | 12 +++++++++-- .../verification/Resources/BasicMergeTest.txt | 12 +++++++++-- .../Resources/CharacterReplacementTest.txt | 20 +++++++++++++++++-- .../Resources/ChildExtendedTestAddHooks.txt | 12 +++++++++-- .../Resources/ChildExtendedTestMerging.txt | 12 +++++++++-- .../Resources/ChildExtendedTestNoParent.txt | 16 +++++++++++++++ .../ChildExtendedTestRemoveAction.txt | 12 +++++++++-- .../ChildExtendedTestRemoveHookAction.txt | 12 +++++++++-- .../Resources/ChildExtendedTestReplace.txt | 12 +++++++++-- .../ChildExtendedTestReplaceHook.txt | 12 +++++++++-- .../Resources/DataActionsTest.txt | 20 +++++++++++++++++-- .../Resources/DataReplacementTest.txt | 20 +++++++++++++++++-- .../Resources/DeprecatedEntitiesTest.txt | 20 +++++++++++++++++-- .../verification/Resources/DeprecatedTest.txt | 20 +++++++++++++++++-- .../Resources/ExecuteJsEscapingTest.txt | 20 +++++++++++++++++-- .../Resources/ExtendParentDataTest.txt | 20 +++++++++++++++++-- .../Resources/ExtendedActionGroup.txt | 20 +++++++++++++++++-- .../ExtendedActionGroupReturningValueTest.txt | 9 +++++++-- ...ndedChildActionGroupReturningValueTest.txt | 20 +++++++++++++++++-- .../ExtendedChildTestInSuiteCest.txt | 12 +++++++++-- .../Resources/ExtendedChildTestNotInSuite.txt | 12 +++++++++-- .../Resources/ExtendedParameterArrayTest.txt | 20 +++++++++++++++++-- .../Resources/ExtendedRemoveActionGroup.txt | 20 +++++++++++++++++-- .../Resources/ExtendingSkippedTest.txt | 16 +++++++++++++++ .../Resources/GroupSkipGenerationTest.txt | 20 +++++++++++++++++-- .../Resources/HookActionsTest.txt | 12 +++++++++-- .../Resources/LocatorFunctionTest.txt | 20 +++++++++++++++++-- .../Resources/MergeMassViaInsertAfter.txt | 20 +++++++++++++++++-- .../Resources/MergeMassViaInsertBefore.txt | 20 +++++++++++++++++-- .../verification/Resources/MergeSkip.txt | 16 +++++++++++++++ .../MergedActionGroupReturningValueTest.txt | 12 +++++++++-- .../Resources/MergedActionGroupTest.txt | 12 +++++++++-- .../Resources/MergedReferencesTest.txt | 12 +++++++++-- .../Resources/MultipleActionGroupsTest.txt | 12 +++++++++-- .../Resources/PageReplacementTest.txt | 20 +++++++++++++++++-- .../Resources/ParameterArrayTest.txt | 20 +++++++++++++++++-- .../Resources/ParentExtendedTest.txt | 12 +++++++++-- .../PersistedAndXmlEntityArguments.txt | 20 +++++++++++++++++-- .../Resources/PersistedReplacementTest.txt | 20 +++++++++++++++++-- .../PersistenceActionGroupAppendingTest.txt | 20 +++++++++++++++++-- .../Resources/PersistenceCustomFieldsTest.txt | 20 +++++++++++++++++-- .../Resources/SectionReplacementTest.txt | 20 +++++++++++++++++-- .../verification/Resources/SkippedTest.txt | 16 +++++++++++++++ .../Resources/SkippedTestTwoIssues.txt | 16 +++++++++++++++ .../Resources/SkippedTestWithHooks.txt | 16 +++++++++++++++ .../Resources/XmlCommentedActionGroupTest.txt | 20 +++++++++++++++++-- .../Resources/XmlCommentedTest.txt | 12 +++++++++-- .../Util/TestGenerator.php | 17 ++++++++++++++-- 75 files changed, 1140 insertions(+), 138 deletions(-) diff --git a/dev/tests/verification/Resources/ActionGroupContainsStepKeyInArgText.txt b/dev/tests/verification/Resources/ActionGroupContainsStepKeyInArgText.txt index ad906d4ea..710612750 100644 --- a/dev/tests/verification/Resources/ActionGroupContainsStepKeyInArgText.txt +++ b/dev/tests/verification/Resources/ActionGroupContainsStepKeyInArgText.txt @@ -17,6 +17,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ActionGroupContainsStepKeyInArgTextCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -28,6 +33,17 @@ class ActionGroupContainsStepKeyInArgTextCest $I->comment("Exiting Action Group [actionGroup] actionGroupContainsStepKeyInArgValue"); } + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -44,7 +60,7 @@ class ActionGroupContainsStepKeyInArgTextCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ActionGroupMergedViaInsertAfter.txt b/dev/tests/verification/Resources/ActionGroupMergedViaInsertAfter.txt index a69b8d212..ab10b3b80 100644 --- a/dev/tests/verification/Resources/ActionGroupMergedViaInsertAfter.txt +++ b/dev/tests/verification/Resources/ActionGroupMergedViaInsertAfter.txt @@ -17,6 +17,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ActionGroupMergedViaInsertAfterCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -38,7 +54,7 @@ class ActionGroupMergedViaInsertAfterCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ActionGroupMergedViaInsertBefore.txt b/dev/tests/verification/Resources/ActionGroupMergedViaInsertBefore.txt index 45d5188d4..05d82165a 100644 --- a/dev/tests/verification/Resources/ActionGroupMergedViaInsertBefore.txt +++ b/dev/tests/verification/Resources/ActionGroupMergedViaInsertBefore.txt @@ -17,6 +17,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ActionGroupMergedViaInsertBeforeCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -38,7 +54,7 @@ class ActionGroupMergedViaInsertBeforeCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ActionGroupReturningValueTest.txt b/dev/tests/verification/Resources/ActionGroupReturningValueTest.txt index 2d0220e65..1fb0726e1 100644 --- a/dev/tests/verification/Resources/ActionGroupReturningValueTest.txt +++ b/dev/tests/verification/Resources/ActionGroupReturningValueTest.txt @@ -18,6 +18,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ActionGroupReturningValueTestCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -41,6 +46,9 @@ class ActionGroupReturningValueTestCest $I->fillField("#foo", "myData1"); // stepKey: fillField1AfterGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2AfterGroup $I->comment("Exiting Action Group [afterGroup] FunctionalActionGroup"); + if ($this->isSuccess) { + unlink(__FILE__); + } } /** @@ -75,7 +83,7 @@ class ActionGroupReturningValueTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ActionGroupToExtend.txt b/dev/tests/verification/Resources/ActionGroupToExtend.txt index 14ef8a29a..5ec7f0a0e 100644 --- a/dev/tests/verification/Resources/ActionGroupToExtend.txt +++ b/dev/tests/verification/Resources/ActionGroupToExtend.txt @@ -17,6 +17,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ActionGroupToExtendCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -34,7 +50,7 @@ class ActionGroupToExtendCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt b/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt index 8afc91f6f..b451abc2b 100644 --- a/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt +++ b/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt @@ -17,6 +17,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ActionGroupUsingCreateDataCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -29,6 +34,17 @@ class ActionGroupUsingCreateDataCest $I->comment("Exiting Action Group [Key1] actionGroupWithCreateData"); } + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -42,7 +58,7 @@ class ActionGroupUsingCreateDataCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ActionGroupUsingNestedArgument.txt b/dev/tests/verification/Resources/ActionGroupUsingNestedArgument.txt index 657046cd5..ff745ba05 100644 --- a/dev/tests/verification/Resources/ActionGroupUsingNestedArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupUsingNestedArgument.txt @@ -17,6 +17,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ActionGroupUsingNestedArgumentCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -34,7 +50,7 @@ class ActionGroupUsingNestedArgumentCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt b/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt index bf430a668..2ecc0f729 100644 --- a/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt +++ b/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt @@ -18,6 +18,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ActionGroupWithDataOverrideTestCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -41,6 +46,9 @@ class ActionGroupWithDataOverrideTestCest $I->fillField("#foo", "myData1"); // stepKey: fillField1AfterGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2AfterGroup $I->comment("Exiting Action Group [afterGroup] FunctionalActionGroup"); + if ($this->isSuccess) { + unlink(__FILE__); + } } /** @@ -76,7 +84,7 @@ class ActionGroupWithDataOverrideTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ActionGroupWithDataTest.txt b/dev/tests/verification/Resources/ActionGroupWithDataTest.txt index 0de660c0e..bde1dcdd6 100644 --- a/dev/tests/verification/Resources/ActionGroupWithDataTest.txt +++ b/dev/tests/verification/Resources/ActionGroupWithDataTest.txt @@ -18,6 +18,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ActionGroupWithDataTestCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -31,6 +36,17 @@ class ActionGroupWithDataTestCest $I->comment("Exiting Action Group [beforeGroup] FunctionalActionGroup"); } + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @param AcceptanceTester $I * @throws \Exception @@ -76,7 +92,7 @@ class ActionGroupWithDataTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ActionGroupWithDefaultArgumentAndStringSelectorParam.txt b/dev/tests/verification/Resources/ActionGroupWithDefaultArgumentAndStringSelectorParam.txt index 21f54d3ed..7a68cf16a 100644 --- a/dev/tests/verification/Resources/ActionGroupWithDefaultArgumentAndStringSelectorParam.txt +++ b/dev/tests/verification/Resources/ActionGroupWithDefaultArgumentAndStringSelectorParam.txt @@ -18,6 +18,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ActionGroupWithDefaultArgumentAndStringSelectorParamCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Severity(level = SeverityLevel::BLOCKER) * @Features({"TestModule"}) @@ -35,7 +51,7 @@ class ActionGroupWithDefaultArgumentAndStringSelectorParamCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.txt b/dev/tests/verification/Resources/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.txt index b24fac754..6b8c738e0 100644 --- a/dev/tests/verification/Resources/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.txt @@ -18,6 +18,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ActionGroupWithMultipleParameterSelectorsFromDefaultArgumentCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Severity(level = SeverityLevel::BLOCKER) * @Features({"TestModule"}) @@ -35,7 +51,7 @@ class ActionGroupWithMultipleParameterSelectorsFromDefaultArgumentCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ActionGroupWithNoArguments.txt b/dev/tests/verification/Resources/ActionGroupWithNoArguments.txt index 383164241..2371d86dd 100644 --- a/dev/tests/verification/Resources/ActionGroupWithNoArguments.txt +++ b/dev/tests/verification/Resources/ActionGroupWithNoArguments.txt @@ -18,6 +18,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ActionGroupWithNoArgumentsCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Severity(level = SeverityLevel::BLOCKER) * @Features({"TestModule"}) @@ -35,7 +51,7 @@ class ActionGroupWithNoArgumentsCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt b/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt index 97a060d1c..19f3de5ad 100644 --- a/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt +++ b/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt @@ -18,6 +18,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ActionGroupWithNoDefaultTestCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -41,6 +46,9 @@ class ActionGroupWithNoDefaultTestCest $I->fillField("#foo", "myData1"); // stepKey: fillField1AfterGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2AfterGroup $I->comment("Exiting Action Group [afterGroup] FunctionalActionGroup"); + if ($this->isSuccess) { + unlink(__FILE__); + } } /** @@ -74,7 +82,7 @@ class ActionGroupWithNoDefaultTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ActionGroupWithParameterizedElementWithHyphen.txt b/dev/tests/verification/Resources/ActionGroupWithParameterizedElementWithHyphen.txt index 53657a2ae..17a9d766b 100644 --- a/dev/tests/verification/Resources/ActionGroupWithParameterizedElementWithHyphen.txt +++ b/dev/tests/verification/Resources/ActionGroupWithParameterizedElementWithHyphen.txt @@ -17,6 +17,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ActionGroupWithParameterizedElementWithHyphenCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -33,7 +49,7 @@ class ActionGroupWithParameterizedElementWithHyphenCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ActionGroupWithParameterizedElementsWithStepKeyReferences.txt b/dev/tests/verification/Resources/ActionGroupWithParameterizedElementsWithStepKeyReferences.txt index 47d0566eb..2f31d0686 100644 --- a/dev/tests/verification/Resources/ActionGroupWithParameterizedElementsWithStepKeyReferences.txt +++ b/dev/tests/verification/Resources/ActionGroupWithParameterizedElementsWithStepKeyReferences.txt @@ -17,6 +17,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ActionGroupWithParameterizedElementsWithStepKeyReferencesCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -38,7 +54,7 @@ class ActionGroupWithParameterizedElementsWithStepKeyReferencesCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ActionGroupWithPassedArgumentAndStringSelectorParam.txt b/dev/tests/verification/Resources/ActionGroupWithPassedArgumentAndStringSelectorParam.txt index 31771d938..e58d8c5a5 100644 --- a/dev/tests/verification/Resources/ActionGroupWithPassedArgumentAndStringSelectorParam.txt +++ b/dev/tests/verification/Resources/ActionGroupWithPassedArgumentAndStringSelectorParam.txt @@ -18,6 +18,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ActionGroupWithPassedArgumentAndStringSelectorParamCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Severity(level = SeverityLevel::BLOCKER) * @Features({"TestModule"}) @@ -35,7 +51,7 @@ class ActionGroupWithPassedArgumentAndStringSelectorParamCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt b/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt index 3943f1271..782e27a8e 100644 --- a/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt +++ b/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt @@ -18,6 +18,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ActionGroupWithPersistedDataCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -41,6 +46,9 @@ class ActionGroupWithPersistedDataCest $I->fillField("#foo", "myData1"); // stepKey: fillField1AfterGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2AfterGroup $I->comment("Exiting Action Group [afterGroup] FunctionalActionGroup"); + if ($this->isSuccess) { + unlink(__FILE__); + } } /** @@ -75,7 +83,7 @@ class ActionGroupWithPersistedDataCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ActionGroupWithSectionAndDataAsArguments.txt b/dev/tests/verification/Resources/ActionGroupWithSectionAndDataAsArguments.txt index 71519b234..d07a32cd0 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSectionAndDataAsArguments.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSectionAndDataAsArguments.txt @@ -17,6 +17,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ActionGroupWithSectionAndDataAsArgumentsCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -33,7 +49,7 @@ class ActionGroupWithSectionAndDataAsArgumentsCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromDefaultArgument.txt b/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromDefaultArgument.txt index 72ade673a..ab5465ca0 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromDefaultArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromDefaultArgument.txt @@ -18,6 +18,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ActionGroupWithSimpleDataUsageFromDefaultArgumentCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) @@ -35,7 +51,7 @@ class ActionGroupWithSimpleDataUsageFromDefaultArgumentCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromPassedArgument.txt b/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromPassedArgument.txt index b19c6b20f..c86e9dc4f 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromPassedArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromPassedArgument.txt @@ -18,6 +18,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ActionGroupWithSimpleDataUsageFromPassedArgumentCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) @@ -62,7 +78,7 @@ class ActionGroupWithSimpleDataUsageFromPassedArgumentCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromDefaultArgument.txt b/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromDefaultArgument.txt index 81712b6fe..34ba535f8 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromDefaultArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromDefaultArgument.txt @@ -18,6 +18,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ActionGroupWithSingleParameterSelectorFromDefaultArgumentCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Severity(level = SeverityLevel::BLOCKER) * @Features({"TestModule"}) @@ -35,7 +51,7 @@ class ActionGroupWithSingleParameterSelectorFromDefaultArgumentCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromPassedArgument.txt b/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromPassedArgument.txt index eeb346b60..45f72a95b 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromPassedArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromPassedArgument.txt @@ -18,6 +18,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ActionGroupWithSingleParameterSelectorFromPassedArgumentCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Severity(level = SeverityLevel::BLOCKER) * @Features({"TestModule"}) @@ -35,7 +51,7 @@ class ActionGroupWithSingleParameterSelectorFromPassedArgumentCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt b/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt index ef20ee94b..532c70868 100644 --- a/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt +++ b/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt @@ -17,6 +17,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ActionGroupWithStepKeyReferencesCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -58,7 +74,7 @@ class ActionGroupWithStepKeyReferencesCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt b/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt index daba0ab12..285e66370 100644 --- a/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt +++ b/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt @@ -18,6 +18,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ActionGroupWithTopLevelPersistedDataCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -41,6 +46,9 @@ class ActionGroupWithTopLevelPersistedDataCest $I->fillField("#foo", "myData1"); // stepKey: fillField1AfterGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2AfterGroup $I->comment("Exiting Action Group [afterGroup] FunctionalActionGroup"); + if ($this->isSuccess) { + unlink(__FILE__); + } } /** @@ -74,7 +82,7 @@ class ActionGroupWithTopLevelPersistedDataCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt b/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt index 2ea282f07..b643eb759 100644 --- a/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt +++ b/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt @@ -18,6 +18,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ArgumentWithSameNameAsElementCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -41,6 +46,9 @@ class ArgumentWithSameNameAsElementCest $I->fillField("#foo", "myData1"); // stepKey: fillField1AfterGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2AfterGroup $I->comment("Exiting Action Group [afterGroup] FunctionalActionGroup"); + if ($this->isSuccess) { + unlink(__FILE__); + } } /** @@ -71,7 +79,7 @@ class ArgumentWithSameNameAsElementCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/AssertTest.txt b/dev/tests/verification/Resources/AssertTest.txt index c4fe946e4..6c30b7273 100644 --- a/dev/tests/verification/Resources/AssertTest.txt +++ b/dev/tests/verification/Resources/AssertTest.txt @@ -17,6 +17,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class AssertTestCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -26,6 +31,17 @@ class AssertTestCest $I->createEntity("createData1", "hook", "ReplacementPerson", [], []); // stepKey: createData1 } + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -163,7 +179,7 @@ class AssertTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/BasicActionGroupTest.txt b/dev/tests/verification/Resources/BasicActionGroupTest.txt index e2bfdae7e..45cac4937 100644 --- a/dev/tests/verification/Resources/BasicActionGroupTest.txt +++ b/dev/tests/verification/Resources/BasicActionGroupTest.txt @@ -18,6 +18,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class BasicActionGroupTestCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -31,6 +36,17 @@ class BasicActionGroupTestCest $I->comment("Exiting Action Group [beforeGroup] FunctionalActionGroup"); } + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) @@ -52,7 +68,7 @@ class BasicActionGroupTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/BasicFunctionalTest.txt b/dev/tests/verification/Resources/BasicFunctionalTest.txt index e6ac37f12..c5ce0305c 100644 --- a/dev/tests/verification/Resources/BasicFunctionalTest.txt +++ b/dev/tests/verification/Resources/BasicFunctionalTest.txt @@ -19,6 +19,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class BasicFunctionalTestCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -35,6 +40,9 @@ class BasicFunctionalTestCest public function _after(AcceptanceTester $I) { $I->amOnPage("/afterUrl"); // stepKey: afterAmOnPageKey + if ($this->isSuccess) { + unlink(__FILE__); + } } /** @@ -188,7 +196,7 @@ class BasicFunctionalTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/BasicMergeTest.txt b/dev/tests/verification/Resources/BasicMergeTest.txt index a32d6b50e..0ccd3e898 100644 --- a/dev/tests/verification/Resources/BasicMergeTest.txt +++ b/dev/tests/verification/Resources/BasicMergeTest.txt @@ -20,6 +20,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class BasicMergeTestCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -37,6 +42,9 @@ class BasicMergeTestCest public function _after(AcceptanceTester $I) { $I->amOnPage("/afterUrl1"); // stepKey: after1 + if ($this->isSuccess) { + unlink(__FILE__); + } } /** @@ -78,7 +86,7 @@ class BasicMergeTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/CharacterReplacementTest.txt b/dev/tests/verification/Resources/CharacterReplacementTest.txt index 3cdccd7e6..b87c36a40 100644 --- a/dev/tests/verification/Resources/CharacterReplacementTest.txt +++ b/dev/tests/verification/Resources/CharacterReplacementTest.txt @@ -17,6 +17,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class CharacterReplacementTestCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -38,7 +54,7 @@ class CharacterReplacementTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt b/dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt index 782eec26f..2e949082a 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt @@ -19,6 +19,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ChildExtendedTestAddHooksCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -35,6 +40,9 @@ class ChildExtendedTestAddHooksCest public function _after(AcceptanceTester $I) { $I->amOnPage("/afterUrl"); // stepKey: afterAmOnPageKey + if ($this->isSuccess) { + unlink(__FILE__); + } } /** @@ -61,7 +69,7 @@ class ChildExtendedTestAddHooksCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ChildExtendedTestMerging.txt b/dev/tests/verification/Resources/ChildExtendedTestMerging.txt index dd8fba438..9e892e290 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestMerging.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestMerging.txt @@ -19,6 +19,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ChildExtendedTestMergingCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -37,6 +42,9 @@ class ChildExtendedTestMergingCest public function _after(AcceptanceTester $I) { $I->amOnPage("/afterUrl"); // stepKey: afterAmOnPageKey + if ($this->isSuccess) { + unlink(__FILE__); + } } /** @@ -67,7 +75,7 @@ class ChildExtendedTestMergingCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ChildExtendedTestNoParent.txt b/dev/tests/verification/Resources/ChildExtendedTestNoParent.txt index 779f89c7e..12094a518 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestNoParent.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestNoParent.txt @@ -20,6 +20,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ChildExtendedTestNoParentCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) diff --git a/dev/tests/verification/Resources/ChildExtendedTestRemoveAction.txt b/dev/tests/verification/Resources/ChildExtendedTestRemoveAction.txt index 2a0eddf57..28b4ec7fd 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestRemoveAction.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestRemoveAction.txt @@ -19,6 +19,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ChildExtendedTestRemoveActionCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -35,6 +40,9 @@ class ChildExtendedTestRemoveActionCest public function _after(AcceptanceTester $I) { $I->amOnPage("/afterUrl"); // stepKey: afterAmOnPageKey + if ($this->isSuccess) { + unlink(__FILE__); + } } /** @@ -61,7 +69,7 @@ class ChildExtendedTestRemoveActionCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ChildExtendedTestRemoveHookAction.txt b/dev/tests/verification/Resources/ChildExtendedTestRemoveHookAction.txt index 2ab9eaf11..3649c85fe 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestRemoveHookAction.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestRemoveHookAction.txt @@ -19,6 +19,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ChildExtendedTestRemoveHookActionCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -34,6 +39,9 @@ class ChildExtendedTestRemoveHookActionCest public function _after(AcceptanceTester $I) { $I->amOnPage("/afterUrl"); // stepKey: afterAmOnPageKey + if ($this->isSuccess) { + unlink(__FILE__); + } } /** @@ -61,7 +69,7 @@ class ChildExtendedTestRemoveHookActionCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ChildExtendedTestReplace.txt b/dev/tests/verification/Resources/ChildExtendedTestReplace.txt index daf1bfe2f..a3cfdd2aa 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestReplace.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestReplace.txt @@ -19,6 +19,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ChildExtendedTestReplaceCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -35,6 +40,9 @@ class ChildExtendedTestReplaceCest public function _after(AcceptanceTester $I) { $I->amOnPage("/afterUrl"); // stepKey: afterAmOnPageKey + if ($this->isSuccess) { + unlink(__FILE__); + } } /** @@ -62,7 +70,7 @@ class ChildExtendedTestReplaceCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ChildExtendedTestReplaceHook.txt b/dev/tests/verification/Resources/ChildExtendedTestReplaceHook.txt index 67ef1b40e..abe55a071 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestReplaceHook.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestReplaceHook.txt @@ -19,6 +19,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ChildExtendedTestReplaceHookCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -35,6 +40,9 @@ class ChildExtendedTestReplaceHookCest public function _after(AcceptanceTester $I) { $I->amOnPage("/afterUrl"); // stepKey: afterAmOnPageKey + if ($this->isSuccess) { + unlink(__FILE__); + } } /** @@ -62,7 +70,7 @@ class ChildExtendedTestReplaceHookCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/DataActionsTest.txt b/dev/tests/verification/Resources/DataActionsTest.txt index 2c735ed35..f84f97040 100644 --- a/dev/tests/verification/Resources/DataActionsTest.txt +++ b/dev/tests/verification/Resources/DataActionsTest.txt @@ -17,6 +17,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class DataActionsTestCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -28,6 +33,17 @@ class DataActionsTestCest $I->deleteEntity("createdInBefore", "hook"); // stepKey: deleteInBefore } + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -46,7 +62,7 @@ class DataActionsTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/DataReplacementTest.txt b/dev/tests/verification/Resources/DataReplacementTest.txt index f1d405750..00c28b31e 100644 --- a/dev/tests/verification/Resources/DataReplacementTest.txt +++ b/dev/tests/verification/Resources/DataReplacementTest.txt @@ -17,6 +17,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class DataReplacementTestCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -92,7 +108,7 @@ class DataReplacementTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/DeprecatedEntitiesTest.txt b/dev/tests/verification/Resources/DeprecatedEntitiesTest.txt index 4d0652bb3..9a0ec8a27 100644 --- a/dev/tests/verification/Resources/DeprecatedEntitiesTest.txt +++ b/dev/tests/verification/Resources/DeprecatedEntitiesTest.txt @@ -17,6 +17,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class DeprecatedEntitiesTestCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -34,7 +50,7 @@ class DeprecatedEntitiesTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/DeprecatedTest.txt b/dev/tests/verification/Resources/DeprecatedTest.txt index 71fc1de4d..acdb53cc0 100644 --- a/dev/tests/verification/Resources/DeprecatedTest.txt +++ b/dev/tests/verification/Resources/DeprecatedTest.txt @@ -17,6 +17,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class DeprecatedTestCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -34,7 +50,7 @@ class DeprecatedTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ExecuteJsEscapingTest.txt b/dev/tests/verification/Resources/ExecuteJsEscapingTest.txt index 6d4de9ad1..fc1331ef2 100644 --- a/dev/tests/verification/Resources/ExecuteJsEscapingTest.txt +++ b/dev/tests/verification/Resources/ExecuteJsEscapingTest.txt @@ -17,6 +17,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ExecuteJsEscapingTestCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -35,7 +51,7 @@ class ExecuteJsEscapingTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ExtendParentDataTest.txt b/dev/tests/verification/Resources/ExtendParentDataTest.txt index 7e97473bd..6b96cbbda 100644 --- a/dev/tests/verification/Resources/ExtendParentDataTest.txt +++ b/dev/tests/verification/Resources/ExtendParentDataTest.txt @@ -17,6 +17,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ExtendParentDataTestCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -36,7 +52,7 @@ class ExtendParentDataTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ExtendedActionGroup.txt b/dev/tests/verification/Resources/ExtendedActionGroup.txt index 71e9121fa..a2cc9fc74 100644 --- a/dev/tests/verification/Resources/ExtendedActionGroup.txt +++ b/dev/tests/verification/Resources/ExtendedActionGroup.txt @@ -17,6 +17,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ExtendedActionGroupCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -37,7 +53,7 @@ class ExtendedActionGroupCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ExtendedActionGroupReturningValueTest.txt b/dev/tests/verification/Resources/ExtendedActionGroupReturningValueTest.txt index 9b89b3825..e5efd6cc9 100644 --- a/dev/tests/verification/Resources/ExtendedActionGroupReturningValueTest.txt +++ b/dev/tests/verification/Resources/ExtendedActionGroupReturningValueTest.txt @@ -18,6 +18,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ExtendedActionGroupReturningValueTestCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) @@ -40,7 +45,7 @@ class ExtendedActionGroupReturningValueTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ExtendedChildActionGroupReturningValueTest.txt b/dev/tests/verification/Resources/ExtendedChildActionGroupReturningValueTest.txt index e0d9e29f6..c262ffd85 100644 --- a/dev/tests/verification/Resources/ExtendedChildActionGroupReturningValueTest.txt +++ b/dev/tests/verification/Resources/ExtendedChildActionGroupReturningValueTest.txt @@ -18,6 +18,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ExtendedChildActionGroupReturningValueTestCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) @@ -43,7 +59,7 @@ class ExtendedChildActionGroupReturningValueTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ExtendedChildTestInSuiteCest.txt b/dev/tests/verification/Resources/ExtendedChildTestInSuiteCest.txt index 2d1c91630..2e6da3464 100644 --- a/dev/tests/verification/Resources/ExtendedChildTestInSuiteCest.txt +++ b/dev/tests/verification/Resources/ExtendedChildTestInSuiteCest.txt @@ -19,6 +19,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ExtendedChildTestInSuiteCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -35,6 +40,9 @@ class ExtendedChildTestInSuiteCest public function _after(AcceptanceTester $I) { $I->amOnPage("/afterUrl"); // stepKey: afterAmOnPageKey + if ($this->isSuccess) { + unlink(__FILE__); + } } /** @@ -62,7 +70,7 @@ class ExtendedChildTestInSuiteCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt b/dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt index 30d188c9d..a18346a77 100644 --- a/dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt +++ b/dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt @@ -18,6 +18,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ExtendedChildTestNotInSuiteCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -34,6 +39,9 @@ class ExtendedChildTestNotInSuiteCest public function _after(AcceptanceTester $I) { $I->amOnPage("/afterUrl"); // stepKey: afterAmOnPageKey + if ($this->isSuccess) { + unlink(__FILE__); + } } /** @@ -61,7 +69,7 @@ class ExtendedChildTestNotInSuiteCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ExtendedParameterArrayTest.txt b/dev/tests/verification/Resources/ExtendedParameterArrayTest.txt index 306f10fee..7af46fe5a 100644 --- a/dev/tests/verification/Resources/ExtendedParameterArrayTest.txt +++ b/dev/tests/verification/Resources/ExtendedParameterArrayTest.txt @@ -16,6 +16,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ExtendParentDataTestCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -35,7 +51,7 @@ class ExtendParentDataTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ExtendedRemoveActionGroup.txt b/dev/tests/verification/Resources/ExtendedRemoveActionGroup.txt index 792a4ac4f..1e24e644a 100644 --- a/dev/tests/verification/Resources/ExtendedRemoveActionGroup.txt +++ b/dev/tests/verification/Resources/ExtendedRemoveActionGroup.txt @@ -17,6 +17,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ExtendedRemoveActionGroupCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -32,7 +48,7 @@ class ExtendedRemoveActionGroupCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ExtendingSkippedTest.txt b/dev/tests/verification/Resources/ExtendingSkippedTest.txt index 45b8614e4..0b78b5136 100644 --- a/dev/tests/verification/Resources/ExtendingSkippedTest.txt +++ b/dev/tests/verification/Resources/ExtendingSkippedTest.txt @@ -19,6 +19,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ExtendingSkippedTestCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) diff --git a/dev/tests/verification/Resources/GroupSkipGenerationTest.txt b/dev/tests/verification/Resources/GroupSkipGenerationTest.txt index 1a6156cac..b13aa399a 100644 --- a/dev/tests/verification/Resources/GroupSkipGenerationTest.txt +++ b/dev/tests/verification/Resources/GroupSkipGenerationTest.txt @@ -19,6 +19,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class GroupSkipGenerationTestCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Stories({"GroupSkipGenerationTestStory"}) * @Severity(level = SeverityLevel::MINOR) @@ -34,7 +50,7 @@ class GroupSkipGenerationTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/HookActionsTest.txt b/dev/tests/verification/Resources/HookActionsTest.txt index 0ffabfd9e..a04a980a1 100644 --- a/dev/tests/verification/Resources/HookActionsTest.txt +++ b/dev/tests/verification/Resources/HookActionsTest.txt @@ -17,6 +17,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class HookActionsTestCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -36,6 +41,9 @@ class HookActionsTestCest { $I->createEntity("sampleCreateAfter", "hook", "sampleCreatedEntity", [], []); // stepKey: sampleCreateAfter $I->deleteEntity("sampleCreateForAfter", "hook"); // stepKey: sampleDeleteAfter + if ($this->isSuccess) { + unlink(__FILE__); + } } /** @@ -60,7 +68,7 @@ class HookActionsTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/LocatorFunctionTest.txt b/dev/tests/verification/Resources/LocatorFunctionTest.txt index deffe887b..86d744a2d 100644 --- a/dev/tests/verification/Resources/LocatorFunctionTest.txt +++ b/dev/tests/verification/Resources/LocatorFunctionTest.txt @@ -17,6 +17,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class LocatorFunctionTestCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -43,7 +59,7 @@ class LocatorFunctionTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/MergeMassViaInsertAfter.txt b/dev/tests/verification/Resources/MergeMassViaInsertAfter.txt index 250cb8b18..49c246251 100644 --- a/dev/tests/verification/Resources/MergeMassViaInsertAfter.txt +++ b/dev/tests/verification/Resources/MergeMassViaInsertAfter.txt @@ -17,6 +17,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class MergeMassViaInsertAfterCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -36,7 +52,7 @@ class MergeMassViaInsertAfterCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/MergeMassViaInsertBefore.txt b/dev/tests/verification/Resources/MergeMassViaInsertBefore.txt index 2e14981b0..6080a5f23 100644 --- a/dev/tests/verification/Resources/MergeMassViaInsertBefore.txt +++ b/dev/tests/verification/Resources/MergeMassViaInsertBefore.txt @@ -17,6 +17,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class MergeMassViaInsertBeforeCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -36,7 +52,7 @@ class MergeMassViaInsertBeforeCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/MergeSkip.txt b/dev/tests/verification/Resources/MergeSkip.txt index 885d622ac..8ce10f3e1 100644 --- a/dev/tests/verification/Resources/MergeSkip.txt +++ b/dev/tests/verification/Resources/MergeSkip.txt @@ -17,6 +17,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class MergeSkipCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") diff --git a/dev/tests/verification/Resources/MergedActionGroupReturningValueTest.txt b/dev/tests/verification/Resources/MergedActionGroupReturningValueTest.txt index ef7960d21..71d8ed94a 100644 --- a/dev/tests/verification/Resources/MergedActionGroupReturningValueTest.txt +++ b/dev/tests/verification/Resources/MergedActionGroupReturningValueTest.txt @@ -18,6 +18,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class MergedActionGroupReturningValueTestCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -41,6 +46,9 @@ class MergedActionGroupReturningValueTestCest $I->fillField("#foo", "myData1"); // stepKey: fillField1AfterGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2AfterGroup $I->comment("Exiting Action Group [afterGroup] FunctionalActionGroup"); + if ($this->isSuccess) { + unlink(__FILE__); + } } /** @@ -77,7 +85,7 @@ class MergedActionGroupReturningValueTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/MergedActionGroupTest.txt b/dev/tests/verification/Resources/MergedActionGroupTest.txt index f592a9806..e92a06f6f 100644 --- a/dev/tests/verification/Resources/MergedActionGroupTest.txt +++ b/dev/tests/verification/Resources/MergedActionGroupTest.txt @@ -18,6 +18,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class MergedActionGroupTestCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -41,6 +46,9 @@ class MergedActionGroupTestCest $I->fillField("#foo", "myData1"); // stepKey: fillField1AfterGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2AfterGroup $I->comment("Exiting Action Group [afterGroup] FunctionalActionGroup"); + if ($this->isSuccess) { + unlink(__FILE__); + } } /** @@ -73,7 +81,7 @@ class MergedActionGroupTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/MergedReferencesTest.txt b/dev/tests/verification/Resources/MergedReferencesTest.txt index 678ae79fe..b1f95d56c 100644 --- a/dev/tests/verification/Resources/MergedReferencesTest.txt +++ b/dev/tests/verification/Resources/MergedReferencesTest.txt @@ -19,6 +19,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class MergedReferencesTestCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -35,6 +40,9 @@ class MergedReferencesTestCest public function _after(AcceptanceTester $I) { $I->amOnPage("/afterUrl"); // stepKey: after1 + if ($this->isSuccess) { + unlink(__FILE__); + } } /** @@ -63,7 +71,7 @@ class MergedReferencesTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/MultipleActionGroupsTest.txt b/dev/tests/verification/Resources/MultipleActionGroupsTest.txt index 6a387eb76..15659f21f 100644 --- a/dev/tests/verification/Resources/MultipleActionGroupsTest.txt +++ b/dev/tests/verification/Resources/MultipleActionGroupsTest.txt @@ -18,6 +18,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class MultipleActionGroupsTestCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -41,6 +46,9 @@ class MultipleActionGroupsTestCest $I->fillField("#foo", "myData1"); // stepKey: fillField1AfterGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2AfterGroup $I->comment("Exiting Action Group [afterGroup] FunctionalActionGroup"); + if ($this->isSuccess) { + unlink(__FILE__); + } } /** @@ -83,7 +91,7 @@ class MultipleActionGroupsTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/PageReplacementTest.txt b/dev/tests/verification/Resources/PageReplacementTest.txt index a83a8ac02..af4defdb9 100644 --- a/dev/tests/verification/Resources/PageReplacementTest.txt +++ b/dev/tests/verification/Resources/PageReplacementTest.txt @@ -17,6 +17,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class PageReplacementTestCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -42,7 +58,7 @@ class PageReplacementTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ParameterArrayTest.txt b/dev/tests/verification/Resources/ParameterArrayTest.txt index b6ed5ac8c..6488db6b0 100644 --- a/dev/tests/verification/Resources/ParameterArrayTest.txt +++ b/dev/tests/verification/Resources/ParameterArrayTest.txt @@ -17,6 +17,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ParameterArrayTestCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -53,7 +69,7 @@ class ParameterArrayTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/ParentExtendedTest.txt b/dev/tests/verification/Resources/ParentExtendedTest.txt index 3a035ede7..73e6b7aa0 100644 --- a/dev/tests/verification/Resources/ParentExtendedTest.txt +++ b/dev/tests/verification/Resources/ParentExtendedTest.txt @@ -19,6 +19,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class ParentExtendedTestCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -35,6 +40,9 @@ class ParentExtendedTestCest public function _after(AcceptanceTester $I) { $I->amOnPage("/afterUrl"); // stepKey: afterAmOnPageKey + if ($this->isSuccess) { + unlink(__FILE__); + } } /** @@ -62,7 +70,7 @@ class ParentExtendedTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/PersistedAndXmlEntityArguments.txt b/dev/tests/verification/Resources/PersistedAndXmlEntityArguments.txt index 9e991362a..f4cc8cfaa 100644 --- a/dev/tests/verification/Resources/PersistedAndXmlEntityArguments.txt +++ b/dev/tests/verification/Resources/PersistedAndXmlEntityArguments.txt @@ -17,6 +17,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class PersistedAndXmlEntityArgumentsCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -33,7 +49,7 @@ class PersistedAndXmlEntityArgumentsCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/PersistedReplacementTest.txt b/dev/tests/verification/Resources/PersistedReplacementTest.txt index f0609e4a8..95706e75b 100644 --- a/dev/tests/verification/Resources/PersistedReplacementTest.txt +++ b/dev/tests/verification/Resources/PersistedReplacementTest.txt @@ -17,6 +17,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class PersistedReplacementTestCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @param AcceptanceTester $I * @throws \Exception @@ -62,7 +78,7 @@ class PersistedReplacementTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt b/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt index b966d7ca6..d1f75ccb6 100644 --- a/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt +++ b/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt @@ -17,6 +17,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class PersistenceActionGroupAppendingTestCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -32,6 +37,17 @@ class PersistenceActionGroupAppendingTestCest $I->comment("Exiting Action Group [ACTIONGROUPBEFORE] DataPersistenceAppendingActionGroup"); } + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -52,7 +68,7 @@ class PersistenceActionGroupAppendingTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt b/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt index 34409d108..5bbc0b325 100644 --- a/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt +++ b/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt @@ -17,6 +17,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class PersistenceCustomFieldsTestCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -30,6 +35,17 @@ class PersistenceCustomFieldsTestCest $I->createEntity("createData2", "hook", "uniqueData", ["createData1"], $createData2Fields); // stepKey: createData2 } + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -64,7 +80,7 @@ class PersistenceCustomFieldsTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/SectionReplacementTest.txt b/dev/tests/verification/Resources/SectionReplacementTest.txt index 8b3eadc1b..a71d1c4ef 100644 --- a/dev/tests/verification/Resources/SectionReplacementTest.txt +++ b/dev/tests/verification/Resources/SectionReplacementTest.txt @@ -17,6 +17,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class SectionReplacementTestCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") @@ -66,7 +82,7 @@ class SectionReplacementTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/SkippedTest.txt b/dev/tests/verification/Resources/SkippedTest.txt index b50145c0e..99832ef9a 100644 --- a/dev/tests/verification/Resources/SkippedTest.txt +++ b/dev/tests/verification/Resources/SkippedTest.txt @@ -18,6 +18,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class SkippedTestCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Stories({"skipped"}) * @Severity(level = SeverityLevel::MINOR) diff --git a/dev/tests/verification/Resources/SkippedTestTwoIssues.txt b/dev/tests/verification/Resources/SkippedTestTwoIssues.txt index a494328ba..951d15678 100644 --- a/dev/tests/verification/Resources/SkippedTestTwoIssues.txt +++ b/dev/tests/verification/Resources/SkippedTestTwoIssues.txt @@ -18,6 +18,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class SkippedTestTwoIssuesCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Stories({"skippedMultiple"}) * @Severity(level = SeverityLevel::MINOR) diff --git a/dev/tests/verification/Resources/SkippedTestWithHooks.txt b/dev/tests/verification/Resources/SkippedTestWithHooks.txt index 15936c463..84b0203c4 100644 --- a/dev/tests/verification/Resources/SkippedTestWithHooks.txt +++ b/dev/tests/verification/Resources/SkippedTestWithHooks.txt @@ -18,6 +18,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class SkippedTestWithHooksCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Stories({"skippedWithHooks"}) * @Severity(level = SeverityLevel::MINOR) diff --git a/dev/tests/verification/Resources/XmlCommentedActionGroupTest.txt b/dev/tests/verification/Resources/XmlCommentedActionGroupTest.txt index 5765aab13..f45e8f0b2 100644 --- a/dev/tests/verification/Resources/XmlCommentedActionGroupTest.txt +++ b/dev/tests/verification/Resources/XmlCommentedActionGroupTest.txt @@ -18,6 +18,22 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class XmlCommentedActionGroupTestCest { + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) @@ -36,7 +52,7 @@ class XmlCommentedActionGroupTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/dev/tests/verification/Resources/XmlCommentedTest.txt b/dev/tests/verification/Resources/XmlCommentedTest.txt index 663732493..9e7a300ee 100644 --- a/dev/tests/verification/Resources/XmlCommentedTest.txt +++ b/dev/tests/verification/Resources/XmlCommentedTest.txt @@ -18,6 +18,11 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; */ class XmlCommentedTestCest { + /** + * @var bool + */ + private $isSuccess = false; + /** * @param AcceptanceTester $I * @throws \Exception @@ -38,6 +43,9 @@ class XmlCommentedTestCest $I->comment("< > & \$abc \" abc ' <click stepKey=\"click\" userInput=\"\$\$createDataHook.firstname\$\$\" selector=\"#id_1\">/"); $I->amOnPage("/afterUrl"); // stepKey: afterAmOnPageKey $I->comment("< > & \$abc \" abc ' <click stepKey=\"click\" userInput=\"\$\$createDataHook.firstname\$\$\" selector=\"#id_2\">/"); + if ($this->isSuccess) { + unlink(__FILE__); + } } /** @@ -73,7 +81,7 @@ class XmlCommentedTestCest public function _passed(AcceptanceTester $I) { - // Deleting itself so that we can rerun only failed tests. - unlink(__FILE__); + // Test passed successfully. + $this->isSuccess = true; } } diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 8ea831963..c0249a32b 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -279,6 +279,10 @@ public function assembleTestPhp($testObject) $cestPhp .= $classAnnotationsPhp; $cestPhp .= sprintf("class %s\n", $className); $cestPhp .= "{\n"; + $cestPhp .= "\t/**\n"; + $cestPhp .= "\t * @var bool\n"; + $cestPhp .= "\t */\n"; + $cestPhp .= "\tprivate \$isSuccess = false;\n\n"; $cestPhp .= $this->generateInjectMethod(); $cestPhp .= $hookPhp; $cestPhp .= $testsPhp; @@ -1743,6 +1747,10 @@ private function generateHooksPhp($hookObjects) { $hooks = ""; + if (!isset($hookObjects['after'])) { + $hookObjects['after'] = new TestHookObject('after', '', []); + } + foreach ($hookObjects as $hookObject) { $type = $hookObject->getType(); $dependencies = 'AcceptanceTester $I'; @@ -1764,6 +1772,11 @@ private function generateHooksPhp($hookObjects) $hooks .= sprintf("\tpublic function _{$type}(%s)\n", $dependencies); $hooks .= "\t{\n"; $hooks .= $steps; + if ($type === 'after') { + $hooks .= "\t\t" . 'if ($this->isSuccess) {' . "\n"; + $hooks .= "\t\t\t" . 'unlink(__FILE__);' . "\n"; + $hooks .= "\t\t" . '}' . "\n"; + } $hooks .= "\t}\n\n"; } @@ -1816,8 +1829,8 @@ private function generateTestPhp($test) $testPhp .= PHP_EOL; $testPhp .= sprintf("\tpublic function _passed(%s)\n", $dependencies); $testPhp .= "\t{\n"; - $testPhp .= "\t\t// Deleting itself so that we can rerun only failed tests." . PHP_EOL; - $testPhp .= "\t\tunlink(__FILE__);" . PHP_EOL; + $testPhp .= "\t\t// Test passed successfully." . PHP_EOL; + $testPhp .= "\t\t\$this->isSuccess = true;" . PHP_EOL; $testPhp .= "\t}\n"; } From 6ac15c1ef16f0250d703e1d401b05f35f84be797 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Mon, 6 Dec 2021 16:24:43 -0600 Subject: [PATCH 753/888] MQE-3122: Logging of failed test is not working when test fails in `after` section --- .../Resources/ActionGroupWithDataTest.txt | 14 +++----------- .../ExtendedActionGroupReturningValueTest.txt | 11 +++++++++++ .../Resources/ExtendingSkippedTest.txt | 11 ----------- dev/tests/verification/Resources/MergeSkip.txt | 11 ----------- .../Resources/PersistedReplacementTest.txt | 12 ++++++------ dev/tests/verification/Resources/SkippedTest.txt | 11 ----------- .../Resources/SkippedTestTwoIssues.txt | 11 ----------- .../Resources/SkippedTestWithHooks.txt | 11 ----------- 8 files changed, 20 insertions(+), 72 deletions(-) diff --git a/dev/tests/verification/Resources/ActionGroupWithDataTest.txt b/dev/tests/verification/Resources/ActionGroupWithDataTest.txt index bde1dcdd6..1cfc77d0a 100644 --- a/dev/tests/verification/Resources/ActionGroupWithDataTest.txt +++ b/dev/tests/verification/Resources/ActionGroupWithDataTest.txt @@ -36,17 +36,6 @@ class ActionGroupWithDataTestCest $I->comment("Exiting Action Group [beforeGroup] FunctionalActionGroup"); } - /** - * @param AcceptanceTester $I - * @throws \Exception - */ - public function _after(AcceptanceTester $I) - { - if ($this->isSuccess) { - unlink(__FILE__); - } - } - /** * @param AcceptanceTester $I * @throws \Exception @@ -57,6 +46,9 @@ class ActionGroupWithDataTestCest $I->fillField("#foo", "myData1"); // stepKey: fillField1AfterGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2AfterGroup $I->comment("Exiting Action Group [afterGroup] FunctionalActionGroup"); + if ($this->isSuccess) { + unlink(__FILE__); + } } /** diff --git a/dev/tests/verification/Resources/ExtendedActionGroupReturningValueTest.txt b/dev/tests/verification/Resources/ExtendedActionGroupReturningValueTest.txt index e5efd6cc9..5ecc0d0cd 100644 --- a/dev/tests/verification/Resources/ExtendedActionGroupReturningValueTest.txt +++ b/dev/tests/verification/Resources/ExtendedActionGroupReturningValueTest.txt @@ -23,6 +23,17 @@ class ExtendedActionGroupReturningValueTestCest */ private $isSuccess = false; + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + if ($this->isSuccess) { + unlink(__FILE__); + } + } + /** * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) diff --git a/dev/tests/verification/Resources/ExtendingSkippedTest.txt b/dev/tests/verification/Resources/ExtendingSkippedTest.txt index 0b78b5136..304376ebf 100644 --- a/dev/tests/verification/Resources/ExtendingSkippedTest.txt +++ b/dev/tests/verification/Resources/ExtendingSkippedTest.txt @@ -24,17 +24,6 @@ class ExtendingSkippedTestCest */ private $isSuccess = false; - /** - * @param AcceptanceTester $I - * @throws \Exception - */ - public function _after(AcceptanceTester $I) - { - if ($this->isSuccess) { - unlink(__FILE__); - } - } - /** * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) diff --git a/dev/tests/verification/Resources/MergeSkip.txt b/dev/tests/verification/Resources/MergeSkip.txt index 8ce10f3e1..d807f994f 100644 --- a/dev/tests/verification/Resources/MergeSkip.txt +++ b/dev/tests/verification/Resources/MergeSkip.txt @@ -22,17 +22,6 @@ class MergeSkipCest */ private $isSuccess = false; - /** - * @param AcceptanceTester $I - * @throws \Exception - */ - public function _after(AcceptanceTester $I) - { - if ($this->isSuccess) { - unlink(__FILE__); - } - } - /** * @Features({"TestModule"}) * @Parameter(name = "AcceptanceTester", value="$I") diff --git a/dev/tests/verification/Resources/PersistedReplacementTest.txt b/dev/tests/verification/Resources/PersistedReplacementTest.txt index 95706e75b..e8e249bf7 100644 --- a/dev/tests/verification/Resources/PersistedReplacementTest.txt +++ b/dev/tests/verification/Resources/PersistedReplacementTest.txt @@ -26,20 +26,20 @@ class PersistedReplacementTestCest * @param AcceptanceTester $I * @throws \Exception */ - public function _after(AcceptanceTester $I) + public function _before(AcceptanceTester $I) { - if ($this->isSuccess) { - unlink(__FILE__); - } + $I->createEntity("createData1", "hook", "ReplacementPerson", [], []); // stepKey: createData1 } /** * @param AcceptanceTester $I * @throws \Exception */ - public function _before(AcceptanceTester $I) + public function _after(AcceptanceTester $I) { - $I->createEntity("createData1", "hook", "ReplacementPerson", [], []); // stepKey: createData1 + if ($this->isSuccess) { + unlink(__FILE__); + } } /** diff --git a/dev/tests/verification/Resources/SkippedTest.txt b/dev/tests/verification/Resources/SkippedTest.txt index 99832ef9a..c261a77ad 100644 --- a/dev/tests/verification/Resources/SkippedTest.txt +++ b/dev/tests/verification/Resources/SkippedTest.txt @@ -23,17 +23,6 @@ class SkippedTestCest */ private $isSuccess = false; - /** - * @param AcceptanceTester $I - * @throws \Exception - */ - public function _after(AcceptanceTester $I) - { - if ($this->isSuccess) { - unlink(__FILE__); - } - } - /** * @Stories({"skipped"}) * @Severity(level = SeverityLevel::MINOR) diff --git a/dev/tests/verification/Resources/SkippedTestTwoIssues.txt b/dev/tests/verification/Resources/SkippedTestTwoIssues.txt index 951d15678..a2941e5f1 100644 --- a/dev/tests/verification/Resources/SkippedTestTwoIssues.txt +++ b/dev/tests/verification/Resources/SkippedTestTwoIssues.txt @@ -23,17 +23,6 @@ class SkippedTestTwoIssuesCest */ private $isSuccess = false; - /** - * @param AcceptanceTester $I - * @throws \Exception - */ - public function _after(AcceptanceTester $I) - { - if ($this->isSuccess) { - unlink(__FILE__); - } - } - /** * @Stories({"skippedMultiple"}) * @Severity(level = SeverityLevel::MINOR) diff --git a/dev/tests/verification/Resources/SkippedTestWithHooks.txt b/dev/tests/verification/Resources/SkippedTestWithHooks.txt index 84b0203c4..fdc56c5e1 100644 --- a/dev/tests/verification/Resources/SkippedTestWithHooks.txt +++ b/dev/tests/verification/Resources/SkippedTestWithHooks.txt @@ -23,17 +23,6 @@ class SkippedTestWithHooksCest */ private $isSuccess = false; - /** - * @param AcceptanceTester $I - * @throws \Exception - */ - public function _after(AcceptanceTester $I) - { - if ($this->isSuccess) { - unlink(__FILE__); - } - } - /** * @Stories({"skippedWithHooks"}) * @Severity(level = SeverityLevel::MINOR) From fe20f1bb70525e8c6cc94bdeae2d1db68f998b4b Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Tue, 7 Dec 2021 10:35:03 -0600 Subject: [PATCH 754/888] MQE-3122: Logging of failed test is not working when test fails in `after` section - preparing everything for release --- CHANGELOG.md | 7 +++++++ composer.json | 2 +- composer.lock | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eaa96a63e..52fa211e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ Magento Functional Testing Framework Changelog ================================================ +3.7.2 +--------- + +### Bug fix: +* Failed tests weren't logged correctly to `failed` file which caused a failure during run:failed command execution + + 3.7.1 --------- diff --git a/composer.json b/composer.json index 61ff7b158..48c35e618 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "3.7.1", + "version": "3.7.2", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index 7c4e8d9c9..3a589c395 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f74783e12acad4c892369ccf2820dff5", + "content-hash": "b91a4e8102c543f132c120747714e9ab", "packages": [ { "name": "allure-framework/allure-codeception", From f3164918ae5e7f73d4b18e471afd0c6731322637 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 7 Dec 2021 16:04:47 -0600 Subject: [PATCH 755/888] MQE-3124: fix unbalanced parallel groups --- .../Test/Objects/TestObject.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php index 8341fc7b1..f49c8f3c4 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php @@ -21,12 +21,20 @@ class TestObject const TEST_ACTION_WEIGHT = [ 'waitForPageLoad' => 1500, - 'amOnPage' => 1000, + 'amOnPage' => 1500, 'waitForLoadingMaskToDisappear' => 500, 'wait' => self::WAIT_TIME_ATTRIBUTE, + 'waitForAjaxLoad' => 500, + 'waitForJS' => 500, 'comment' => 5, 'assertCount' => 5, - 'closeAdminNotification' => 10 + 'closeAdminNotification' => 10, + 'magentoCLI' => 1000, + 'magentoCron' => 3000, + 'createData' => 500, + 'deleteData' => 100, + 'updateData' => 100, + 'getOTP' => 200, ]; /** From 75b00c5f82f52858d78c34d95fb5cd08197e8f48 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Thu, 9 Dec 2021 10:09:47 -0600 Subject: [PATCH 756/888] MQE-3124: fix unbalanced parallel groups --- .../FunctionalTestingFramework/Test/Objects/TestObject.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php index f49c8f3c4..bce0f70a9 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php @@ -32,9 +32,9 @@ class TestObject 'magentoCLI' => 1000, 'magentoCron' => 3000, 'createData' => 500, - 'deleteData' => 100, - 'updateData' => 100, - 'getOTP' => 200, + 'deleteData' => 200, + 'updateData' => 200, + 'getOTP' => 1000, ]; /** From 76c0d7c9ba051066125a2f94a248e6cb4b1c853c Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 14 Dec 2021 11:14:24 -0600 Subject: [PATCH 757/888] MQE-3124: fix unbalanced parallel groups --- .../Test/Objects/TestObject.php | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php index bce0f70a9..be162cb51 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php @@ -37,6 +37,15 @@ class TestObject 'getOTP' => 1000, ]; + const WEBAPI_AUTH_TEST_ACTIONS = [ + 'createData', + 'deleteData', + 'updateData', + 'getData', + ]; + + const WEBAPI_AUTH_TEST_ACTION_WEIGHT = 6000; + /** * Name of the test * @@ -93,6 +102,11 @@ class TestObject */ private $deprecated; + /** + * Indicates if a test contains an action that requires Web API authentication. + */ + private bool $hasWebApiAuthAction; + /** * TestObject constructor. * @@ -120,6 +134,7 @@ public function __construct( $this->filename = $filename; $this->parentTest = $parentTest; $this->deprecated = $deprecated; + $this->hasWebApiAuthAction = false; } /** @@ -230,7 +245,11 @@ public function getEstimatedDuration() $testTime = $this->calculateWeightedActionTimes($this->getOrderedActions()); - return $hookTime + $testTime; + if ($this->hasWebApiAuthAction) { + return $hookTime + $testTime + self::WEBAPI_AUTH_TEST_ACTION_WEIGHT; + } else { + return $hookTime + $testTime; + } } /** @@ -245,6 +264,11 @@ private function calculateWeightedActionTimes($actions) // search for any actions of special type foreach ($actions as $action) { /** @var ActionObject $action */ + + if (!$this->hasWebApiAuthAction && in_array($action->getType(), self::WEBAPI_AUTH_TEST_ACTIONS)) { + $this->hasWebApiAuthAction = true; + } + if (array_key_exists($action->getType(), self::TEST_ACTION_WEIGHT)) { $weight = self::TEST_ACTION_WEIGHT[$action->getType()]; if ($weight === self::WAIT_TIME_ATTRIBUTE) { From d508adbd71fdf8ad6aaeeea3fecae02edd64ec69 Mon Sep 17 00:00:00 2001 From: David Haecker <dhaecker@magento.com> Date: Tue, 14 Dec 2021 14:43:48 -0600 Subject: [PATCH 758/888] adding pagebuilder file upload spinner to loadingMaskLocators --- .../FunctionalTestingFramework/Module/MagentoWebDriver.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 708cdfb7e..238bbae48 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -72,6 +72,7 @@ class MagentoWebDriver extends WebDriver '//div[contains(@class, "admin__data-grid-loading-mask")]', '//div[contains(@class, "admin__form-loading-mask")]', '//div[@data-role="spinner"]', + '//div[@class="file-uploader-spinner"]', ]; /** From 69006336d66864975fb4196ffafa3dc1db801f2f Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Tue, 14 Dec 2021 13:18:30 -0600 Subject: [PATCH 759/888] MQE-3124: fix unbalanced parallel groups --- .../Test/Objects/TestObject.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php index be162cb51..f556947f1 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php @@ -25,6 +25,10 @@ class TestObject 'waitForLoadingMaskToDisappear' => 500, 'wait' => self::WAIT_TIME_ATTRIBUTE, 'waitForAjaxLoad' => 500, + 'waitForElementNotVisible' => 500, + 'waitForElementVisible' => 500, + 'waitForText' => 500, + 'waitForElement' => 500, 'waitForJS' => 500, 'comment' => 5, 'assertCount' => 5, @@ -104,8 +108,10 @@ class TestObject /** * Indicates if a test contains an action that requires Web API authentication. + * + * @var boolean */ - private bool $hasWebApiAuthAction; + private $hasWebApiAuthAction; /** * TestObject constructor. From cad424a79d2d13996ed84da7fcac5957411f1e9e Mon Sep 17 00:00:00 2001 From: "Shashik.K.Singh" <shashik.k.singh@BLR1-LMC-N71386.domain.name> Date: Wed, 15 Dec 2021 17:09:45 +0530 Subject: [PATCH 760/888] throw error message if key value pair is not mapped properly in .credentials file --- .../DataGenerator/Handlers/SecretStorage/FileStorage.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/FileStorage.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/FileStorage.php index 479c608e4..1d122b9c5 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/FileStorage.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/FileStorage.php @@ -101,6 +101,11 @@ private function encryptCredFileContents($credContents) if (substr($credValue, 0, 1) === '#' || empty($credValue)) { continue; } + elseif (is_bool(strpos($credValue, "="))){ + throw new TestFrameworkException( + $credValue." not configured correctly in .credentials file" + ); + } list($key, $value) = explode("=", $credValue, 2); if (!empty($value)) { From c22f9f96c7e4845a580d8d4c0cfc5dc1e29f8ecb Mon Sep 17 00:00:00 2001 From: David Haecker <dhaecker@magento.com> Date: Wed, 15 Dec 2021 09:42:54 -0600 Subject: [PATCH 761/888] adding more locators to loadingMaskLocators --- .../FunctionalTestingFramework/Module/MagentoWebDriver.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 238bbae48..c9203dbbb 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -72,7 +72,9 @@ class MagentoWebDriver extends WebDriver '//div[contains(@class, "admin__data-grid-loading-mask")]', '//div[contains(@class, "admin__form-loading-mask")]', '//div[@data-role="spinner"]', - '//div[@class="file-uploader-spinner"]', + '//div[contains(@class,"file-uploader-spinner")]', + '//div[contains(@class,"image-uploader-spinner")]', + '//div[contains(@class,"progressbar")]//ancestor::div[@class="file-row"]', ]; /** From feff762ab3dce36c87eb9d55fa03daa0bc310658 Mon Sep 17 00:00:00 2001 From: David Haecker <dhaecker@magento.com> Date: Wed, 15 Dec 2021 11:11:40 -0600 Subject: [PATCH 762/888] editing loadingMaskLocators --- .../FunctionalTestingFramework/Module/MagentoWebDriver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index c9203dbbb..68d2efd4b 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -74,7 +74,7 @@ class MagentoWebDriver extends WebDriver '//div[@data-role="spinner"]', '//div[contains(@class,"file-uploader-spinner")]', '//div[contains(@class,"image-uploader-spinner")]', - '//div[contains(@class,"progressbar")]//ancestor::div[@class="file-row"]', + '//div[contains(@class,"uploader")]//div[@class="file-row"]', ]; /** From da431d64c0cb0878fc72490036338874efa02794 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Wed, 15 Dec 2021 17:58:55 -0600 Subject: [PATCH 763/888] MQE-3155: Release MFTF 3.7.3 - update composer.json and CHANGELOG.md --- CHANGELOG.md | 8 ++++++++ composer.json | 2 +- composer.lock | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52fa211e3..2d8a662fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ Magento Functional Testing Framework Changelog ================================================ +3.7.3 +--------- + +### Updates: +* Fix encoding issue when secret key contains plus sign +* Adding pagebuilder file upload spinner to loadingMaskLocators + + 3.7.2 --------- diff --git a/composer.json b/composer.json index 48c35e618..8fedf25a8 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "3.7.2", + "version": "3.7.3", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index 3a589c395..4a1a7d2be 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b91a4e8102c543f132c120747714e9ab", + "content-hash": "822c40666da3ff087f25393fd4dc9371", "packages": [ { "name": "allure-framework/allure-codeception", From 34504b702ad0bbeb22921175e7b32f51b6fdb2c1 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Mon, 20 Dec 2021 12:47:30 +0530 Subject: [PATCH 764/888] MQE-1794 : Removed Parameters from allure report --- .../FunctionalTestingFramework/Util/TestGenerator.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index c0249a32b..5aaef4623 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -525,11 +525,7 @@ private function generateMethodAnnotations($annotationType = null, $annotationNa break; case null: - $annotationToAppend = sprintf( - "{$indent} * @Parameter(name = \"%s\", value=\"$%s\")\n", - "AcceptanceTester", - "I" - ); + $annotationToAppend = ""; $annotationToAppend .= sprintf("{$indent} * @param %s $%s\n", "AcceptanceTester", "I"); $annotationToAppend .= "{$indent} * @return void\n"; $annotationToAppend .= "{$indent} * @throws \Exception\n"; From 47980b2bf3c7d4fa22388ae02c3e1b85c6c1742e Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@ip-192-168-29-250.ec2.internal> Date: Mon, 20 Dec 2021 13:12:52 +0530 Subject: [PATCH 765/888] fixed tests --- .../Resources/ActionGroupContainsStepKeyInArgText.txt | 1 - .../verification/Resources/ActionGroupMergedViaInsertBefore.txt | 1 - .../verification/Resources/ActionGroupReturningValueTest.txt | 1 - dev/tests/verification/Resources/ActionGroupToExtend.txt | 1 - dev/tests/verification/Resources/ActionGroupUsingCreateData.txt | 1 - .../verification/Resources/ActionGroupUsingNestedArgument.txt | 1 - .../verification/Resources/ActionGroupWithDataOverrideTest.txt | 1 - dev/tests/verification/Resources/ActionGroupWithDataTest.txt | 1 - .../ActionGroupWithDefaultArgumentAndStringSelectorParam.txt | 1 - ...ionGroupWithMultipleParameterSelectorsFromDefaultArgument.txt | 1 - dev/tests/verification/Resources/ActionGroupWithNoArguments.txt | 1 - .../verification/Resources/ActionGroupWithNoDefaultTest.txt | 1 - .../Resources/ActionGroupWithParameterizedElementWithHyphen.txt | 1 - ...ActionGroupWithParameterizedElementsWithStepKeyReferences.txt | 1 - .../ActionGroupWithPassedArgumentAndStringSelectorParam.txt | 1 - .../verification/Resources/ActionGroupWithPersistedData.txt | 1 - .../Resources/ActionGroupWithSectionAndDataAsArguments.txt | 1 - .../ActionGroupWithSimpleDataUsageFromDefaultArgument.txt | 1 - .../ActionGroupWithSimpleDataUsageFromPassedArgument.txt | 1 - ...ActionGroupWithSingleParameterSelectorFromDefaultArgument.txt | 1 - .../ActionGroupWithSingleParameterSelectorFromPassedArgument.txt | 1 - .../verification/Resources/ActionGroupWithStepKeyReferences.txt | 1 - .../Resources/ActionGroupWithTopLevelPersistedData.txt | 1 - .../verification/Resources/ArgumentWithSameNameAsElement.txt | 1 - dev/tests/verification/Resources/AssertTest.txt | 1 - dev/tests/verification/Resources/BasicFunctionalTest.txt | 1 - dev/tests/verification/Resources/BasicMergeTest.txt | 1 - dev/tests/verification/Resources/CharacterReplacementTest.txt | 1 - dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt | 1 - dev/tests/verification/Resources/ChildExtendedTestMerging.txt | 1 - dev/tests/verification/Resources/ChildExtendedTestNoParent.txt | 1 - .../verification/Resources/ChildExtendedTestRemoveAction.txt | 1 - .../verification/Resources/ChildExtendedTestRemoveHookAction.txt | 1 - dev/tests/verification/Resources/ChildExtendedTestReplace.txt | 1 - .../verification/Resources/ChildExtendedTestReplaceHook.txt | 1 - dev/tests/verification/Resources/DataActionsTest.txt | 1 - dev/tests/verification/Resources/DataReplacementTest.txt | 1 - dev/tests/verification/Resources/DeprecatedEntitiesTest.txt | 1 - dev/tests/verification/Resources/DeprecatedTest.txt | 1 - dev/tests/verification/Resources/ExecuteJsEscapingTest.txt | 1 - dev/tests/verification/Resources/ExtendParentDataTest.txt | 1 - dev/tests/verification/Resources/ExtendedActionGroup.txt | 1 - .../Resources/ExtendedActionGroupReturningValueTest.txt | 1 - .../verification/Resources/ExtendedChildTestInSuiteCest.txt | 1 - dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt | 1 - dev/tests/verification/Resources/ExtendedRemoveActionGroup.txt | 1 - dev/tests/verification/Resources/ExtendingSkippedTest.txt | 1 - dev/tests/verification/Resources/GroupSkipGenerationTest.txt | 1 - dev/tests/verification/Resources/HookActionsTest.txt | 1 - dev/tests/verification/Resources/LocatorFunctionTest.txt | 1 - dev/tests/verification/Resources/MergeMassViaInsertAfter.txt | 1 - dev/tests/verification/Resources/MergeMassViaInsertBefore.txt | 1 - dev/tests/verification/Resources/MergeSkip.txt | 1 - .../Resources/MergedActionGroupReturningValueTest.txt | 1 - dev/tests/verification/Resources/MergedActionGroupTest.txt | 1 - dev/tests/verification/Resources/MergedReferencesTest.txt | 1 - dev/tests/verification/Resources/MultipleActionGroupsTest.txt | 1 - dev/tests/verification/Resources/PageReplacementTest.txt | 1 - dev/tests/verification/Resources/ParameterArrayTest.txt | 1 - dev/tests/verification/Resources/ParentExtendedTest.txt | 1 - .../verification/Resources/PersistedAndXmlEntityArguments.txt | 1 - dev/tests/verification/Resources/PersistedReplacementTest.txt | 1 - .../Resources/PersistenceActionGroupAppendingTest.txt | 1 - dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt | 1 - dev/tests/verification/Resources/SectionReplacementTest.txt | 1 - dev/tests/verification/Resources/SkippedTest.txt | 1 - dev/tests/verification/Resources/SkippedTestTwoIssues.txt | 1 - dev/tests/verification/Resources/SkippedTestWithHooks.txt | 1 - dev/tests/verification/Resources/XmlCommentedActionGroupTest.txt | 1 - dev/tests/verification/Resources/XmlCommentedTest.txt | 1 - 70 files changed, 70 deletions(-) diff --git a/dev/tests/verification/Resources/ActionGroupContainsStepKeyInArgText.txt b/dev/tests/verification/Resources/ActionGroupContainsStepKeyInArgText.txt index 710612750..f2066e1d8 100644 --- a/dev/tests/verification/Resources/ActionGroupContainsStepKeyInArgText.txt +++ b/dev/tests/verification/Resources/ActionGroupContainsStepKeyInArgText.txt @@ -46,7 +46,6 @@ class ActionGroupContainsStepKeyInArgTextCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ActionGroupMergedViaInsertBefore.txt b/dev/tests/verification/Resources/ActionGroupMergedViaInsertBefore.txt index 05d82165a..1479f8d9d 100644 --- a/dev/tests/verification/Resources/ActionGroupMergedViaInsertBefore.txt +++ b/dev/tests/verification/Resources/ActionGroupMergedViaInsertBefore.txt @@ -35,7 +35,6 @@ class ActionGroupMergedViaInsertBeforeCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ActionGroupReturningValueTest.txt b/dev/tests/verification/Resources/ActionGroupReturningValueTest.txt index 1fb0726e1..92461bfaa 100644 --- a/dev/tests/verification/Resources/ActionGroupReturningValueTest.txt +++ b/dev/tests/verification/Resources/ActionGroupReturningValueTest.txt @@ -64,7 +64,6 @@ class ActionGroupReturningValueTestCest * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) * @Stories({"MQE-433"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ActionGroupToExtend.txt b/dev/tests/verification/Resources/ActionGroupToExtend.txt index 5ec7f0a0e..7fd1a8f05 100644 --- a/dev/tests/verification/Resources/ActionGroupToExtend.txt +++ b/dev/tests/verification/Resources/ActionGroupToExtend.txt @@ -35,7 +35,6 @@ class ActionGroupToExtendCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt b/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt index b451abc2b..2b3c56883 100644 --- a/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt +++ b/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt @@ -47,7 +47,6 @@ class ActionGroupUsingCreateDataCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ActionGroupUsingNestedArgument.txt b/dev/tests/verification/Resources/ActionGroupUsingNestedArgument.txt index ff745ba05..40254de00 100644 --- a/dev/tests/verification/Resources/ActionGroupUsingNestedArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupUsingNestedArgument.txt @@ -35,7 +35,6 @@ class ActionGroupUsingNestedArgumentCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt b/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt index 2ecc0f729..34486ead4 100644 --- a/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt +++ b/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt @@ -64,7 +64,6 @@ class ActionGroupWithDataOverrideTestCest * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) * @Stories({"MQE-433"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ActionGroupWithDataTest.txt b/dev/tests/verification/Resources/ActionGroupWithDataTest.txt index 1cfc77d0a..542796ab6 100644 --- a/dev/tests/verification/Resources/ActionGroupWithDataTest.txt +++ b/dev/tests/verification/Resources/ActionGroupWithDataTest.txt @@ -64,7 +64,6 @@ class ActionGroupWithDataTestCest * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) * @Stories({"MQE-433"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ActionGroupWithDefaultArgumentAndStringSelectorParam.txt b/dev/tests/verification/Resources/ActionGroupWithDefaultArgumentAndStringSelectorParam.txt index 7a68cf16a..838c98e3b 100644 --- a/dev/tests/verification/Resources/ActionGroupWithDefaultArgumentAndStringSelectorParam.txt +++ b/dev/tests/verification/Resources/ActionGroupWithDefaultArgumentAndStringSelectorParam.txt @@ -37,7 +37,6 @@ class ActionGroupWithDefaultArgumentAndStringSelectorParamCest /** * @Severity(level = SeverityLevel::BLOCKER) * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.txt b/dev/tests/verification/Resources/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.txt index 6b8c738e0..31a77b903 100644 --- a/dev/tests/verification/Resources/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithMultipleParameterSelectorsFromDefaultArgument.txt @@ -37,7 +37,6 @@ class ActionGroupWithMultipleParameterSelectorsFromDefaultArgumentCest /** * @Severity(level = SeverityLevel::BLOCKER) * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ActionGroupWithNoArguments.txt b/dev/tests/verification/Resources/ActionGroupWithNoArguments.txt index 2371d86dd..9d06b309e 100644 --- a/dev/tests/verification/Resources/ActionGroupWithNoArguments.txt +++ b/dev/tests/verification/Resources/ActionGroupWithNoArguments.txt @@ -37,7 +37,6 @@ class ActionGroupWithNoArgumentsCest /** * @Severity(level = SeverityLevel::BLOCKER) * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt b/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt index 19f3de5ad..2705c5ca1 100644 --- a/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt +++ b/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt @@ -64,7 +64,6 @@ class ActionGroupWithNoDefaultTestCest * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) * @Stories({"MQE-433"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ActionGroupWithParameterizedElementWithHyphen.txt b/dev/tests/verification/Resources/ActionGroupWithParameterizedElementWithHyphen.txt index 17a9d766b..376a6298d 100644 --- a/dev/tests/verification/Resources/ActionGroupWithParameterizedElementWithHyphen.txt +++ b/dev/tests/verification/Resources/ActionGroupWithParameterizedElementWithHyphen.txt @@ -35,7 +35,6 @@ class ActionGroupWithParameterizedElementWithHyphenCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ActionGroupWithParameterizedElementsWithStepKeyReferences.txt b/dev/tests/verification/Resources/ActionGroupWithParameterizedElementsWithStepKeyReferences.txt index 2f31d0686..83aaecf08 100644 --- a/dev/tests/verification/Resources/ActionGroupWithParameterizedElementsWithStepKeyReferences.txt +++ b/dev/tests/verification/Resources/ActionGroupWithParameterizedElementsWithStepKeyReferences.txt @@ -35,7 +35,6 @@ class ActionGroupWithParameterizedElementsWithStepKeyReferencesCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ActionGroupWithPassedArgumentAndStringSelectorParam.txt b/dev/tests/verification/Resources/ActionGroupWithPassedArgumentAndStringSelectorParam.txt index e58d8c5a5..1a2e886bb 100644 --- a/dev/tests/verification/Resources/ActionGroupWithPassedArgumentAndStringSelectorParam.txt +++ b/dev/tests/verification/Resources/ActionGroupWithPassedArgumentAndStringSelectorParam.txt @@ -37,7 +37,6 @@ class ActionGroupWithPassedArgumentAndStringSelectorParamCest /** * @Severity(level = SeverityLevel::BLOCKER) * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt b/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt index 782e27a8e..243569e46 100644 --- a/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt +++ b/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt @@ -64,7 +64,6 @@ class ActionGroupWithPersistedDataCest * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) * @Stories({"MQE-433"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ActionGroupWithSectionAndDataAsArguments.txt b/dev/tests/verification/Resources/ActionGroupWithSectionAndDataAsArguments.txt index d07a32cd0..65d25df00 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSectionAndDataAsArguments.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSectionAndDataAsArguments.txt @@ -35,7 +35,6 @@ class ActionGroupWithSectionAndDataAsArgumentsCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromDefaultArgument.txt b/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromDefaultArgument.txt index ab5465ca0..65ce18e9f 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromDefaultArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromDefaultArgument.txt @@ -37,7 +37,6 @@ class ActionGroupWithSimpleDataUsageFromDefaultArgumentCest /** * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromPassedArgument.txt b/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromPassedArgument.txt index c86e9dc4f..d33a7da1e 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromPassedArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSimpleDataUsageFromPassedArgument.txt @@ -37,7 +37,6 @@ class ActionGroupWithSimpleDataUsageFromPassedArgumentCest /** * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromDefaultArgument.txt b/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromDefaultArgument.txt index 34ba535f8..7aa0ba5a6 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromDefaultArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromDefaultArgument.txt @@ -37,7 +37,6 @@ class ActionGroupWithSingleParameterSelectorFromDefaultArgumentCest /** * @Severity(level = SeverityLevel::BLOCKER) * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromPassedArgument.txt b/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromPassedArgument.txt index 45f72a95b..93fb74898 100644 --- a/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromPassedArgument.txt +++ b/dev/tests/verification/Resources/ActionGroupWithSingleParameterSelectorFromPassedArgument.txt @@ -37,7 +37,6 @@ class ActionGroupWithSingleParameterSelectorFromPassedArgumentCest /** * @Severity(level = SeverityLevel::BLOCKER) * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt b/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt index 532c70868..e5886ab8e 100644 --- a/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt +++ b/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt @@ -35,7 +35,6 @@ class ActionGroupWithStepKeyReferencesCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt b/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt index 285e66370..7cc0ef505 100644 --- a/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt +++ b/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt @@ -64,7 +64,6 @@ class ActionGroupWithTopLevelPersistedDataCest * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) * @Stories({"MQE-433"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt b/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt index b643eb759..55ea28d00 100644 --- a/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt +++ b/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt @@ -64,7 +64,6 @@ class ArgumentWithSameNameAsElementCest * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) * @Stories({"MQE-433"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/AssertTest.txt b/dev/tests/verification/Resources/AssertTest.txt index 6c30b7273..381ab4818 100644 --- a/dev/tests/verification/Resources/AssertTest.txt +++ b/dev/tests/verification/Resources/AssertTest.txt @@ -44,7 +44,6 @@ class AssertTestCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/BasicFunctionalTest.txt b/dev/tests/verification/Resources/BasicFunctionalTest.txt index c5ce0305c..526162e3e 100644 --- a/dev/tests/verification/Resources/BasicFunctionalTest.txt +++ b/dev/tests/verification/Resources/BasicFunctionalTest.txt @@ -58,7 +58,6 @@ class BasicFunctionalTestCest * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) * @Stories({"MQE-305"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/BasicMergeTest.txt b/dev/tests/verification/Resources/BasicMergeTest.txt index 0ccd3e898..27b22bd34 100644 --- a/dev/tests/verification/Resources/BasicMergeTest.txt +++ b/dev/tests/verification/Resources/BasicMergeTest.txt @@ -60,7 +60,6 @@ class BasicMergeTestCest * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) * @Stories({"MQE-433"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/CharacterReplacementTest.txt b/dev/tests/verification/Resources/CharacterReplacementTest.txt index b87c36a40..bf10c94fc 100644 --- a/dev/tests/verification/Resources/CharacterReplacementTest.txt +++ b/dev/tests/verification/Resources/CharacterReplacementTest.txt @@ -35,7 +35,6 @@ class CharacterReplacementTestCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt b/dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt index 2e949082a..63b874964 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt @@ -58,7 +58,6 @@ class ChildExtendedTestAddHooksCest * @Severity(level = SeverityLevel::MINOR) * @Features({"TestModule"}) * @Stories({"Parent"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ChildExtendedTestMerging.txt b/dev/tests/verification/Resources/ChildExtendedTestMerging.txt index 9e892e290..5f506e58c 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestMerging.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestMerging.txt @@ -60,7 +60,6 @@ class ChildExtendedTestMergingCest * @Severity(level = SeverityLevel::TRIVIAL) * @Features({"TestModule"}) * @Stories({"Child"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ChildExtendedTestNoParent.txt b/dev/tests/verification/Resources/ChildExtendedTestNoParent.txt index 12094a518..1bd027399 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestNoParent.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestNoParent.txt @@ -40,7 +40,6 @@ class ChildExtendedTestNoParentCest * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) * @Stories({"Child"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ChildExtendedTestRemoveAction.txt b/dev/tests/verification/Resources/ChildExtendedTestRemoveAction.txt index 28b4ec7fd..64ae855b8 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestRemoveAction.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestRemoveAction.txt @@ -58,7 +58,6 @@ class ChildExtendedTestRemoveActionCest * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) * @Stories({"Child"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ChildExtendedTestRemoveHookAction.txt b/dev/tests/verification/Resources/ChildExtendedTestRemoveHookAction.txt index 3649c85fe..e4acdf155 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestRemoveHookAction.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestRemoveHookAction.txt @@ -57,7 +57,6 @@ class ChildExtendedTestRemoveHookActionCest * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) * @Stories({"Child"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ChildExtendedTestReplace.txt b/dev/tests/verification/Resources/ChildExtendedTestReplace.txt index a3cfdd2aa..0b62e3762 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestReplace.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestReplace.txt @@ -58,7 +58,6 @@ class ChildExtendedTestReplaceCest * @Severity(level = SeverityLevel::TRIVIAL) * @Features({"TestModule"}) * @Stories({"Child"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ChildExtendedTestReplaceHook.txt b/dev/tests/verification/Resources/ChildExtendedTestReplaceHook.txt index abe55a071..1e8366351 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestReplaceHook.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestReplaceHook.txt @@ -58,7 +58,6 @@ class ChildExtendedTestReplaceHookCest * @Severity(level = SeverityLevel::TRIVIAL) * @Features({"TestModule"}) * @Stories({"Child"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/DataActionsTest.txt b/dev/tests/verification/Resources/DataActionsTest.txt index f84f97040..4a49db289 100644 --- a/dev/tests/verification/Resources/DataActionsTest.txt +++ b/dev/tests/verification/Resources/DataActionsTest.txt @@ -46,7 +46,6 @@ class DataActionsTestCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/DataReplacementTest.txt b/dev/tests/verification/Resources/DataReplacementTest.txt index 00c28b31e..940504c63 100644 --- a/dev/tests/verification/Resources/DataReplacementTest.txt +++ b/dev/tests/verification/Resources/DataReplacementTest.txt @@ -35,7 +35,6 @@ class DataReplacementTestCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/DeprecatedEntitiesTest.txt b/dev/tests/verification/Resources/DeprecatedEntitiesTest.txt index 9a0ec8a27..cc205c438 100644 --- a/dev/tests/verification/Resources/DeprecatedEntitiesTest.txt +++ b/dev/tests/verification/Resources/DeprecatedEntitiesTest.txt @@ -35,7 +35,6 @@ class DeprecatedEntitiesTestCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/DeprecatedTest.txt b/dev/tests/verification/Resources/DeprecatedTest.txt index acdb53cc0..7e34131d5 100644 --- a/dev/tests/verification/Resources/DeprecatedTest.txt +++ b/dev/tests/verification/Resources/DeprecatedTest.txt @@ -35,7 +35,6 @@ class DeprecatedTestCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ExecuteJsEscapingTest.txt b/dev/tests/verification/Resources/ExecuteJsEscapingTest.txt index fc1331ef2..8718d188b 100644 --- a/dev/tests/verification/Resources/ExecuteJsEscapingTest.txt +++ b/dev/tests/verification/Resources/ExecuteJsEscapingTest.txt @@ -35,7 +35,6 @@ class ExecuteJsEscapingTestCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ExtendParentDataTest.txt b/dev/tests/verification/Resources/ExtendParentDataTest.txt index 6b96cbbda..93ea3b754 100644 --- a/dev/tests/verification/Resources/ExtendParentDataTest.txt +++ b/dev/tests/verification/Resources/ExtendParentDataTest.txt @@ -35,7 +35,6 @@ class ExtendParentDataTestCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ExtendedActionGroup.txt b/dev/tests/verification/Resources/ExtendedActionGroup.txt index a2cc9fc74..2d2373c0d 100644 --- a/dev/tests/verification/Resources/ExtendedActionGroup.txt +++ b/dev/tests/verification/Resources/ExtendedActionGroup.txt @@ -35,7 +35,6 @@ class ExtendedActionGroupCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ExtendedActionGroupReturningValueTest.txt b/dev/tests/verification/Resources/ExtendedActionGroupReturningValueTest.txt index 5ecc0d0cd..4c19fea5e 100644 --- a/dev/tests/verification/Resources/ExtendedActionGroupReturningValueTest.txt +++ b/dev/tests/verification/Resources/ExtendedActionGroupReturningValueTest.txt @@ -37,7 +37,6 @@ class ExtendedActionGroupReturningValueTestCest /** * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ExtendedChildTestInSuiteCest.txt b/dev/tests/verification/Resources/ExtendedChildTestInSuiteCest.txt index 2e6da3464..fae417d55 100644 --- a/dev/tests/verification/Resources/ExtendedChildTestInSuiteCest.txt +++ b/dev/tests/verification/Resources/ExtendedChildTestInSuiteCest.txt @@ -58,7 +58,6 @@ class ExtendedChildTestInSuiteCest * @Severity(level = SeverityLevel::TRIVIAL) * @Features({"TestModule"}) * @Stories({"ExtendedChildTestInSuite"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt b/dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt index a18346a77..be3ffbf58 100644 --- a/dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt +++ b/dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt @@ -57,7 +57,6 @@ class ExtendedChildTestNotInSuiteCest * @Severity(level = SeverityLevel::TRIVIAL) * @Features({"TestModule"}) * @Stories({"ExtendedChildTestNotInSuite"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ExtendedRemoveActionGroup.txt b/dev/tests/verification/Resources/ExtendedRemoveActionGroup.txt index 1e24e644a..809fd2874 100644 --- a/dev/tests/verification/Resources/ExtendedRemoveActionGroup.txt +++ b/dev/tests/verification/Resources/ExtendedRemoveActionGroup.txt @@ -35,7 +35,6 @@ class ExtendedRemoveActionGroupCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ExtendingSkippedTest.txt b/dev/tests/verification/Resources/ExtendingSkippedTest.txt index 304376ebf..522ba7620 100644 --- a/dev/tests/verification/Resources/ExtendingSkippedTest.txt +++ b/dev/tests/verification/Resources/ExtendingSkippedTest.txt @@ -28,7 +28,6 @@ class ExtendingSkippedTestCest * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) * @Stories({"Child"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/GroupSkipGenerationTest.txt b/dev/tests/verification/Resources/GroupSkipGenerationTest.txt index b13aa399a..034307e37 100644 --- a/dev/tests/verification/Resources/GroupSkipGenerationTest.txt +++ b/dev/tests/verification/Resources/GroupSkipGenerationTest.txt @@ -39,7 +39,6 @@ class GroupSkipGenerationTestCest * @Stories({"GroupSkipGenerationTestStory"}) * @Severity(level = SeverityLevel::MINOR) * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/HookActionsTest.txt b/dev/tests/verification/Resources/HookActionsTest.txt index a04a980a1..0132cd48c 100644 --- a/dev/tests/verification/Resources/HookActionsTest.txt +++ b/dev/tests/verification/Resources/HookActionsTest.txt @@ -57,7 +57,6 @@ class HookActionsTestCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/LocatorFunctionTest.txt b/dev/tests/verification/Resources/LocatorFunctionTest.txt index 86d744a2d..f26f2aa4f 100644 --- a/dev/tests/verification/Resources/LocatorFunctionTest.txt +++ b/dev/tests/verification/Resources/LocatorFunctionTest.txt @@ -35,7 +35,6 @@ class LocatorFunctionTestCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/MergeMassViaInsertAfter.txt b/dev/tests/verification/Resources/MergeMassViaInsertAfter.txt index 49c246251..60cfdb410 100644 --- a/dev/tests/verification/Resources/MergeMassViaInsertAfter.txt +++ b/dev/tests/verification/Resources/MergeMassViaInsertAfter.txt @@ -35,7 +35,6 @@ class MergeMassViaInsertAfterCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/MergeMassViaInsertBefore.txt b/dev/tests/verification/Resources/MergeMassViaInsertBefore.txt index 6080a5f23..eb6be579b 100644 --- a/dev/tests/verification/Resources/MergeMassViaInsertBefore.txt +++ b/dev/tests/verification/Resources/MergeMassViaInsertBefore.txt @@ -35,7 +35,6 @@ class MergeMassViaInsertBeforeCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/MergeSkip.txt b/dev/tests/verification/Resources/MergeSkip.txt index d807f994f..498aa1054 100644 --- a/dev/tests/verification/Resources/MergeSkip.txt +++ b/dev/tests/verification/Resources/MergeSkip.txt @@ -24,7 +24,6 @@ class MergeSkipCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/MergedActionGroupReturningValueTest.txt b/dev/tests/verification/Resources/MergedActionGroupReturningValueTest.txt index 71d8ed94a..cce383b6c 100644 --- a/dev/tests/verification/Resources/MergedActionGroupReturningValueTest.txt +++ b/dev/tests/verification/Resources/MergedActionGroupReturningValueTest.txt @@ -64,7 +64,6 @@ class MergedActionGroupReturningValueTestCest * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) * @Stories({"MQE-433"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/MergedActionGroupTest.txt b/dev/tests/verification/Resources/MergedActionGroupTest.txt index e92a06f6f..e1a67c144 100644 --- a/dev/tests/verification/Resources/MergedActionGroupTest.txt +++ b/dev/tests/verification/Resources/MergedActionGroupTest.txt @@ -64,7 +64,6 @@ class MergedActionGroupTestCest * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) * @Stories({"MQE-433"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/MergedReferencesTest.txt b/dev/tests/verification/Resources/MergedReferencesTest.txt index b1f95d56c..d020c3466 100644 --- a/dev/tests/verification/Resources/MergedReferencesTest.txt +++ b/dev/tests/verification/Resources/MergedReferencesTest.txt @@ -58,7 +58,6 @@ class MergedReferencesTestCest * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) * @Stories({"MQE-433"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/MultipleActionGroupsTest.txt b/dev/tests/verification/Resources/MultipleActionGroupsTest.txt index 15659f21f..bcc0f31e0 100644 --- a/dev/tests/verification/Resources/MultipleActionGroupsTest.txt +++ b/dev/tests/verification/Resources/MultipleActionGroupsTest.txt @@ -64,7 +64,6 @@ class MultipleActionGroupsTestCest * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) * @Stories({"MQE-433"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/PageReplacementTest.txt b/dev/tests/verification/Resources/PageReplacementTest.txt index af4defdb9..097a8be02 100644 --- a/dev/tests/verification/Resources/PageReplacementTest.txt +++ b/dev/tests/verification/Resources/PageReplacementTest.txt @@ -35,7 +35,6 @@ class PageReplacementTestCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ParameterArrayTest.txt b/dev/tests/verification/Resources/ParameterArrayTest.txt index 6488db6b0..1439dacdc 100644 --- a/dev/tests/verification/Resources/ParameterArrayTest.txt +++ b/dev/tests/verification/Resources/ParameterArrayTest.txt @@ -35,7 +35,6 @@ class ParameterArrayTestCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ParentExtendedTest.txt b/dev/tests/verification/Resources/ParentExtendedTest.txt index 73e6b7aa0..3c24988ac 100644 --- a/dev/tests/verification/Resources/ParentExtendedTest.txt +++ b/dev/tests/verification/Resources/ParentExtendedTest.txt @@ -58,7 +58,6 @@ class ParentExtendedTestCest * @Severity(level = SeverityLevel::MINOR) * @Features({"TestModule"}) * @Stories({"Parent"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/PersistedAndXmlEntityArguments.txt b/dev/tests/verification/Resources/PersistedAndXmlEntityArguments.txt index f4cc8cfaa..35eb126cd 100644 --- a/dev/tests/verification/Resources/PersistedAndXmlEntityArguments.txt +++ b/dev/tests/verification/Resources/PersistedAndXmlEntityArguments.txt @@ -35,7 +35,6 @@ class PersistedAndXmlEntityArgumentsCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/PersistedReplacementTest.txt b/dev/tests/verification/Resources/PersistedReplacementTest.txt index e8e249bf7..2f0bde2ab 100644 --- a/dev/tests/verification/Resources/PersistedReplacementTest.txt +++ b/dev/tests/verification/Resources/PersistedReplacementTest.txt @@ -44,7 +44,6 @@ class PersistedReplacementTestCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt b/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt index d1f75ccb6..b3b10a38b 100644 --- a/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt +++ b/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt @@ -50,7 +50,6 @@ class PersistenceActionGroupAppendingTestCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt b/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt index 5bbc0b325..6558daa74 100644 --- a/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt +++ b/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt @@ -48,7 +48,6 @@ class PersistenceCustomFieldsTestCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/SectionReplacementTest.txt b/dev/tests/verification/Resources/SectionReplacementTest.txt index a71d1c4ef..586280197 100644 --- a/dev/tests/verification/Resources/SectionReplacementTest.txt +++ b/dev/tests/verification/Resources/SectionReplacementTest.txt @@ -35,7 +35,6 @@ class SectionReplacementTestCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/SkippedTest.txt b/dev/tests/verification/Resources/SkippedTest.txt index c261a77ad..2e7decf9d 100644 --- a/dev/tests/verification/Resources/SkippedTest.txt +++ b/dev/tests/verification/Resources/SkippedTest.txt @@ -27,7 +27,6 @@ class SkippedTestCest * @Stories({"skipped"}) * @Severity(level = SeverityLevel::MINOR) * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/SkippedTestTwoIssues.txt b/dev/tests/verification/Resources/SkippedTestTwoIssues.txt index a2941e5f1..2deaa9beb 100644 --- a/dev/tests/verification/Resources/SkippedTestTwoIssues.txt +++ b/dev/tests/verification/Resources/SkippedTestTwoIssues.txt @@ -27,7 +27,6 @@ class SkippedTestTwoIssuesCest * @Stories({"skippedMultiple"}) * @Severity(level = SeverityLevel::MINOR) * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/SkippedTestWithHooks.txt b/dev/tests/verification/Resources/SkippedTestWithHooks.txt index fdc56c5e1..0299eb67a 100644 --- a/dev/tests/verification/Resources/SkippedTestWithHooks.txt +++ b/dev/tests/verification/Resources/SkippedTestWithHooks.txt @@ -27,7 +27,6 @@ class SkippedTestWithHooksCest * @Stories({"skippedWithHooks"}) * @Severity(level = SeverityLevel::MINOR) * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/XmlCommentedActionGroupTest.txt b/dev/tests/verification/Resources/XmlCommentedActionGroupTest.txt index f45e8f0b2..c406af2d5 100644 --- a/dev/tests/verification/Resources/XmlCommentedActionGroupTest.txt +++ b/dev/tests/verification/Resources/XmlCommentedActionGroupTest.txt @@ -37,7 +37,6 @@ class XmlCommentedActionGroupTestCest /** * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/XmlCommentedTest.txt b/dev/tests/verification/Resources/XmlCommentedTest.txt index 9e7a300ee..d3c11d781 100644 --- a/dev/tests/verification/Resources/XmlCommentedTest.txt +++ b/dev/tests/verification/Resources/XmlCommentedTest.txt @@ -60,7 +60,6 @@ class XmlCommentedTestCest /** * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception From 3cc61924414bd9101e60a0bb8fdd44e6965c070b Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@ip-192-168-29-250.ec2.internal> Date: Mon, 20 Dec 2021 13:19:10 +0530 Subject: [PATCH 766/888] fixed tests --- .../verification/Resources/ActionGroupMergedViaInsertAfter.txt | 1 - dev/tests/verification/Resources/BasicActionGroupTest.txt | 1 - dev/tests/verification/Resources/ExtendedParameterArrayTest.txt | 1 - 3 files changed, 3 deletions(-) diff --git a/dev/tests/verification/Resources/ActionGroupMergedViaInsertAfter.txt b/dev/tests/verification/Resources/ActionGroupMergedViaInsertAfter.txt index ab10b3b80..56f80c3af 100644 --- a/dev/tests/verification/Resources/ActionGroupMergedViaInsertAfter.txt +++ b/dev/tests/verification/Resources/ActionGroupMergedViaInsertAfter.txt @@ -35,7 +35,6 @@ class ActionGroupMergedViaInsertAfterCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/BasicActionGroupTest.txt b/dev/tests/verification/Resources/BasicActionGroupTest.txt index 45cac4937..8a5da2f11 100644 --- a/dev/tests/verification/Resources/BasicActionGroupTest.txt +++ b/dev/tests/verification/Resources/BasicActionGroupTest.txt @@ -51,7 +51,6 @@ class BasicActionGroupTestCest * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) * @Stories({"MQE-433"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Resources/ExtendedParameterArrayTest.txt b/dev/tests/verification/Resources/ExtendedParameterArrayTest.txt index 7af46fe5a..21d711c28 100644 --- a/dev/tests/verification/Resources/ExtendedParameterArrayTest.txt +++ b/dev/tests/verification/Resources/ExtendedParameterArrayTest.txt @@ -34,7 +34,6 @@ class ExtendParentDataTestCest /** * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception From bba26811857472912ad31620370e489a308bc17d Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@ip-192-168-29-250.ec2.internal> Date: Mon, 20 Dec 2021 13:45:50 +0530 Subject: [PATCH 767/888] fixed tests --- .../Resources/ExtendedChildActionGroupReturningValueTest.txt | 1 - dev/tests/verification/Tests/SecretCredentialDataTest.php | 1 - 2 files changed, 2 deletions(-) diff --git a/dev/tests/verification/Resources/ExtendedChildActionGroupReturningValueTest.txt b/dev/tests/verification/Resources/ExtendedChildActionGroupReturningValueTest.txt index c262ffd85..a25ba031d 100644 --- a/dev/tests/verification/Resources/ExtendedChildActionGroupReturningValueTest.txt +++ b/dev/tests/verification/Resources/ExtendedChildActionGroupReturningValueTest.txt @@ -37,7 +37,6 @@ class ExtendedChildActionGroupReturningValueTestCest /** * @Severity(level = SeverityLevel::CRITICAL) * @Features({"TestModule"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception diff --git a/dev/tests/verification/Tests/SecretCredentialDataTest.php b/dev/tests/verification/Tests/SecretCredentialDataTest.php index d1ef43745..351a3d800 100644 --- a/dev/tests/verification/Tests/SecretCredentialDataTest.php +++ b/dev/tests/verification/Tests/SecretCredentialDataTest.php @@ -25,7 +25,6 @@ class SecretCredentialDataTestCest { /** * @Features({"AdminNotification"}) - * @Parameter(name = "AcceptanceTester", value="$I") * @param AcceptanceTester $I * @return void * @throws \Exception From 0a6db1855f8c8200d1cdd9164d24c9a84345a76c Mon Sep 17 00:00:00 2001 From: Nadiya Syvokonenko <syvokone@adobe.com> Date: Tue, 21 Dec 2021 10:44:20 -0600 Subject: [PATCH 768/888] MQE-2575: Allow MFTF Helpers to Return Data to MFTF Test --- .../Util/TestGenerator.php | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index c0249a32b..17e645e76 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -898,7 +898,12 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $stepKey, $customActionAttributes['class'] . '::' . $customActionAttributes['method'] ); - $testSteps .= $this->wrapFunctionCall($actor, $actionObject, $arguments); + $testSteps .= $this->wrapFunctionCallWithReturnValue( + $stepKey, + $actor, + $actionObject, + $arguments + ); break; case "createData": $entity = $customActionAttributes['entity']; @@ -2016,16 +2021,7 @@ private function addDollarSign($input) */ private function wrapFunctionCall($actor, $action, ...$args) { - $isFirst = true; - $isActionHelper = $action->getType() === 'helper'; - $actionType = $action->getType(); - if ($isActionHelper) { - $actor = "this->helperContainer->get('" . $action->getCustomActionAttributes()['class'] . "')"; - $args = $args[0]; - $actionType = $action->getCustomActionAttributes()['method']; - } - - $output = sprintf("\t\t$%s->%s(", $actor, $actionType); + $output = sprintf("\t\t$%s->%s(", $actor, $action->getType()); for ($i = 0; $i < count($args); $i++) { if (null === $args[$i]) { continue; @@ -2055,8 +2051,13 @@ private function wrapFunctionCall($actor, $action, ...$args) */ private function wrapFunctionCallWithReturnValue($returnVariable, $actor, $action, ...$args) { - $isFirst = true; - $output = sprintf("\t\t$%s = $%s->%s(", $returnVariable, $actor, $action->getType()); + $actionType = $action->getType(); + if ($actionType === 'helper') { + $actor = "this->helperContainer->get('" . $action->getCustomActionAttributes()['class'] . "')"; + $args = $args[0]; + $actionType = $action->getCustomActionAttributes()['method']; + } + $output = sprintf("\t\t$%s = $%s->%s(", $returnVariable, $actor, $actionType); for ($i = 0; $i < count($args); $i++) { if (null === $args[$i]) { continue; From 8ad5910b6af9c57990317255b53b6ff0c58789c7 Mon Sep 17 00:00:00 2001 From: Nadiya Syvokonenko <syvokone@adobe.com> Date: Tue, 21 Dec 2021 11:12:12 -0600 Subject: [PATCH 769/888] MQE-2575: Allow MFTF Helpers to Return Data to MFTF Test --- src/Magento/FunctionalTestingFramework/Util/TestGenerator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 17e645e76..7a9c987be 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -2044,7 +2044,7 @@ private function wrapFunctionCall($actor, $action, ...$args) * * @param string $returnVariable * @param string $actor - * @param string $action + * @param actionObject $action * @param array ...$args * @return string * @throws \Exception From 32747f8a2647fdb2ecf1c3602bf7a7e93b8d736f Mon Sep 17 00:00:00 2001 From: Nadiya Syvokonenko <syvokone@adobe.com> Date: Tue, 21 Dec 2021 17:14:42 -0600 Subject: [PATCH 770/888] MQE-2575: Allow MFTF Helpers to Return Data to MFTF Test - fix static tests --- .../FunctionalTestingFramework/Util/TestGenerator.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 7a9c987be..9519b921b 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -2042,10 +2042,10 @@ private function wrapFunctionCall($actor, $action, ...$args) /** * Wrap parameters into a function call with a return value. * - * @param string $returnVariable - * @param string $actor + * @param string $returnVariable + * @param string $actor * @param actionObject $action - * @param array ...$args + * @param array ...$args * @return string * @throws \Exception */ From ccfcf4f8e3f5ff6e670c87e92ae8f60eec842dd3 Mon Sep 17 00:00:00 2001 From: Nadiya Syvokonenko <syvokone@adobe.com> Date: Wed, 22 Dec 2021 12:23:52 -0600 Subject: [PATCH 771/888] MQE-2575: Allow MFTF Helpers to Return Data to MFTF Test - fix static tests --- .../tests/MFTF/DevDocs/Helper/CustomHelper.php | 11 +++++++++++ .../tests/MFTF/DevDocs/Test/DevDocsTest.xml | 8 ++++++++ 2 files changed, 19 insertions(+) diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php b/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php index 46fba18d9..3705ec1d0 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php +++ b/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php @@ -46,4 +46,15 @@ public function goTo( print('$bla = ' . $bla . PHP_EOL); print('array $arraysomething = [' . implode(', ', $arraysomething) . ']' . PHP_EOL); } + + /** + * Returns value of provided param $text + * + * @param string $text + * @return string + */ + public function getText(string $text): string + { + return $text; + } } diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml b/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml index bf074d516..911bc65eb 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml @@ -42,6 +42,14 @@ <argument name="int">987</argument> </helper> + <helper class="\MFTF\DevDocs\Helper\CustomHelper" method="getText" stepKey="getText"> + <argument name="text">some text</argument> + </helper> + <assertEquals stepKey="assertHelperReturnValue" message="Method getText of CustomHelper should return value which may be used as variable in test"> + <expectedResult type="string">some text</expectedResult> + <actualResult type="variable">getText</actualResult> + </assertEquals> + <actionGroup ref="HelperActionGroup" stepKey="actionGroupWithCustomHelper"> <argument name="test" value="{{HelperData.entityField}}" /> <argument name="entityTest" value="HelperData" /> From e9b5b0dfb6d47c5093ecae458e30ec8855532bca Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Fri, 24 Dec 2021 12:39:25 +0530 Subject: [PATCH 772/888] MQE-1518 : Added new action WaitForElementClickable --- .../Resources/WaitForElementClickableTest.txt | 69 +++++++++++++++++++ .../Test/WaitForElementClickableTest.xml | 22 ++++++ .../Tests/WaitForElementClickableTest.php | 24 +++++++ docs/test/actions.md | 20 +++++- .../Test/etc/Actions/waitActions.xsd | 17 +++++ 5 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 dev/tests/verification/Resources/WaitForElementClickableTest.txt create mode 100644 dev/tests/verification/TestModule/Test/WaitForElementClickableTest.xml create mode 100644 dev/tests/verification/Tests/WaitForElementClickableTest.php diff --git a/dev/tests/verification/Resources/WaitForElementClickableTest.txt b/dev/tests/verification/Resources/WaitForElementClickableTest.txt new file mode 100644 index 000000000..7840bc5dd --- /dev/null +++ b/dev/tests/verification/Resources/WaitForElementClickableTest.txt @@ -0,0 +1,69 @@ +<?php +namespace Magento\AcceptanceTest\_default\Backend; + +use Magento\FunctionalTestingFramework\AcceptanceTester; +use \Codeception\Util\Locator; +use Yandex\Allure\Adapter\Annotation\Features; +use Yandex\Allure\Adapter\Annotation\Stories; +use Yandex\Allure\Adapter\Annotation\Title; +use Yandex\Allure\Adapter\Annotation\Description; +use Yandex\Allure\Adapter\Annotation\Parameter; +use Yandex\Allure\Adapter\Annotation\Severity; +use Yandex\Allure\Adapter\Model\SeverityLevel; +use Yandex\Allure\Adapter\Annotation\TestCaseId; + +/** + * @Description("<h3>Test files</h3>vendor/magento/module-page-builder/Test/Mftf/Test/AdminPageBuilderColumnTest/WaitForElementClickableTest.xml<br>") + */ +class WaitForElementClickableTest +{ + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _before(AcceptanceTester $I) + { + $I->comment("Entering Action Group [loginAsAdmin] AdminLoginActionGroup"); + $I->amOnPage((getenv("MAGENTO_BACKEND_BASE_URL") ? rtrim(getenv("MAGENTO_BACKEND_BASE_URL"), "/") : "") . "/" . getenv("MAGENTO_BACKEND_NAME") . "/admin"); // stepKey: navigateToAdminLoginAsAdmin + $I->fillField("#username", getenv("MAGENTO_ADMIN_USERNAME")); // stepKey: fillUsernameLoginAsAdmin + $I->fillField("#login", getenv("MAGENTO_ADMIN_PASSWORD")); // stepKey: fillPasswordLoginAsAdmin + $I->click(".actions .action-primary"); // stepKey: clickLoginLoginAsAdmin + $I->waitForPageLoad(30); // stepKey: clickLoginLoginAsAdminWaitForPageLoad + $I->conditionalClick(".modal-popup .action-secondary", ".modal-popup .action-secondary", true); // stepKey: clickDontAllowButtonIfVisibleLoginAsAdmin + $I->closeAdminNotification(); // stepKey: closeAdminNotificationLoginAsAdmin + $I->comment("Exiting Action Group [loginAsAdmin] AdminLoginActionGroup"); + } + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _after(AcceptanceTester $I) + { + $I->comment("Entering Action Group [logout] AdminLogoutActionGroup"); + $I->amOnPage((getenv("MAGENTO_BACKEND_BASE_URL") ? rtrim(getenv("MAGENTO_BACKEND_BASE_URL"), "/") : "") . "/" . getenv("MAGENTO_BACKEND_NAME") . "/admin/auth/logout/"); // stepKey: amOnLogoutPageLogout + $I->comment("Exiting Action Group [logout] AdminLogoutActionGroup"); + } + + /** + * @param AcceptanceTester $I + * @throws \Exception + */ + public function _failed(AcceptanceTester $I) + { + $I->saveScreenshot(); // stepKey: saveScreenshot + } + + /** + * @Features({"PageBuilder"}) + * @param AcceptanceTester $I + * @return void + * @throws \Exception + */ + public function WaitForElementClickableTest(AcceptanceTester $I) + { + $I->moveMouseOver("(//div[@data-content-type=\"column\"])[1]"); // stepKey: moveMouseOverColumn + $I->waitForPageLoad(30); // stepKey: waitForMouseOver + $I->waitForElementClickable("(//div[contains(@class, \"pagebuilder-content-type\") and contains(@class, \"pagebuilder-column\")])[1]//div[contains(@class,\"pagebuilder-options-visible\")]"); // stepKey: waitForOptions + } +} diff --git a/dev/tests/verification/TestModule/Test/WaitForElementClickableTest.xml b/dev/tests/verification/TestModule/Test/WaitForElementClickableTest.xml new file mode 100644 index 000000000..7118751be --- /dev/null +++ b/dev/tests/verification/TestModule/Test/WaitForElementClickableTest.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="WaitForElementClickableTest"> + + <before> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + </before> + <after> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + </after> + <moveMouseOver selector="{{ColumnOnBackend.base('1')}}" stepKey="moveMouseOverColumn"/> + <waitForPageLoad stepKey="waitForMouseOver"/> + <waitForElementClickable selector="{{PageBuilderContentTypeOptionsMenu.contentTypeOptionsMenuByIndex(PageBuilderColumnContentType.role, '1')}}" stepKey="waitForOptions"/> + </test> +</tests> diff --git a/dev/tests/verification/Tests/WaitForElementClickableTest.php b/dev/tests/verification/Tests/WaitForElementClickableTest.php new file mode 100644 index 000000000..2b83c4b72 --- /dev/null +++ b/dev/tests/verification/Tests/WaitForElementClickableTest.php @@ -0,0 +1,24 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace tests\verification\Tests; + +use tests\util\MftfTestCase; + +class WaitForElementClickableTest extends MftfTestCase +{ + /** + * WaitForElementClickable: + * Tests flat generation of a hardcoded test file with no external references. + * + * @throws \Exception + * @throws \Magento\FunctionalTestingFramework\Exceptions\TestReferenceException + */ + public function testWaitForElementClickableAction() + { + $this->generateAndCompareTest('WaitForElementClickableTest'); + } + +} diff --git a/docs/test/actions.md b/docs/test/actions.md index 42ecde053..373a44ee0 100644 --- a/docs/test/actions.md +++ b/docs/test/actions.md @@ -2374,10 +2374,28 @@ Attribute|Type|Use|Description #### Example ```xml -<!-- Wait up to 30 seconds for `<div id="changedElement" ... >...</div>` to become visible on the page before continuing. --> <waitForElementVisible selector="#changedElement" stepKey="waitForElementVisible"/> ``` +### waitForElementClickable + +See [waitForElementClickable docs on codeception.com](http://codeception.com/docs/modules/WebDriver#waitForElementClickable). + +Attribute|Type|Use|Description +---|---|---|--- +`selector`|string|optional| The selector identifying the corresponding HTML element. +`time`|string|optional| The number of seconds to wait for the element to appear. +`stepKey`|string|required| A unique identifier of the action. +`before`|string|optional| `stepKey` of action that must be executed next. +`after`|string|optional| `stepKey` of preceding action. + +#### Example + +```xml +<!-- Waits up to $timeout seconds for the given element to be clickable. If element doesn’t become clickable, a timeout exception is thrown. --> +<waitForElementClickable selector="#changedElement" stepKey="waitForElementClickable"/> +``` + ### waitForJS See [waitForJS docs on codeception.com](http://codeception.com/docs/modules/WebDriver#waitForJS). diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/waitActions.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/waitActions.xsd index 70b8201a1..18214ba9a 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/waitActions.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/waitActions.xsd @@ -23,6 +23,8 @@ <xs:element type="waitForPwaElementNotVisibleType" name="waitForPwaElementNotVisible" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="waitForPwaElementVisibleType" name="waitForPwaElementVisible" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="waitForTextType" name="waitForText" minOccurs="0" maxOccurs="unbounded"/> + <xs:element type="waitForElementClickableType" name="waitForElementClickable" minOccurs="0" maxOccurs="unbounded"/> + </xs:choice> </xs:group> @@ -224,4 +226,19 @@ </xs:extension> </xs:simpleContent> </xs:complexType> + <xs:complexType name="waitForElementClickableType"> + <xs:annotation> + <xs:documentation> + Waits up to $timeout seconds for the given element to be clickable. + If element doesn’t become clickable, a timeout exception is thrown. + </xs:documentation> + </xs:annotation> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute ref="selector" use="required"/> + <xs:attribute ref="time"/> + <xs:attributeGroup ref="commonActionAttributes"/> + </xs:extension> + </xs:simpleContent> + </xs:complexType> </xs:schema> \ No newline at end of file From 6ea8ac24fc8773cd144e53dc330a635be18a8a7d Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Fri, 24 Dec 2021 14:44:59 +0530 Subject: [PATCH 773/888] fixed psr --- dev/tests/verification/Tests/WaitForElementClickableTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dev/tests/verification/Tests/WaitForElementClickableTest.php b/dev/tests/verification/Tests/WaitForElementClickableTest.php index 2b83c4b72..768fc1ab0 100644 --- a/dev/tests/verification/Tests/WaitForElementClickableTest.php +++ b/dev/tests/verification/Tests/WaitForElementClickableTest.php @@ -10,7 +10,7 @@ class WaitForElementClickableTest extends MftfTestCase { /** - * WaitForElementClickable: + * BasicFunctionalTest: * Tests flat generation of a hardcoded test file with no external references. * * @throws \Exception @@ -20,5 +20,4 @@ public function testWaitForElementClickableAction() { $this->generateAndCompareTest('WaitForElementClickableTest'); } - } From c0ee4a395eec7f7ecff3e7dcdd5b5cc3a831ad57 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Fri, 24 Dec 2021 16:01:46 +0530 Subject: [PATCH 774/888] fixed verification test --- .../verification/Resources/WaitForElementClickableTest.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/verification/Resources/WaitForElementClickableTest.txt b/dev/tests/verification/Resources/WaitForElementClickableTest.txt index 7840bc5dd..05359dba9 100644 --- a/dev/tests/verification/Resources/WaitForElementClickableTest.txt +++ b/dev/tests/verification/Resources/WaitForElementClickableTest.txt @@ -15,7 +15,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Description("<h3>Test files</h3>vendor/magento/module-page-builder/Test/Mftf/Test/AdminPageBuilderColumnTest/WaitForElementClickableTest.xml<br>") */ -class WaitForElementClickableTest +class WaitForElementClickableTestCest { /** * @param AcceptanceTester $I From 9eab78e92ff01075f2f6425373bb85aca3164f46 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Tue, 28 Dec 2021 12:36:25 +0530 Subject: [PATCH 775/888] fixed verification test --- .../Resources/DataActionsTest.txt | 1 + .../Resources/WaitForElementClickableTest.txt | 69 ------------------- .../TestModule/Test/DataActionsTest.xml | 3 +- .../Test/WaitForElementClickableTest.xml | 22 ------ .../Tests/WaitForElementClickableTest.php | 23 ------- 5 files changed, 3 insertions(+), 115 deletions(-) delete mode 100644 dev/tests/verification/Resources/WaitForElementClickableTest.txt delete mode 100644 dev/tests/verification/TestModule/Test/WaitForElementClickableTest.xml delete mode 100644 dev/tests/verification/Tests/WaitForElementClickableTest.php diff --git a/dev/tests/verification/Resources/DataActionsTest.txt b/dev/tests/verification/Resources/DataActionsTest.txt index f84f97040..56da03cd6 100644 --- a/dev/tests/verification/Resources/DataActionsTest.txt +++ b/dev/tests/verification/Resources/DataActionsTest.txt @@ -31,6 +31,7 @@ class DataActionsTestCest $I->createEntity("createdInBefore", "hook", "entity", [], []); // stepKey: createdInBefore $I->updateEntity("createdInBefore", "hook", "entity",[]); // stepKey: updateInBefore $I->deleteEntity("createdInBefore", "hook"); // stepKey: deleteInBefore + $I->waitForElementClickable(".functionalTestSelector"); // stepKey: waitForElementClickable } /** diff --git a/dev/tests/verification/Resources/WaitForElementClickableTest.txt b/dev/tests/verification/Resources/WaitForElementClickableTest.txt deleted file mode 100644 index 05359dba9..000000000 --- a/dev/tests/verification/Resources/WaitForElementClickableTest.txt +++ /dev/null @@ -1,69 +0,0 @@ -<?php -namespace Magento\AcceptanceTest\_default\Backend; - -use Magento\FunctionalTestingFramework\AcceptanceTester; -use \Codeception\Util\Locator; -use Yandex\Allure\Adapter\Annotation\Features; -use Yandex\Allure\Adapter\Annotation\Stories; -use Yandex\Allure\Adapter\Annotation\Title; -use Yandex\Allure\Adapter\Annotation\Description; -use Yandex\Allure\Adapter\Annotation\Parameter; -use Yandex\Allure\Adapter\Annotation\Severity; -use Yandex\Allure\Adapter\Model\SeverityLevel; -use Yandex\Allure\Adapter\Annotation\TestCaseId; - -/** - * @Description("<h3>Test files</h3>vendor/magento/module-page-builder/Test/Mftf/Test/AdminPageBuilderColumnTest/WaitForElementClickableTest.xml<br>") - */ -class WaitForElementClickableTestCest -{ - /** - * @param AcceptanceTester $I - * @throws \Exception - */ - public function _before(AcceptanceTester $I) - { - $I->comment("Entering Action Group [loginAsAdmin] AdminLoginActionGroup"); - $I->amOnPage((getenv("MAGENTO_BACKEND_BASE_URL") ? rtrim(getenv("MAGENTO_BACKEND_BASE_URL"), "/") : "") . "/" . getenv("MAGENTO_BACKEND_NAME") . "/admin"); // stepKey: navigateToAdminLoginAsAdmin - $I->fillField("#username", getenv("MAGENTO_ADMIN_USERNAME")); // stepKey: fillUsernameLoginAsAdmin - $I->fillField("#login", getenv("MAGENTO_ADMIN_PASSWORD")); // stepKey: fillPasswordLoginAsAdmin - $I->click(".actions .action-primary"); // stepKey: clickLoginLoginAsAdmin - $I->waitForPageLoad(30); // stepKey: clickLoginLoginAsAdminWaitForPageLoad - $I->conditionalClick(".modal-popup .action-secondary", ".modal-popup .action-secondary", true); // stepKey: clickDontAllowButtonIfVisibleLoginAsAdmin - $I->closeAdminNotification(); // stepKey: closeAdminNotificationLoginAsAdmin - $I->comment("Exiting Action Group [loginAsAdmin] AdminLoginActionGroup"); - } - - /** - * @param AcceptanceTester $I - * @throws \Exception - */ - public function _after(AcceptanceTester $I) - { - $I->comment("Entering Action Group [logout] AdminLogoutActionGroup"); - $I->amOnPage((getenv("MAGENTO_BACKEND_BASE_URL") ? rtrim(getenv("MAGENTO_BACKEND_BASE_URL"), "/") : "") . "/" . getenv("MAGENTO_BACKEND_NAME") . "/admin/auth/logout/"); // stepKey: amOnLogoutPageLogout - $I->comment("Exiting Action Group [logout] AdminLogoutActionGroup"); - } - - /** - * @param AcceptanceTester $I - * @throws \Exception - */ - public function _failed(AcceptanceTester $I) - { - $I->saveScreenshot(); // stepKey: saveScreenshot - } - - /** - * @Features({"PageBuilder"}) - * @param AcceptanceTester $I - * @return void - * @throws \Exception - */ - public function WaitForElementClickableTest(AcceptanceTester $I) - { - $I->moveMouseOver("(//div[@data-content-type=\"column\"])[1]"); // stepKey: moveMouseOverColumn - $I->waitForPageLoad(30); // stepKey: waitForMouseOver - $I->waitForElementClickable("(//div[contains(@class, \"pagebuilder-content-type\") and contains(@class, \"pagebuilder-column\")])[1]//div[contains(@class,\"pagebuilder-options-visible\")]"); // stepKey: waitForOptions - } -} diff --git a/dev/tests/verification/TestModule/Test/DataActionsTest.xml b/dev/tests/verification/TestModule/Test/DataActionsTest.xml index b75bc98f8..eede5e9f9 100644 --- a/dev/tests/verification/TestModule/Test/DataActionsTest.xml +++ b/dev/tests/verification/TestModule/Test/DataActionsTest.xml @@ -13,8 +13,9 @@ <createData entity="entity" stepKey="createdInBefore"/> <updateData entity="entity" createDataKey="createdInBefore" stepKey="updateInBefore"/> <deleteData createDataKey="createdInBefore" stepKey="deleteInBefore"/> - </before> + <waitForElementClickable selector=".functionalTestSelector" time="30" stepKey="waitForElementClickable" /> + </before> <createData entity="entity" stepKey="createdInTest"/> <updateData entity="entity" createDataKey="createdInTest" stepKey="updateInTest"/> <deleteData createDataKey="createdInTest" stepKey="deleteInTest"/> diff --git a/dev/tests/verification/TestModule/Test/WaitForElementClickableTest.xml b/dev/tests/verification/TestModule/Test/WaitForElementClickableTest.xml deleted file mode 100644 index 7118751be..000000000 --- a/dev/tests/verification/TestModule/Test/WaitForElementClickableTest.xml +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> - <test name="WaitForElementClickableTest"> - - <before> - <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> - </before> - <after> - <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> - </after> - <moveMouseOver selector="{{ColumnOnBackend.base('1')}}" stepKey="moveMouseOverColumn"/> - <waitForPageLoad stepKey="waitForMouseOver"/> - <waitForElementClickable selector="{{PageBuilderContentTypeOptionsMenu.contentTypeOptionsMenuByIndex(PageBuilderColumnContentType.role, '1')}}" stepKey="waitForOptions"/> - </test> -</tests> diff --git a/dev/tests/verification/Tests/WaitForElementClickableTest.php b/dev/tests/verification/Tests/WaitForElementClickableTest.php deleted file mode 100644 index 768fc1ab0..000000000 --- a/dev/tests/verification/Tests/WaitForElementClickableTest.php +++ /dev/null @@ -1,23 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace tests\verification\Tests; - -use tests\util\MftfTestCase; - -class WaitForElementClickableTest extends MftfTestCase -{ - /** - * BasicFunctionalTest: - * Tests flat generation of a hardcoded test file with no external references. - * - * @throws \Exception - * @throws \Magento\FunctionalTestingFramework\Exceptions\TestReferenceException - */ - public function testWaitForElementClickableAction() - { - $this->generateAndCompareTest('WaitForElementClickableTest'); - } -} From 1ca49786fc57de14d596d08050d54545c6122b57 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Tue, 28 Dec 2021 12:43:44 +0530 Subject: [PATCH 776/888] verification test for waitForElementClickable --- dev/tests/verification/Resources/DataActionsTest.txt | 2 +- dev/tests/verification/TestModule/Test/DataActionsTest.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/tests/verification/Resources/DataActionsTest.txt b/dev/tests/verification/Resources/DataActionsTest.txt index 56da03cd6..178c579da 100644 --- a/dev/tests/verification/Resources/DataActionsTest.txt +++ b/dev/tests/verification/Resources/DataActionsTest.txt @@ -31,7 +31,6 @@ class DataActionsTestCest $I->createEntity("createdInBefore", "hook", "entity", [], []); // stepKey: createdInBefore $I->updateEntity("createdInBefore", "hook", "entity",[]); // stepKey: updateInBefore $I->deleteEntity("createdInBefore", "hook"); // stepKey: deleteInBefore - $I->waitForElementClickable(".functionalTestSelector"); // stepKey: waitForElementClickable } /** @@ -54,6 +53,7 @@ class DataActionsTestCest */ public function DataActionsTest(AcceptanceTester $I) { + $I->waitForElementClickable(".functionalTestSelector"); // stepKey: waitForElementClickable $I->createEntity("createdInTest", "test", "entity", [], []); // stepKey: createdInTest $I->updateEntity("createdInTest", "test", "entity",[]); // stepKey: updateInTest $I->deleteEntity("createdInTest", "test"); // stepKey: deleteInTest diff --git a/dev/tests/verification/TestModule/Test/DataActionsTest.xml b/dev/tests/verification/TestModule/Test/DataActionsTest.xml index eede5e9f9..2575c41b0 100644 --- a/dev/tests/verification/TestModule/Test/DataActionsTest.xml +++ b/dev/tests/verification/TestModule/Test/DataActionsTest.xml @@ -13,9 +13,9 @@ <createData entity="entity" stepKey="createdInBefore"/> <updateData entity="entity" createDataKey="createdInBefore" stepKey="updateInBefore"/> <deleteData createDataKey="createdInBefore" stepKey="deleteInBefore"/> - <waitForElementClickable selector=".functionalTestSelector" time="30" stepKey="waitForElementClickable" /> </before> + <waitForElementClickable selector=".functionalTestSelector" time="30" stepKey="waitForElementClickable" /> <createData entity="entity" stepKey="createdInTest"/> <updateData entity="entity" createDataKey="createdInTest" stepKey="updateInTest"/> <deleteData createDataKey="createdInTest" stepKey="deleteInTest"/> From 4f66a1cb3a978f1416464c73bfd9781a3fb7aad4 Mon Sep 17 00:00:00 2001 From: Dmytro Shevtsov <shevtsov@adobe.com> Date: Wed, 5 Jan 2022 10:40:02 -0600 Subject: [PATCH 777/888] Deleted the unused images --- docs/img/issue.png | Bin 13879 -> 0 bytes docs/img/pull-request.png | Bin 7649 -> 0 bytes docs/img/switching-the-base.png | Bin 7064 -> 0 bytes docs/img/trouble-chrome232.png | Bin 25375 -> 0 bytes 4 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/img/issue.png delete mode 100644 docs/img/pull-request.png delete mode 100644 docs/img/switching-the-base.png delete mode 100644 docs/img/trouble-chrome232.png diff --git a/docs/img/issue.png b/docs/img/issue.png deleted file mode 100644 index 1dcf78ce23b222e7ccf4ea7003f87314383f6cbc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13879 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 diff --git a/docs/img/pull-request.png b/docs/img/pull-request.png deleted file mode 100644 index c492350d8d280bd0830e9480fbcb00127c0ba4ee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7649 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 aj+CNV$eFO_%|sjo0<_ij)v6xYMgAAWTMpm= diff --git a/docs/img/switching-the-base.png b/docs/img/switching-the-base.png deleted file mode 100644 index 412ab1624a72af887f3a793b21c14c39a2fd35e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7064 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 diff --git a/docs/img/trouble-chrome232.png b/docs/img/trouble-chrome232.png deleted file mode 100644 index 1dc44f6a4d41c522bac726b972c639db13cc0f0d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25375 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 From 3b8f99c7fcc2fe9f4e749d97a19e81955a564a81 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Thu, 6 Jan 2022 09:46:01 -0600 Subject: [PATCH 778/888] MQE-3182: Release MFTF 3.8.0 --- CHANGELOG.md | 8 ++++++++ composer.json | 2 +- composer.lock | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d8a662fe..04999e2c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ Magento Functional Testing Framework Changelog ================================================ +3.8.0 +--------- + +### Updates: +* Allow MFTF Helpers to Return Data to MFTF Test +* Improve parallel grouping and fix an issue with unbalanced groups +* Added new action WaitForElementClickable + 3.7.3 --------- diff --git a/composer.json b/composer.json index 8fedf25a8..9a7757c5d 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "3.7.3", + "version": "3.8.0", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index 4a1a7d2be..8000882be 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "822c40666da3ff087f25393fd4dc9371", + "content-hash": "35ff8c71326b9f8ab0885c8b55dd59cf", "packages": [ { "name": "allure-framework/allure-codeception", From 8aa7fd2bfca4a2e36c108d7f432afc065ca0d587 Mon Sep 17 00:00:00 2001 From: "Shashik.K.Singh" <shashik.k.singh@RedmiNote5-Redmi.domain.name> Date: Wed, 12 Jan 2022 11:28:15 +0530 Subject: [PATCH 779/888] change condition as requested --- .../DataGenerator/Handlers/SecretStorage/FileStorage.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/FileStorage.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/FileStorage.php index 1d122b9c5..81d39d608 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/FileStorage.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/FileStorage.php @@ -101,7 +101,7 @@ private function encryptCredFileContents($credContents) if (substr($credValue, 0, 1) === '#' || empty($credValue)) { continue; } - elseif (is_bool(strpos($credValue, "="))){ + elseif (strpos($credValue, "=") === false){ throw new TestFrameworkException( $credValue." not configured correctly in .credentials file" ); From c402e2e038e0280a2e82dfbc838b425a4b83173b Mon Sep 17 00:00:00 2001 From: glo00108 <glo00108@adobe.com> Date: Tue, 18 Jan 2022 13:59:57 +0530 Subject: [PATCH 780/888] unit test added --- .../SecretStorage/FileStorageTest.php | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/FileStorageTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/FileStorageTest.php index be97e04ab..5a1b2195c 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/FileStorageTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/FileStorageTest.php @@ -45,4 +45,37 @@ public function testBasicEncryptDecrypt(): void // assert that we are able to successfully decrypt our secret value $this->assertEquals($testValue, $actualValue); } + + /** + * Test empty value encryption/decryption functionality in FileStorage class. + */ + public function testEmptyValueEncryptDecrypt(): void + { + $testKey = 'magento/myKey'; + $testValue = ''; + $creds = ["$testKey"]; + + $fileStorage = new FileStorage(); + $reflection = new ReflectionClass(FileStorage::class); + + // Emulate initialize() function result with the test credentials + $reflectionMethod = $reflection->getMethod('encryptCredFileContents'); + $reflectionMethod->setAccessible(true); + $secretData = $reflectionMethod->invokeArgs($fileStorage, [$creds]); + + // Set encrypted test credentials to the private 'secretData' property + $reflectionProperty = $reflection->getProperty('secretData'); + $reflectionProperty->setAccessible(true); + $reflectionProperty->setValue($fileStorage, $secretData); + + $encryptedCred = $fileStorage->getEncryptedValue($testKey); + + // assert the value we've gotten is in fact not identical to our test value + $this->assertNotEquals($testValue, $encryptedCred); + + $actualValue = $fileStorage->getDecryptedValue($encryptedCred); + + // assert that we are able to successfully decrypt our secret value + $this->assertEquals($testValue, $actualValue); + } } From e67dd090366c89d02df5e1145eacc8cd82ec7158 Mon Sep 17 00:00:00 2001 From: glo00108 <glo00108@adobe.com> Date: Wed, 19 Jan 2022 18:29:23 +0530 Subject: [PATCH 781/888] add exception assert --- .../SecretStorage/FileStorageTest.php | 44 +++++++++---------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/FileStorageTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/FileStorageTest.php index 5a1b2195c..3d5922f9e 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/FileStorageTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/FileStorageTest.php @@ -8,19 +8,22 @@ namespace tests\unit\Magento\FunctionalTestFramework\DataGenerator\Handlers\SecretStorage; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\SecretStorage\FileStorage; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use ReflectionClass; +use ReflectionException; use tests\unit\Util\MagentoTestCase; class FileStorageTest extends MagentoTestCase { /** * Test basic encryption/decryption functionality in FileStorage class. + * @throws TestFrameworkException|ReflectionException */ public function testBasicEncryptDecrypt(): void { $testKey = 'magento/myKey'; $testValue = 'myValue'; - $creds = ["$testKey=$testValue"]; + $cred = ["$testKey=$testValue"]; $fileStorage = new FileStorage(); $reflection = new ReflectionClass(FileStorage::class); @@ -28,7 +31,7 @@ public function testBasicEncryptDecrypt(): void // Emulate initialize() function result with the test credentials $reflectionMethod = $reflection->getMethod('encryptCredFileContents'); $reflectionMethod->setAccessible(true); - $secretData = $reflectionMethod->invokeArgs($fileStorage, [$creds]); + $secretData = $reflectionMethod->invokeArgs($fileStorage, [$cred]); // Set encrypted test credentials to the private 'secretData' property $reflectionProperty = $reflection->getProperty('secretData'); @@ -48,34 +51,29 @@ public function testBasicEncryptDecrypt(): void /** * Test empty value encryption/decryption functionality in FileStorage class. + * @return void + * @throws TestFrameworkException|ReflectionException */ public function testEmptyValueEncryptDecrypt(): void { - $testKey = 'magento/myKey'; - $testValue = ''; - $creds = ["$testKey"]; + $this->expectException(TestFrameworkException::class); - $fileStorage = new FileStorage(); - $reflection = new ReflectionClass(FileStorage::class); - - // Emulate initialize() function result with the test credentials - $reflectionMethod = $reflection->getMethod('encryptCredFileContents'); - $reflectionMethod->setAccessible(true); - $secretData = $reflectionMethod->invokeArgs($fileStorage, [$creds]); - - // Set encrypted test credentials to the private 'secretData' property - $reflectionProperty = $reflection->getProperty('secretData'); - $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($fileStorage, $secretData); + $testKey = 'magento/myKey'; + $cred = ["$testKey"]; - $encryptedCred = $fileStorage->getEncryptedValue($testKey); + $fileStorage = new FileStorage(); + $reflection = new ReflectionClass(FileStorage::class); - // assert the value we've gotten is in fact not identical to our test value - $this->assertNotEquals($testValue, $encryptedCred); + // Emulate initialize() function result with the test credentials + $reflectionMethod = $reflection->getMethod('encryptCredFileContents'); + $reflectionMethod->setAccessible(true); + $secretData = $reflectionMethod->invokeArgs($fileStorage, [$cred]); - $actualValue = $fileStorage->getDecryptedValue($encryptedCred); + // Set encrypted test credentials to the private 'secretData' property + $reflectionProperty = $reflection->getProperty('secretData'); + $reflectionProperty->setAccessible(true); + $reflectionProperty->setValue($fileStorage, $secretData); - // assert that we are able to successfully decrypt our secret value - $this->assertEquals($testValue, $actualValue); + $fileStorage->getEncryptedValue($testKey); } } From 41ff3f11082220ee9e508384b8205469d4469569 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@ip-192-168-29-250.ec2.internal> Date: Thu, 20 Jan 2022 14:13:04 +0530 Subject: [PATCH 782/888] MQE-1190 : max characters limit is increased --- .../Codeception/Subscriber/Console.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Codeception/Subscriber/Console.php b/src/Magento/FunctionalTestingFramework/Codeception/Subscriber/Console.php index c6c6a4eec..4b6cb93a7 100644 --- a/src/Magento/FunctionalTestingFramework/Codeception/Subscriber/Console.php +++ b/src/Magento/FunctionalTestingFramework/Codeception/Subscriber/Console.php @@ -193,7 +193,7 @@ private function printStepKeys(Step $step) $stepString = str_replace( [ActionGroupObject::ACTION_GROUP_CONTEXT_START, ActionGroupObject::ACTION_GROUP_CONTEXT_END], '', - $step->toString(150) + $step->toString(10000) ); $msg->append(OutputFormatter::escape($stepString)); From 4a4667f19843d566ca7f6b69f75ac9c0a06ba8b5 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@ip-192-168-29-250.ec2.internal> Date: Thu, 20 Jan 2022 14:14:31 +0530 Subject: [PATCH 783/888] MQE-1190 : max characters limit is increased --- .../Codeception/Subscriber/Console.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Codeception/Subscriber/Console.php b/src/Magento/FunctionalTestingFramework/Codeception/Subscriber/Console.php index 4b6cb93a7..961f68440 100644 --- a/src/Magento/FunctionalTestingFramework/Codeception/Subscriber/Console.php +++ b/src/Magento/FunctionalTestingFramework/Codeception/Subscriber/Console.php @@ -193,7 +193,7 @@ private function printStepKeys(Step $step) $stepString = str_replace( [ActionGroupObject::ACTION_GROUP_CONTEXT_START, ActionGroupObject::ACTION_GROUP_CONTEXT_END], '', - $step->toString(10000) + $step->toString(1000) ); $msg->append(OutputFormatter::escape($stepString)); From 19c785919b63c1dad704b88031010150dde1df38 Mon Sep 17 00:00:00 2001 From: glo00108 <glo00108@adobe.com> Date: Fri, 21 Jan 2022 13:12:38 +0530 Subject: [PATCH 784/888] fix static test error --- .../Handlers/SecretStorage/FileStorage.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/FileStorage.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/FileStorage.php index 81d39d608..48087e890 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/FileStorage.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/FileStorage.php @@ -6,8 +6,8 @@ namespace Magento\FunctionalTestingFramework\DataGenerator\Handlers\SecretStorage; -use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; @@ -93,6 +93,7 @@ private function readInCredentialsFile() * * @param array $credContents * @return array + * @throws TestFrameworkException */ private function encryptCredFileContents($credContents) { @@ -100,11 +101,10 @@ private function encryptCredFileContents($credContents) foreach ($credContents as $credValue) { if (substr($credValue, 0, 1) === '#' || empty($credValue)) { continue; - } - elseif (strpos($credValue, "=") === false){ - throw new TestFrameworkException( - $credValue." not configured correctly in .credentials file" - ); + } elseif (strpos($credValue, "=") === false) { + throw new TestFrameworkException( + $credValue . " not configured correctly in .credentials file" + ); } list($key, $value) = explode("=", $credValue, 2); From 9970faf83dd5392c98afbb36bbaf1ca98d7d0634 Mon Sep 17 00:00:00 2001 From: "Mohit.k.Sharma" <mohit.k.sharma@BLR1-LMC-N71405.local> Date: Fri, 28 Jan 2022 09:39:49 +0530 Subject: [PATCH 785/888] Test before/after comments in test/allure --- .../Util/TestGenerator.php | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index c5368b779..06c32ea03 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1770,6 +1770,32 @@ private function generateHooksPhp($hookObjects) throw new TestReferenceException($e->getMessage() . " in Element \"" . $type . "\""); } + if ($type == 'before') { + $steps = sprintf( + "\t\t$%s->comment('[%s]');" . PHP_EOL, + 'I', + 'START BEFORE HOOK' + ) . $steps; + $steps = $steps . sprintf( + "\t\t$%s->comment('[%s]');" . PHP_EOL, + 'I', + 'END BEFORE HOOK' + ); + } + + if ($type == 'after') { + $steps = sprintf( + "\t\t$%s->comment('[%s]');" . PHP_EOL, + 'I', + 'START AFTER HOOK' + ) . $steps; + $steps = $steps . sprintf( + "\t\t$%s->comment('[%s]');" . PHP_EOL, + 'I', + 'END AFTER HOOK' + ); + } + $hooks .= sprintf("\tpublic function _{$type}(%s)\n", $dependencies); $hooks .= "\t{\n"; $hooks .= $steps; From 91c64e6144ca19fa163f83dc05e18688889ff516 Mon Sep 17 00:00:00 2001 From: glo00108 <glo00108@adobe.com> Date: Tue, 1 Feb 2022 10:42:48 +0530 Subject: [PATCH 786/888] added startMessageQueue variable in testobject file --- .../Handlers/SecretStorage/FileStorageTest.php | 8 ++++---- .../Test/Objects/TestObject.php | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/FileStorageTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/FileStorageTest.php index 3d5922f9e..672de5a21 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/FileStorageTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/FileStorageTest.php @@ -23,7 +23,7 @@ public function testBasicEncryptDecrypt(): void { $testKey = 'magento/myKey'; $testValue = 'myValue'; - $cred = ["$testKey=$testValue"]; + $creds = ["$testKey=$testValue"]; $fileStorage = new FileStorage(); $reflection = new ReflectionClass(FileStorage::class); @@ -31,7 +31,7 @@ public function testBasicEncryptDecrypt(): void // Emulate initialize() function result with the test credentials $reflectionMethod = $reflection->getMethod('encryptCredFileContents'); $reflectionMethod->setAccessible(true); - $secretData = $reflectionMethod->invokeArgs($fileStorage, [$cred]); + $secretData = $reflectionMethod->invokeArgs($fileStorage, [$creds]); // Set encrypted test credentials to the private 'secretData' property $reflectionProperty = $reflection->getProperty('secretData'); @@ -59,7 +59,7 @@ public function testEmptyValueEncryptDecrypt(): void $this->expectException(TestFrameworkException::class); $testKey = 'magento/myKey'; - $cred = ["$testKey"]; + $creds = ["$testKey"]; $fileStorage = new FileStorage(); $reflection = new ReflectionClass(FileStorage::class); @@ -67,7 +67,7 @@ public function testEmptyValueEncryptDecrypt(): void // Emulate initialize() function result with the test credentials $reflectionMethod = $reflection->getMethod('encryptCredFileContents'); $reflectionMethod->setAccessible(true); - $secretData = $reflectionMethod->invokeArgs($fileStorage, [$cred]); + $secretData = $reflectionMethod->invokeArgs($fileStorage, [$creds]); // Set encrypted test credentials to the private 'secretData' property $reflectionProperty = $reflection->getProperty('secretData'); diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php index f556947f1..9da9191cd 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php @@ -39,6 +39,7 @@ class TestObject 'deleteData' => 200, 'updateData' => 200, 'getOTP' => 1000, + 'startMessageQueue' => 700, ]; const WEBAPI_AUTH_TEST_ACTIONS = [ From 7aaf83be62ab1bc1fdeca4c5eec5a20e6c7c94c8 Mon Sep 17 00:00:00 2001 From: "Mohit.k.Sharma" <mohit.k.sharma@BLR1-LMC-N71405.local> Date: Tue, 1 Feb 2022 19:35:18 +0530 Subject: [PATCH 787/888] Fix verification checks ans static checks error --- .../ActionGroupContainsStepKeyInArgText.txt | 2 + .../ActionGroupReturningValueTest.txt | 4 ++ .../Resources/ActionGroupUsingCreateData.txt | 2 + .../ActionGroupWithDataOverrideTest.txt | 4 ++ .../Resources/ActionGroupWithDataTest.txt | 4 ++ .../ActionGroupWithNoDefaultTest.txt | 4 ++ .../ActionGroupWithPersistedData.txt | 4 ++ .../ActionGroupWithTopLevelPersistedData.txt | 4 ++ .../ArgumentWithSameNameAsElement.txt | 4 ++ .../verification/Resources/AssertTest.txt | 2 + .../Resources/BasicActionGroupTest.txt | 2 + .../Resources/BasicFunctionalTest.txt | 4 ++ .../verification/Resources/BasicMergeTest.txt | 4 ++ .../Resources/ChildExtendedTestAddHooks.txt | 4 ++ .../Resources/ChildExtendedTestMerging.txt | 4 ++ .../ChildExtendedTestRemoveAction.txt | 4 ++ .../ChildExtendedTestRemoveHookAction.txt | 2 + .../Resources/ChildExtendedTestReplace.txt | 4 ++ .../ChildExtendedTestReplaceHook.txt | 4 ++ .../Resources/DataActionsTest.txt | 2 + .../ExtendedChildTestInSuiteCest.txt | 4 ++ .../Resources/ExtendedChildTestNotInSuite.txt | 4 ++ .../Resources/HookActionsTest.txt | 4 ++ .../MergedActionGroupReturningValueTest.txt | 4 ++ .../Resources/MergedActionGroupTest.txt | 4 ++ .../Resources/MergedReferencesTest.txt | 4 ++ .../Resources/MultipleActionGroupsTest.txt | 4 ++ .../Resources/ParentExtendedTest.txt | 4 ++ .../Resources/PersistedReplacementTest.txt | 2 + .../PersistenceActionGroupAppendingTest.txt | 2 + .../Resources/PersistenceCustomFieldsTest.txt | 2 + .../Resources/XmlCommentedTest.txt | 4 ++ .../Util/TestGenerator.php | 38 +++++++++---------- 33 files changed, 129 insertions(+), 19 deletions(-) diff --git a/dev/tests/verification/Resources/ActionGroupContainsStepKeyInArgText.txt b/dev/tests/verification/Resources/ActionGroupContainsStepKeyInArgText.txt index f2066e1d8..3faa07c06 100644 --- a/dev/tests/verification/Resources/ActionGroupContainsStepKeyInArgText.txt +++ b/dev/tests/verification/Resources/ActionGroupContainsStepKeyInArgText.txt @@ -28,9 +28,11 @@ class ActionGroupContainsStepKeyInArgTextCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->comment("Entering Action Group [actionGroup] actionGroupContainsStepKeyInArgValue"); $I->see("arg1", ".selector"); // stepKey: arg1ActionGroup $I->comment("Exiting Action Group [actionGroup] actionGroupContainsStepKeyInArgValue"); + $I->comment('[END BEFORE HOOK]'); } /** diff --git a/dev/tests/verification/Resources/ActionGroupReturningValueTest.txt b/dev/tests/verification/Resources/ActionGroupReturningValueTest.txt index 92461bfaa..fdf05ad4b 100644 --- a/dev/tests/verification/Resources/ActionGroupReturningValueTest.txt +++ b/dev/tests/verification/Resources/ActionGroupReturningValueTest.txt @@ -29,11 +29,13 @@ class ActionGroupReturningValueTestCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->createEntity("createPersonParam", "hook", "ReplacementPerson", [], []); // stepKey: createPersonParam $I->comment("Entering Action Group [beforeGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1BeforeGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2BeforeGroup $I->comment("Exiting Action Group [beforeGroup] FunctionalActionGroup"); + $I->comment('[END BEFORE HOOK]'); } /** @@ -42,10 +44,12 @@ class ActionGroupReturningValueTestCest */ public function _after(AcceptanceTester $I) { + $I->comment('[START AFTER HOOK]'); $I->comment("Entering Action Group [afterGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1AfterGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2AfterGroup $I->comment("Exiting Action Group [afterGroup] FunctionalActionGroup"); + $I->comment('[END AFTER HOOK]'); if ($this->isSuccess) { unlink(__FILE__); } diff --git a/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt b/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt index 2b3c56883..88f1f0183 100644 --- a/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt +++ b/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt @@ -28,10 +28,12 @@ class ActionGroupUsingCreateDataCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->comment("Entering Action Group [Key1] actionGroupWithCreateData"); $I->createEntity("createCategoryKey1", "hook", "ApiCategory", [], []); // stepKey: createCategoryKey1 $I->createEntity("createConfigProductKey1", "hook", "ApiConfigurableProduct", ["createCategoryKey1"], []); // stepKey: createConfigProductKey1 $I->comment("Exiting Action Group [Key1] actionGroupWithCreateData"); + $I->comment('[END BEFORE HOOK]'); } /** diff --git a/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt b/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt index 34486ead4..79f182e8a 100644 --- a/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt +++ b/dev/tests/verification/Resources/ActionGroupWithDataOverrideTest.txt @@ -29,11 +29,13 @@ class ActionGroupWithDataOverrideTestCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->createEntity("createPersonParam", "hook", "ReplacementPerson", [], []); // stepKey: createPersonParam $I->comment("Entering Action Group [beforeGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1BeforeGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2BeforeGroup $I->comment("Exiting Action Group [beforeGroup] FunctionalActionGroup"); + $I->comment('[END BEFORE HOOK]'); } /** @@ -42,10 +44,12 @@ class ActionGroupWithDataOverrideTestCest */ public function _after(AcceptanceTester $I) { + $I->comment('[START AFTER HOOK]'); $I->comment("Entering Action Group [afterGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1AfterGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2AfterGroup $I->comment("Exiting Action Group [afterGroup] FunctionalActionGroup"); + $I->comment('[END AFTER HOOK]'); if ($this->isSuccess) { unlink(__FILE__); } diff --git a/dev/tests/verification/Resources/ActionGroupWithDataTest.txt b/dev/tests/verification/Resources/ActionGroupWithDataTest.txt index 542796ab6..ed8b69a77 100644 --- a/dev/tests/verification/Resources/ActionGroupWithDataTest.txt +++ b/dev/tests/verification/Resources/ActionGroupWithDataTest.txt @@ -29,11 +29,13 @@ class ActionGroupWithDataTestCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->createEntity("createPersonParam", "hook", "ReplacementPerson", [], []); // stepKey: createPersonParam $I->comment("Entering Action Group [beforeGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1BeforeGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2BeforeGroup $I->comment("Exiting Action Group [beforeGroup] FunctionalActionGroup"); + $I->comment('[END BEFORE HOOK]'); } /** @@ -42,10 +44,12 @@ class ActionGroupWithDataTestCest */ public function _after(AcceptanceTester $I) { + $I->comment('[START AFTER HOOK]'); $I->comment("Entering Action Group [afterGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1AfterGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2AfterGroup $I->comment("Exiting Action Group [afterGroup] FunctionalActionGroup"); + $I->comment('[END AFTER HOOK]'); if ($this->isSuccess) { unlink(__FILE__); } diff --git a/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt b/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt index 2705c5ca1..435b8a5cc 100644 --- a/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt +++ b/dev/tests/verification/Resources/ActionGroupWithNoDefaultTest.txt @@ -29,11 +29,13 @@ class ActionGroupWithNoDefaultTestCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->createEntity("createPersonParam", "hook", "ReplacementPerson", [], []); // stepKey: createPersonParam $I->comment("Entering Action Group [beforeGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1BeforeGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2BeforeGroup $I->comment("Exiting Action Group [beforeGroup] FunctionalActionGroup"); + $I->comment('[END BEFORE HOOK]'); } /** @@ -42,10 +44,12 @@ class ActionGroupWithNoDefaultTestCest */ public function _after(AcceptanceTester $I) { + $I->comment('[START AFTER HOOK]'); $I->comment("Entering Action Group [afterGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1AfterGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2AfterGroup $I->comment("Exiting Action Group [afterGroup] FunctionalActionGroup"); + $I->comment('[END AFTER HOOK]'); if ($this->isSuccess) { unlink(__FILE__); } diff --git a/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt b/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt index 243569e46..12aae9c21 100644 --- a/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt +++ b/dev/tests/verification/Resources/ActionGroupWithPersistedData.txt @@ -29,11 +29,13 @@ class ActionGroupWithPersistedDataCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->createEntity("createPersonParam", "hook", "ReplacementPerson", [], []); // stepKey: createPersonParam $I->comment("Entering Action Group [beforeGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1BeforeGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2BeforeGroup $I->comment("Exiting Action Group [beforeGroup] FunctionalActionGroup"); + $I->comment('[END BEFORE HOOK]'); } /** @@ -42,10 +44,12 @@ class ActionGroupWithPersistedDataCest */ public function _after(AcceptanceTester $I) { + $I->comment('[START AFTER HOOK]'); $I->comment("Entering Action Group [afterGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1AfterGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2AfterGroup $I->comment("Exiting Action Group [afterGroup] FunctionalActionGroup"); + $I->comment('[END AFTER HOOK]'); if ($this->isSuccess) { unlink(__FILE__); } diff --git a/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt b/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt index 7cc0ef505..4db67f901 100644 --- a/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt +++ b/dev/tests/verification/Resources/ActionGroupWithTopLevelPersistedData.txt @@ -29,11 +29,13 @@ class ActionGroupWithTopLevelPersistedDataCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->createEntity("createPersonParam", "hook", "ReplacementPerson", [], []); // stepKey: createPersonParam $I->comment("Entering Action Group [beforeGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1BeforeGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2BeforeGroup $I->comment("Exiting Action Group [beforeGroup] FunctionalActionGroup"); + $I->comment('[END BEFORE HOOK]'); } /** @@ -42,10 +44,12 @@ class ActionGroupWithTopLevelPersistedDataCest */ public function _after(AcceptanceTester $I) { + $I->comment('[START AFTER HOOK]'); $I->comment("Entering Action Group [afterGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1AfterGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2AfterGroup $I->comment("Exiting Action Group [afterGroup] FunctionalActionGroup"); + $I->comment('[END AFTER HOOK]'); if ($this->isSuccess) { unlink(__FILE__); } diff --git a/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt b/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt index 55ea28d00..a5e24c0a1 100644 --- a/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt +++ b/dev/tests/verification/Resources/ArgumentWithSameNameAsElement.txt @@ -29,11 +29,13 @@ class ArgumentWithSameNameAsElementCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->createEntity("createPersonParam", "hook", "ReplacementPerson", [], []); // stepKey: createPersonParam $I->comment("Entering Action Group [beforeGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1BeforeGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2BeforeGroup $I->comment("Exiting Action Group [beforeGroup] FunctionalActionGroup"); + $I->comment('[END BEFORE HOOK]'); } /** @@ -42,10 +44,12 @@ class ArgumentWithSameNameAsElementCest */ public function _after(AcceptanceTester $I) { + $I->comment('[START AFTER HOOK]'); $I->comment("Entering Action Group [afterGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1AfterGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2AfterGroup $I->comment("Exiting Action Group [afterGroup] FunctionalActionGroup"); + $I->comment('[END AFTER HOOK]'); if ($this->isSuccess) { unlink(__FILE__); } diff --git a/dev/tests/verification/Resources/AssertTest.txt b/dev/tests/verification/Resources/AssertTest.txt index 381ab4818..75c5266bd 100644 --- a/dev/tests/verification/Resources/AssertTest.txt +++ b/dev/tests/verification/Resources/AssertTest.txt @@ -28,7 +28,9 @@ class AssertTestCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->createEntity("createData1", "hook", "ReplacementPerson", [], []); // stepKey: createData1 + $I->comment('[END BEFORE HOOK]'); } /** diff --git a/dev/tests/verification/Resources/BasicActionGroupTest.txt b/dev/tests/verification/Resources/BasicActionGroupTest.txt index 8a5da2f11..5412afa70 100644 --- a/dev/tests/verification/Resources/BasicActionGroupTest.txt +++ b/dev/tests/verification/Resources/BasicActionGroupTest.txt @@ -29,11 +29,13 @@ class BasicActionGroupTestCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->createEntity("createPersonParam", "hook", "ReplacementPerson", [], []); // stepKey: createPersonParam $I->comment("Entering Action Group [beforeGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1BeforeGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2BeforeGroup $I->comment("Exiting Action Group [beforeGroup] FunctionalActionGroup"); + $I->comment('[END BEFORE HOOK]'); } /** diff --git a/dev/tests/verification/Resources/BasicFunctionalTest.txt b/dev/tests/verification/Resources/BasicFunctionalTest.txt index 526162e3e..e30f50c34 100644 --- a/dev/tests/verification/Resources/BasicFunctionalTest.txt +++ b/dev/tests/verification/Resources/BasicFunctionalTest.txt @@ -30,7 +30,9 @@ class BasicFunctionalTestCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->amOnPage("/beforeUrl"); // stepKey: beforeAmOnPageKey + $I->comment('[END BEFORE HOOK]'); } /** @@ -39,7 +41,9 @@ class BasicFunctionalTestCest */ public function _after(AcceptanceTester $I) { + $I->comment('[START AFTER HOOK]'); $I->amOnPage("/afterUrl"); // stepKey: afterAmOnPageKey + $I->comment('[END AFTER HOOK]'); if ($this->isSuccess) { unlink(__FILE__); } diff --git a/dev/tests/verification/Resources/BasicMergeTest.txt b/dev/tests/verification/Resources/BasicMergeTest.txt index 27b22bd34..df625aa57 100644 --- a/dev/tests/verification/Resources/BasicMergeTest.txt +++ b/dev/tests/verification/Resources/BasicMergeTest.txt @@ -31,8 +31,10 @@ class BasicMergeTestCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->amOnPage("/beforeUrl"); // stepKey: before1 $I->see("#before2"); // stepKey: before2 + $I->comment('[END BEFORE HOOK]'); } /** @@ -41,7 +43,9 @@ class BasicMergeTestCest */ public function _after(AcceptanceTester $I) { + $I->comment('[START AFTER HOOK]'); $I->amOnPage("/afterUrl1"); // stepKey: after1 + $I->comment('[END AFTER HOOK]'); if ($this->isSuccess) { unlink(__FILE__); } diff --git a/dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt b/dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt index 63b874964..01fa652d8 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestAddHooks.txt @@ -30,7 +30,9 @@ class ChildExtendedTestAddHooksCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->amOnPage("/beforeUrl"); // stepKey: beforeAmOnPageKey + $I->comment('[END BEFORE HOOK]'); } /** @@ -39,7 +41,9 @@ class ChildExtendedTestAddHooksCest */ public function _after(AcceptanceTester $I) { + $I->comment('[START AFTER HOOK]'); $I->amOnPage("/afterUrl"); // stepKey: afterAmOnPageKey + $I->comment('[END AFTER HOOK]'); if ($this->isSuccess) { unlink(__FILE__); } diff --git a/dev/tests/verification/Resources/ChildExtendedTestMerging.txt b/dev/tests/verification/Resources/ChildExtendedTestMerging.txt index 5f506e58c..8b78c5a5e 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestMerging.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestMerging.txt @@ -30,9 +30,11 @@ class ChildExtendedTestMergingCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->amOnPage("/firstUrl"); // stepKey: firstBeforeAmOnPageKey $I->amOnPage("/beforeUrl"); // stepKey: beforeAmOnPageKey $I->amOnPage("/lastUrl"); // stepKey: lastBefore + $I->comment('[END BEFORE HOOK]'); } /** @@ -41,7 +43,9 @@ class ChildExtendedTestMergingCest */ public function _after(AcceptanceTester $I) { + $I->comment('[START AFTER HOOK]'); $I->amOnPage("/afterUrl"); // stepKey: afterAmOnPageKey + $I->comment('[END AFTER HOOK]'); if ($this->isSuccess) { unlink(__FILE__); } diff --git a/dev/tests/verification/Resources/ChildExtendedTestRemoveAction.txt b/dev/tests/verification/Resources/ChildExtendedTestRemoveAction.txt index 64ae855b8..859bc8226 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestRemoveAction.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestRemoveAction.txt @@ -30,7 +30,9 @@ class ChildExtendedTestRemoveActionCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->amOnPage("/beforeUrl"); // stepKey: beforeAmOnPageKey + $I->comment('[END BEFORE HOOK]'); } /** @@ -39,7 +41,9 @@ class ChildExtendedTestRemoveActionCest */ public function _after(AcceptanceTester $I) { + $I->comment('[START AFTER HOOK]'); $I->amOnPage("/afterUrl"); // stepKey: afterAmOnPageKey + $I->comment('[END AFTER HOOK]'); if ($this->isSuccess) { unlink(__FILE__); } diff --git a/dev/tests/verification/Resources/ChildExtendedTestRemoveHookAction.txt b/dev/tests/verification/Resources/ChildExtendedTestRemoveHookAction.txt index e4acdf155..d48fb9743 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestRemoveHookAction.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestRemoveHookAction.txt @@ -38,7 +38,9 @@ class ChildExtendedTestRemoveHookActionCest */ public function _after(AcceptanceTester $I) { + $I->comment('[START AFTER HOOK]'); $I->amOnPage("/afterUrl"); // stepKey: afterAmOnPageKey + $I->comment('[END AFTER HOOK]'); if ($this->isSuccess) { unlink(__FILE__); } diff --git a/dev/tests/verification/Resources/ChildExtendedTestReplace.txt b/dev/tests/verification/Resources/ChildExtendedTestReplace.txt index 0b62e3762..acb8eced9 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestReplace.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestReplace.txt @@ -30,7 +30,9 @@ class ChildExtendedTestReplaceCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->amOnPage("/beforeUrl"); // stepKey: beforeAmOnPageKey + $I->comment('[END BEFORE HOOK]'); } /** @@ -39,7 +41,9 @@ class ChildExtendedTestReplaceCest */ public function _after(AcceptanceTester $I) { + $I->comment('[START AFTER HOOK]'); $I->amOnPage("/afterUrl"); // stepKey: afterAmOnPageKey + $I->comment('[END AFTER HOOK]'); if ($this->isSuccess) { unlink(__FILE__); } diff --git a/dev/tests/verification/Resources/ChildExtendedTestReplaceHook.txt b/dev/tests/verification/Resources/ChildExtendedTestReplaceHook.txt index 1e8366351..db6912e95 100644 --- a/dev/tests/verification/Resources/ChildExtendedTestReplaceHook.txt +++ b/dev/tests/verification/Resources/ChildExtendedTestReplaceHook.txt @@ -30,7 +30,9 @@ class ChildExtendedTestReplaceHookCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->amOnPage("/slightlyDifferentBeforeUrl"); // stepKey: beforeAmOnPageKey + $I->comment('[END BEFORE HOOK]'); } /** @@ -39,7 +41,9 @@ class ChildExtendedTestReplaceHookCest */ public function _after(AcceptanceTester $I) { + $I->comment('[START AFTER HOOK]'); $I->amOnPage("/afterUrl"); // stepKey: afterAmOnPageKey + $I->comment('[END AFTER HOOK]'); if ($this->isSuccess) { unlink(__FILE__); } diff --git a/dev/tests/verification/Resources/DataActionsTest.txt b/dev/tests/verification/Resources/DataActionsTest.txt index da89f4d59..cf4de53a3 100644 --- a/dev/tests/verification/Resources/DataActionsTest.txt +++ b/dev/tests/verification/Resources/DataActionsTest.txt @@ -28,9 +28,11 @@ class DataActionsTestCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->createEntity("createdInBefore", "hook", "entity", [], []); // stepKey: createdInBefore $I->updateEntity("createdInBefore", "hook", "entity",[]); // stepKey: updateInBefore $I->deleteEntity("createdInBefore", "hook"); // stepKey: deleteInBefore + $I->comment('[END BEFORE HOOK]'); } /** diff --git a/dev/tests/verification/Resources/ExtendedChildTestInSuiteCest.txt b/dev/tests/verification/Resources/ExtendedChildTestInSuiteCest.txt index fae417d55..c46076353 100644 --- a/dev/tests/verification/Resources/ExtendedChildTestInSuiteCest.txt +++ b/dev/tests/verification/Resources/ExtendedChildTestInSuiteCest.txt @@ -30,7 +30,9 @@ class ExtendedChildTestInSuiteCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->amOnPage("/beforeUrl"); // stepKey: beforeAmOnPageKey + $I->comment('[END BEFORE HOOK]'); } /** @@ -39,7 +41,9 @@ class ExtendedChildTestInSuiteCest */ public function _after(AcceptanceTester $I) { + $I->comment('[START AFTER HOOK]'); $I->amOnPage("/afterUrl"); // stepKey: afterAmOnPageKey + $I->comment('[END AFTER HOOK]'); if ($this->isSuccess) { unlink(__FILE__); } diff --git a/dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt b/dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt index be3ffbf58..38ba62faf 100644 --- a/dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt +++ b/dev/tests/verification/Resources/ExtendedChildTestNotInSuite.txt @@ -29,7 +29,9 @@ class ExtendedChildTestNotInSuiteCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->amOnPage("/beforeUrl"); // stepKey: beforeAmOnPageKey + $I->comment('[END BEFORE HOOK]'); } /** @@ -38,7 +40,9 @@ class ExtendedChildTestNotInSuiteCest */ public function _after(AcceptanceTester $I) { + $I->comment('[START AFTER HOOK]'); $I->amOnPage("/afterUrl"); // stepKey: afterAmOnPageKey + $I->comment('[END AFTER HOOK]'); if ($this->isSuccess) { unlink(__FILE__); } diff --git a/dev/tests/verification/Resources/HookActionsTest.txt b/dev/tests/verification/Resources/HookActionsTest.txt index 0132cd48c..01edd913d 100644 --- a/dev/tests/verification/Resources/HookActionsTest.txt +++ b/dev/tests/verification/Resources/HookActionsTest.txt @@ -28,9 +28,11 @@ class HookActionsTestCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->createEntity("sampleCreateBefore", "hook", "sampleCreatedEntity", [], []); // stepKey: sampleCreateBefore $I->deleteEntity("sampleCreateBefore", "hook"); // stepKey: sampleDeleteBefore $I->createEntity("sampleCreateForAfter", "hook", "sampleCreatedEntity", [], []); // stepKey: sampleCreateForAfter + $I->comment('[END BEFORE HOOK]'); } /** @@ -39,8 +41,10 @@ class HookActionsTestCest */ public function _after(AcceptanceTester $I) { + $I->comment('[START AFTER HOOK]'); $I->createEntity("sampleCreateAfter", "hook", "sampleCreatedEntity", [], []); // stepKey: sampleCreateAfter $I->deleteEntity("sampleCreateForAfter", "hook"); // stepKey: sampleDeleteAfter + $I->comment('[END AFTER HOOK]'); if ($this->isSuccess) { unlink(__FILE__); } diff --git a/dev/tests/verification/Resources/MergedActionGroupReturningValueTest.txt b/dev/tests/verification/Resources/MergedActionGroupReturningValueTest.txt index cce383b6c..68fec4cfa 100644 --- a/dev/tests/verification/Resources/MergedActionGroupReturningValueTest.txt +++ b/dev/tests/verification/Resources/MergedActionGroupReturningValueTest.txt @@ -29,11 +29,13 @@ class MergedActionGroupReturningValueTestCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->createEntity("createPersonParam", "hook", "ReplacementPerson", [], []); // stepKey: createPersonParam $I->comment("Entering Action Group [beforeGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1BeforeGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2BeforeGroup $I->comment("Exiting Action Group [beforeGroup] FunctionalActionGroup"); + $I->comment('[END BEFORE HOOK]'); } /** @@ -42,10 +44,12 @@ class MergedActionGroupReturningValueTestCest */ public function _after(AcceptanceTester $I) { + $I->comment('[START AFTER HOOK]'); $I->comment("Entering Action Group [afterGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1AfterGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2AfterGroup $I->comment("Exiting Action Group [afterGroup] FunctionalActionGroup"); + $I->comment('[END AFTER HOOK]'); if ($this->isSuccess) { unlink(__FILE__); } diff --git a/dev/tests/verification/Resources/MergedActionGroupTest.txt b/dev/tests/verification/Resources/MergedActionGroupTest.txt index e1a67c144..a4abf2820 100644 --- a/dev/tests/verification/Resources/MergedActionGroupTest.txt +++ b/dev/tests/verification/Resources/MergedActionGroupTest.txt @@ -29,11 +29,13 @@ class MergedActionGroupTestCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->createEntity("createPersonParam", "hook", "ReplacementPerson", [], []); // stepKey: createPersonParam $I->comment("Entering Action Group [beforeGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1BeforeGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2BeforeGroup $I->comment("Exiting Action Group [beforeGroup] FunctionalActionGroup"); + $I->comment('[END BEFORE HOOK]'); } /** @@ -42,10 +44,12 @@ class MergedActionGroupTestCest */ public function _after(AcceptanceTester $I) { + $I->comment('[START AFTER HOOK]'); $I->comment("Entering Action Group [afterGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1AfterGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2AfterGroup $I->comment("Exiting Action Group [afterGroup] FunctionalActionGroup"); + $I->comment('[END AFTER HOOK]'); if ($this->isSuccess) { unlink(__FILE__); } diff --git a/dev/tests/verification/Resources/MergedReferencesTest.txt b/dev/tests/verification/Resources/MergedReferencesTest.txt index d020c3466..40c9b3cdb 100644 --- a/dev/tests/verification/Resources/MergedReferencesTest.txt +++ b/dev/tests/verification/Resources/MergedReferencesTest.txt @@ -30,7 +30,9 @@ class MergedReferencesTestCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->amOnPage("/beforeUrl"); // stepKey: before1 + $I->comment('[END BEFORE HOOK]'); } /** @@ -39,7 +41,9 @@ class MergedReferencesTestCest */ public function _after(AcceptanceTester $I) { + $I->comment('[START AFTER HOOK]'); $I->amOnPage("/afterUrl"); // stepKey: after1 + $I->comment('[END AFTER HOOK]'); if ($this->isSuccess) { unlink(__FILE__); } diff --git a/dev/tests/verification/Resources/MultipleActionGroupsTest.txt b/dev/tests/verification/Resources/MultipleActionGroupsTest.txt index bcc0f31e0..02ffcdf84 100644 --- a/dev/tests/verification/Resources/MultipleActionGroupsTest.txt +++ b/dev/tests/verification/Resources/MultipleActionGroupsTest.txt @@ -29,11 +29,13 @@ class MultipleActionGroupsTestCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->createEntity("createPersonParam", "hook", "ReplacementPerson", [], []); // stepKey: createPersonParam $I->comment("Entering Action Group [beforeGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1BeforeGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2BeforeGroup $I->comment("Exiting Action Group [beforeGroup] FunctionalActionGroup"); + $I->comment('[END BEFORE HOOK]'); } /** @@ -42,10 +44,12 @@ class MultipleActionGroupsTestCest */ public function _after(AcceptanceTester $I) { + $I->comment('[START AFTER HOOK]'); $I->comment("Entering Action Group [afterGroup] FunctionalActionGroup"); $I->fillField("#foo", "myData1"); // stepKey: fillField1AfterGroup $I->fillField("#bar", "myData2"); // stepKey: fillField2AfterGroup $I->comment("Exiting Action Group [afterGroup] FunctionalActionGroup"); + $I->comment('[END AFTER HOOK]'); if ($this->isSuccess) { unlink(__FILE__); } diff --git a/dev/tests/verification/Resources/ParentExtendedTest.txt b/dev/tests/verification/Resources/ParentExtendedTest.txt index 3c24988ac..a06efd830 100644 --- a/dev/tests/verification/Resources/ParentExtendedTest.txt +++ b/dev/tests/verification/Resources/ParentExtendedTest.txt @@ -30,7 +30,9 @@ class ParentExtendedTestCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->amOnPage("/beforeUrl"); // stepKey: beforeAmOnPageKey + $I->comment('[END BEFORE HOOK]'); } /** @@ -39,7 +41,9 @@ class ParentExtendedTestCest */ public function _after(AcceptanceTester $I) { + $I->comment('[START AFTER HOOK]'); $I->amOnPage("/afterUrl"); // stepKey: afterAmOnPageKey + $I->comment('[END AFTER HOOK]'); if ($this->isSuccess) { unlink(__FILE__); } diff --git a/dev/tests/verification/Resources/PersistedReplacementTest.txt b/dev/tests/verification/Resources/PersistedReplacementTest.txt index 2f0bde2ab..0763d5da2 100644 --- a/dev/tests/verification/Resources/PersistedReplacementTest.txt +++ b/dev/tests/verification/Resources/PersistedReplacementTest.txt @@ -28,7 +28,9 @@ class PersistedReplacementTestCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->createEntity("createData1", "hook", "ReplacementPerson", [], []); // stepKey: createData1 + $I->comment('[END BEFORE HOOK]'); } /** diff --git a/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt b/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt index b3b10a38b..43689fc0a 100644 --- a/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt +++ b/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt @@ -28,6 +28,7 @@ class PersistenceActionGroupAppendingTestCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->comment("Entering Action Group [ACTIONGROUPBEFORE] DataPersistenceAppendingActionGroup"); $I->createEntity("createDataACTIONGROUPBEFORE", "hook", "entity", [], []); // stepKey: createDataACTIONGROUPBEFORE $I->updateEntity("createDataACTIONGROUPBEFORE", "hook", "newEntity",[]); // stepKey: updateDataACTIONGROUPBEFORE @@ -35,6 +36,7 @@ class PersistenceActionGroupAppendingTestCest $I->getEntity("getDataACTIONGROUPBEFORE", "hook", "someEneity", [], null); // stepKey: getDataACTIONGROUPBEFORE $I->comment($I->retrieveEntityField('createData', 'field', 'hook')); $I->comment("Exiting Action Group [ACTIONGROUPBEFORE] DataPersistenceAppendingActionGroup"); + $I->comment('[END BEFORE HOOK]'); } /** diff --git a/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt b/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt index 6558daa74..4039b952f 100644 --- a/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt +++ b/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt @@ -28,11 +28,13 @@ class PersistenceCustomFieldsTestCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $createData1Fields['firstname'] = "Mac"; $createData1Fields['lastname'] = "Doe"; $I->createEntity("createData1", "hook", "DefaultPerson", [], $createData1Fields); // stepKey: createData1 $createData2Fields['firstname'] = $I->retrieveEntityField('createData1', 'firstname', 'hook'); $I->createEntity("createData2", "hook", "uniqueData", ["createData1"], $createData2Fields); // stepKey: createData2 + $I->comment('[END BEFORE HOOK]'); } /** diff --git a/dev/tests/verification/Resources/XmlCommentedTest.txt b/dev/tests/verification/Resources/XmlCommentedTest.txt index d3c11d781..26563b7f4 100644 --- a/dev/tests/verification/Resources/XmlCommentedTest.txt +++ b/dev/tests/verification/Resources/XmlCommentedTest.txt @@ -29,9 +29,11 @@ class XmlCommentedTestCest */ public function _before(AcceptanceTester $I) { + $I->comment('[START BEFORE HOOK]'); $I->comment("< > & \$abc \" abc ' <click stepKey=\"click\" userInput=\"\$\$createDataHook.firstname\$\$\" selector=\"#id_1\">/"); $I->amOnPage("/beforeUrl"); // stepKey: beforeAmOnPageKey $I->comment("< > & \$abc \" abc ' <click stepKey=\"click\" userInput=\"\$\$createDataHook.firstname\$\$\" selector=\"#id_2\">/"); + $I->comment('[END BEFORE HOOK]'); } /** @@ -40,9 +42,11 @@ class XmlCommentedTestCest */ public function _after(AcceptanceTester $I) { + $I->comment('[START AFTER HOOK]'); $I->comment("< > & \$abc \" abc ' <click stepKey=\"click\" userInput=\"\$\$createDataHook.firstname\$\$\" selector=\"#id_1\">/"); $I->amOnPage("/afterUrl"); // stepKey: afterAmOnPageKey $I->comment("< > & \$abc \" abc ' <click stepKey=\"click\" userInput=\"\$\$createDataHook.firstname\$\$\" selector=\"#id_2\">/"); + $I->comment('[END AFTER HOOK]'); if ($this->isSuccess) { unlink(__FILE__); } diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 06c32ea03..bb9dc6978 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1770,29 +1770,29 @@ private function generateHooksPhp($hookObjects) throw new TestReferenceException($e->getMessage() . " in Element \"" . $type . "\""); } - if ($type == 'before') { - $steps = sprintf( - "\t\t$%s->comment('[%s]');" . PHP_EOL, - 'I', - 'START BEFORE HOOK' - ) . $steps; - $steps = $steps . sprintf( - "\t\t$%s->comment('[%s]');" . PHP_EOL, - 'I', - 'END BEFORE HOOK' + if ($type === 'before' && $steps) { + $steps = sprintf( + "\t\t$%s->comment('[%s]');" . PHP_EOL, + 'I', + 'START BEFORE HOOK' + ) . $steps; + $steps = $steps . sprintf( + "\t\t$%s->comment('[%s]');" . PHP_EOL, + 'I', + 'END BEFORE HOOK' ); } - if ($type == 'after') { - $steps = sprintf( - "\t\t$%s->comment('[%s]');" . PHP_EOL, - 'I', - 'START AFTER HOOK' + if ($type === 'after' && $steps) { + $steps = sprintf( + "\t\t$%s->comment('[%s]');" . PHP_EOL, + 'I', + 'START AFTER HOOK' ) . $steps; - $steps = $steps . sprintf( - "\t\t$%s->comment('[%s]');" . PHP_EOL, - 'I', - 'END AFTER HOOK' + $steps = $steps . sprintf( + "\t\t$%s->comment('[%s]');" . PHP_EOL, + 'I', + 'END AFTER HOOK' ); } From 3608a7f58dbc315747aa3a88c62af26efaa62bdd Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Sun, 6 Feb 2022 18:53:48 +0530 Subject: [PATCH 788/888] MQE-1677 : Static check for created data outside action group --- ...CreatedDataFromOutsideActionGroupCheck.php | 207 ++++++++++++++++++ .../StaticCheck/StaticChecksList.php | 4 +- 2 files changed, 210 insertions(+), 1 deletion(-) create mode 100644 src/Magento/FunctionalTestingFramework/StaticCheck/CreatedDataFromOutsideActionGroupCheck.php diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/CreatedDataFromOutsideActionGroupCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/CreatedDataFromOutsideActionGroupCheck.php new file mode 100644 index 000000000..fadfe203f --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/CreatedDataFromOutsideActionGroupCheck.php @@ -0,0 +1,207 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\FunctionalTestingFramework\StaticCheck; + +use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use InvalidArgumentException; +use Exception; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Exceptions\XmlException; +use Magento\FunctionalTestingFramework\Page\Objects\SectionObject; +use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; +use Magento\FunctionalTestingFramework\Page\Objects\ElementObject; +use Magento\FunctionalTestingFramework\Test\Objects\ActionGroupObject; +use Magento\FunctionalTestingFramework\Page\Objects\PageObject; +use Magento\FunctionalTestingFramework\Test\Objects\TestObject; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Finder\Finder; +use Magento\FunctionalTestingFramework\Util\Script\ScriptUtil; +use Magento\FunctionalTestingFramework\DataGenerator\Handlers\OperationDefinitionObjectHandler; +use Magento\FunctionalTestingFramework\DataGenerator\Objects\OperationDefinitionObject; +use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; +use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; +use Symfony\Component\Finder\SplFileInfo; +use DOMNodeList; +use DOMElement; + +/** + * Class CreatedDataFromOutsideActionGroupCheck + * @package Magento\FunctionalTestingFramework\StaticCheck + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class CreatedDataFromOutsideActionGroupCheck implements StaticCheckInterface +{ + const ACTIONGROUP_REGEX_PATTERN = '/\$(\$)*([\w.]+)(\$)*\$/'; + + const ERROR_LOG_FILENAME = 'create-data-from-outside-action-group'; + const ERROR_LOG_MESSAGE = 'Created Data From Outside Action Group'; + + /** + * Array containing all errors found after running the execute() function + * + * @var array + */ + private $errors = []; + + /** + * String representing the output summary found after running the execute() function + * + * @var string + */ + private $output; + + /** + * ScriptUtil instance + * + * @var ScriptUtil + */ + private $scriptUtil; + + /** + * Action group xml files to scan + * + * @var Finder|array + */ + private $actionGroupXmlFiles = []; + + /** + * Checks test dependencies, determined by references in tests versus the dependencies listed in the Magento module + * + * @param InputInterface $input + * @return void + * @throws Exception + */ + public function execute(InputInterface $input) + { + $this->scriptUtil = new ScriptUtil(); + $this->loadAllXmlFiles($input); + $this->errors = []; + + $this->errors += $this->findReferenceErrorsInActionFiles($this->actionGroupXmlFiles); + + $this->output = $this->scriptUtil->printErrorsToFile( + $this->errors, + StaticChecksList::getErrorFilesPath() . DIRECTORY_SEPARATOR . self::ERROR_LOG_FILENAME . '.txt', + self::ERROR_LOG_MESSAGE + ); + } + + /** + * Return array containing all errors found after running the execute() function + * + * @return array + */ + public function getErrors() + { + return $this->errors; + } + + /** + * Return string of a short human readable result of the check. For example: "No Dependency errors found." + * + * @return string + */ + public function getOutput() + { + return $this->output; + } + + /** + * Read all XML files for scanning + * + * @param InputInterface $input + * @return void + * @throws Exception + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + */ + private function loadAllXmlFiles($input) + { + $modulePaths = []; + $includeRootPath = true; + $path = $input->getOption('path'); + if ($path) { + if (!realpath($path)) { + throw new InvalidArgumentException('Invalid --path option: ' . $path); + } + MftfApplicationConfig::create( + true, + MftfApplicationConfig::UNIT_TEST_PHASE, + false, + MftfApplicationConfig::LEVEL_DEFAULT, + true + ); + $modulePaths[] = realpath($path); + $includeRootPath = false; + } else { + $modulePaths = $this->scriptUtil->getAllModulePaths(); + } + + // These files can contain references to other entities + $this->actionGroupXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, 'ActionGroup'); + + if (empty($this->actionGroupXmlFiles)) { + if ($path) { + throw new InvalidArgumentException( + 'Invalid --path option: ' + . $path + . PHP_EOL + . 'Please make sure --path points to a valid MFTF Test Module.' + ); + } elseif (empty($this->rootSuiteXmlFiles)) { + throw new TestFrameworkException('No xml file to scan.'); + } + } + } + + /** + * Find reference errors in set of action files + * + * @param Finder $files + * @return array + * @throws XmlException + */ + private function findReferenceErrorsInActionFiles($files) + { + $testErrors = []; + /** @var SplFileInfo $filePath */ + foreach ($files as $filePath) { + $contents = file_get_contents($filePath); + preg_match_all(self::ACTIONGROUP_REGEX_PATTERN, $contents, $actionGroupReferences); + if(count( $actionGroupReferences) > 0) { + $testErrors = array_merge($testErrors, $this->setErrorOutput($actionGroupReferences, $filePath)); + } + } + + return $testErrors; + } + + /** + * Build and return error output for violating references + * + * @param array $actionGroupReferences + * @param SplFileInfo $path + * @return mixed + */ + private function setErrorOutput( $actionGroupReferences , $path) + { + $testErrors = []; + $errorOutput = ""; + $filePath = StaticChecksList::getFilePath($path->getRealPath()); + + foreach($actionGroupReferences as $key => $actionGroupReferencesData) { + foreach($actionGroupReferencesData as $actionGroupReferencesDataResult) { + + $errorOutput .= "\nFile \"{$filePath}\" contains: ". "\n\t {$actionGroupReferencesDataResult} in {$filePath}"; + $testErrors[$filePath][] = $errorOutput; + } + + + } + return $testErrors; + } + +} diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php b/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php index 07c52ce8c..39b9ae748 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php @@ -18,6 +18,7 @@ class StaticChecksList implements StaticCheckListInterface { const DEPRECATED_ENTITY_USAGE_CHECK_NAME = 'deprecatedEntityUsage'; const PAUSE_ACTION_USAGE_CHECK_NAME = 'pauseActionUsage'; + const CREATED_DATA_FROM_OUTSIDE_ACTIONGROUP = 'createdDataFromOutsideActionGroup'; const STATIC_RESULTS = 'tests' . DIRECTORY_SEPARATOR .'_output' . DIRECTORY_SEPARATOR . 'static-results'; /** @@ -47,7 +48,8 @@ public function __construct(array $checks = []) 'actionGroupArguments' => new ActionGroupArgumentsCheck(), self::DEPRECATED_ENTITY_USAGE_CHECK_NAME => new DeprecatedEntityUsageCheck(), 'annotations' => new AnnotationsCheck(), - self::PAUSE_ACTION_USAGE_CHECK_NAME => new PauseActionUsageCheck() + self::PAUSE_ACTION_USAGE_CHECK_NAME => new PauseActionUsageCheck(), + self::CREATED_DATA_FROM_OUTSIDE_ACTIONGROUP => new CreatedDataFromOutsideActionGroupCheck() ] + $checks; // Static checks error files directory From 902fa7d7503472361df8eb8bd222ccf0b995d677 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Sun, 6 Feb 2022 19:39:03 +0530 Subject: [PATCH 789/888] MQE-1677 : Static check for created data outside action group --- ...CreatedDataFromOutsideActionGroupCheck.php | 284 +++++++++--------- 1 file changed, 139 insertions(+), 145 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/CreatedDataFromOutsideActionGroupCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/CreatedDataFromOutsideActionGroupCheck.php index fadfe203f..eec27b157 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/CreatedDataFromOutsideActionGroupCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/CreatedDataFromOutsideActionGroupCheck.php @@ -35,173 +35,167 @@ */ class CreatedDataFromOutsideActionGroupCheck implements StaticCheckInterface { - const ACTIONGROUP_REGEX_PATTERN = '/\$(\$)*([\w.]+)(\$)*\$/'; - - const ERROR_LOG_FILENAME = 'create-data-from-outside-action-group'; - const ERROR_LOG_MESSAGE = 'Created Data From Outside Action Group'; - - /** - * Array containing all errors found after running the execute() function - * - * @var array - */ - private $errors = []; - - /** - * String representing the output summary found after running the execute() function - * - * @var string - */ - private $output; - - /** - * ScriptUtil instance - * - * @var ScriptUtil - */ - private $scriptUtil; - - /** - * Action group xml files to scan - * - * @var Finder|array - */ - private $actionGroupXmlFiles = []; - - /** - * Checks test dependencies, determined by references in tests versus the dependencies listed in the Magento module - * - * @param InputInterface $input - * @return void - * @throws Exception - */ - public function execute(InputInterface $input) - { + const ACTIONGROUP_REGEX_PATTERN = '/\$(\$)*([\w.]+)(\$)*\$/'; + const ERROR_LOG_FILENAME = 'create-data-from-outside-action-group'; + const ERROR_LOG_MESSAGE = 'Created Data From Outside Action Group'; + + /** + * Array containing all errors found after running the execute() function + * + * @var array + */ + private $errors = []; + + /** + * String representing the output summary found after running the execute() function + * + * @var string + */ + private $output; + + /** + * ScriptUtil instance + * + * @var ScriptUtil + */ + private $scriptUtil; + + /** + * Action group xml files to scan + * + * @var Finder|array + */ + private $actionGroupXmlFiles = []; + + /** + * Checks test dependencies, determined by references in tests versus the dependencies listed in the Magento module + * + * @param InputInterface $input + * @return void + * @throws Exception + */ + public function execute(InputInterface $input) + { $this->scriptUtil = new ScriptUtil(); $this->loadAllXmlFiles($input); $this->errors = []; - $this->errors += $this->findReferenceErrorsInActionFiles($this->actionGroupXmlFiles); - $this->output = $this->scriptUtil->printErrorsToFile( $this->errors, StaticChecksList::getErrorFilesPath() . DIRECTORY_SEPARATOR . self::ERROR_LOG_FILENAME . '.txt', self::ERROR_LOG_MESSAGE ); - } - - /** - * Return array containing all errors found after running the execute() function - * - * @return array - */ - public function getErrors() - { - return $this->errors; - } - - /** - * Return string of a short human readable result of the check. For example: "No Dependency errors found." - * - * @return string - */ - public function getOutput() - { - return $this->output; - } + } - /** - * Read all XML files for scanning - * - * @param InputInterface $input - * @return void - * @throws Exception - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - */ - private function loadAllXmlFiles($input) - { - $modulePaths = []; - $includeRootPath = true; - $path = $input->getOption('path'); - if ($path) { - if (!realpath($path)) { - throw new InvalidArgumentException('Invalid --path option: ' . $path); - } - MftfApplicationConfig::create( - true, - MftfApplicationConfig::UNIT_TEST_PHASE, - false, - MftfApplicationConfig::LEVEL_DEFAULT, - true - ); - $modulePaths[] = realpath($path); - $includeRootPath = false; - } else { - $modulePaths = $this->scriptUtil->getAllModulePaths(); + /** + * Return array containing all errors found after running the execute() function + * + * @return array + */ + public function getErrors() + { + return $this->errors; } - // These files can contain references to other entities - $this->actionGroupXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, 'ActionGroup'); - - if (empty($this->actionGroupXmlFiles)) { - if ($path) { - throw new InvalidArgumentException( - 'Invalid --path option: ' - . $path - . PHP_EOL - . 'Please make sure --path points to a valid MFTF Test Module.' - ); - } elseif (empty($this->rootSuiteXmlFiles)) { - throw new TestFrameworkException('No xml file to scan.'); - } + /** + * Return string of a short human readable result of the check. For example: "No Dependency errors found." + * + * @return string + */ + public function getOutput() + { + return $this->output; } - } - /** - * Find reference errors in set of action files - * - * @param Finder $files - * @return array - * @throws XmlException - */ - private function findReferenceErrorsInActionFiles($files) - { - $testErrors = []; - /** @var SplFileInfo $filePath */ - foreach ($files as $filePath) { - $contents = file_get_contents($filePath); - preg_match_all(self::ACTIONGROUP_REGEX_PATTERN, $contents, $actionGroupReferences); - if(count( $actionGroupReferences) > 0) { - $testErrors = array_merge($testErrors, $this->setErrorOutput($actionGroupReferences, $filePath)); + /** + * Read all XML files for scanning + * + * @param InputInterface $input + * @return void + * @throws Exception + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + */ + private function loadAllXmlFiles($input) + { + $modulePaths = []; + $includeRootPath = true; + $path = $input->getOption('path'); + if ($path) { + if (!realpath($path)) { + throw new InvalidArgumentException('Invalid --path option: ' . $path); + } + MftfApplicationConfig::create( + true, + MftfApplicationConfig::UNIT_TEST_PHASE, + false, + MftfApplicationConfig::LEVEL_DEFAULT, + true + ); + $modulePaths[] = realpath($path); + $includeRootPath = false; + } else { + $modulePaths = $this->scriptUtil->getAllModulePaths(); + } + + // These files can contain references to other entities + $this->actionGroupXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, 'ActionGroup'); + + if (empty($this->actionGroupXmlFiles)) { + if ($path) { + throw new InvalidArgumentException( + 'Invalid --path option: ' + . $path + . PHP_EOL + . 'Please make sure --path points to a valid MFTF Test Module.' + ); + } elseif (empty($this->rootSuiteXmlFiles)) { + throw new TestFrameworkException('No xml file to scan.'); + } } } - return $testErrors; - } + /** + * Find reference errors in set of action files + * + * @param Finder $files + * @return array + * @throws XmlException + */ + private function findReferenceErrorsInActionFiles($files) + { + $testErrors = []; + /** @var SplFileInfo $filePath */ + foreach ($files as $filePath) { + $contents = file_get_contents($filePath); + preg_match_all(self::ACTIONGROUP_REGEX_PATTERN, $contents, $actionGroupReferences); + if (count($actionGroupReferences) > 0) { + $testErrors = array_merge($testErrors, $this->setErrorOutput($actionGroupReferences, $filePath)); + } + } + + return $testErrors; + } - /** - * Build and return error output for violating references - * - * @param array $actionGroupReferences - * @param SplFileInfo $path - * @return mixed - */ - private function setErrorOutput( $actionGroupReferences , $path) - { - $testErrors = []; + /** + * Build and return error output for violating references + * + * @param array $actionGroupReferences + * @param SplFileInfo $path + * @return mixed + */ + private function setErrorOutput($actionGroupReferences, $path) + { + $testErrors = []; $errorOutput = ""; $filePath = StaticChecksList::getFilePath($path->getRealPath()); - foreach($actionGroupReferences as $key => $actionGroupReferencesData) { - foreach($actionGroupReferencesData as $actionGroupReferencesDataResult) { - - $errorOutput .= "\nFile \"{$filePath}\" contains: ". "\n\t {$actionGroupReferencesDataResult} in {$filePath}"; - $testErrors[$filePath][] = $errorOutput; - } - - + foreach ($actionGroupReferences as $key => $actionGroupReferencesData) { + foreach ($actionGroupReferencesData as $actionGroupReferencesDataResult) { + $errorOutput .= "\nFile \"{$filePath}\" contains: ". "\n\t + {$actionGroupReferencesDataResult} in {$filePath}"; + $testErrors[$filePath][] = $errorOutput; + } } return $testErrors; } - } From a9ba4475283011af5d9e2d388aa91218672de658 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Sun, 6 Feb 2022 19:54:02 +0530 Subject: [PATCH 790/888] MQE-1677 : Static check for created data outside action group --- ...CreatedDataFromOutsideActionGroupCheck.php | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/CreatedDataFromOutsideActionGroupCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/CreatedDataFromOutsideActionGroupCheck.php index eec27b157..611e2946b 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/CreatedDataFromOutsideActionGroupCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/CreatedDataFromOutsideActionGroupCheck.php @@ -37,7 +37,7 @@ class CreatedDataFromOutsideActionGroupCheck implements StaticCheckInterface { const ACTIONGROUP_REGEX_PATTERN = '/\$(\$)*([\w.]+)(\$)*\$/'; const ERROR_LOG_FILENAME = 'create-data-from-outside-action-group'; - const ERROR_LOG_MESSAGE = 'Created Data From Outside Action Group'; + const ERROR_MESSAGE = 'Created Data From Outside Action Group'; /** * Array containing all errors found after running the execute() function @@ -60,13 +60,6 @@ class CreatedDataFromOutsideActionGroupCheck implements StaticCheckInterface */ private $scriptUtil; - /** - * Action group xml files to scan - * - * @var Finder|array - */ - private $actionGroupXmlFiles = []; - /** * Checks test dependencies, determined by references in tests versus the dependencies listed in the Magento module * @@ -79,11 +72,12 @@ public function execute(InputInterface $input) $this->scriptUtil = new ScriptUtil(); $this->loadAllXmlFiles($input); $this->errors = []; - $this->errors += $this->findReferenceErrorsInActionFiles($this->actionGroupXmlFiles); + $this->errors += $this->findReferenceErrorsInActionFiles($this->actionGroupXmlFile); + // hold on to the output and print any errors to a file $this->output = $this->scriptUtil->printErrorsToFile( $this->errors, StaticChecksList::getErrorFilesPath() . DIRECTORY_SEPARATOR . self::ERROR_LOG_FILENAME . '.txt', - self::ERROR_LOG_MESSAGE + self::ERROR_MESSAGE ); } @@ -118,7 +112,6 @@ public function getOutput() private function loadAllXmlFiles($input) { $modulePaths = []; - $includeRootPath = true; $path = $input->getOption('path'); if ($path) { if (!realpath($path)) { @@ -132,15 +125,14 @@ private function loadAllXmlFiles($input) true ); $modulePaths[] = realpath($path); - $includeRootPath = false; } else { $modulePaths = $this->scriptUtil->getAllModulePaths(); } // These files can contain references to other entities - $this->actionGroupXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, 'ActionGroup'); + $this->actionGroupXmlFile = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, 'ActionGroup'); - if (empty($this->actionGroupXmlFiles)) { + if (empty($this->actionGroupXmlFile)) { if ($path) { throw new InvalidArgumentException( 'Invalid --path option: ' From 51b6fadfb767f70e51f0dad7deede116e4535175 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Mon, 7 Feb 2022 10:27:54 +0530 Subject: [PATCH 791/888] Resolved conflicts --- .../Resources/DataActionsTest.txt | 2 ++ .../TestModule/Test/DataActionsTest.xml | 3 ++ .../Test/etc/Actions/dataActions.xsd | 28 +++++++++++++++---- .../Util/TestGenerator.php | 19 +++++++++---- 4 files changed, 42 insertions(+), 10 deletions(-) diff --git a/dev/tests/verification/Resources/DataActionsTest.txt b/dev/tests/verification/Resources/DataActionsTest.txt index cf4de53a3..95bb0631e 100644 --- a/dev/tests/verification/Resources/DataActionsTest.txt +++ b/dev/tests/verification/Resources/DataActionsTest.txt @@ -32,6 +32,8 @@ class DataActionsTestCest $I->createEntity("createdInBefore", "hook", "entity", [], []); // stepKey: createdInBefore $I->updateEntity("createdInBefore", "hook", "entity",[]); // stepKey: updateInBefore $I->deleteEntity("createdInBefore", "hook"); // stepKey: deleteInBefore + $customerFields['lastname'] = "foo61f90e3156e25"; + $I->createEntity("customer", "hook", "Simple_Customer_Without_Address", [], $customerFields); // stepKey: customer $I->comment('[END BEFORE HOOK]'); } diff --git a/dev/tests/verification/TestModule/Test/DataActionsTest.xml b/dev/tests/verification/TestModule/Test/DataActionsTest.xml index 2575c41b0..de3d8d0ab 100644 --- a/dev/tests/verification/TestModule/Test/DataActionsTest.xml +++ b/dev/tests/verification/TestModule/Test/DataActionsTest.xml @@ -13,6 +13,9 @@ <createData entity="entity" stepKey="createdInBefore"/> <updateData entity="entity" createDataKey="createdInBefore" stepKey="updateInBefore"/> <deleteData createDataKey="createdInBefore" stepKey="deleteInBefore"/> + <createData stepKey="customer" entity="Simple_Customer_Without_Address"> + <field key="lastname" unique="suffix" >foo</field> + </createData> </before> <waitForElementClickable selector=".functionalTestSelector" time="30" stepKey="waitForElementClickable" /> diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/dataActions.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/dataActions.xsd index 2cd614266..400cbf942 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/dataActions.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/dataActions.xsd @@ -125,14 +125,32 @@ </xs:simpleContent> </xs:complexType> + <xs:complexType name="additionalFieldType"> - <xs:annotation> - <xs:documentation>field used to override defined fields from metadata or existing data definitions, during operation.</xs:documentation> - </xs:annotation> <xs:simpleContent> <xs:extension base="xs:string"> - <xs:attribute name="key" use="required"/> + <xs:attribute type="xs:string" name="key" use="optional"> + <xs:annotation> + <xs:documentation>xp + Key attribute of data/value pair. + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute type="uniquenessEnumType" name="unique" use="optional"> + <xs:annotation> + <xs:documentation> + Add suite or test wide unique sequence as "prefix" or "suffix" to the data value if specified. + </xs:documentation> + </xs:annotation> + </xs:attribute> </xs:extension> </xs:simpleContent> </xs:complexType> -</xs:schema> \ No newline at end of file + + <xs:simpleType name="uniquenessEnumType"> + <xs:restriction base="xs:string"> + <xs:enumeration value="prefix" /> + <xs:enumeration value="suffix" /> + </xs:restriction> + </xs:simpleType> +</xs:schema> diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index bb9dc6978..fb7ad12a2 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -525,7 +525,11 @@ private function generateMethodAnnotations($annotationType = null, $annotationNa break; case null: - $annotationToAppend = ""; + $annotationToAppend = sprintf( + "{$indent} * @Parameter(name = \"%s\", value=\"$%s\")\n", + "AcceptanceTester", + "I" + ); $annotationToAppend .= sprintf("{$indent} * @param %s $%s\n", "AcceptanceTester", "I"); $annotationToAppend .= "{$indent} * @return void\n"; $annotationToAppend .= "{$indent} * @throws \Exception\n"; @@ -1462,11 +1466,14 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $actionObject->getActionOrigin() )[0]; $argRef = "\t\t\$"; - $input = $this->resolveAllRuntimeReferences([$input])[0]; + if (isset($actionObject->getCustomActionAttributes()['unique'])) { + $input = ($actionObject->getCustomActionAttributes()['unique'] == 'prefix') + ? '"'.uniqid().str_replace('"', '', $input).'"' + : '"'.str_replace('"', '', $input).uniqid().'"'; + } $argRef .= str_replace(ucfirst($fieldKey), "", $stepKey) . "Fields['{$fieldKey}'] = ${input};"; - $testSteps .= $argRef; break; case "generateDate": @@ -1801,7 +1808,7 @@ private function generateHooksPhp($hookObjects) $hooks .= $steps; if ($type === 'after') { $hooks .= "\t\t" . 'if ($this->isSuccess) {' . "\n"; - $hooks .= "\t\t\t" . 'unlink(__FILE__);' . "\n"; +// $hooks .= "\t\t\t" . 'unlink(__FILE__);' . "\n"; $hooks .= "\t\t" . '}' . "\n"; } $hooks .= "\t}\n\n"; @@ -1841,7 +1848,7 @@ private function generateTestPhp($test) } else { $skipString .= "No issues have been specified."; } - $steps = "\t\t" . 'unlink(__FILE__);' . "\n"; +// $steps = "\t\t" . 'unlink(__FILE__);' . "\n"; $steps .= "\t\t" . '$scenario->skip("' . $skipString . '");' . "\n"; $dependencies .= ', \Codeception\Scenario $scenario'; } @@ -1861,6 +1868,8 @@ private function generateTestPhp($test) $testPhp .= "\t}\n"; } + echo $testPhp; + exit; return $testPhp; } From 9c7b1eafffb1eab1ad84c4f373bc0d7c1593cebe Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Tue, 1 Feb 2022 16:22:17 +0530 Subject: [PATCH 792/888] MQE-2021 : Added new attribute unique --- dev/tests/verification/Resources/DataActionsTest.txt | 2 +- dev/tests/verification/TestModule/Test/DataActionsTest.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/tests/verification/Resources/DataActionsTest.txt b/dev/tests/verification/Resources/DataActionsTest.txt index 95bb0631e..4e675b192 100644 --- a/dev/tests/verification/Resources/DataActionsTest.txt +++ b/dev/tests/verification/Resources/DataActionsTest.txt @@ -32,7 +32,7 @@ class DataActionsTestCest $I->createEntity("createdInBefore", "hook", "entity", [], []); // stepKey: createdInBefore $I->updateEntity("createdInBefore", "hook", "entity",[]); // stepKey: updateInBefore $I->deleteEntity("createdInBefore", "hook"); // stepKey: deleteInBefore - $customerFields['lastname'] = "foo61f90e3156e25"; + $customerFields['firstname'] = "foo61f90e3156e25"; $I->createEntity("customer", "hook", "Simple_Customer_Without_Address", [], $customerFields); // stepKey: customer $I->comment('[END BEFORE HOOK]'); } diff --git a/dev/tests/verification/TestModule/Test/DataActionsTest.xml b/dev/tests/verification/TestModule/Test/DataActionsTest.xml index de3d8d0ab..f974ec2b1 100644 --- a/dev/tests/verification/TestModule/Test/DataActionsTest.xml +++ b/dev/tests/verification/TestModule/Test/DataActionsTest.xml @@ -14,7 +14,7 @@ <updateData entity="entity" createDataKey="createdInBefore" stepKey="updateInBefore"/> <deleteData createDataKey="createdInBefore" stepKey="deleteInBefore"/> <createData stepKey="customer" entity="Simple_Customer_Without_Address"> - <field key="lastname" unique="suffix" >foo</field> + <field key="firstname" unique="suffix" >foo</field> </createData> </before> From cb019081ec51d8728142eb90bfef6a69a1415c38 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Tue, 1 Feb 2022 16:24:52 +0530 Subject: [PATCH 793/888] MQE-2021 : Added new attribute unique --- .../FunctionalTestingFramework/Util/TestGenerator.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index fb7ad12a2..ed48b5906 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1808,7 +1808,7 @@ private function generateHooksPhp($hookObjects) $hooks .= $steps; if ($type === 'after') { $hooks .= "\t\t" . 'if ($this->isSuccess) {' . "\n"; -// $hooks .= "\t\t\t" . 'unlink(__FILE__);' . "\n"; + $hooks .= "\t\t\t" . 'unlink(__FILE__);' . "\n"; $hooks .= "\t\t" . '}' . "\n"; } $hooks .= "\t}\n\n"; @@ -1848,7 +1848,7 @@ private function generateTestPhp($test) } else { $skipString .= "No issues have been specified."; } -// $steps = "\t\t" . 'unlink(__FILE__);' . "\n"; + $steps = "\t\t" . 'unlink(__FILE__);' . "\n"; $steps .= "\t\t" . '$scenario->skip("' . $skipString . '");' . "\n"; $dependencies .= ', \Codeception\Scenario $scenario'; } @@ -1868,8 +1868,6 @@ private function generateTestPhp($test) $testPhp .= "\t}\n"; } - echo $testPhp; - exit; return $testPhp; } From d0cf06ecc10806cd318bdbc4c1ec2c25f7369f01 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Tue, 1 Feb 2022 16:27:56 +0530 Subject: [PATCH 794/888] MQE-2021 : Added new attribute unique --- src/Magento/FunctionalTestingFramework/Util/TestGenerator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index ed48b5906..1e57e8ef8 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1808,7 +1808,7 @@ private function generateHooksPhp($hookObjects) $hooks .= $steps; if ($type === 'after') { $hooks .= "\t\t" . 'if ($this->isSuccess) {' . "\n"; - $hooks .= "\t\t\t" . 'unlink(__FILE__);' . "\n"; + $hooks .= "\t\t\t" . 'unlink(__FILE__);' . "\n"; $hooks .= "\t\t" . '}' . "\n"; } $hooks .= "\t}\n\n"; From bbed911a46b052781d8f291b291824b3d6163d62 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Tue, 1 Feb 2022 16:29:11 +0530 Subject: [PATCH 795/888] MQE-2021 : Added new attribute unique --- .../FunctionalTestingFramework/Util/TestGenerator.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 1e57e8ef8..e6187beea 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -525,11 +525,7 @@ private function generateMethodAnnotations($annotationType = null, $annotationNa break; case null: - $annotationToAppend = sprintf( - "{$indent} * @Parameter(name = \"%s\", value=\"$%s\")\n", - "AcceptanceTester", - "I" - ); + $annotationToAppend = ""; $annotationToAppend .= sprintf("{$indent} * @param %s $%s\n", "AcceptanceTester", "I"); $annotationToAppend .= "{$indent} * @return void\n"; $annotationToAppend .= "{$indent} * @throws \Exception\n"; From caf6ec26bf4f9cd233421000126122ffb8b9d82c Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Tue, 1 Feb 2022 16:32:48 +0530 Subject: [PATCH 796/888] MQE-2021 : Added new attribute unique --- dev/tests/verification/Resources/DataActionsTest.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/verification/Resources/DataActionsTest.txt b/dev/tests/verification/Resources/DataActionsTest.txt index 4e675b192..acfe544cf 100644 --- a/dev/tests/verification/Resources/DataActionsTest.txt +++ b/dev/tests/verification/Resources/DataActionsTest.txt @@ -32,7 +32,7 @@ class DataActionsTestCest $I->createEntity("createdInBefore", "hook", "entity", [], []); // stepKey: createdInBefore $I->updateEntity("createdInBefore", "hook", "entity",[]); // stepKey: updateInBefore $I->deleteEntity("createdInBefore", "hook"); // stepKey: deleteInBefore - $customerFields['firstname'] = "foo61f90e3156e25"; + $customerFields['firstname'] = "foo61f9129fd15f1"; $I->createEntity("customer", "hook", "Simple_Customer_Without_Address", [], $customerFields); // stepKey: customer $I->comment('[END BEFORE HOOK]'); } From 2702caebb08e608286b321e8b31b87b3a3780fd0 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Tue, 1 Feb 2022 17:22:44 +0530 Subject: [PATCH 797/888] MQE-2021 : Added new attribute unique --- dev/tests/verification/Resources/DataActionsTest.txt | 2 +- dev/tests/verification/TestModule/Test/DataActionsTest.xml | 4 ++-- .../Test/etc/Actions/dataActions.xsd | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dev/tests/verification/Resources/DataActionsTest.txt b/dev/tests/verification/Resources/DataActionsTest.txt index acfe544cf..12fe3e979 100644 --- a/dev/tests/verification/Resources/DataActionsTest.txt +++ b/dev/tests/verification/Resources/DataActionsTest.txt @@ -32,7 +32,7 @@ class DataActionsTestCest $I->createEntity("createdInBefore", "hook", "entity", [], []); // stepKey: createdInBefore $I->updateEntity("createdInBefore", "hook", "entity",[]); // stepKey: updateInBefore $I->deleteEntity("createdInBefore", "hook"); // stepKey: deleteInBefore - $customerFields['firstname'] = "foo61f9129fd15f1"; + $customerFields['lastname'] = "foo"; $I->createEntity("customer", "hook", "Simple_Customer_Without_Address", [], $customerFields); // stepKey: customer $I->comment('[END BEFORE HOOK]'); } diff --git a/dev/tests/verification/TestModule/Test/DataActionsTest.xml b/dev/tests/verification/TestModule/Test/DataActionsTest.xml index f974ec2b1..d7a2d205b 100644 --- a/dev/tests/verification/TestModule/Test/DataActionsTest.xml +++ b/dev/tests/verification/TestModule/Test/DataActionsTest.xml @@ -14,7 +14,7 @@ <updateData entity="entity" createDataKey="createdInBefore" stepKey="updateInBefore"/> <deleteData createDataKey="createdInBefore" stepKey="deleteInBefore"/> <createData stepKey="customer" entity="Simple_Customer_Without_Address"> - <field key="firstname" unique="suffix" >foo</field> + <field key="lastname">foo</field> </createData> </before> @@ -26,4 +26,4 @@ <updateData entity="entity" createDataKey="createdInBefore" stepKey="updatedDataOutOfScope"/> <deleteData createDataKey="createdInBefore" stepKey="deleteDataOutOfScope"/> </test> -</tests> +</tests> \ No newline at end of file diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/dataActions.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/dataActions.xsd index 400cbf942..003760bfc 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/dataActions.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/dataActions.xsd @@ -129,7 +129,7 @@ <xs:complexType name="additionalFieldType"> <xs:simpleContent> <xs:extension base="xs:string"> - <xs:attribute type="xs:string" name="key" use="optional"> + <xs:attribute type="xs:string" name="key" use="required"> <xs:annotation> <xs:documentation>xp Key attribute of data/value pair. From a43787f5804af914a3a598f3ad3a4513227d2fca Mon Sep 17 00:00:00 2001 From: glo00108 <glo00108@adobe.com> Date: Tue, 8 Feb 2022 12:28:34 +0530 Subject: [PATCH 798/888] remove redudant file --- .../Handlers/SecretStorage/FileStorageTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/FileStorageTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/FileStorageTest.php index 672de5a21..3d5922f9e 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/FileStorageTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/SecretStorage/FileStorageTest.php @@ -23,7 +23,7 @@ public function testBasicEncryptDecrypt(): void { $testKey = 'magento/myKey'; $testValue = 'myValue'; - $creds = ["$testKey=$testValue"]; + $cred = ["$testKey=$testValue"]; $fileStorage = new FileStorage(); $reflection = new ReflectionClass(FileStorage::class); @@ -31,7 +31,7 @@ public function testBasicEncryptDecrypt(): void // Emulate initialize() function result with the test credentials $reflectionMethod = $reflection->getMethod('encryptCredFileContents'); $reflectionMethod->setAccessible(true); - $secretData = $reflectionMethod->invokeArgs($fileStorage, [$creds]); + $secretData = $reflectionMethod->invokeArgs($fileStorage, [$cred]); // Set encrypted test credentials to the private 'secretData' property $reflectionProperty = $reflection->getProperty('secretData'); @@ -59,7 +59,7 @@ public function testEmptyValueEncryptDecrypt(): void $this->expectException(TestFrameworkException::class); $testKey = 'magento/myKey'; - $creds = ["$testKey"]; + $cred = ["$testKey"]; $fileStorage = new FileStorage(); $reflection = new ReflectionClass(FileStorage::class); @@ -67,7 +67,7 @@ public function testEmptyValueEncryptDecrypt(): void // Emulate initialize() function result with the test credentials $reflectionMethod = $reflection->getMethod('encryptCredFileContents'); $reflectionMethod->setAccessible(true); - $secretData = $reflectionMethod->invokeArgs($fileStorage, [$creds]); + $secretData = $reflectionMethod->invokeArgs($fileStorage, [$cred]); // Set encrypted test credentials to the private 'secretData' property $reflectionProperty = $reflection->getProperty('secretData'); From e8095204ec90015eb83dad82aca70bd587019134 Mon Sep 17 00:00:00 2001 From: glo00108 <glo00108@adobe.com> Date: Tue, 8 Feb 2022 12:37:54 +0530 Subject: [PATCH 799/888] add check for null values --- .../Page/Objects/ElementObject.php | 2 +- .../Util/TestGenerator.php | 20 ++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Page/Objects/ElementObject.php b/src/Magento/FunctionalTestingFramework/Page/Objects/ElementObject.php index f00ded056..262647b34 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Objects/ElementObject.php +++ b/src/Magento/FunctionalTestingFramework/Page/Objects/ElementObject.php @@ -85,7 +85,7 @@ public function __construct($name, $type, $selector, $locatorFunction, $timeout, $this->type = $type; $this->selector = $selector; $this->locatorFunction = $locatorFunction; - if (strpos($locatorFunction, "Locator::") === false) { + if ($locatorFunction !== null && strpos($locatorFunction, "Locator::") === false) { $this->locatorFunction = "Locator::" . $locatorFunction; } $this->timeout = $timeout; diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index c5368b779..00b78cb06 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -2097,18 +2097,20 @@ private function resolveRuntimeReference($args, $regex, $func) foreach ($args as $key => $arg) { $newArgs[$key] = $arg; - preg_match_all($regex, $arg, $matches); - if (!empty($matches[0])) { - foreach ($matches[0] as $matchKey => $fullMatch) { - $refVariable = $matches[1][$matchKey]; + if($arg !== null) { + preg_match_all($regex, $arg, $matches); + if (!empty($matches[0])) { + foreach ($matches[0] as $matchKey => $fullMatch) { + $refVariable = $matches[1][$matchKey]; - $replacement = $this->getReplacement($func, $refVariable); + $replacement = $this->getReplacement($func, $refVariable); - $outputArg = $this->processQuoteBreaks($fullMatch, $newArgs[$key], $replacement); - $newArgs[$key] = $outputArg; + $outputArg = $this->processQuoteBreaks($fullMatch, $newArgs[$key], $replacement); + $newArgs[$key] = $outputArg; + } + unset($matches); + continue; } - unset($matches); - continue; } } From c0eb49596cd76e6ebbcddb90dc20f32d920cfa62 Mon Sep 17 00:00:00 2001 From: glo00108 <glo00108@adobe.com> Date: Tue, 8 Feb 2022 12:45:56 +0530 Subject: [PATCH 800/888] add check for null values --- src/Magento/FunctionalTestingFramework/Util/TestGenerator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 00b78cb06..e546cd1d2 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -2097,7 +2097,7 @@ private function resolveRuntimeReference($args, $regex, $func) foreach ($args as $key => $arg) { $newArgs[$key] = $arg; - if($arg !== null) { + if ($arg !== null) { preg_match_all($regex, $arg, $matches); if (!empty($matches[0])) { foreach ($matches[0] as $matchKey => $fullMatch) { From ad0078d832186c916ee7c0c124c0ddf93b42a360 Mon Sep 17 00:00:00 2001 From: glo00108 <glo00108@adobe.com> Date: Tue, 8 Feb 2022 12:56:18 +0530 Subject: [PATCH 801/888] MQE-2668: Some MFTF tests fail without access to S3 --- src/Magento/FunctionalTestingFramework/Util/TestGenerator.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index bb9dc6978..bfd218e57 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -258,6 +258,7 @@ public function createAllTestFiles($testManifest = null, $testsToIgnore = null) */ public function assembleTestPhp($testObject) { + $this->customHelpers = []; $usePhp = $this->generateUseStatementsPhp(); $className = $testObject->getCodeceptionName(); From 1bb3e5e6d1ebfd448f2ec0406e1b8333848737e0 Mon Sep 17 00:00:00 2001 From: "Mohit.k.Sharma" <mohit.k.sharma@BLR1-LMC-N71405.local> Date: Wed, 9 Feb 2022 15:45:42 +0530 Subject: [PATCH 802/888] MQE-1693 | Ability To Run MFTF JSON Configuration From File --- .../Console/GenerateTestsCommand.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php index b277f9c4e..257189d83 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php @@ -128,6 +128,10 @@ protected function execute(InputInterface $input, OutputInterface $output) return 1; } + if ($json !== null && is_file($json)) { + $json = file_get_contents($json); + } + if (!empty($tests)) { $json = $this->getTestAndSuiteConfiguration($tests); } From aef58fa766c421af2ac0667eae178391ca1d477e Mon Sep 17 00:00:00 2001 From: "Mohit.k.Sharma" <mohit.k.sharma@BLR1-LMC-N71405.local> Date: Fri, 11 Feb 2022 09:39:36 +0530 Subject: [PATCH 803/888] MQE-1693 | Ability To Run MFTF JSON Configuration From File --- .../Console/GenerateTestsCommand.php | 2 +- .../Console/RunTestCommand.php | 25 ++++++++++++++++--- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php index 257189d83..15ab977c9 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php @@ -69,7 +69,7 @@ protected function configure() 'tests', 't', InputOption::VALUE_REQUIRED, - 'A parameter accepting a JSON string used to determine the test configuration' + 'A parameter accepting a JSON string or JSON file path used to determine the test configuration' )->addOption( 'filter', null, diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php index 096c6794c..10c48c579 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php @@ -40,15 +40,19 @@ protected function configure() ->setDescription("generation and execution of test(s) defined in xml") ->addArgument( 'name', - InputArgument::REQUIRED | InputArgument::IS_ARRAY, + InputArgument::OPTIONAL | InputArgument::IS_ARRAY, "name of tests to generate and execute" )->addOption( 'skip-generate', 'k', InputOption::VALUE_NONE, "skip generation and execute existing test" + )->addOption( + 'tests', + 't', + InputOption::VALUE_REQUIRED, + 'A parameter accepting a JSON string or JSON file path used to determine the test configuration' ); - parent::configure(); } @@ -63,6 +67,7 @@ protected function configure() protected function execute(InputInterface $input, OutputInterface $output): int { $tests = $input->getArgument('name'); + $json = $input->getOption('tests'); // for backward compatibility $skipGeneration = $input->getOption('skip-generate'); $force = $input->getOption('force'); $remove = $input->getOption('remove'); @@ -86,7 +91,18 @@ protected function execute(InputInterface $input, OutputInterface $output): int $allowSkipped ); - $testConfiguration = $this->getTestAndSuiteConfiguration($tests); + if ($json !== null && is_file($json)) { + $testConfiguration = file_get_contents($json); + } + + if (!empty($tests)) { + $testConfiguration = $this->getTestAndSuiteConfiguration($tests); + } + + if ($testConfiguration !== null && !json_decode($testConfiguration)) { + // stop execution if we have failed to properly parse any json passed in by the user + throw new TestFrameworkException("JSON could not be parsed: " . json_last_error_msg()); + } $generationErrorCode = 0; @@ -98,7 +114,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int '--remove' => $remove, '--debug' => $debug, '--allow-skipped' => $allowSkipped, - '-v' => $verbose + '-v' => $verbose, + '' ]; $command->run(new ArrayInput($args), $output); From 2e1b1a2bcee74a7cc23e0465df15e3649e540766 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Sun, 13 Feb 2022 12:28:57 +0530 Subject: [PATCH 804/888] MQE-2021 : Added unit test --- .../Util/TestGeneratorTest.php | 60 +++++++++++++++++++ .../Util/TestGenerator.php | 23 +++++-- 2 files changed, 78 insertions(+), 5 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php index 217cf7f09..a40959db3 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php @@ -88,6 +88,66 @@ public function testEntityException(): void $this->assertArrayHasKey('sampleTest', $testErrors); } + /** + * Basic test to check unique id is appended to input as prefix + * + * @return void + * @throws Exception + */ + public function testUniqueIdAppendedToInputStringAsPrefix() + { + $actionObject = new ActionObject('fakeAction', 'comment', [ + 'userInput' => '{{someEntity.entity}}' + ]); + + $testObject = new TestObject('sampleTest', ['merge123' => $actionObject], [], [], 'filename'); + $testGeneratorObject = TestGenerator::getInstance('', ['sampleTest' => $testObject]); + + $result = $testGeneratorObject->getUniqueIdForInput('prefix' , "foo"); + + $this->assertMatchesRegularExpression('/[A-Za-z0-9]+foo/' ,$result ); + } + + /** + * Basic test to check unique id is appended to input as suffix + * + * @return void + * @throws Exception + */ + public function testUniqueIdAppendedToInputStringAsSuffix() + { + $actionObject = new ActionObject('fakeAction', 'comment', [ + 'userInput' => '{{someEntity.entity}}' + ]); + + $testObject = new TestObject('sampleTest', ['merge123' => $actionObject], [], [], 'filename'); + $testGeneratorObject = TestGenerator::getInstance('', ['sampleTest' => $testObject]); + + $result = $testGeneratorObject->getUniqueIdForInput('suffix' , "foo"); + + $this->assertMatchesRegularExpression('/foo[A-Za-z0-9]+/' ,$result ); + } + + /** + * Basic test for wrong output for input + * + * @return void + * @throws Exception + */ + public function testFailedRegexForUniqueAttribute() + { + $actionObject = new ActionObject('fakeAction', 'comment', [ + 'userInput' => '{{someEntity.entity}}' + ]); + + $testObject = new TestObject('sampleTest', ['merge123' => $actionObject], [], [], 'filename'); + $testGeneratorObject = TestGenerator::getInstance('', ['sampleTest' => $testObject]); + + $result = $testGeneratorObject->getUniqueIdForInput('suffix' , "foo"); + + $this->assertDoesNotMatchRegularExpression('/bar[A-Za-z0-9]+/' ,$result ); + } + /** * Tests that skipped tests do not have a fully generated body. * diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index e6187beea..9773079df 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1463,11 +1463,9 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato )[0]; $argRef = "\t\t\$"; $input = $this->resolveAllRuntimeReferences([$input])[0]; - if (isset($actionObject->getCustomActionAttributes()['unique'])) { - $input = ($actionObject->getCustomActionAttributes()['unique'] == 'prefix') - ? '"'.uniqid().str_replace('"', '', $input).'"' - : '"'.str_replace('"', '', $input).uniqid().'"'; - } + $input = (isset($actionObject->getCustomActionAttributes()['unique'])) ? + $this->getUniqueIdForInput( $actionObject->getCustomActionAttributes()['unique'], $input) + : $input; $argRef .= str_replace(ucfirst($fieldKey), "", $stepKey) . "Fields['{$fieldKey}'] = ${input};"; $testSteps .= $argRef; @@ -1516,6 +1514,21 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato return $testSteps; } + /** + * Get unique value appended to input string + * + * @param string $uniqueValue + * @param string $input + * @return string + */ + public function getUniqueIdForInput( $uniqueValue, $input) + { + $input = ( $uniqueValue == 'prefix') + ? '"'.uniqid().str_replace('"', '', $input).'"' + : '"'.str_replace('"', '', $input).uniqid().'"'; + return $input; + } + /** * Resolves Locator:: in given $attribute if it is found. * From b91f3a3e399e4c5f4be1e6f7bcda689b2f0d4322 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Sun, 13 Feb 2022 12:31:50 +0530 Subject: [PATCH 805/888] MQE-2021 : Added unit test --- .../FunctionalTestingFramework/Util/TestGenerator.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 9773079df..c4748ee81 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1464,7 +1464,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $argRef = "\t\t\$"; $input = $this->resolveAllRuntimeReferences([$input])[0]; $input = (isset($actionObject->getCustomActionAttributes()['unique'])) ? - $this->getUniqueIdForInput( $actionObject->getCustomActionAttributes()['unique'], $input) + $this->getUniqueIdForInput($actionObject->getCustomActionAttributes()['unique'], $input) : $input; $argRef .= str_replace(ucfirst($fieldKey), "", $stepKey) . "Fields['{$fieldKey}'] = ${input};"; @@ -1521,9 +1521,9 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato * @param string $input * @return string */ - public function getUniqueIdForInput( $uniqueValue, $input) + public function getUniqueIdForInput( $uniqueValue, $input) { - $input = ( $uniqueValue == 'prefix') + $input = ($uniqueValue == 'prefix') ? '"'.uniqid().str_replace('"', '', $input).'"' : '"'.str_replace('"', '', $input).uniqid().'"'; return $input; From 37e51717cc6750cb1481f90a5e65272a5615631f Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Sun, 13 Feb 2022 12:33:04 +0530 Subject: [PATCH 806/888] MQE-2021 : Added unit test --- src/Magento/FunctionalTestingFramework/Util/TestGenerator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index c4748ee81..cd6544f82 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1521,7 +1521,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato * @param string $input * @return string */ - public function getUniqueIdForInput( $uniqueValue, $input) + public function getUniqueIdForInput($uniqueValue, $input) { $input = ($uniqueValue == 'prefix') ? '"'.uniqid().str_replace('"', '', $input).'"' From 01e7b4f1ec8c38217eca915ce332d6c988b7b046 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Sun, 13 Feb 2022 12:38:13 +0530 Subject: [PATCH 807/888] MQE-2021 : Added unit test --- .../Util/TestGeneratorTest.php | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php index a40959db3..d59811d4a 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php @@ -103,9 +103,9 @@ public function testUniqueIdAppendedToInputStringAsPrefix() $testObject = new TestObject('sampleTest', ['merge123' => $actionObject], [], [], 'filename'); $testGeneratorObject = TestGenerator::getInstance('', ['sampleTest' => $testObject]); - $result = $testGeneratorObject->getUniqueIdForInput('prefix' , "foo"); + $result = $testGeneratorObject->getUniqueIdForInput('prefix', "foo"); - $this->assertMatchesRegularExpression('/[A-Za-z0-9]+foo/' ,$result ); + $this->assertMatchesRegularExpression('/[A-Za-z0-9]+foo/', $result); } /** @@ -123,17 +123,17 @@ public function testUniqueIdAppendedToInputStringAsSuffix() $testObject = new TestObject('sampleTest', ['merge123' => $actionObject], [], [], 'filename'); $testGeneratorObject = TestGenerator::getInstance('', ['sampleTest' => $testObject]); - $result = $testGeneratorObject->getUniqueIdForInput('suffix' , "foo"); + $result = $testGeneratorObject->getUniqueIdForInput('suffix', "foo"); - $this->assertMatchesRegularExpression('/foo[A-Za-z0-9]+/' ,$result ); + $this->assertMatchesRegularExpression('/foo[A-Za-z0-9]+/', $result); } /** - * Basic test for wrong output for input - * - * @return void - * @throws Exception - */ + * Basic test for wrong output for input + * + * @return void + * @throws Exception + */ public function testFailedRegexForUniqueAttribute() { $actionObject = new ActionObject('fakeAction', 'comment', [ @@ -143,9 +143,9 @@ public function testFailedRegexForUniqueAttribute() $testObject = new TestObject('sampleTest', ['merge123' => $actionObject], [], [], 'filename'); $testGeneratorObject = TestGenerator::getInstance('', ['sampleTest' => $testObject]); - $result = $testGeneratorObject->getUniqueIdForInput('suffix' , "foo"); + $result = $testGeneratorObject->getUniqueIdForInput('suffix', "foo"); - $this->assertDoesNotMatchRegularExpression('/bar[A-Za-z0-9]+/' ,$result ); + $this->assertDoesNotMatchRegularExpression('/bar[A-Za-z0-9]+/', $result); } /** From daa2742464bb9fea0e1e1d0c20d8f5b2a387277f Mon Sep 17 00:00:00 2001 From: "Mohit.k.Sharma" <mohit.k.sharma@BLR1-LMC-N71405.local> Date: Mon, 14 Feb 2022 09:30:03 +0530 Subject: [PATCH 808/888] Static Checks Error Fix --- .../Console/RunTestCommand.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php index 10c48c579..cf58bc050 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php @@ -20,6 +20,9 @@ use Symfony\Component\Process\Process; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +/** + * @SuppressWarnings(PHPMD) + */ class RunTestCommand extends BaseGenerateCommand { /** @@ -91,8 +94,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int $allowSkipped ); - if ($json !== null && is_file($json)) { - $testConfiguration = file_get_contents($json); + if ($json !== null) { + if (is_file($json)) { + $testConfiguration = file_get_contents($json); + } else { + $testConfiguration = $json; + } } if (!empty($tests)) { From 64b13bc64140f0ebdc9f742a3487909607f01d40 Mon Sep 17 00:00:00 2001 From: Jonatan Santos <jonatan.zarowny@gmail.com> Date: Tue, 15 Feb 2022 19:38:59 -0300 Subject: [PATCH 809/888] Fix #885 - Implement correct params on Vault PHP lib call --- composer.json | 1 + composer.lock | 95 ++++++++++++++++++- .../Handlers/SecretStorage/VaultStorage.php | 20 ++-- .../SecretStorage/VaultTokenAuthStrategy.php | 2 +- 4 files changed, 108 insertions(+), 10 deletions(-) diff --git a/composer.json b/composer.json index 9a7757c5d..b6c0a5d88 100755 --- a/composer.json +++ b/composer.json @@ -24,6 +24,7 @@ "composer/composer": "^1.9||^2.0", "csharpru/vault-php": "^4.2.1", "guzzlehttp/guzzle": "^7.3.0", + "laminas/laminas-diactoros": "^2.8", "monolog/monolog": "^2.3", "mustache/mustache": "~2.5", "nikic/php-parser": "^4.4", diff --git a/composer.lock b/composer.lock index 8000882be..d3c3432f1 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "35ff8c71326b9f8ab0885c8b55dd59cf", + "content-hash": "1fbed16ee8423681934f65424c9d0374", "packages": [ { "name": "allure-framework/allure-codeception", @@ -2141,6 +2141,97 @@ }, "time": "2021-07-22T09:24:00+00:00" }, + { + "name": "laminas/laminas-diactoros", + "version": "2.8.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-diactoros.git", + "reference": "0c26ef1d95b6d7e6e3943a243ba3dc0797227199" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/0c26ef1d95b6d7e6e3943a243ba3dc0797227199", + "reference": "0c26ef1d95b6d7e6e3943a243ba3dc0797227199", + "shasum": "" + }, + "require": { + "php": "^7.3 || ~8.0.0 || ~8.1.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0" + }, + "conflict": { + "phpspec/prophecy": "<1.9.0", + "zendframework/zend-diactoros": "*" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "ext-curl": "*", + "ext-dom": "*", + "ext-gd": "*", + "ext-libxml": "*", + "http-interop/http-factory-tests": "^0.8.0", + "laminas/laminas-coding-standard": "~1.0.0", + "php-http/psr7-integration-tests": "^1.1", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.1", + "psalm/plugin-phpunit": "^0.14.0", + "vimeo/psalm": "^4.3" + }, + "type": "library", + "extra": { + "laminas": { + "config-provider": "Laminas\\Diactoros\\ConfigProvider", + "module": "Laminas\\Diactoros" + } + }, + "autoload": { + "files": [ + "src/functions/create_uploaded_file.php", + "src/functions/marshal_headers_from_sapi.php", + "src/functions/marshal_method_from_sapi.php", + "src/functions/marshal_protocol_version_from_sapi.php", + "src/functions/marshal_uri_from_sapi.php", + "src/functions/normalize_server.php", + "src/functions/normalize_uploaded_files.php", + "src/functions/parse_cookie_header.php", + "src/functions/create_uploaded_file.legacy.php", + "src/functions/marshal_headers_from_sapi.legacy.php", + "src/functions/marshal_method_from_sapi.legacy.php", + "src/functions/marshal_protocol_version_from_sapi.legacy.php", + "src/functions/marshal_uri_from_sapi.legacy.php", + "src/functions/normalize_server.legacy.php", + "src/functions/normalize_uploaded_files.legacy.php", + "src/functions/parse_cookie_header.legacy.php" + ], + "psr-4": { + "Laminas\\Diactoros\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "PSR HTTP Message implementations", + "homepage": "https://laminas.dev", + "keywords": [ + "http", + "laminas", + "psr", + "psr-17", + "psr-7" + ], + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "time": "2021-09-22T03:54:36+00:00" + }, { "name": "monolog/monolog", "version": "2.3.5", @@ -7800,5 +7891,5 @@ "ext-openssl": "*" }, "platform-dev": [], - "plugin-api-version": "2.1.0" + "plugin-api-version": "1.1.0" } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/VaultStorage.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/VaultStorage.php index cc0b3e7a8..7e307b30c 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/VaultStorage.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/VaultStorage.php @@ -6,6 +6,9 @@ namespace Magento\FunctionalTestingFramework\DataGenerator\Handlers\SecretStorage; +use Laminas\Diactoros\RequestFactory; +use Laminas\Diactoros\StreamFactory; +use Laminas\Diactoros\Uri; use GuzzleHttp\Client as GuzzleClient; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; @@ -79,13 +82,16 @@ public function __construct($baseUrl, $secretBasePath) parent::__construct(); if (null === $this->client) { // client configuration and override http errors settings - $config = [ - 'timeout' => 15, - 'base_uri' => $baseUrl, - 'http_errors' => false - ]; - - $this->client = new Client(new GuzzleClient($config)); + $this->client = new Client( + new Uri($baseUrl), + new GuzzleClient([ + 'timeout' => 15, + 'base_uri' => $baseUrl, + 'http_errors' => false + ]), + new RequestFactory(), + new StreamFactory() + ); $this->secretBasePath = $secretBasePath; } $this->readVaultTokenFromFileSystem(); diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/VaultTokenAuthStrategy.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/VaultTokenAuthStrategy.php index 716344ca1..0f071216d 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/VaultTokenAuthStrategy.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/VaultTokenAuthStrategy.php @@ -36,7 +36,7 @@ public function __construct($token) * @return Auth * @throws TestFrameworkException */ - public function authenticate() + public function authenticate(): ?Auth { try { return new Auth(['clientToken' => $this->token]); From 4ef9e51f33e1366df358ec5149fbcdbcfe48997c Mon Sep 17 00:00:00 2001 From: glo00108 <glo00108@adobe.com> Date: Thu, 17 Feb 2022 13:06:00 +0530 Subject: [PATCH 810/888] resolve static check --- .../FunctionalTestingFramework/Util/TestGenerator.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index e546cd1d2..52ebdee5e 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -2101,12 +2101,10 @@ private function resolveRuntimeReference($args, $regex, $func) preg_match_all($regex, $arg, $matches); if (!empty($matches[0])) { foreach ($matches[0] as $matchKey => $fullMatch) { - $refVariable = $matches[1][$matchKey]; - - $replacement = $this->getReplacement($func, $refVariable); - - $outputArg = $this->processQuoteBreaks($fullMatch, $newArgs[$key], $replacement); - $newArgs[$key] = $outputArg; + $refVariable = $matches[1][$matchKey]; + $replacement = $this->getReplacement($func, $refVariable); + $outputArg = $this->processQuoteBreaks($fullMatch, $newArgs[$key], $replacement); + $newArgs[$key] = $outputArg; } unset($matches); continue; From e92f7af3d69e68a125fb2cacc286837d10636ff3 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Fri, 18 Feb 2022 12:32:02 +0530 Subject: [PATCH 811/888] MQE-2088 : Test generation error on invalid entities --- .../Util/TestGenerator.php | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 01f1a3cba..66468fe3e 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -31,6 +31,7 @@ use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Mustache_Engine; use Mustache_Loader_FilesystemLoader; +use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; /** * Class TestGenerator @@ -904,7 +905,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato break; case "createData": $entity = $customActionAttributes['entity']; - + $this->entityExistsCheck($entity , $stepKey); //TODO refactor entity field override to not be individual actionObjects $customEntityFields = $customActionAttributes[ActionObjectExtractor::ACTION_OBJECT_PERSISTENCE_FIELDS] ?? []; @@ -922,7 +923,6 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato if (!empty($requiredEntityKeys)) { $requiredEntityKeysArray = '"' . implode('", "', $requiredEntityKeys) . '"'; } - $scope = $this->getObjectScope($generationScope); $createEntityFunctionCall = "\t\t\${$actor}->createEntity("; @@ -1511,7 +1511,8 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato } $testSteps .= PHP_EOL; } - + + return $testSteps; } @@ -1673,6 +1674,9 @@ private function resolveStepKeyReferences($input, $actionGroupOrigin, $matchAll $testInvocationKey = ucfirst($actionGroupOrigin[ActionGroupObject::ACTION_GROUP_ORIGIN_TEST_REF]); foreach ($stepKeys as $stepKey) { + + + // MQE-1011 $stepKeyVarRef = "$" . $stepKey; @@ -1877,7 +1881,6 @@ private function generateTestPhp($test) $testPhp .= "\t\t\$this->isSuccess = true;" . PHP_EOL; $testPhp .= "\t}\n"; } - return $testPhp; } @@ -2049,6 +2052,23 @@ private function addDollarSign($input) return sprintf("$%s", ltrim($this->stripQuotes($input), '$')); } + /** + * Check if the entity exists + * + * @param string $entity + * @param string $stepKey + * @throws TestReferenceException + */ + public function entityExistsCheck($entity , $stepKey) + { + $retrievedEntity = DataObjectHandler::getInstance()->getObject($entity); + if ($retrievedEntity === null) { + throw new TestReferenceException( + "Test generation failed as entity \"" . $entity . "\" does not exist. at stepkey ".$stepKey + ); + } + } + /** * Wrap parameters into a function call. * From 5a1041e87e13d0f06c467fb7e5550ee43b96eb81 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Fri, 18 Feb 2022 12:34:19 +0530 Subject: [PATCH 812/888] MQE-2088 : Test generation error on invalid entities --- .../FunctionalTestingFramework/Util/TestGenerator.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 66468fe3e..078148f61 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1511,8 +1511,6 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato } $testSteps .= PHP_EOL; } - - return $testSteps; } @@ -1674,9 +1672,6 @@ private function resolveStepKeyReferences($input, $actionGroupOrigin, $matchAll $testInvocationKey = ucfirst($actionGroupOrigin[ActionGroupObject::ACTION_GROUP_ORIGIN_TEST_REF]); foreach ($stepKeys as $stepKey) { - - - // MQE-1011 $stepKeyVarRef = "$" . $stepKey; From 700e79586521f0f3070ce21673b09ceecfa19f71 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Fri, 18 Feb 2022 12:36:38 +0530 Subject: [PATCH 813/888] MQE-2088 : Test generation error on invalid entities --- .../FunctionalTestingFramework/Util/TestGenerator.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 078148f61..5265b0102 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -905,7 +905,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato break; case "createData": $entity = $customActionAttributes['entity']; - $this->entityExistsCheck($entity , $stepKey); + $this->entityExistsCheck($entity, $stepKey); //TODO refactor entity field override to not be individual actionObjects $customEntityFields = $customActionAttributes[ActionObjectExtractor::ACTION_OBJECT_PERSISTENCE_FIELDS] ?? []; @@ -2052,9 +2052,10 @@ private function addDollarSign($input) * * @param string $entity * @param string $stepKey + * @return void * @throws TestReferenceException */ - public function entityExistsCheck($entity , $stepKey) + public function entityExistsCheck($entity, $stepKey) { $retrievedEntity = DataObjectHandler::getInstance()->getObject($entity); if ($retrievedEntity === null) { From f7f9f34736332cf17a1ca30d44d5b35bdff3902a Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Fri, 18 Feb 2022 15:45:14 +0530 Subject: [PATCH 814/888] unit test added --- .../Util/TestGeneratorTest.php | 18 ++++++++++++++++++ .../Util/TestGenerator.php | 2 ++ 2 files changed, 20 insertions(+) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php index d59811d4a..cc0316e57 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php @@ -108,6 +108,24 @@ public function testUniqueIdAppendedToInputStringAsPrefix() $this->assertMatchesRegularExpression('/[A-Za-z0-9]+foo/', $result); } + /** + * Basic test to check if exception is thrown when invalid entity is found in xml file + * + * @return void + * @throws Exception + */ + public function testInvalidEntity() + { + $actionObject = new ActionObject('fakeAction', 'comment', [ + 'userInput' => '{{someEntity.entity}}' + ]); + + $testObject = new TestObject('sampleTest', ['merge123' => $actionObject], [], [], 'filename'); + $testGeneratorObject = TestGenerator::getInstance('', ['sampleTest' => $testObject]); + $this->expectException(TestReferenceException::class); + $result = $testGeneratorObject->entityExistsCheck('testintity', "teststepkey"); + } + /** * Basic test to check unique id is appended to input as suffix * diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 5265b0102..bf67ca1cd 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -977,6 +977,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato true ); $updateEntity = $customActionAttributes['entity']; + $this->entityExistsCheck($updateEntity, $stepKey); $actionGroup = $actionObject->getCustomActionAttributes()['actionGroup'] ?? null; $key .= $actionGroup; @@ -1010,6 +1011,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato break; case "getData": $entity = $customActionAttributes['entity']; + $this->entityExistsCheck($entity, $stepKey); $index = null; if (isset($customActionAttributes['index'])) { $index = (int)$customActionAttributes['index']; From 1f1331a885bb5270ce96bd5e6a061d0f3baa3554 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Fri, 18 Feb 2022 15:52:24 +0530 Subject: [PATCH 815/888] unit test added --- .../FunctionalTestFramework/Util/TestGeneratorTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php index cc0316e57..dbdff8304 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/TestGeneratorTest.php @@ -108,7 +108,7 @@ public function testUniqueIdAppendedToInputStringAsPrefix() $this->assertMatchesRegularExpression('/[A-Za-z0-9]+foo/', $result); } - /** + /** * Basic test to check if exception is thrown when invalid entity is found in xml file * * @return void @@ -123,9 +123,9 @@ public function testInvalidEntity() $testObject = new TestObject('sampleTest', ['merge123' => $actionObject], [], [], 'filename'); $testGeneratorObject = TestGenerator::getInstance('', ['sampleTest' => $testObject]); $this->expectException(TestReferenceException::class); - $result = $testGeneratorObject->entityExistsCheck('testintity', "teststepkey"); + $result = $testGeneratorObject->entityExistsCheck('testintity', "teststepkey"); } - + /** * Basic test to check unique id is appended to input as suffix * From 9a7f1404fc8a4a51921b47cea2a567e8e103624a Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Fri, 18 Feb 2022 16:01:23 +0530 Subject: [PATCH 816/888] unit test added --- src/Magento/FunctionalTestingFramework/Util/TestGenerator.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index bf67ca1cd..5265b0102 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -977,7 +977,6 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato true ); $updateEntity = $customActionAttributes['entity']; - $this->entityExistsCheck($updateEntity, $stepKey); $actionGroup = $actionObject->getCustomActionAttributes()['actionGroup'] ?? null; $key .= $actionGroup; @@ -1011,7 +1010,6 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato break; case "getData": $entity = $customActionAttributes['entity']; - $this->entityExistsCheck($entity, $stepKey); $index = null; if (isset($customActionAttributes['index'])) { $index = (int)$customActionAttributes['index']; From 5b43951fcc81339e9ad3894935d396efe8bf3952 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Mon, 21 Feb 2022 18:35:08 +0530 Subject: [PATCH 817/888] Fixed Verification test --- .../Resources/ActionGroupUsingCreateData.txt | 3 +-- .../ActionGroupWithStepKeyReferences.txt | 3 +-- .../Resources/DataActionsTest.txt | 4 ---- .../Resources/HookActionsTest.txt | 6 ----- .../PersistenceActionGroupAppendingTest.txt | 4 ++-- .../Resources/PersistenceCustomFieldsTest.txt | 22 +------------------ .../ActionGroupWithCreateDataActionGroup.xml | 3 +-- ...nGroupWithStepKeyReferencesActionGroup.xml | 3 +-- .../DataPersistenceAppendingActionGroup.xml | 2 +- .../PersistenceActionGroup.xml | 6 ++--- .../TestModule/Data/DefaultPerson.xml | 15 +++++++++++++ .../verification/TestModule/Data/TestData.xml | 14 ++++++++++++ .../TestModule/Data/UniquePerson.xml | 16 ++++++++++++++ .../verification/TestModule/Data/entity1.xml | 13 +++++++++++ .../verification/TestModule/Data/entity2.xml | 13 +++++++++++ .../TestModule/Test/DataActionsTest.xml | 7 ------ .../TestModule/Test/HookActionsTest.xml | 4 ---- .../Test/PersistenceCustomFieldsTest.xml | 16 +------------- 18 files changed, 83 insertions(+), 71 deletions(-) create mode 100644 dev/tests/verification/TestModule/Data/DefaultPerson.xml create mode 100644 dev/tests/verification/TestModule/Data/TestData.xml create mode 100644 dev/tests/verification/TestModule/Data/UniquePerson.xml create mode 100644 dev/tests/verification/TestModule/Data/entity1.xml create mode 100644 dev/tests/verification/TestModule/Data/entity2.xml diff --git a/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt b/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt index 88f1f0183..2ca4e0a63 100644 --- a/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt +++ b/dev/tests/verification/Resources/ActionGroupUsingCreateData.txt @@ -30,8 +30,7 @@ class ActionGroupUsingCreateDataCest { $I->comment('[START BEFORE HOOK]'); $I->comment("Entering Action Group [Key1] actionGroupWithCreateData"); - $I->createEntity("createCategoryKey1", "hook", "ApiCategory", [], []); // stepKey: createCategoryKey1 - $I->createEntity("createConfigProductKey1", "hook", "ApiConfigurableProduct", ["createCategoryKey1"], []); // stepKey: createConfigProductKey1 + $I->createEntity("createConfigProductKey1", "hook", "TestData", ["createCategory"], []); // stepKey: createConfigProductKey1 $I->comment("Exiting Action Group [Key1] actionGroupWithCreateData"); $I->comment('[END BEFORE HOOK]'); } diff --git a/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt b/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt index e5886ab8e..04195a1da 100644 --- a/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt +++ b/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt @@ -42,7 +42,7 @@ class ActionGroupWithStepKeyReferencesCest public function ActionGroupWithStepKeyReferences(AcceptanceTester $I) { $I->comment("Entering Action Group [actionGroup] FunctionActionGroupWithStepKeyReferences"); - $I->createEntity("createSimpleDataActionGroup", "test", "simpleData", [], []); // stepKey: createSimpleDataActionGroup + $I->createEntity("createSimpleDataActionGroup", "test", "TestData", [], []); // stepKey: createSimpleDataActionGroup $grabTextDataActionGroup = $I->grabTextFrom(".class"); // stepKey: grabTextDataActionGroup $I->fillField(".{$grabTextDataActionGroup}", $I->retrieveEntityField('createSimpleDataActionGroup', 'field', 'test')); // stepKey: fill1ActionGroup $I->comment("Invocation stepKey will not be appended in non stepKey instances"); @@ -61,7 +61,6 @@ class ActionGroupWithStepKeyReferencesCest $I->deleteEntity("{$action7ActionGroupActionGroup}", "test"); // stepKey: action7ActionGroup $I->getEntity("action8ActionGroup", "test", "{$action8}", [], null); // stepKey: action8ActionGroup $I->updateEntity("1", "test", "{$action9}",[]); // stepKey: action9ActionGroup - $I->createEntity("action10ActionGroup", "test", "{$action10}", [], []); // stepKey: action10ActionGroup $action11ActionGroup = $I->grabAttributeFrom($action11ActionGroup, "someInput"); // stepKey: action11ActionGroup $action12ActionGroup = $I->grabCookie($action12ActionGroup, ['domain' => 'www.google.com']); // stepKey: action12ActionGroup $action13ActionGroup = $I->grabFromCurrentUrl($action13ActionGroup); // stepKey: action13ActionGroup diff --git a/dev/tests/verification/Resources/DataActionsTest.txt b/dev/tests/verification/Resources/DataActionsTest.txt index 12fe3e979..882d5fe1a 100644 --- a/dev/tests/verification/Resources/DataActionsTest.txt +++ b/dev/tests/verification/Resources/DataActionsTest.txt @@ -29,11 +29,8 @@ class DataActionsTestCest public function _before(AcceptanceTester $I) { $I->comment('[START BEFORE HOOK]'); - $I->createEntity("createdInBefore", "hook", "entity", [], []); // stepKey: createdInBefore $I->updateEntity("createdInBefore", "hook", "entity",[]); // stepKey: updateInBefore $I->deleteEntity("createdInBefore", "hook"); // stepKey: deleteInBefore - $customerFields['lastname'] = "foo"; - $I->createEntity("customer", "hook", "Simple_Customer_Without_Address", [], $customerFields); // stepKey: customer $I->comment('[END BEFORE HOOK]'); } @@ -57,7 +54,6 @@ class DataActionsTestCest public function DataActionsTest(AcceptanceTester $I) { $I->waitForElementClickable(".functionalTestSelector"); // stepKey: waitForElementClickable - $I->createEntity("createdInTest", "test", "entity", [], []); // stepKey: createdInTest $I->updateEntity("createdInTest", "test", "entity",[]); // stepKey: updateInTest $I->deleteEntity("createdInTest", "test"); // stepKey: deleteInTest $I->updateEntity("createdInBefore", "test", "entity",[]); // stepKey: updatedDataOutOfScope diff --git a/dev/tests/verification/Resources/HookActionsTest.txt b/dev/tests/verification/Resources/HookActionsTest.txt index 01edd913d..6ff14a09c 100644 --- a/dev/tests/verification/Resources/HookActionsTest.txt +++ b/dev/tests/verification/Resources/HookActionsTest.txt @@ -28,11 +28,6 @@ class HookActionsTestCest */ public function _before(AcceptanceTester $I) { - $I->comment('[START BEFORE HOOK]'); - $I->createEntity("sampleCreateBefore", "hook", "sampleCreatedEntity", [], []); // stepKey: sampleCreateBefore - $I->deleteEntity("sampleCreateBefore", "hook"); // stepKey: sampleDeleteBefore - $I->createEntity("sampleCreateForAfter", "hook", "sampleCreatedEntity", [], []); // stepKey: sampleCreateForAfter - $I->comment('[END BEFORE HOOK]'); } /** @@ -42,7 +37,6 @@ class HookActionsTestCest public function _after(AcceptanceTester $I) { $I->comment('[START AFTER HOOK]'); - $I->createEntity("sampleCreateAfter", "hook", "sampleCreatedEntity", [], []); // stepKey: sampleCreateAfter $I->deleteEntity("sampleCreateForAfter", "hook"); // stepKey: sampleDeleteAfter $I->comment('[END AFTER HOOK]'); if ($this->isSuccess) { diff --git a/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt b/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt index 43689fc0a..4901e3341 100644 --- a/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt +++ b/dev/tests/verification/Resources/PersistenceActionGroupAppendingTest.txt @@ -30,7 +30,7 @@ class PersistenceActionGroupAppendingTestCest { $I->comment('[START BEFORE HOOK]'); $I->comment("Entering Action Group [ACTIONGROUPBEFORE] DataPersistenceAppendingActionGroup"); - $I->createEntity("createDataACTIONGROUPBEFORE", "hook", "entity", [], []); // stepKey: createDataACTIONGROUPBEFORE + $I->createEntity("createDataACTIONGROUPBEFORE", "hook", "DefaultPerson", [], []); // stepKey: createDataACTIONGROUPBEFORE $I->updateEntity("createDataACTIONGROUPBEFORE", "hook", "newEntity",[]); // stepKey: updateDataACTIONGROUPBEFORE $I->deleteEntity("createDataACTIONGROUPBEFORE", "hook"); // stepKey: deleteDataACTIONGROUPBEFORE $I->getEntity("getDataACTIONGROUPBEFORE", "hook", "someEneity", [], null); // stepKey: getDataACTIONGROUPBEFORE @@ -59,7 +59,7 @@ class PersistenceActionGroupAppendingTestCest public function PersistenceActionGroupAppendingTest(AcceptanceTester $I) { $I->comment("Entering Action Group [ACTIONGROUP] DataPersistenceAppendingActionGroup"); - $I->createEntity("createDataACTIONGROUP", "test", "entity", [], []); // stepKey: createDataACTIONGROUP + $I->createEntity("createDataACTIONGROUP", "test", "DefaultPerson", [], []); // stepKey: createDataACTIONGROUP $I->updateEntity("createDataACTIONGROUP", "test", "newEntity",[]); // stepKey: updateDataACTIONGROUP $I->deleteEntity("createDataACTIONGROUP", "test"); // stepKey: deleteDataACTIONGROUP $I->getEntity("getDataACTIONGROUP", "test", "someEneity", [], null); // stepKey: getDataACTIONGROUP diff --git a/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt b/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt index 4039b952f..5a3270922 100644 --- a/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt +++ b/dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt @@ -30,10 +30,8 @@ class PersistenceCustomFieldsTestCest { $I->comment('[START BEFORE HOOK]'); $createData1Fields['firstname'] = "Mac"; - $createData1Fields['lastname'] = "Doe"; + $createData1Fields['lastname'] = "Bar"; $I->createEntity("createData1", "hook", "DefaultPerson", [], $createData1Fields); // stepKey: createData1 - $createData2Fields['firstname'] = $I->retrieveEntityField('createData1', 'firstname', 'hook'); - $I->createEntity("createData2", "hook", "uniqueData", ["createData1"], $createData2Fields); // stepKey: createData2 $I->comment('[END BEFORE HOOK]'); } @@ -56,27 +54,9 @@ class PersistenceCustomFieldsTestCest */ public function PersistenceCustomFieldsTest(AcceptanceTester $I) { - $createdDataFields['favoriteIndex'] = "1"; - $createdDataFields['middlename'] = "Kovacs"; - $I->createEntity("createdData", "test", "simpleData", [], $createdDataFields); // stepKey: createdData $createdData3Fields['firstname'] = "Takeshi"; $createdData3Fields['lastname'] = "Kovacs"; $I->createEntity("createdData3", "test", "UniquePerson", ["createdData"], $createdData3Fields); // stepKey: createdData3 - $I->comment("Entering Action Group [createdAG] PersistenceActionGroup"); - $createDataAG1CreatedAGFields['firstname'] = "string1"; - $I->createEntity("createDataAG1CreatedAG", "test", "simpleData", [], $createDataAG1CreatedAGFields); // stepKey: createDataAG1CreatedAG - $createDataAG2CreatedAGFields['firstname'] = "Jane"; - $I->createEntity("createDataAG2CreatedAG", "test", "simpleData", [], $createDataAG2CreatedAGFields); // stepKey: createDataAG2CreatedAG - $createDataAG3CreatedAGFields['firstname'] = $I->retrieveEntityField('createdData3', 'firstname', 'test'); - $I->createEntity("createDataAG3CreatedAG", "test", "simpleData", [], $createDataAG3CreatedAGFields); // stepKey: createDataAG3CreatedAG - $I->comment("Exiting Action Group [createdAG] PersistenceActionGroup"); - $I->comment("Entering Action Group [AGKEY] DataPersistenceSelfReferenceActionGroup"); - $I->createEntity("createData1AGKEY", "test", "entity1", [], []); // stepKey: createData1AGKEY - $I->createEntity("createData2AGKEY", "test", "entity2", [], []); // stepKey: createData2AGKEY - $createData3AGKEYFields['key1'] = $I->retrieveEntityField('createData1AGKEY', 'field', 'test'); - $createData3AGKEYFields['key2'] = $I->retrieveEntityField('createData2AGKEY', 'field', 'test'); - $I->createEntity("createData3AGKEY", "test", "entity3", [], $createData3AGKEYFields); // stepKey: createData3AGKEY - $I->comment("Exiting Action Group [AGKEY] DataPersistenceSelfReferenceActionGroup"); } public function _passed(AcceptanceTester $I) diff --git a/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithCreateDataActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithCreateDataActionGroup.xml index 9f3a11a4f..7bf83c230 100644 --- a/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithCreateDataActionGroup.xml +++ b/dev/tests/verification/TestModule/ActionGroup/BasicActionGroup/ActionGroupWithCreateDataActionGroup.xml @@ -8,8 +8,7 @@ <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="actionGroupWithCreateData"> - <createData entity="ApiCategory" stepKey="createCategory"/> - <createData entity="ApiConfigurableProduct" stepKey="createConfigProduct"> + <createData entity="TestData" stepKey="createConfigProduct"> <requiredEntity createDataKey="createCategory"/> </createData> </actionGroup> diff --git a/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionActionGroupWithStepKeyReferencesActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionActionGroupWithStepKeyReferencesActionGroup.xml index 516c2895b..205e32b3a 100644 --- a/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionActionGroupWithStepKeyReferencesActionGroup.xml +++ b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionActionGroupWithStepKeyReferencesActionGroup.xml @@ -8,7 +8,7 @@ <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="FunctionActionGroupWithStepKeyReferences"> - <createData entity="simpleData" stepKey="createSimpleData"/> + <createData entity="TestData" stepKey="createSimpleData"/> <grabTextFrom selector=".class" stepKey="grabTextData"/> <fillField stepKey="fill1" selector=".{$grabTextData}" userInput="$createSimpleData.field$"/> <comment userInput="Invocation stepKey will not be appended in non stepKey instances" stepKey="comment1"/> @@ -22,7 +22,6 @@ <deleteData createDataKey="{$action7}" stepKey="action7"/> <getData entity="{$action8}" stepKey="action8"/> <updateData entity="{$action9}" stepKey="action9" createDataKey="1"/> - <createData entity="{$action10}" stepKey="action10"/> <grabAttributeFrom selector="{$action11}" userInput="someInput" stepKey="action11"/> <grabCookie userInput="{$action12}" parameterArray="['domain' => 'www.google.com']" stepKey="action12"/> <grabFromCurrentUrl regex="{$action13}" stepKey="action13"/> diff --git a/dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup/DataPersistenceAppendingActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup/DataPersistenceAppendingActionGroup.xml index e5ee7ce4f..2fa5cb0aa 100644 --- a/dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup/DataPersistenceAppendingActionGroup.xml +++ b/dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup/DataPersistenceAppendingActionGroup.xml @@ -8,7 +8,7 @@ <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="DataPersistenceAppendingActionGroup"> - <createData entity="entity" stepKey="createData"/> + <createData entity="DefaultPerson" stepKey="createData"/> <updateData entity="newEntity" createDataKey="createData" stepKey="updateData"/> <deleteData createDataKey="createData" stepKey="deleteData"/> <getData entity="someEneity" stepKey="getData"/> diff --git a/dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup/PersistenceActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup/PersistenceActionGroup.xml index c164e13c8..2a7b4873d 100644 --- a/dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup/PersistenceActionGroup.xml +++ b/dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup/PersistenceActionGroup.xml @@ -13,13 +13,13 @@ <argument name="arg2"/> <argument name="arg3"/> </arguments> - <createData entity="simpleData" stepKey="createDataAG1"> + <createData entity="DefaultPerson" stepKey="createDataAG1"> <field key="firstname">{{arg1}}</field> </createData> - <createData entity="simpleData" stepKey="createDataAG2"> + <createData entity="DefaultPerson" stepKey="createDataAG2"> <field key="firstname">{{arg2}}</field> </createData> - <createData entity="simpleData" stepKey="createDataAG3"> + <createData entity="DefaultPerson" stepKey="createDataAG3"> <field key="firstname">{{arg3}}</field> </createData> </actionGroup> diff --git a/dev/tests/verification/TestModule/Data/DefaultPerson.xml b/dev/tests/verification/TestModule/Data/DefaultPerson.xml new file mode 100644 index 000000000..d513b1fe1 --- /dev/null +++ b/dev/tests/verification/TestModule/Data/DefaultPerson.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="DefaultPerson" deprecated="Default Person"> + <data key="firstname">test</data> + <data key="lastname"> bar</data> + </entity> +</entities> diff --git a/dev/tests/verification/TestModule/Data/TestData.xml b/dev/tests/verification/TestModule/Data/TestData.xml new file mode 100644 index 000000000..bbd9bdaf6 --- /dev/null +++ b/dev/tests/verification/TestModule/Data/TestData.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="TestData" deprecated="Test Data"> + <data key="field">test</data> + </entity> +</entities> diff --git a/dev/tests/verification/TestModule/Data/UniquePerson.xml b/dev/tests/verification/TestModule/Data/UniquePerson.xml new file mode 100644 index 000000000..5027b1d2a --- /dev/null +++ b/dev/tests/verification/TestModule/Data/UniquePerson.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="UniquePerson" deprecated="Unique Person"> + <requiredEntity type="createdData">Qty_1000</requiredEntity> + <data key="firstname">test</data> + <data key="lastname"> bar</data> + </entity> +</entities> diff --git a/dev/tests/verification/TestModule/Data/entity1.xml b/dev/tests/verification/TestModule/Data/entity1.xml new file mode 100644 index 000000000..c000223c2 --- /dev/null +++ b/dev/tests/verification/TestModule/Data/entity1.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="entity1" deprecated="Entity one"> + </entity> +</entities> diff --git a/dev/tests/verification/TestModule/Data/entity2.xml b/dev/tests/verification/TestModule/Data/entity2.xml new file mode 100644 index 000000000..0e1455f2d --- /dev/null +++ b/dev/tests/verification/TestModule/Data/entity2.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="entity2" > + </entity> +</entities> diff --git a/dev/tests/verification/TestModule/Test/DataActionsTest.xml b/dev/tests/verification/TestModule/Test/DataActionsTest.xml index d7a2d205b..3d0e4172b 100644 --- a/dev/tests/verification/TestModule/Test/DataActionsTest.xml +++ b/dev/tests/verification/TestModule/Test/DataActionsTest.xml @@ -10,19 +10,12 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="DataActionsTest"> <before> - <createData entity="entity" stepKey="createdInBefore"/> <updateData entity="entity" createDataKey="createdInBefore" stepKey="updateInBefore"/> <deleteData createDataKey="createdInBefore" stepKey="deleteInBefore"/> - <createData stepKey="customer" entity="Simple_Customer_Without_Address"> - <field key="lastname">foo</field> - </createData> - </before> <waitForElementClickable selector=".functionalTestSelector" time="30" stepKey="waitForElementClickable" /> - <createData entity="entity" stepKey="createdInTest"/> <updateData entity="entity" createDataKey="createdInTest" stepKey="updateInTest"/> <deleteData createDataKey="createdInTest" stepKey="deleteInTest"/> - <updateData entity="entity" createDataKey="createdInBefore" stepKey="updatedDataOutOfScope"/> <deleteData createDataKey="createdInBefore" stepKey="deleteDataOutOfScope"/> </test> diff --git a/dev/tests/verification/TestModule/Test/HookActionsTest.xml b/dev/tests/verification/TestModule/Test/HookActionsTest.xml index 0a26256d0..b1350a0a7 100644 --- a/dev/tests/verification/TestModule/Test/HookActionsTest.xml +++ b/dev/tests/verification/TestModule/Test/HookActionsTest.xml @@ -10,12 +10,8 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="HookActionsTest"> <before> - <createData entity="sampleCreatedEntity" stepKey="sampleCreateBefore"/> - <deleteData createDataKey="sampleCreateBefore" stepKey="sampleDeleteBefore"/> - <createData entity="sampleCreatedEntity" stepKey="sampleCreateForAfter"/> </before> <after> - <createData entity="sampleCreatedEntity" stepKey="sampleCreateAfter"/> <deleteData createDataKey="sampleCreateForAfter" stepKey="sampleDeleteAfter"/> </after> </test> diff --git a/dev/tests/verification/TestModule/Test/PersistenceCustomFieldsTest.xml b/dev/tests/verification/TestModule/Test/PersistenceCustomFieldsTest.xml index 77a85060b..867dd35ff 100644 --- a/dev/tests/verification/TestModule/Test/PersistenceCustomFieldsTest.xml +++ b/dev/tests/verification/TestModule/Test/PersistenceCustomFieldsTest.xml @@ -12,27 +12,13 @@ <before> <createData entity="DefaultPerson" stepKey="createData1"> <field key="firstname">Mac</field> - <field key="lastname">{{simpleData.lastname}}</field> - </createData> - <createData entity="uniqueData" stepKey="createData2"> - <requiredEntity createDataKey="createData1"/> - <field key="firstname">$$createData1.firstname$$</field> + <field key="lastname">Bar</field> </createData> </before> - <createData entity="simpleData" stepKey="createdData"> - <field key="favoriteIndex">1</field> - <field key="middlename">Kovacs</field> - </createData> <createData entity="UniquePerson" stepKey="createdData3"> <requiredEntity createDataKey="createdData"/> <field key="firstname">Takeshi</field> <field key="lastname">Kovacs</field> </createData> - <actionGroup ref="PersistenceActionGroup" stepKey="createdAG"> - <argument name="arg1" value="string1"/> - <argument name="arg2" value="DefaultPerson.firstname"/> - <argument name="arg3" value="$createdData3.firstname$"/> - </actionGroup> - <actionGroup ref="DataPersistenceSelfReferenceActionGroup" stepKey="AGKEY"/> </test> </tests> From 44cd1d2c23b7f9c913003aa77f1fcfbe5fca7500 Mon Sep 17 00:00:00 2001 From: "Mohit.k.Sharma" <mohit.k.sharma@BLR1-LMC-N71405.local> Date: Mon, 28 Feb 2022 09:35:08 +0530 Subject: [PATCH 818/888] MQE-1693 | Doc added for generate test by json file --- docs/commands/mftf.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 67fc61e02..74a41dea9 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -173,7 +173,7 @@ vendor/bin/mftf generate:tests [option] [<test name>] [<test name>] [--remove] | `--force` | Forces test generation, regardless of the module merge order defined in the Magento instance. Example: `generate:tests --force`. | | `-i,--time` | Set time in minutes to determine the group size when `--config=parallel` is used. <br/>Example: `generate:tests --config=parallel --time=15` <br/>Option `--time` will be the default and the __default value__ is `10` when neither `--time` nor `--groups` is specified. <br/>Example: `generate:tests --config=parallel`| | `-g,--groups` | Set number of groups to be split into when `--config=parallel` is used. <br>Example: `generate:tests --config=parallel --groups=300` <br/>Options `--time` and `--groups` are mutually exclusive and only one should be used.| -| `--tests` | Defines the test configuration as a JSON string.| +| `--tests` | Defines the test configuration as a JSON string or JSON file path.| | `--allow-skipped` | Allows MFTF to generate and run tests marked with `<skip>.`| | `--debug` | Performs schema validations on XML files. <br/> DEFAULT: `generate:tests` implicitly performs schema validation on merged files. It does not indicate the file name where the error is encountered. <br/> DEVELOPER: `--debug` performs per-file validation and returns additional debug information (such as the filename where an error occurred) when test generation fails because of an invalid XML schema. This option takes extra processing time. Use it after test generation has failed once.<br/>| | `-r,--remove`| Removes the existing generated suites and tests cleaning up the `_generated` directory before the actual run. For example, `generate:tests SampleTest --remove` cleans up the entire `_generated` directory and generates `SampleTest` only.| @@ -224,12 +224,20 @@ Complex configuration to generate a few non-suite tests, a single test in a suit The command that encodes this complex configuration: +Command to generate test by json string: + ```bash vendor/bin/mftf generate:tests --tests '{"tests":["general_test1","general_test2","general_test3"],"suites":{"sample":["suite_test1"],"sample2":null}}' ``` Note that the strings must be escaped and surrounded in quotes. +Command to generate test by json file: + +```bash +vendor/bin/mftf generate:tests --tests ./foldername/filename.json +``` + ### `generate:suite` #### Description From 8c85258c9bf38647864594e49282a6ed910b7c84 Mon Sep 17 00:00:00 2001 From: Shashi Kumar Singh <92144509+glo00108@users.noreply.github.com> Date: Mon, 28 Feb 2022 20:39:39 +0530 Subject: [PATCH 819/888] MQE-3121 MFTF config parallel to support input test names from a file (#167) * MQE-3121 MFTF config parallel to support input test names from a file * fix static checks and ac. * updated doc * added example * Update mftf.md Co-authored-by: Kevin Kozan <kkozan@adobe.com> Co-authored-by: Kevin Kozan <kkozan@magento.com> --- docs/commands/mftf.md | 39 +++++++++++++------ .../Console/GenerateTestsCommand.php | 33 ++++++++++++++++ 2 files changed, 61 insertions(+), 11 deletions(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 67fc61e02..049facdd0 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -42,6 +42,23 @@ vendor/bin/mftf generate:tests vendor/bin/mftf generate:tests AdminLoginSuccessfulTest StorefrontPersistedCustomerLoginTest ``` +### Generate tests by testNames.txt file + +```bash +vendor/bin/mftf generate:tests -p path/to/your/testNames.txt +``` + +This command generate all tests specified in a testNames.txt file. + +#### Example + +```bash +testName1 +testName2 +testNameN +suiteName:testInSuite +``` + ### Generate test by test and suite name ```bash @@ -183,7 +200,7 @@ vendor/bin/mftf generate:tests [option] [<test name>] [<test name>] [--remove] The configuration to generate a single test with no suites: ```json -{ +{ "tests":[ "general_test1" //Generate the "general_test1" test. ], @@ -194,9 +211,9 @@ The configuration to generate a single test with no suites: The configuration to generate a single test in the suite: ```json -{ +{ "tests": null, // No tests outside the suite configuration will be generated. - "suites":{ + "suites":{ "sample":[ // The suite that contains the test. "suite_test1" // The test to be generated. ] @@ -207,8 +224,8 @@ The configuration to generate a single test in the suite: Complex configuration to generate a few non-suite tests, a single test in a suite, and an entire suite: ```json -{ - "tests":[ +{ + "tests":[ "general_test1", "general_test2", "general_test3" @@ -368,7 +385,7 @@ vendor/bin/mftf run:test LoginCustomerTest StorefrontCreateCustomerTest Runs a testManifest.txt file. -This command runs all tests specified in a testManifest.xml file. It does not generate tests for you. You must do that as first. +This command runs all tests specified in a testManifest.xml file. It does not generate tests for you. You must do that as first. #### Usage @@ -449,7 +466,7 @@ The example parameters are taken from the `etc/config/.env.example` file. ### `static-checks` -Runs all or specific MFTF static-checks on the test codebase that MFTF is currently attached to. +Runs all or specific MFTF static-checks on the test codebase that MFTF is currently attached to. Behavior for determining what tests to run is as follows: * If test names are specified, only those tests are run. @@ -469,7 +486,7 @@ vendor/bin/mftf static-checks [<names>]... | Option | Description | |-----------------------|-----------------------------------------------------------------------------------------------------------| | `-p, --path` | Path to a MFTF test module to run "deprecatedEntityUsage" and "pauseActionUsage" static check scripts. Option is ignored by other static check scripts. - + #### Examples To check what existing static check scripts are available @@ -478,7 +495,7 @@ To check what existing static check scripts are available vendor/bin/mftf static-checks --help ``` -To run all existing static check scripts +To run all existing static check scripts ```bash vendor/bin/mftf static-checks @@ -527,7 +544,7 @@ vendor/bin/mftf static-checks testDependencies actionGroupArguments |`deprecatedEntityUsage`| Checks that deprecated test entities are not being referenced.| |`annotations`| Checks various details of test annotations, such as missing annotations or duplicate annotations.| |`pauseUsage`| Checks that pause action is not used in action groups, tests or suites.| - + #### Defining ruleset The `static-checks` command will look for a `staticRuleset.json` file under either: @@ -623,7 +640,7 @@ vendor/bin/mftf codecept:run functional --verbose --steps -g default <div class="bs-callout-warning"> <p> -Note: You may want to limit the usage of this Codeception command with arguments and options for "acceptance" only, since it is what's supported by MFTF. +Note: You may want to limit the usage of this Codeception command with arguments and options for "acceptance" only, since it is what's supported by MFTF. When using this command, you should change "acceptance" to "functional" when referring to Codeception documentation. </p> </div> diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php index b277f9c4e..88b9dc7b6 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php @@ -80,6 +80,11 @@ protected function configure() . '<info>Existing severity values:</info> BLOCKER, CRITICAL, MAJOR, AVERAGE, MINOR.' . PHP_EOL . '<info>Example:</info> --filter=severity:CRITICAL' . ' --filter=includeGroup:customer --filter=excludeGroup:customerAnalytics' . PHP_EOL + )->addOption( + 'path', + 'p', + InputOption::VALUE_REQUIRED, + 'path to a test names file.', ); parent::configure(); @@ -113,6 +118,11 @@ protected function execute(InputInterface $input, OutputInterface $output) list($filterType, $filterValue) = explode(':', $filter); $filterList[$filterType][] = $filterValue; } + $path = $input->getOption('path'); + // check filepath is given for generate test file + if (!empty($path)) { + $tests = $this->generateTestFileFromPath($path); + } // Set application configuration so we can references the user options in our framework try { MftfApplicationConfig::create( @@ -311,4 +321,27 @@ private function parseConfigParallelOptions($time, $groups) throw new FastFailException("'groups' option must be an integer and greater than 0"); } } + + /** + * @param string $path + * @return array + * @throws TestFrameworkException + */ + private function generateTestFileFromPath(string $path): array + { + if (!file_exists($path)) { + throw new TestFrameworkException("Could not find file $path. Check the path and try again."); + } + + $test_names = file($path, FILE_IGNORE_NEW_LINES); + $tests = []; + foreach ($test_names as $test_name) { + if (empty(trim($test_name))) { + continue; + } + $test_name_array = explode(' ', trim($test_name)); + $tests = array_merge($tests, $test_name_array); + } + return $tests; + } } From 2c5c3d2656f2ef591877096afc5e7d9d2c8bb15e Mon Sep 17 00:00:00 2001 From: glo00108 <glo00108@adobe.com> Date: Tue, 8 Mar 2022 15:14:03 +0530 Subject: [PATCH 820/888] MQE-2342 Provide MFTF group summary file --- .../Manifest/BaseParallelTestManifest.php | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/Magento/FunctionalTestingFramework/Util/Manifest/BaseParallelTestManifest.php b/src/Magento/FunctionalTestingFramework/Util/Manifest/BaseParallelTestManifest.php index da0f9d353..0708d9e63 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Manifest/BaseParallelTestManifest.php +++ b/src/Magento/FunctionalTestingFramework/Util/Manifest/BaseParallelTestManifest.php @@ -41,6 +41,12 @@ abstract class BaseParallelTestManifest extends BaseTestManifest */ protected $dirPath; + /** + * An array of test name count in a single group + * @var array + */ + protected $testCountsToGroup = []; + /** * BaseParallelTestManifest constructor. * @@ -87,6 +93,8 @@ public function generate() foreach ($this->testGroups as $groupNumber => $groupContents) { $this->generateGroupFile($groupContents, $groupNumber, $suites); } + + $this->generateGroupSummaryFile($this->testCountsToGroup); } /** @@ -114,17 +122,35 @@ protected function generateGroupFile($testGroup, $nodeNumber, $suites) foreach ($testGroup as $entryName => $testValue) { $fileResource = fopen($this->dirPath . DIRECTORY_SEPARATOR . "group{$nodeNumber}.txt", 'a'); + $this->testCountsToGroup["group{$nodeNumber}"] = $this->testCountsToGroup["group{$nodeNumber}"] ?? 0; + $line = null; if (!empty($suites[$entryName])) { $line = "-g {$entryName}"; } else { $line = $this->relativeDirPath . DIRECTORY_SEPARATOR . $entryName . '.php'; + $this->testCountsToGroup["group{$nodeNumber}"]++; } fwrite($fileResource, $line . PHP_EOL); fclose($fileResource); } } + /** + * @param array $groups + * @return void + */ + protected function generateGroupSummaryFile(array $groups) + { + $fileResource = fopen($this->dirPath . DIRECTORY_SEPARATOR . "mftf_group_summary.txt", 'w'); + $contents = "Total Number of Groups: " . count($groups) . PHP_EOL; + foreach ($groups as $key => $value) { + $contents .= $key . " - ". $value . "tests" .PHP_EOL; + } + fwrite($fileResource, $contents); + fclose($fileResource); + } + /** * Function which recusrively parses a given potentially multidimensional array of suites containing their split * groups. The result is a flattened array of suite names to relevant tests for generation of the manifest. From 5228185c324ff79c7654606b28c3879259dc0830 Mon Sep 17 00:00:00 2001 From: manjusha729 <93243302+manjusha729@users.noreply.github.com> Date: Thu, 24 Mar 2022 20:15:56 +0530 Subject: [PATCH 821/888] MQE-2328 : Detect unused Entities (#173) * MQE-2328 : Detect unused Entities * MQE-2328 : Detect unused Entities * MQE-2328 : Detect unused Entities * MQE-2328 : Detect unused Entities * MQE-2328 : Detect unused Entities * MQE-2328 : Detect unused Entities * MQE-2328 : Detect unused Entities * MQE-2328 : Detect unused Entities * MQE-2328 : Detect unused Entities * MQE-2328 : Detect unused Entities * added variable above foreach Co-authored-by: Manjusha.S <manjusha.s@BLR1-LMC-N71373.local> --- .../StaticCheck/StaticChecksList.php | 2 + .../StaticCheck/UnusedEntityCheck.php | 658 ++++++++++++++++++ 2 files changed, 660 insertions(+) create mode 100644 src/Magento/FunctionalTestingFramework/StaticCheck/UnusedEntityCheck.php diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php b/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php index 39b9ae748..7eda14f1b 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php @@ -19,6 +19,7 @@ class StaticChecksList implements StaticCheckListInterface const DEPRECATED_ENTITY_USAGE_CHECK_NAME = 'deprecatedEntityUsage'; const PAUSE_ACTION_USAGE_CHECK_NAME = 'pauseActionUsage'; const CREATED_DATA_FROM_OUTSIDE_ACTIONGROUP = 'createdDataFromOutsideActionGroup'; + const UNUSED_ENTITY_CHECK = 'unusedEntityCheck'; const STATIC_RESULTS = 'tests' . DIRECTORY_SEPARATOR .'_output' . DIRECTORY_SEPARATOR . 'static-results'; /** @@ -49,6 +50,7 @@ public function __construct(array $checks = []) self::DEPRECATED_ENTITY_USAGE_CHECK_NAME => new DeprecatedEntityUsageCheck(), 'annotations' => new AnnotationsCheck(), self::PAUSE_ACTION_USAGE_CHECK_NAME => new PauseActionUsageCheck(), + self::UNUSED_ENTITY_CHECK => new UnusedEntityCheck(), self::CREATED_DATA_FROM_OUTSIDE_ACTIONGROUP => new CreatedDataFromOutsideActionGroupCheck() ] + $checks; diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/UnusedEntityCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/UnusedEntityCheck.php new file mode 100644 index 000000000..72c5ea801 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/UnusedEntityCheck.php @@ -0,0 +1,658 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\FunctionalTestingFramework\StaticCheck; + +use Exception; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Finder\Finder; +use Magento\FunctionalTestingFramework\Util\Script\ScriptUtil; +use Symfony\Component\Finder\SplFileInfo; +use DOMElement; + +/** + * Class UnusedEntityCheck + * + * @package Magento\FunctionalTestingFramework\StaticCheck + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class UnusedEntityCheck implements StaticCheckInterface +{ + const ERROR_LOG_FILENAME = "mftf-unused-entity-usage-checks"; + const ENTITY_REGEX_PATTERN = "/\{(\{)*([\w.]+)(\})*\}/"; + const SELECTOR_REGEX_PATTERN = '/selector=["\']([^\'"]*)/'; + const ERROR_LOG_MESSAGE = "MFTF Unused Entity Usage Check"; + const SECTION_REGEX_PATTERN = "/\w*Section\b/"; + const REQUIRED_ENTITY = '/<requiredEntity(.*?)>(.+?)<\/requiredEntity>/'; + const ENTITY_SEPERATED_BY_DOT_REFERENCE = '/([\w]+)(\.)+([\w]+)/'; + + /** + * ScriptUtil instance + * + * @var ScriptUtil $scriptUtil + */ + private $scriptUtil; + + /** + * Checks test dependencies, determined by references in tests versus the dependencies listed in the Magento module + * + * @param InputInterface $input + * @return void + * @throws Exception + */ + public function execute(InputInterface $input) + { + $this->scriptUtil = new ScriptUtil(); + $domDocument = new \DOMDocument(); + $modulePaths = $this->scriptUtil->getAllModulePaths(); + $testXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, "Test"); + $actionGroupXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, "ActionGroup"); + $dataXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, "Data"); + $pageXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, "Page"); + $sectionXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, "Section"); + $suiteXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, 'Suite'); + $this->errors = $this->unusedEntities( + $domDocument, + $dataXmlFiles, + $actionGroupXmlFiles, + $sectionXmlFiles, + $pageXmlFiles, + $testXmlFiles, + $suiteXmlFiles + ); + $this->output = $this->scriptUtil->printErrorsToFile( + $this->errors, + StaticChecksList::getErrorFilesPath() . DIRECTORY_SEPARATOR . self::ERROR_LOG_FILENAME . '.txt', + self::ERROR_LOG_MESSAGE + ); + } + + /** + * Centralized method to get unused Entities + * + * @param DOMDocument $domDocument + * @param ScriptUtil $dataXmlFiles + * @param ScriptUtil $actionGroupXmlFiles + * @param ScriptUtil $sectionXmlFiles + * @param ScriptUtil $pageXmlFiles + * @param ScriptUtil $testXmlFiles + * @param ScriptUtil $suiteXmlFiles + * @return array + * @throws Exception + */ + private function unusedEntities( + $domDocument, + $dataXmlFiles, + $actionGroupXmlFiles, + $sectionXmlFiles, + $pageXmlFiles, + $testXmlFiles, + $suiteXmlFiles + ) { + foreach ($dataXmlFiles as $filePath) { + $domDocument->load($filePath); + $entityResult = $this->getAttributesFromDOMNodeList( + $domDocument->getElementsByTagName("entity"), + ["type" => "name"] + ); + foreach ($entityResult as $entitiesResultData) { + $dataNames[$entitiesResultData[key($entitiesResultData)]] = [ + "dataFilePath"=>StaticChecksList::getFilePath($filePath->getRealPath()) + ]; + } + } + foreach ($actionGroupXmlFiles as $filePath) { + $domDocument->load($filePath); + $actionGroupName = $domDocument->getElementsByTagName("actionGroup")->item(0)->getAttribute("name"); + if (!empty($domDocument->getElementsByTagName("actionGroup")->item(0)->getAttribute("deprecated"))) { + continue; + } + $allActionGroupFileNames[$actionGroupName ] = + StaticChecksList::getFilePath($filePath->getRealPath()); + } + + foreach ($sectionXmlFiles as $filePath) { + $domDocument->load($filePath); + $sectionName = $domDocument->getElementsByTagName("section")->item(0)->getAttribute("name"); + $sectionFileNames[$sectionName] = StaticChecksList::getFilePath($filePath->getRealPath()); + } + + foreach ($pageXmlFiles as $filePath) { + $domDocument->load($filePath); + $pageName = $domDocument->getElementsByTagName("page")->item(0)->getAttribute("name"); + $pageFiles[$pageName] = StaticChecksList::getFilePath( + $filePath->getRealPath() + ); + } + $actionGroupReferences = $this->unusedActionEntity( + $domDocument, + $actionGroupXmlFiles, + $testXmlFiles, + $allActionGroupFileNames, + $suiteXmlFiles + ); + $entityReferences = $this->unusedData( + $domDocument, + $actionGroupXmlFiles, + $testXmlFiles, + $dataNames, + $dataXmlFiles + ); + $pagesReference = $this->unusedPageEntity( + $domDocument, + $actionGroupXmlFiles, + $testXmlFiles, + $pageFiles, + $suiteXmlFiles + ); + $sectionReference = $this->unusedSectionEntity( + $domDocument, + $actionGroupXmlFiles, + $testXmlFiles, + $pageXmlFiles, + $sectionFileNames, + $suiteXmlFiles + ); + return $this->setErrorOutput( + array_merge( + array_values($actionGroupReferences), + array_values($entityReferences), + array_values($pagesReference), + array_values($sectionReference) + ) + ); + } + /** + * Setting error message + * + * @return array + * @throws Exception + */ + private function setErrorOutput($unusedFilePath) + { + $testErrors = []; + foreach ($unusedFilePath as $files) { + $errorOutput = " Unused Entity File Path "; + $errorOutput .= "\n\t".$files."\t\n"; + $testErrors[$files][] = $errorOutput; + } + return $testErrors; + } + + /** + * Retrieves Unused Action Group Entities + * + * @param DOMDocument $domDocument + * @param ScriptUtil $actionGroupXmlFiles + * @param ScriptUtil $testXmlFiles + * @param ScriptUtil $allActionGroupFileNames + * @param ScriptUtil $suiteXmlFiles + * @return array + * @throws Exception + */ + private function unusedActionEntity( + $domDocument, + $actionGroupXmlFiles, + $testXmlFiles, + $allActionGroupFileNames, + $suiteXmlFiles + ) { + foreach ($suiteXmlFiles as $filePath) { + $domDocument->load($filePath); + $referencesSuite= $this->getAttributesFromDOMNodeList( + $domDocument->getElementsByTagName("actionGroup"), + "ref" + ); + foreach ($referencesSuite as $referencesResultSuite) { + if (isset($allActionGroupFileNames[$referencesResultSuite])) { + unset($allActionGroupFileNames[$referencesResultSuite]); + } + } + } + + foreach ($actionGroupXmlFiles as $filePath) { + $domDocument->load($filePath); + $actionGroup = $domDocument->getElementsByTagName("actionGroup")->item(0); + $references = $actionGroup->getAttribute("extends"); + if (in_array($references, array_keys($allActionGroupFileNames))) { + unset($allActionGroupFileNames[$references]); + } + } + foreach ($testXmlFiles as $filePath) { + $domDocument->load($filePath); + $testReferences = $this->getAttributesFromDOMNodeList( + $domDocument->getElementsByTagName("actionGroup"), + "ref" + ); + foreach ($testReferences as $testReferencesResult) { + if (isset($allActionGroupFileNames[$testReferencesResult])) { + unset($allActionGroupFileNames[$testReferencesResult]); + } + } + } + return $allActionGroupFileNames; + } + + /** + * Retrieves Unused Page Entities + * + * @param DOMDocument $domDocument + * @return array + * @throws Exception + */ + private function unusedPageEntity($domDocument, $actionGroupXmlFiles, $testXmlFiles, $pageNames, $suiteXmlFiles) + { + + foreach ($suiteXmlFiles as $filePath) { + $domDocument->load($filePath); + $contents = file_get_contents($filePath); + $pagesReferencesInSuites = $this->getAttributesFromDOMNodeList( + $domDocument->getElementsByTagName("amOnPage"), + "url" + ); + foreach ($pagesReferencesInSuites as $pagesReferencesInSuitesResult) { + $explodepagesReferencesResult = explode( + ".", + trim($pagesReferencesInSuitesResult, "{}") + ); + unset($pageNames[$explodepagesReferencesResult[0]]); + } + $pageNames = $this->entityReferencePatternCheck($domDocument, $pageNames, $contents, false, []); + } + foreach ($actionGroupXmlFiles as $filePath) { + $domDocument->load($filePath); + $contents = file_get_contents($filePath); + $pagesReferences = $this->getAttributesFromDOMNodeList( + $domDocument->getElementsByTagName("amOnPage"), + "url" + ); + foreach ($pagesReferences as $pagesReferencesResult) { + $explodepagesReferencesResult = explode( + ".", + trim($pagesReferencesResult, "{}") + ); + unset($pageNames[$explodepagesReferencesResult[0]]); + } + $pageNames = $this->entityReferencePatternCheck($domDocument, $pageNames, $contents, false, []); + } + + foreach ($testXmlFiles as $filePath) { + $domDocument->load($filePath); + $contents = file_get_contents($filePath); + $testReferences = $this->getAttributesFromDOMNodeList( + $domDocument->getElementsByTagName("amOnPage"), + "url" + ); + foreach ($testReferences as $pagesReferencesResult) { + $explodepagesReferencesResult = explode( + ".", + trim($pagesReferencesResult, "{}") + ); + unset($pageNames[$explodepagesReferencesResult[0]]); + } + $pageNames = $this->entityReferencePatternCheck($domDocument, $pageNames, $contents, false, []); + } + return $pageNames; + } + + /** + * Common Pattern Check Method + * + * @param DOMDocument $domDocument + * @param array $fileNames + * @param string $contents + * @return array + * @throws Exception + */ + private function entityReferencePatternCheck($domDocument, $fileNames, $contents, $data, $removeDataFilePath) + { + $sectionArgumentValueReference = $this->getAttributesFromDOMNodeList( + $domDocument->getElementsByTagName("argument"), + "value" + ); + $sectionDefaultValueArgumentReference = $this->getAttributesFromDOMNodeList( + $domDocument->getElementsByTagName("argument"), + "defaultValue" + ); + $sectionArgumentValue = array_merge($sectionArgumentValueReference, $sectionDefaultValueArgumentReference); + foreach ($sectionArgumentValue as $sectionArgumentValueResult) { + $explodedReference = str_contains($sectionArgumentValueResult, '$') + ? explode(".", trim($sectionArgumentValueResult, '$')) + : explode(".", trim($sectionArgumentValueResult, "{}")); + if (in_array($explodedReference[0], array_keys($fileNames))) { + $removeDataFilePath[] = isset($fileNames[$explodedReference[0]]["dataFilePath"]) + ? $fileNames[$explodedReference[0]]["dataFilePath"] + : []; + unset($fileNames[$explodedReference[0]]); + } + } + preg_match_all(self::ENTITY_REGEX_PATTERN, $contents, $bracketReferencesData); + preg_match_all( + self::ENTITY_SEPERATED_BY_DOT_REFERENCE, + $contents, + $entitySeperatedByDotReferenceActionGroup + ); + $entityReferenceDataResultActionGroup = array_merge( + array_unique($bracketReferencesData[0]), + array_unique($entitySeperatedByDotReferenceActionGroup[0]) + ); + + foreach (array_unique($entityReferenceDataResultActionGroup) as $bracketReferencesResults) { + $bracketReferencesDataResultOutput = explode(".", trim($bracketReferencesResults, "{}")); + if (in_array($bracketReferencesDataResultOutput[0], array_keys($fileNames))) { + $removeDataFilePath[] = isset($fileNames[$bracketReferencesDataResultOutput[0]]["dataFilePath"]) + ? $fileNames[$bracketReferencesDataResultOutput[0]]["dataFilePath"] + : []; + unset($fileNames[$bracketReferencesDataResultOutput[0]]); + } + } + + return ($data === true) ? ['dataFilePath'=>$removeDataFilePath ,'fileNames'=> $fileNames ] : $fileNames ; + } + + /** + * Retrieves Unused Section Entities + * + * @param DOMDocument $domDocument + * @param ScriptUtil $actionGroupXmlFiles + * @param ScriptUtil $testXmlFiles + * @param ScriptUtil $pageXmlFiles + * @param array $sectionFileNames + * @param ScriptUtil $suiteXmlFiles + * @return array + * @throws Exception + */ + private function unusedSectionEntity( + $domDocument, + $actionGroupXmlFiles, + $testXmlFiles, + $pageXmlFiles, + $sectionFileNames, + $suiteXmlFiles + ) { + foreach ($suiteXmlFiles as $filePath) { + $contents = file_get_contents($filePath); + $domDocument->load($filePath); + preg_match_all( + self::SELECTOR_REGEX_PATTERN, + $contents, + $selectorReferences + ); + + if (isset($selectorReferences[1])) { + foreach (array_unique($selectorReferences[1]) as $selectorReferencesResult) { + $trimSelector = explode(".", trim($selectorReferencesResult, "{{}}")); + if (isset($sectionFileNames[$trimSelector[0]])) { + unset($sectionFileNames[$trimSelector[0]]); + } + } + } + $sectionFileNames = $this->entityReferencePatternCheck( + $domDocument, + $sectionFileNames, + $contents, + false, + [] + ); + } + foreach ($actionGroupXmlFiles as $filePath) { + $contents = file_get_contents($filePath); + $domDocument->load($filePath); + preg_match_all( + self::SELECTOR_REGEX_PATTERN, + $contents, + $selectorReferences + ); + + if (isset($selectorReferences[1])) { + foreach (array_unique($selectorReferences[1]) as $selectorReferencesResult) { + $trimSelector = explode(".", trim($selectorReferencesResult, "{{}}")); + if (isset($sectionFileNames[$trimSelector[0]])) { + unset($sectionFileNames[$trimSelector[0]]); + } + } + } + $sectionFileNames = $this->entityReferencePatternCheck( + $domDocument, + $sectionFileNames, + $contents, + false, + [] + ); + } + $sectionFileNames = $this->getUnusedSectionEntitiesReferenceInActionGroupAndTestFiles( + $testXmlFiles, + $pageXmlFiles, + $domDocument, + $sectionFileNames + ); + return $sectionFileNames; + } + + /** + * Get unused section entities reference in Action group and Test files + * @param ScriptUtil $testXmlFiles + * @param ScriptUtil $pageXmlFiles + * @param DOMDocument $domDocument + * @param array $sectionFileNames + * @return array + * @throws Exception + */ + private function getUnusedSectionEntitiesReferenceInActionGroupAndTestFiles( + $testXmlFiles, + $pageXmlFiles, + $domDocument, + $sectionFileNames + ) { + foreach ($testXmlFiles as $filePath) { + $contents = file_get_contents($filePath); + $domDocument->load($filePath); + preg_match_all( + self::SELECTOR_REGEX_PATTERN, + $contents, + $selectorReferences + ); + if (isset($selectorReferences[1])) { + foreach (array_unique($selectorReferences[1]) as $selectorReferencesResult) { + $trimSelector = explode(".", trim($selectorReferencesResult, "{{}}")); + if (isset($sectionFileNames[$trimSelector[0]])) { + unset($sectionFileNames[$trimSelector[0]]); + } + } + } + $sectionFileNames = $this->entityReferencePatternCheck( + $domDocument, + $sectionFileNames, + $contents, + false, + [] + ); + } + + foreach ($pageXmlFiles as $filePath) { + $contents = file_get_contents($filePath); + preg_match_all( + self::SELECTOR_REGEX_PATTERN, + $contents, + $selectorReferences + ); + if (isset($selectorReferences[1])) { + foreach (array_unique($selectorReferences[1]) as $selectorReferencesResult) { + $trimSelector = explode(".", trim($selectorReferencesResult, "{{}}")); + if (isset($sectionFileNames[$trimSelector[0]])) { + unset($sectionFileNames[$trimSelector[0]]); + } + } + } + $sectionFileNames = $this->entityReferencePatternCheck( + $domDocument, + $sectionFileNames, + $contents, + false, + [] + ); + } + return $sectionFileNames; + } + /** + * Return Unused Data entities + * + * @param DOMDocument $domDocument + * @return array + */ + private function unusedData( + $domDocument, + $actionGroupXmlFiles, + $testXmlFiles, + $dataNames, + $dataXmlFiles + ) { + $removeDataFilePath = []; + foreach ($dataXmlFiles as $filePath) { + $domDocument->load($filePath); + $contents = file_get_contents($filePath); + preg_match_all(self::REQUIRED_ENTITY, $contents, $requiredEntityReference); + foreach ($requiredEntityReference[2] as $requiredEntityReferenceResult) { + if (isset($dataNames[$requiredEntityReferenceResult])) { + $removeDataFilePath[] = + $dataNames[$requiredEntityReferenceResult]["dataFilePath"]; + unset($dataNames[$requiredEntityReferenceResult]); + } + } + } + foreach ($actionGroupXmlFiles as $filePath) { + $domDocument->load($filePath); + $contents = file_get_contents($filePath); + $getUnusedFilePath = $this->entityReferencePatternCheck( + $domDocument, + $dataNames, + $contents, + true, + $removeDataFilePath + ); + $dataNames = $getUnusedFilePath['fileNames']; + $removeDataFilePath = $getUnusedFilePath['dataFilePath']; + } + foreach ($testXmlFiles as $filePath) { + $domDocument->load($filePath); + $contents = file_get_contents($filePath); + $getUnusedFilePath = $this->entityReferencePatternCheck( + $domDocument, + $dataNames, + $contents, + true, + $removeDataFilePath + ); + $dataNames = $getUnusedFilePath['fileNames']; + $removeDataFilePath = $getUnusedFilePath['dataFilePath']; + $createdDataReferences = $this->getAttributesFromDOMNodeList( + $domDocument->getElementsByTagName("createData"), + "entity" + ); + $updatedDataReferences = $this->getAttributesFromDOMNodeList( + $domDocument->getElementsByTagName("updateData"), + "entity" + ); + $getDataReferences = $this->getAttributesFromDOMNodeList( + $domDocument->getElementsByTagName("getData"), + "entity" + ); + $dataReferences = array_unique( + array_merge( + $createdDataReferences, + $updatedDataReferences, + $getDataReferences + ) + ); + if (count($dataReferences) > 0) { + foreach ($dataReferences as $dataReferencesResult) { + if (isset($dataNames[$dataReferencesResult])) { + $removeDataFilePath[] = $dataNames[$dataReferencesResult]["dataFilePath"]; + unset($dataNames[$dataReferencesResult]); + } + } + } + } + $dataFilePathResult = $this->unsetFilePath($dataNames, $removeDataFilePath); + return array_unique($dataFilePathResult); + } + + /** + * Remove used entities file path from unused entities array + * + * @return array + */ + private function unsetFilePath($dataNames, $removeDataFilePath) + { + $dataFilePathResult = []; + foreach ($dataNames as $key => $dataNamesResult) { + if (in_array($dataNamesResult["dataFilePath"], $removeDataFilePath)) { + unset($dataNames[$key]); + continue; + } + $dataFilePathResult[] = $dataNames[$key]['dataFilePath']; + } + return array_unique($dataFilePathResult); + } + + /** + * Return attribute value for each node in DOMNodeList as an array + * + * @param DOMNodeList $nodes + * @param string $attributeName + * @return array + */ + private function getAttributesFromDOMNodeList($nodes, $attributeName) + { + $attributes = []; + foreach ($nodes as $node) { + if (is_string($attributeName)) { + $attributeValue = $node->getAttribute($attributeName); + } else { + $attributeValue = [$node->getAttribute(key($attributeName)) => + $node->getAttribute($attributeName[key($attributeName)])]; + } + if (!empty($attributeValue)) { + $attributes[] = $attributeValue; + } + } + return $attributes; + } + + /** + * Extract actionGroup DomElement from xml file + * + * @param string $contents + * @return \DOMElement + */ + public function getActionGroupDomElement(string $contents): DOMElement + { + $domDocument = new \DOMDocument(); + $domDocument->loadXML($contents); + return $domDocument->getElementsByTagName("actionGroup")[0]; + } + + /** + * Return array containing all errors found after running the execute() function + * + * @return array + */ + public function getErrors() + { + return $this->errors; + } + + /** + * Return output + * + * @return array + */ + public function getOutput() + { + return $this->output; + } +} From fe04f75ccc9d8e6ba6a305cc8d7ff42bf31de59e Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 21 Mar 2022 21:36:37 -0500 Subject: [PATCH 822/888] MQE-3267: trim invalid utf-8 characters from response --- composer.json | 1 + composer.lock | 7 +++-- .../Module/MagentoWebDriver.php | 28 ++++++++++++++++++- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 9a7757c5d..8bc9aa988 100755 --- a/composer.json +++ b/composer.json @@ -15,6 +15,7 @@ "ext-intl": "*", "ext-json": "*", "ext-openssl": "*", + "ext-iconv": "*", "allure-framework/allure-codeception": "^1.4", "aws/aws-sdk-php": "^3.132", "codeception/codeception": "^4.1", diff --git a/composer.lock b/composer.lock index 8000882be..110b8530d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "35ff8c71326b9f8ab0885c8b55dd59cf", + "content-hash": "827f1612ae8476f99dae2541f722221c", "packages": [ { "name": "allure-framework/allure-codeception", @@ -7797,8 +7797,9 @@ "ext-dom": "*", "ext-intl": "*", "ext-json": "*", - "ext-openssl": "*" + "ext-openssl": "*", + "ext-iconv": "*" }, "platform-dev": [], - "plugin-api-version": "2.1.0" + "plugin-api-version": "2.2.0" } diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 68d2efd4b..84007099a 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -584,7 +584,8 @@ public function magentoCLI($command, $timeout = null, $arguments = null) $response = $executor->read(); $executor->close(); - return $response; + $response = trim($this->safeUtf8Conversion($response)); + return $response != "" ? $response : "CLI did not return output."; } /** @@ -1059,4 +1060,29 @@ public function pause($pauseOnFail = false) $this->codeceptPause(); } + + /** + * Return UTF-8 encoding string with control/invisible characters removed, return original string on error. + * + * @param string $input + * @return string + */ + private function safeUtf8Conversion(string $input): string + { + // Convert $input string to UTF-8 encoding + $convInput = iconv("ISO-8859-1", "UTF-8//IGNORE", $input); + if ($convInput !== false) { + // Remove invisible control characters, unused code points and replacement character + // so that they don't break xml test results for Allure + $cleanInput = preg_replace('/[^\PC\s]|\x{FFFD}/u', '', $convInput); + if ($cleanInput !== null) { + return $cleanInput; + } else { + $err = preg_last_error_msg(); + print("MagentoCLI response preg_replace() with error $err.\n"); + } + } + + return $input; + } } From 722c74f98c17b283ea8e1577e6a64c3fb9c87ade Mon Sep 17 00:00:00 2001 From: "Ashish.Kumar18" <ashish.kumar18@BLR1-LMC-N71378.local> Date: Tue, 29 Mar 2022 14:45:22 +0530 Subject: [PATCH 823/888] MQE-2903:Implement rapid times X clicks on UI element in MFTF --- .../Module/MagentoWebDriver.php | 15 ++++++++++ .../Test/etc/actionTypeTags.xsd | 28 +++++++++++++++++++ .../Util/TestGenerator.php | 8 ++++++ 3 files changed, 51 insertions(+) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 68d2efd4b..4bafbafa4 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -390,6 +390,21 @@ public function searchAndMultiSelectOption($select, array $options, $requireActi } } + /** + * Simple rapid click as per given count number. + * + * @param string $selector + * @param string $count + * @return void + * @throws \Exception + */ + public function rapidClick($selector, $count) + { + for ($i = 0; $i < $count; $i++) { + $this->click($selector); + } + } + /** * Select multiple options from a drop down using a filter and text field to narrow results. * diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/actionTypeTags.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/actionTypeTags.xsd index d68cf43db..1ce58001d 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/actionTypeTags.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/actionTypeTags.xsd @@ -34,6 +34,7 @@ <xs:element type="closeTabType" name="closeTab" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="commentType" name="comment" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="dragAndDropType" name="dragAndDrop" minOccurs="0" maxOccurs="unbounded"/> + <xs:element type="rapidClickType" name="rapidClick" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="executeJSType" name="executeJS" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="fillFieldType" name="fillField" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="loadSessionSnapshotType" name="loadSessionSnapshot" minOccurs="0" maxOccurs="unbounded"/> @@ -253,6 +254,33 @@ </xs:simpleContent> </xs:complexType> + <xs:complexType name="rapidClickType"> + <xs:annotation> + <xs:documentation> + Performs simple mouse rapid click as per given count. + </xs:documentation> + </xs:annotation> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute type="xs:string" name="selector" use="required"> + <xs:annotation> + <xs:documentation> + Selector for rapid click. + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute type="xs:string" name="count" use="required"> + <xs:annotation> + <xs:documentation> + Click count. + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attributeGroup ref="commonActionAttributes"/> + </xs:extension> + </xs:simpleContent> + </xs:complexType> + <xs:complexType name="dragAndDropType"> <xs:annotation> <xs:documentation> diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 5265b0102..bff24bf67 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1159,6 +1159,14 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $y ); break; + case "rapidClick": + $testSteps .= $this->wrapFunctionCall( + $actor, + $actionObject, + $selector, + $countValue + ); + break; case "selectMultipleOptions": $testSteps .= $this->wrapFunctionCall( $actor, From a3950a8d2d13a2228fa4549abad0016c0df49b3a Mon Sep 17 00:00:00 2001 From: GL-Ashish <92850316+GL-Ashish@users.noreply.github.com> Date: Tue, 29 Mar 2022 15:00:20 +0530 Subject: [PATCH 824/888] Update MagentoWebDriver.php --- .../FunctionalTestingFramework/Module/MagentoWebDriver.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 4bafbafa4..11ffa5fe9 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -393,8 +393,8 @@ public function searchAndMultiSelectOption($select, array $options, $requireActi /** * Simple rapid click as per given count number. * - * @param string $selector - * @param string $count + * @param string $selector + * @param string $count * @return void * @throws \Exception */ From e2769416418f663defa97ae48d77ec8f4433370f Mon Sep 17 00:00:00 2001 From: glo00108 <glo00108@adobe.com> Date: Wed, 30 Mar 2022 12:39:12 +0530 Subject: [PATCH 825/888] count groupname test --- .../Util/Manifest/BaseParallelTestManifest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/Manifest/BaseParallelTestManifest.php b/src/Magento/FunctionalTestingFramework/Util/Manifest/BaseParallelTestManifest.php index 0708d9e63..5f90e24e8 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Manifest/BaseParallelTestManifest.php +++ b/src/Magento/FunctionalTestingFramework/Util/Manifest/BaseParallelTestManifest.php @@ -94,7 +94,7 @@ public function generate() $this->generateGroupFile($groupContents, $groupNumber, $suites); } - $this->generateGroupSummaryFile($this->testCountsToGroup); + $this->generateGroupSummaryFile($this->testCountsToGroup); } /** @@ -124,9 +124,9 @@ protected function generateGroupFile($testGroup, $nodeNumber, $suites) $this->testCountsToGroup["group{$nodeNumber}"] = $this->testCountsToGroup["group{$nodeNumber}"] ?? 0; - $line = null; - if (!empty($suites[$entryName])) { + if (!empty($suites[$entryName])) { $line = "-g {$entryName}"; + $this->testCountsToGroup["group{$nodeNumber}"] += count($suites[$entryName]); } else { $line = $this->relativeDirPath . DIRECTORY_SEPARATOR . $entryName . '.php'; $this->testCountsToGroup["group{$nodeNumber}"]++; @@ -145,7 +145,7 @@ protected function generateGroupSummaryFile(array $groups) $fileResource = fopen($this->dirPath . DIRECTORY_SEPARATOR . "mftf_group_summary.txt", 'w'); $contents = "Total Number of Groups: " . count($groups) . PHP_EOL; foreach ($groups as $key => $value) { - $contents .= $key . " - ". $value . "tests" .PHP_EOL; + $contents .= $key . " - ". $value . " tests" .PHP_EOL; } fwrite($fileResource, $contents); fclose($fileResource); From eba018ddcb61a2b74e7b2b49471cf4a0914530a8 Mon Sep 17 00:00:00 2001 From: glo00108 <glo00108@adobe.com> Date: Wed, 30 Mar 2022 12:42:19 +0530 Subject: [PATCH 826/888] count groupname test --- .../Util/Manifest/BaseParallelTestManifest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/Manifest/BaseParallelTestManifest.php b/src/Magento/FunctionalTestingFramework/Util/Manifest/BaseParallelTestManifest.php index 5f90e24e8..1e9e1d109 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Manifest/BaseParallelTestManifest.php +++ b/src/Magento/FunctionalTestingFramework/Util/Manifest/BaseParallelTestManifest.php @@ -94,7 +94,7 @@ public function generate() $this->generateGroupFile($groupContents, $groupNumber, $suites); } - $this->generateGroupSummaryFile($this->testCountsToGroup); + $this->generateGroupSummaryFile($this->testCountsToGroup); } /** @@ -124,7 +124,7 @@ protected function generateGroupFile($testGroup, $nodeNumber, $suites) $this->testCountsToGroup["group{$nodeNumber}"] = $this->testCountsToGroup["group{$nodeNumber}"] ?? 0; - if (!empty($suites[$entryName])) { + if (!empty($suites[$entryName])) { $line = "-g {$entryName}"; $this->testCountsToGroup["group{$nodeNumber}"] += count($suites[$entryName]); } else { From 792a051e0cd89ddc48b5cd8223ec7f7e923c4fc4 Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Fri, 1 Apr 2022 11:44:39 -0500 Subject: [PATCH 827/888] MQE-3267: trim invalid utf-8 characters from response --- .../Module/Util/ModuleUtilTest.php | 48 +++++++++++++++++++ .../Module/MagentoWebDriver.php | 29 ++--------- .../Module/Util/ModuleUtils.php | 32 +++++++++++++ 3 files changed, 83 insertions(+), 26 deletions(-) create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/Module/Util/ModuleUtilTest.php create mode 100644 src/Magento/FunctionalTestingFramework/Module/Util/ModuleUtils.php diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Module/Util/ModuleUtilTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Module/Util/ModuleUtilTest.php new file mode 100644 index 000000000..dabf46fd0 --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Module/Util/ModuleUtilTest.php @@ -0,0 +1,48 @@ +<?php + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace tests\unit\Magento\FunctionalTestFramework\Module\Util; + +use Magento\FunctionalTestingFramework\Module\Util\ModuleUtils; +use PHPUnit\Framework\TestCase; + +class ModuleUtilTest extends TestCase +{ + /** + * Test utf8SafeControlCharacterTrim() + * + * @param string $input + * @param string $output + * @param string $removed + * + * @return void + * @dataProvider inDataProvider + */ + public function testUtf8SafeControlCharacterTrim(string $input, string $output, $removed): void + { + $util = new ModuleUtils(); + $this->assertStringContainsString($output, $util->utf8SafeControlCharacterTrim($input)); + $this->assertStringNotContainsString($removed, $util->utf8SafeControlCharacterTrim($input)); + } + + /** + * Data input. + * + * @return array + */ + public function inDataProvider(): array + { + $ctr1 = '‹'; + $ctr2 = 'Œ'; + $ctr3 = 'Œ ‹'; + return [ + ["some text $ctr1", 'some text', $ctr1], + ["some text $ctr2", 'some text', $ctr2], + ["some text $ctr3", 'some text', $ctr3] + ]; + } +} diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 84007099a..a7826f1da 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -21,6 +21,7 @@ use Magento\FunctionalTestingFramework\DataTransport\Auth\Tfa\OTP; use Magento\FunctionalTestingFramework\DataTransport\Protocol\CurlInterface; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; +use Magento\FunctionalTestingFramework\Module\Util\ModuleUtils; use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; use Magento\FunctionalTestingFramework\Util\ConfigSanitizerUtil; use Yandex\Allure\Adapter\AllureException; @@ -584,7 +585,8 @@ public function magentoCLI($command, $timeout = null, $arguments = null) $response = $executor->read(); $executor->close(); - $response = trim($this->safeUtf8Conversion($response)); + $util = new ModuleUtils(); + $response = trim($util->utf8SafeControlCharacterTrim($response)); return $response != "" ? $response : "CLI did not return output."; } @@ -1060,29 +1062,4 @@ public function pause($pauseOnFail = false) $this->codeceptPause(); } - - /** - * Return UTF-8 encoding string with control/invisible characters removed, return original string on error. - * - * @param string $input - * @return string - */ - private function safeUtf8Conversion(string $input): string - { - // Convert $input string to UTF-8 encoding - $convInput = iconv("ISO-8859-1", "UTF-8//IGNORE", $input); - if ($convInput !== false) { - // Remove invisible control characters, unused code points and replacement character - // so that they don't break xml test results for Allure - $cleanInput = preg_replace('/[^\PC\s]|\x{FFFD}/u', '', $convInput); - if ($cleanInput !== null) { - return $cleanInput; - } else { - $err = preg_last_error_msg(); - print("MagentoCLI response preg_replace() with error $err.\n"); - } - } - - return $input; - } } diff --git a/src/Magento/FunctionalTestingFramework/Module/Util/ModuleUtils.php b/src/Magento/FunctionalTestingFramework/Module/Util/ModuleUtils.php new file mode 100644 index 000000000..aa73ca7fc --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Module/Util/ModuleUtils.php @@ -0,0 +1,32 @@ +<?php + +namespace Magento\FunctionalTestingFramework\Module\Util; + +class ModuleUtils +{ + /** + * Module util function that returns UTF-8 encoding string with control/invisible characters removed, + * and it returns the original string when on error. + * + * @param string $input + * @return string + */ + public function utf8SafeControlCharacterTrim(string $input): string + { + // Convert $input string to UTF-8 encoding + $convInput = iconv("ISO-8859-1", "UTF-8//IGNORE", $input); + if ($convInput !== false) { + // Remove invisible control characters, unused code points and replacement character + // so that they don't break xml test results for Allure + $cleanInput = preg_replace('/[^\PC\s]|\x{FFFD}/u', '', $convInput); + if ($cleanInput !== null) { + return $cleanInput; + } else { + $err = preg_last_error_msg(); + print("MagentoCLI response preg_replace() with error $err.\n"); + } + } + + return $input; + } +} From e50871ee362a0d126fe59bc30f46fb68ca73f86b Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Fri, 1 Apr 2022 11:54:09 -0500 Subject: [PATCH 828/888] MQE-3267: trim invalid utf-8 characters from response --- .../FunctionalTestingFramework/Module/Util/ModuleUtils.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Magento/FunctionalTestingFramework/Module/Util/ModuleUtils.php b/src/Magento/FunctionalTestingFramework/Module/Util/ModuleUtils.php index aa73ca7fc..d9bc203c4 100644 --- a/src/Magento/FunctionalTestingFramework/Module/Util/ModuleUtils.php +++ b/src/Magento/FunctionalTestingFramework/Module/Util/ModuleUtils.php @@ -1,4 +1,8 @@ <?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ namespace Magento\FunctionalTestingFramework\Module\Util; From 4feed0052f29a03d6fcbe6d92d3539a80e355e01 Mon Sep 17 00:00:00 2001 From: GL-Ashish <92850316+GL-Ashish@users.noreply.github.com> Date: Thu, 7 Apr 2022 12:18:32 +0530 Subject: [PATCH 829/888] Update TestGenerator.php --- .../FunctionalTestingFramework/Util/TestGenerator.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index bff24bf67..1390321f1 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -773,6 +773,12 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $selector = $this->addUniquenessFunctionCall($customActionAttributes['selector']); $selector = $this->resolveLocatorFunctionInAttribute($selector); } + + if (isset($customActionAttributes['count'])) { + $countClickValue = $customActionAttributes['count']; + $countValue = $this->addUniquenessFunctionCall($countClickValue); + $countValue = $this->resolveLocatorFunctionInAttribute($countValue); + } if (isset($customActionAttributes['selector1']) || isset($customActionAttributes['filterSelector'])) { $selectorOneValue = $customActionAttributes['selector1'] ?? $customActionAttributes['filterSelector']; From 58b07574e7a9905f49de645a5ba8935256f1b98d Mon Sep 17 00:00:00 2001 From: "Ashish.Kumar18" <ashish.kumar18@BLR1-LMC-N71378.local> Date: Thu, 7 Apr 2022 16:49:17 +0530 Subject: [PATCH 830/888] Verification test added --- dev/tests/verification/Resources/DataActionsTest.txt | 2 +- dev/tests/verification/TestModule/Test/DataActionsTest.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/tests/verification/Resources/DataActionsTest.txt b/dev/tests/verification/Resources/DataActionsTest.txt index d59329e3b..982c680b2 100644 --- a/dev/tests/verification/Resources/DataActionsTest.txt +++ b/dev/tests/verification/Resources/DataActionsTest.txt @@ -58,7 +58,7 @@ class DataActionsTestCest $I->deleteEntity("createdInTest", "test"); // stepKey: deleteInTest $I->updateEntity("createdInBefore", "test", "entity",[]); // stepKey: updatedDataOutOfScope $I->deleteEntity("createdInBefore", "test"); // stepKey: deleteDataOutOfScope - $I->rapidClick("#general_locale_timezone", "50"); // stepKey: rapidClickTest + $I->rapidClick("#functionalTestSelector", "50"); // stepKey: rapidClickTest } public function _passed(AcceptanceTester $I) diff --git a/dev/tests/verification/TestModule/Test/DataActionsTest.xml b/dev/tests/verification/TestModule/Test/DataActionsTest.xml index e588a239e..6f36803ae 100644 --- a/dev/tests/verification/TestModule/Test/DataActionsTest.xml +++ b/dev/tests/verification/TestModule/Test/DataActionsTest.xml @@ -18,6 +18,6 @@ <deleteData createDataKey="createdInTest" stepKey="deleteInTest"/> <updateData entity="entity" createDataKey="createdInBefore" stepKey="updatedDataOutOfScope"/> <deleteData createDataKey="createdInBefore" stepKey="deleteDataOutOfScope"/> - <rapidClick selector="{{LocaleOptionsSection.timezone}}" count="50" stepKey="rapidClickTest"/> + <rapidClick selector="#functionalTestSelector" count="50" stepKey="rapidClickTest"/> </test> </tests> From 2196d3ee80b87b66f71bd12b7183e42391ba01a6 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Mon, 11 Apr 2022 20:47:50 +0530 Subject: [PATCH 831/888] 3.9.0-RC : 3.9.0 Change log, version bump to master --- CHANGELOG.md | 10 +++ composer.json | 2 +- composer.lock | 170 +++++++++++++++++++++++++------------------------- 3 files changed, 96 insertions(+), 86 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04999e2c5..a8287172a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ Magento Functional Testing Framework Changelog ================================================ +3.9.0 +--------- + +### Fixes: +* Fix for invalid UTF-8 chars returned from magentoCLI breaks Allure reporting + +### GitHub Pull Requests: +* [#175](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/175) -- Fixed invalid UTF-8 chars returned from magentoCLI that breaks allure reporting + + 3.8.0 --------- diff --git a/composer.json b/composer.json index 8bc9aa988..69a974db8 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "3.8.0", + "version": "3.9.0", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index 110b8530d..cc5694857 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "827f1612ae8476f99dae2541f722221c", + "content-hash": "40786b066af41372e12e5af07aeeaf0b", "packages": [ { "name": "allure-framework/allure-codeception", @@ -230,12 +230,12 @@ } }, "autoload": { - "psr-4": { - "Aws\\": "src/" - }, "files": [ "src/functions.php" - ] + ], + "psr-4": { + "Aws\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -298,12 +298,12 @@ }, "type": "library", "autoload": { - "psr-4": { - "Assert\\": "lib/Assert" - }, "files": [ "lib/Assert/functions.php" - ] + ], + "psr-4": { + "Assert\\": "lib/Assert" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -1640,12 +1640,12 @@ } }, "autoload": { - "psr-4": { - "GuzzleHttp\\": "src/" - }, "files": [ "src/functions_include.php" - ] + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -1747,12 +1747,12 @@ } }, "autoload": { - "psr-4": { - "GuzzleHttp\\Promise\\": "src/" - }, "files": [ "src/functions_include.php" - ] + ], + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -1840,12 +1840,12 @@ } }, "autoload": { - "psr-4": { - "GuzzleHttp\\Psr7\\": "src/" - }, "files": [ "src/functions_include.php" - ] + ], + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2272,12 +2272,12 @@ } }, "autoload": { - "psr-4": { - "JmesPath\\": "src/" - }, "files": [ "src/JmesPath.php" - ] + ], + "psr-4": { + "JmesPath\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2378,12 +2378,12 @@ }, "type": "library", "autoload": { - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - }, "files": [ "src/DeepCopy/deep_copy.php" - ] + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2682,12 +2682,12 @@ }, "type": "library", "autoload": { - "psr-4": { - "Facebook\\WebDriver\\": "lib/" - }, "files": [ "lib/Exception/TimeoutException.php" - ] + ], + "psr-4": { + "Facebook\\WebDriver\\": "lib/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3363,11 +3363,11 @@ } }, "autoload": { - "classmap": [ - "src/" - ], "files": [ "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -3899,12 +3899,12 @@ } }, "autoload": { - "psr-4": { - "Ramsey\\Uuid\\": "src/" - }, "files": [ "src/functions.php" - ] + ], + "psr-4": { + "Ramsey\\Uuid\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3954,12 +3954,12 @@ }, "type": "library", "autoload": { - "psr-4": { - "React\\Promise\\": "src/" - }, "files": [ "src/functions_include.php" - ] + ], + "psr-4": { + "React\\Promise\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -5900,12 +5900,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -5981,12 +5981,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Intl\\Idn\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -6066,12 +6066,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Intl\\Normalizer\\": "" - }, "files": [ "bootstrap.php" ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, "classmap": [ "Resources/stubs" ] @@ -6150,12 +6150,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -6227,12 +6227,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php72\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -6303,12 +6303,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php73\\": "" - }, "files": [ "bootstrap.php" ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, "classmap": [ "Resources/stubs" ] @@ -6382,12 +6382,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" - }, "files": [ "bootstrap.php" ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, "classmap": [ "Resources/stubs" ] @@ -6465,12 +6465,12 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php81\\": "" - }, "files": [ "bootstrap.php" ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, "classmap": [ "Resources/stubs" ] @@ -6761,13 +6761,6 @@ } }, "autoload": { - "psr-4": { - "Safe\\": [ - "lib/", - "deprecated/", - "generated/" - ] - }, "files": [ "deprecated/apc.php", "deprecated/libevent.php", @@ -6858,7 +6851,14 @@ "generated/yaz.php", "generated/zip.php", "generated/zlib.php" - ] + ], + "psr-4": { + "Safe\\": [ + "lib/", + "deprecated/", + "generated/" + ] + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -7066,12 +7066,12 @@ } }, "autoload": { - "psr-4": { - "BrainMaestro\\GitHooks\\": "src/" - }, "files": [ "src/helpers.php" - ] + ], + "psr-4": { + "BrainMaestro\\GitHooks\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -7801,5 +7801,5 @@ "ext-iconv": "*" }, "platform-dev": [], - "plugin-api-version": "2.2.0" + "plugin-api-version": "2.1.0" } From d4ae664ea11ddfa8e39e51ae5db9aa8461c5ee6c Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Tue, 12 Apr 2022 14:31:30 +0530 Subject: [PATCH 832/888] Added PRS that has to get merged with master --- CHANGELOG.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a8287172a..53eeaeff9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,20 @@ Magento Functional Testing Framework Changelog ### GitHub Pull Requests: * [#175](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/175) -- Fixed invalid UTF-8 chars returned from magentoCLI that breaks allure reporting - +* [#172](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/172) -- MQE-2342 : Provide MFTF group summary file +* [#173](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/173) -- MQE-2328 : Detect unused entities +* [#164](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/164) -- MQE-1693 | Ability To Run MFTF JSON Configuration From File +* [#171](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/171) --MQE-2088 : Test generation error on invalid entities +* [#161](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/161) --MQE-3228: Update MFTF to not pass NULL into non-nullable arguments +* [#162](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/162) --MQE-2668: Some MFTF tests fail without access to S3 +* [#159](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/159) --MQE-1677 : Static check for created data outside action group +* [#168](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/168) -- Deleted docs/img/issue.png , docs/img/pull-request.png ,docs/img/switching-the-base.png and docs/img/trouble-chrome232.png files +* [#157](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/157) -- MQE-2021 : Added new attribute unique +* [#156](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/156) -- MQE-3205: Set proper weight for action <startMessageQueue> for config parallel generation +* [#152](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/152) -- MQE-1545: Test before/after comments in test/allure +* [#154](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/154) -- MQE-1190: Do not truncate parameters when using MFTF run:test +* [#142](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/142) -- MQE-3092 throw error message if key value pair is not mapped properly in .credentials file +* [#144](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/144) -- MQE-1794 : Removed Parameters from allure report 3.8.0 --------- From ac5b5cfe2a608170256413dc1cb584835fecc1d2 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Tue, 12 Apr 2022 14:44:44 +0530 Subject: [PATCH 833/888] Added PRS that has to get merged with master --- CHANGELOG.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53eeaeff9..d801e5f8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,9 +3,6 @@ Magento Functional Testing Framework Changelog 3.9.0 --------- -### Fixes: -* Fix for invalid UTF-8 chars returned from magentoCLI breaks Allure reporting - ### GitHub Pull Requests: * [#175](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/175) -- Fixed invalid UTF-8 chars returned from magentoCLI that breaks allure reporting * [#172](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/172) -- MQE-2342 : Provide MFTF group summary file From 4fc4334f2a354b3ced627c73bd344b6010be1035 Mon Sep 17 00:00:00 2001 From: "Ashish.Kumar18" <ashish.kumar18@BLR1-LMC-N71378.local> Date: Tue, 12 Apr 2022 17:45:02 +0530 Subject: [PATCH 834/888] MQE-2903: rapidClick doc added in actions.md --- docs/test/actions.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/docs/test/actions.md b/docs/test/actions.md index 373a44ee0..993a9ff84 100644 --- a/docs/test/actions.md +++ b/docs/test/actions.md @@ -973,6 +973,25 @@ Attribute|Type|Use|Description <dragAndDrop selector1="#block1" selector2="#block2" x="50" y="50" stepKey="dragAndDrop"/> ``` +### rapidClick + +See [rapidClick docs on codeception.com](http://codeception.com/docs/modules/WebDriver#rapidClick). + +| Attribute | Type | Use | Description | +|------------|--------|----------|-------------------------------------------------| +| `selector` | string | optional | A selector for the HTML element to rapid click. | +| `count` | string | required | Click count. | +| `stepKey` | string | required | A unique identifier of the action. | +| `before` | string | optional | `stepKey` of action that must be executed next. | +| `after` | string | optional | `stepKey` of preceding action. | + +#### Examples + +```xml +<!-- Rapid click the selected element as per given count number --> +<rapidClick selector="#selector" count="50" stepKey="rapidClick"/> +``` + ### executeJS See [executeJS docs on codeception.com](http://codeception.com/docs/modules/WebDriver#executeJS). @@ -1077,7 +1096,7 @@ This action can optionally contain one or more [requiredEntity](#requiredentity) ### getOTP Generate a one-time password (OTP) based on a saved `secret` at path `magento/tfa/OTP_SHARED_SECRET` in a MFTF credential storage. -The one-time password (OTP) is returned and accessible through the stepkey. +The one-time password (OTP) is returned and accessible through the stepkey. MFTF use TOTP from [Spomky-Labs/otphp](https://github.com/Spomky-Labs/otphp), if you want to learn more about this action. From 0b414d0dce5d56c0c531d5c26ba200c38d2e55ee Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Wed, 13 Apr 2022 11:03:07 +0530 Subject: [PATCH 835/888] Categorized the commits into Enhancements and Fixes --- CHANGELOG.md | 112 ++++++++++++++++++++++++++------------------------- 1 file changed, 58 insertions(+), 54 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d801e5f8a..e634dabb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,22 +3,26 @@ Magento Functional Testing Framework Changelog 3.9.0 --------- -### GitHub Pull Requests: -* [#175](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/175) -- Fixed invalid UTF-8 chars returned from magentoCLI that breaks allure reporting -* [#172](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/172) -- MQE-2342 : Provide MFTF group summary file -* [#173](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/173) -- MQE-2328 : Detect unused entities -* [#164](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/164) -- MQE-1693 | Ability To Run MFTF JSON Configuration From File -* [#171](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/171) --MQE-2088 : Test generation error on invalid entities -* [#161](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/161) --MQE-3228: Update MFTF to not pass NULL into non-nullable arguments -* [#162](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/162) --MQE-2668: Some MFTF tests fail without access to S3 -* [#159](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/159) --MQE-1677 : Static check for created data outside action group -* [#168](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/168) -- Deleted docs/img/issue.png , docs/img/pull-request.png ,docs/img/switching-the-base.png and docs/img/trouble-chrome232.png files -* [#157](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/157) -- MQE-2021 : Added new attribute unique -* [#156](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/156) -- MQE-3205: Set proper weight for action <startMessageQueue> for config parallel generation -* [#152](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/152) -- MQE-1545: Test before/after comments in test/allure -* [#154](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/154) -- MQE-1190: Do not truncate parameters when using MFTF run:test -* [#142](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/142) -- MQE-3092 throw error message if key value pair is not mapped properly in .credentials file -* [#144](https://github.com/magento-commerce/magento2-functional-testing-framework/pull/144) -- MQE-1794 : Removed Parameters from allure report +### Fixes + +* Fixed invalid UTF-8 chars returned from magentoCLI that breaks allure reporting +* Fixed MFTF tests failure without access to S3 + + +### Enhancements +* MFTF group summary file +* Static check to detect unused entities +* Ability To Run MFTF JSON Configuration From File +* Test generation error on invalid entities +* Update MFTF to not pass NULL into non-nullable arguments +* Static check for created data outside action group +* Deleted the unused images +* CreateData's <field> to allow uniqueness attribute +* Set proper weight for action <startMessageQueue> for config parallel generation +* Test before/after comments in test/allure +* Removed truncation of parameters on running MFTF run:test +* Throw error message if key value pair is not mapped properly in .credentials file +* Removed sub heading Parameters from allure report 3.8.0 --------- @@ -90,7 +94,7 @@ Magento Functional Testing Framework Changelog * [#870](https://github.com/magento/magento2-functional-testing-framework/pull/870) -- Removing the csharpru/vault-php-guzzle6-transport not needed dependency * [#871](https://github.com/magento/magento2-functional-testing-framework/pull/871) -- Changed loose comparisons into strict * [#872](https://github.com/magento/magento2-functional-testing-framework/pull/872) -- Fix broken MFTF tests - + 3.6.1 --------- @@ -106,7 +110,7 @@ Magento Functional Testing Framework Changelog * Maintainability * Updated composer dependencies to be PHP 8 compatible with the except of codeception/aspect-mock. - + ### GitHub Pull Requests: * [#830](https://github.com/magento/magento2-functional-testing-framework/pull/830) -- Add ability to configure multiple OTPs @@ -130,7 +134,7 @@ Magento Functional Testing Framework Changelog ### Enhancements * Customizability - * Added new `config:parallel --groups` option in `generate:tests` command to generate and split tests/suites into required number of execution time balanced groups. + * Added new `config:parallel --groups` option in `generate:tests` command to generate and split tests/suites into required number of execution time balanced groups. ### Fixes @@ -149,7 +153,7 @@ Magento Functional Testing Framework Changelog * Maintainability * Added support for composer 2. - + 3.3.0 --------- @@ -157,11 +161,11 @@ Magento Functional Testing Framework Changelog * Usability * [#817](https://github.com/magento/magento2-functional-testing-framework/pull/817) -- Add support for admin WebAPI token refresh. - + * Maintainability * [#814](https://github.com/magento/magento2-functional-testing-framework/pull/814) -- Update dependencies in order to make mftf php8 compatible, fix running phpcpd - * [#815](https://github.com/magento/magento2-functional-testing-framework/pull/815) -- Upgrade csharpru/vault-php to 4.1 - + * [#815](https://github.com/magento/magento2-functional-testing-framework/pull/815) -- Upgrade csharpru/vault-php to 4.1 + ### Fixes * Fixed test generation error in a split suite group (--config=parallel) to allow generation of subsequent groups. @@ -187,8 +191,8 @@ Magento Functional Testing Framework Changelog * Usability * Introduced error tolerance during test and suite generation. See the [command page](./docs/commands/mftf.md#error-tolerance-during-generation) for details. Addressed github issue [#276](https://github.com/magento/magento2-functional-testing-framework/issues/276). - -* Maintainability + +* Maintainability * Updated annotation static-check to check all required annotations. ### Fixes @@ -203,7 +207,7 @@ Magento Functional Testing Framework Changelog * Removed `travis.yml` and replaced with `.github/workflows/main.yml` ### Fixes -Fixed issue with XPath locators for waits in MagentoPwaWebDriver. +Fixed issue with XPath locators for waits in MagentoPwaWebDriver. 3.1.0 --------- @@ -217,13 +221,13 @@ Fixed issue with XPath locators for waits in MagentoPwaWebDriver. * Usability * Introduced new action `pause`, to invoke codeception interactive pause for debugging during test execution. See the [Interactive Pause](./docs/interactive-pause.md) page for details. * Introduced a new `.env` configuration option `ENABLE_PAUSE`, to enable the new pause feature. - -* Maintainability + +* Maintainability * Added a new static check that checks for the usage of the `pause` action. See the [command page](./docs/commands/mftf.md#static-checks) for details. - -* Modularity + +* Modularity * MFTF now supports the use of actions from multiple modules within suites. - + * Traceability * A deprecation notice is now added at test execution time for deprecated metadata usage. @@ -239,7 +243,7 @@ Fixed issue with XPath locators for waits in MagentoPwaWebDriver. * [#683](https://github.com/magento/magento2-functional-testing-framework/pull/683) -- Docs: Renamed sample test name with the correct one * [#691](https://github.com/magento/magento2-functional-testing-framework/pull/691) -- Docs: Branch name updates * [#678](https://github.com/magento/magento2-functional-testing-framework/pull/678) -- Docs: Command added to modify the web server rewrites configuration - * [#745](https://github.com/magento/magento2-functional-testing-framework/pull/745) -- Docs: Remove invalid sample test name + * [#745](https://github.com/magento/magento2-functional-testing-framework/pull/745) -- Docs: Remove invalid sample test name 3.0.0 --------- @@ -250,22 +254,22 @@ Fixed issue with XPath locators for waits in MagentoPwaWebDriver. * Introduced MFTF helpers `<helper>` to create custom actions outside of MFTF.[See custom-helpers page for details](./docs/custom-helpers.md) * Removed deprecated actions `<executeSelenium>` and `<performOn>`. * `<group value="skip"/>` no longer skips a test. Instead, the test is added to the `skip` group. - + * Maintainability * Added support for PHP 7.4. * Added support for PHPUnit 9. * Dropped support for PHP 7.0, 7.1, 7.2. * Schema updates for test entities to only allow single entity per file except Data and Metadata. * Support for sub-folders in test modules. - * Removed support to read test entities from `<magento>dev/tests/acceptance/tests/functional/Magento/FunctionalTest`. + * Removed support to read test entities from `<magento>dev/tests/acceptance/tests/functional/Magento/FunctionalTest`. * Removed file attribute for `<module>` in suiteSchema. * Removed action `pauseExecution` and added `pause`. [See actions page for details](./docs/test/actions.md#pause) - * Removed action `formatMoney` and added `formatCurrency`. [See actions page for details](./docs/test/actions.md#formatcurrency) - * Improved assertion actions to support PHPUnit 9 changes. [See assertions page for details](./docs/test/assertions.md) + * Removed action `formatMoney` and added `formatCurrency`. [See actions page for details](./docs/test/actions.md#formatcurrency) + * Improved assertion actions to support PHPUnit 9 changes. [See assertions page for details](./docs/test/assertions.md) * Added new actions: `assertEqualsWithDelta`, `assertNotEqualsWithDelta`, `assertEqualsCanonicalizing`, `assertNotEqualsCanonicalizing`, `assertEqualsIgnoringCase`, `assertNotEqualsIgnoringCase`. * Added new actions: `assertStringContainsString`, `assertStringNotContainsString`, `assertStringContainsStringIgnoringCase`, `assertStringNotContainsStringIgnoringCase` for string haystacks. * Removed actions: `assertInternalType`, `assertNotInternalType`, `assertArraySubset`. - * Removed delta option from `assertEquals` and `assertNotEquals`. + * Removed delta option from `assertEquals` and `assertNotEquals`. * Added static check `deprecatedEntityUsage` that checks and reports references to deprecated test entities. * Added static check `annotations` that checks and reports missing annotations in tests. * Updated `bin/mftf static-checks` command to allow executing static-checks defined in `staticRuleSet.json` by default. [See command page for details](./docs/commands/mftf.md#static-checks) @@ -274,19 +278,19 @@ Fixed issue with XPath locators for waits in MagentoPwaWebDriver. * `mftf.log` no longer includes notices and warnings at test execution time. * Added unhandledPromptBehavior driver capability for Chrome 75+ support. * Added the Chrome option `--ignore-certificate-errors` to `functional.suite.dist.yml`. - + * Traceability * Removed `--debug` option `NONE` to disallow ability to turn off schema validation. * Notices added for test entity naming convention violations. * Metadata file names changed to `*Meta.xml`. - * Introduced new `.env` configuration `VERBOSE_ARTIFACTS` to toggle saving attachments in Allure. [See configuration page for details](./docs/configuration.md) + * Introduced new `.env` configuration `VERBOSE_ARTIFACTS` to toggle saving attachments in Allure. [See configuration page for details](./docs/configuration.md) * Changed the `bin/mftf static-checks` error file directory from the current working directory to `TESTS_BP/tests/_output/static-results/`. - + * Readability - * Support only nested assertion syntax [See assertions page for details](./docs/test/assertions.md). + * Support only nested assertion syntax [See assertions page for details](./docs/test/assertions.md). * Documented [3.0.0 Backward Incompatible Changes](./docs/backward-incompatible-changes.md). - * Removed blacklist/whitelist terminology in MFTF. - + * Removed blacklist/whitelist terminology in MFTF. + * Upgrade scripts added to upgrade tests to MFTF major version requirements. See upgrade instructions below. * Bumped dependencies to support PHP/PHPUnit upgrade. @@ -374,7 +378,7 @@ Fixed issue with XPath locators for waits in MagentoPwaWebDriver. * Page * Section * Section Element - * See DevDocs for details + * See DevDocs for details * Improved `mftf static-checks` command to allow executing all or specific static checks. * Added a new static check that checks and reports unused arguments in action groups. * Customizability @@ -426,12 +430,12 @@ Fixed issue with XPath locators for waits in MagentoPwaWebDriver. ----- * Traceability - * Allure report enhanced to display file path of tests. + * Allure report enhanced to display file path of tests. * Maintainability * Added support to read MFTF test entities from `<magento>dev/tests/acceptance/tests/functional/<vendor_name>/<module_name>/*` * Removed path deprecation warning from `ModuleResolver`. * Refactored problem methods to reduce cyclomatic complexity. - + ### Fixes * Fixed issue with builds due to absence of AcceptanceTester class. @@ -498,7 +502,7 @@ Fixed issue with XPath locators for waits in MagentoPwaWebDriver. * Customizability * Use of `_CREDS` has been extended to `<magentoCLI>` and `<createData>` actions * Traceability - * A Test step is now generated and injected in the allure report when a test is reported as `BROKEN`. + * A Test step is now generated and injected in the allure report when a test is reported as `BROKEN`. ### Fixes * `static-checks` command now properly returns `1` if any static check failed. @@ -600,7 +604,7 @@ Fixed issue with XPath locators for waits in MagentoPwaWebDriver. ### Enhancements * Maintainability * Added new `mftf run:failed` commands, which reruns all failed tests from last run configuration. - + ### Fixes * Fixed an issue where mftf would fail to parse test materials for extensions installed under `vendor`. * Fixed a Windows compatibility issue around the use of Magento's `ComponentRegistrar` to aggregate paths. @@ -689,15 +693,15 @@ Fixed issue with XPath locators for waits in MagentoPwaWebDriver. 2.3.1 ----- -### Enhancements +### Enhancements * Maintainability * `mftf build:project` now copies over the `command.php` file into the parent Magento installation, if detected. 2.3.0 ----- -### Enhancements +### Enhancements * Traceability - * MFTF now outputs generation run-time information, warnings, and errors to an `mftf.log` file. + * MFTF now outputs generation run-time information, warnings, and errors to an `mftf.log` file. * Overall error messages for various generation errors have been improved. Usage of the `--debug` flag provides file-specific errors for all XML-related errors. * Allure Reports now require a unique `story` and `title` combination, to prevent collisions in Allure Report generation. * The `features` annotation now ignores user input and defaults to the module the test lives under (for clear Allure organization). @@ -748,7 +752,7 @@ Fixed issue with XPath locators for waits in MagentoPwaWebDriver. 2.2.0 ----- -### Enhancements +### Enhancements * Traceability * Javascript errors are now logged and reported in test output. * Test failures are no longer overwritten by failures in an `<after>` hook. @@ -825,7 +829,7 @@ Fixed issue with XPath locators for waits in MagentoPwaWebDriver. ----- ### Enhancements * Traceability - * Severity in `<annotation>` tags now properly reflect Magento severity values. + * Severity in `<annotation>` tags now properly reflect Magento severity values. * Modularity * Added ability to pass in simple values to actionGroups via addition of `type` attribute in actionGroup `<argument>` declaration. * For examples, see devdocs article on actionGroups. @@ -861,7 +865,7 @@ Fixed issue with XPath locators for waits in MagentoPwaWebDriver. * Added the ability to refer to `custom_attribute` data in persisted entities via `key` instead of index. * ex. `url_key` in category entity: `$category.custom_attributes[3][value]$` and `$category.custom_attributes[url_key]$` are both valid. * Maintainability - * Added check for duplicate `stepKey` attributes at test generation. This check is scoped to `<testAction>` tags within a single `<test>` tag in a single file. + * Added check for duplicate `stepKey` attributes at test generation. This check is scoped to `<testAction>` tags within a single `<test>` tag in a single file. ### Fixes * Fixed inability to use `<actionGroup>` with `<arguments>` in test hooks. From ef6634496be1c6cd44d941e23ff8adc07377f27a Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Wed, 13 Apr 2022 11:30:09 +0530 Subject: [PATCH 836/888] moved few data in enhancements to fixes --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e634dabb7..e9b3822aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ Magento Functional Testing Framework Changelog * Fixed invalid UTF-8 chars returned from magentoCLI that breaks allure reporting * Fixed MFTF tests failure without access to S3 +* Removed sub heading Parameters from allure report +* Removed truncation of parameters on running MFTF run:test ### Enhancements @@ -20,9 +22,7 @@ Magento Functional Testing Framework Changelog * CreateData's <field> to allow uniqueness attribute * Set proper weight for action <startMessageQueue> for config parallel generation * Test before/after comments in test/allure -* Removed truncation of parameters on running MFTF run:test * Throw error message if key value pair is not mapped properly in .credentials file -* Removed sub heading Parameters from allure report 3.8.0 --------- From 88ddb9e896c7443395f602e06adcca2b7c24ddd4 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Wed, 13 Apr 2022 11:31:01 +0530 Subject: [PATCH 837/888] moved few data in enhancements to fixes --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9b3822aa..9688654fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,6 @@ Magento Functional Testing Framework Changelog * Removed sub heading Parameters from allure report * Removed truncation of parameters on running MFTF run:test - ### Enhancements * MFTF group summary file * Static check to detect unused entities From 0faa3a011bf420bb1112ab28dbe0e7b305f03c9f Mon Sep 17 00:00:00 2001 From: Shashi Kumar Singh <92144509+glo00108@users.noreply.github.com> Date: Wed, 20 Apr 2022 22:29:55 +0530 Subject: [PATCH 838/888] MQE-2964 Log MFTF test dependencies (#166) * MQE-2964 Log MFTF test dependencies * MQE-2964 Log MFTF test dependencies * MQE-2964 fix static check test dependecies * MQE-2964 fix static check test dependecies * MQE-2964 fix static check test dependecies * new test depencyutil file created * else case added for testEntityJson * update doc for parameters Co-authored-by: Kevin Kozan <kkozan@adobe.com> --- .../Console/GenerateTestsCommandTest.php | 1 + docs/commands/mftf.md | 37 ++- .../Console/GenerateTestsCommand.php | 250 ++++++++++++++++++ .../StaticCheck/TestDependencyCheck.php | 158 ++--------- .../Util/Script/ScriptUtil.php | 32 ++- .../Util/Script/TestDependencyUtil.php | 184 +++++++++++++ 6 files changed, 512 insertions(+), 150 deletions(-) create mode 100644 src/Magento/FunctionalTestingFramework/Util/Script/TestDependencyUtil.php diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Console/GenerateTestsCommandTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Console/GenerateTestsCommandTest.php index 40a96e774..715031c53 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Console/GenerateTestsCommandTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Console/GenerateTestsCommandTest.php @@ -17,6 +17,7 @@ class GenerateTestsCommandTest extends TestCase * @param mixed $expected * @return void * @dataProvider configParallelOptions + * @throws \ReflectionException */ public function testParseConfigParallelOptions($time, $groups, $expected): void { diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 6992189a4..be026cd74 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -65,6 +65,20 @@ suiteName:testInSuite vendor/bin/mftf generate:tests WYSIWYGDisabledSuite:AdminCMSPageCreatePageTest ``` +### Generate test dependencies + +```bash +vendor/bin/mftf generate:tests -l testEntityJson +``` + +This command generate json file consist of all test dependent module. + +### Generate test dependencies by test name + +```bash +vendor/bin/mftf generate:tests testName1 testName2 .. testNameN -l testEntityJson +``` + ### Generate and run the tests for a specified group ```bash @@ -183,17 +197,18 @@ vendor/bin/mftf generate:tests [option] [<test name>] [<test name>] [--remove] #### Options -| Option | Description| -| ---| --- | -| `--config=[<default> or <singleRun> or <parallel>]` | Creates a single manifest file with a list of all tests. The default location is `tests/functional/Magento/FunctionalTest/_generated/testManifest.txt`.<br/> You can split the list into multiple groups using `--config=parallel`; the groups will be generated in `_generated/groups/` like `_generated/groups/group1.txt, group2.txt, ...`.<br/> Available values: `default` (default), `singleRun`(same as `default`), and `parallel`.<br/> Example: `generate:tests --config=parallel`. | -| `--filter` | Option to filter tests to be generated.<br/>Template: '<filterName>:<filterValue>'.<br/>Existing filter types: severity, includeGroup, excludeGroup.<br/>Existing severity values: BLOCKER, CRITICAL, MAJOR, AVERAGE, MINOR.<br/>Example: `vendor/bin/mftf generate:tests --filter=severity:CRITICAL --filter=severity:BLOCKER --filter=includeGroup:customer`| -| `--force` | Forces test generation, regardless of the module merge order defined in the Magento instance. Example: `generate:tests --force`. | -| `-i,--time` | Set time in minutes to determine the group size when `--config=parallel` is used. <br/>Example: `generate:tests --config=parallel --time=15` <br/>Option `--time` will be the default and the __default value__ is `10` when neither `--time` nor `--groups` is specified. <br/>Example: `generate:tests --config=parallel`| -| `-g,--groups` | Set number of groups to be split into when `--config=parallel` is used. <br>Example: `generate:tests --config=parallel --groups=300` <br/>Options `--time` and `--groups` are mutually exclusive and only one should be used.| -| `--tests` | Defines the test configuration as a JSON string or JSON file path.| -| `--allow-skipped` | Allows MFTF to generate and run tests marked with `<skip>.`| -| `--debug` | Performs schema validations on XML files. <br/> DEFAULT: `generate:tests` implicitly performs schema validation on merged files. It does not indicate the file name where the error is encountered. <br/> DEVELOPER: `--debug` performs per-file validation and returns additional debug information (such as the filename where an error occurred) when test generation fails because of an invalid XML schema. This option takes extra processing time. Use it after test generation has failed once.<br/>| -| `-r,--remove`| Removes the existing generated suites and tests cleaning up the `_generated` directory before the actual run. For example, `generate:tests SampleTest --remove` cleans up the entire `_generated` directory and generates `SampleTest` only.| +| Option | Description | +|-----------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `--config=[<default> or <singleRun> or <parallel>]` | Creates a single manifest file with a list of all tests. The default location is `tests/functional/Magento/FunctionalTest/_generated/testManifest.txt`.<br/> You can split the list into multiple groups using `--config=parallel`; the groups will be generated in `_generated/groups/` like `_generated/groups/group1.txt, group2.txt, ...`.<br/> Available values: `default` (default), `singleRun`(same as `default`), and `parallel`.<br/> Example: `generate:tests --config=parallel`. | +| `--filter` | Option to filter tests to be generated.<br/>Template: '<filterName>:<filterValue>'.<br/>Existing filter types: severity, includeGroup, excludeGroup.<br/>Existing severity values: BLOCKER, CRITICAL, MAJOR, AVERAGE, MINOR.<br/>Example: `vendor/bin/mftf generate:tests --filter=severity:CRITICAL --filter=severity:BLOCKER --filter=includeGroup:customer` | +| `--force` | Forces test generation, regardless of the module merge order defined in the Magento instance. Example: `generate:tests --force`. | +| `-i,--time` | Set time in minutes to determine the group size when `--config=parallel` is used. <br/>Example: `generate:tests --config=parallel --time=15` <br/>Option `--time` will be the default and the __default value__ is `10` when neither `--time` nor `--groups` is specified. <br/>Example: `generate:tests --config=parallel` | +| `-g,--groups` | Set number of groups to be split into when `--config=parallel` is used. <br>Example: `generate:tests --config=parallel --groups=300` <br/>Options `--time` and `--groups` are mutually exclusive and only one should be used. | +| `--tests` | Defines the test configuration as a JSON string or JSON file path. | +| `--allow-skipped` | Allows MFTF to generate and run tests marked with `<skip>.` | +| `--debug` | Performs schema validations on XML files. <br/> DEFAULT: `generate:tests` implicitly performs schema validation on merged files. It does not indicate the file name where the error is encountered. <br/> DEVELOPER: `--debug` performs per-file validation and returns additional debug information (such as the filename where an error occurred) when test generation fails because of an invalid XML schema. This option takes extra processing time. Use it after test generation has failed once.<br/> | +| `-r,--remove` | Removes the existing generated suites and tests cleaning up the `_generated` directory before the actual run. For example, `generate:tests SampleTest --remove` cleans up the entire `_generated` directory and generates `SampleTest` only. | +| `-l,--log` | Generate metadata files during test generation. Accepted parameters are: testEntityJson. | #### Examples of the JSON configuration diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php index 2bb5b8091..dc5e18f75 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestsCommand.php @@ -11,18 +11,23 @@ use Magento\FunctionalTestingFramework\Exceptions\FastFailException; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; +use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Suite\SuiteGenerator; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; +use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; use Magento\FunctionalTestingFramework\Util\Manifest\ParallelByTimeTestManifest; use Magento\FunctionalTestingFramework\Util\Manifest\TestManifestFactory; +use Magento\FunctionalTestingFramework\Util\Script\ScriptUtil; +use Magento\FunctionalTestingFramework\Util\Script\TestDependencyUtil; use Magento\FunctionalTestingFramework\Util\TestGenerator; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\Finder\Finder; /** * @SuppressWarnings(PHPMD) @@ -30,6 +35,34 @@ class GenerateTestsCommand extends BaseGenerateCommand { const PARALLEL_DEFAULT_TIME = 10; + const EXTENDS_REGEX_PATTERN = '/extends=["\']([^\'"]*)/'; + const ACTIONGROUP_REGEX_PATTERN = '/ref=["\']([^\'"]*)/'; + const TEST_DEPENDENCY_FILE_LOCATION = 'dev/tests/_output/test-dependencies.json'; + + /** + * @var ScriptUtil + */ + private $scriptUtil; + + /** + * @var TestDependencyUtil + */ + private $testDependencyUtil; + + /** + * @var array + */ + private $moduleNameToPath; + + /** + * @var array + */ + private $moduleNameToComposerName; + + /** + * @var array + */ + private $flattenedDependencies; /** * Configures the current command. @@ -85,6 +118,11 @@ protected function configure() 'p', InputOption::VALUE_REQUIRED, 'path to a test names file.', + )->addOption( + 'log', + 'l', + InputOption::VALUE_REQUIRED, + 'Generate metadata files during test generation.', ); parent::configure(); @@ -98,6 +136,7 @@ protected function configure() * @return void|integer * @throws TestFrameworkException * @throws FastFailException + * @throws XmlException */ protected function execute(InputInterface $input, OutputInterface $output) { @@ -113,16 +152,19 @@ protected function execute(InputInterface $input, OutputInterface $output) $remove = $input->getOption('remove'); $verbose = $output->isVerbose(); $allowSkipped = $input->getOption('allow-skipped'); + $log = $input->getOption('log'); $filters = $input->getOption('filter'); foreach ($filters as $filter) { list($filterType, $filterValue) = explode(':', $filter); $filterList[$filterType][] = $filterValue; } + $path = $input->getOption('path'); // check filepath is given for generate test file if (!empty($path)) { $tests = $this->generateTestFileFromPath($path); } + // Set application configuration so we can references the user options in our framework try { MftfApplicationConfig::create( @@ -204,6 +246,20 @@ protected function execute(InputInterface $input, OutputInterface $output) return 1; } + // check test dependencies log command + if (!empty($log)) { + if ($log === "testEntityJson") { + $this->getTestEntityJson($tests); + $output->writeln( + "Test dependencies file created, Located in: " . self::TEST_DEPENDENCY_FILE_LOCATION + ); + } else { + $output->writeln( + "Wrong parameter for log (-l) option, accepted parameter are: testEntityJson" . PHP_EOL + ); + } + } + if (empty(GenerationErrorHandler::getInstance()->getAllErrors())) { $output->writeln("Generate Tests Command Run" . PHP_EOL); return 0; @@ -326,6 +382,200 @@ private function parseConfigParallelOptions($time, $groups) } } + /** + * console command options --log and create test dependencies in json file + * @return void + * @throws TestFrameworkException + * @throws XmlException|FastFailException + */ + private function getTestEntityJson(array $tests = []) + { + $testDependencies = $this->getTestDependencies($tests); + $this->array2Json($testDependencies); + } + + /** + * Function responsible for getting test dependencies in array + * @param array $tests + * @return array + * @throws FastFailException + * @throws TestFrameworkException + * @throws XmlException + */ + public function getTestDependencies(array $tests = []): array + { + $this->scriptUtil = new ScriptUtil(); + $this->testDependencyUtil = new TestDependencyUtil(); + $allModules = $this->scriptUtil->getAllModulePaths(); + + if (!class_exists('\Magento\Framework\Component\ComponentRegistrar')) { + throw new TestFrameworkException( + "TEST DEPENDENCY CHECK ABORTED: MFTF must be attached or pointing to Magento codebase." + ); + } + $registrar = new \Magento\Framework\Component\ComponentRegistrar(); + $this->moduleNameToPath = $registrar->getPaths(\Magento\Framework\Component\ComponentRegistrar::MODULE); + $this->moduleNameToComposerName = $this->testDependencyUtil->buildModuleNameToComposerName( + $this->moduleNameToPath + ); + $this->flattenedDependencies = $this->testDependencyUtil->buildComposerDependencyList( + $this->moduleNameToPath, + $this->moduleNameToComposerName + ); + + if (!empty($tests)) { + # specific test dependencies will be generate. + $testXmlFiles = $this->scriptUtil->getModuleXmlFilesByTestNames($tests); + } else { + $filePaths = [ + DIRECTORY_SEPARATOR . 'Test' . DIRECTORY_SEPARATOR + ]; + // These files can contain references to other modules. + $testXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($allModules, $filePaths[0]); + } + + list($testDependencies, $extendedTestMapping) = $this->findTestDependentModule($testXmlFiles); + return $this->testDependencyUtil->mergeDependenciesForExtendingTests($testDependencies, $extendedTestMapping); + } + + /** + * Finds all test dependencies in given set of files + * @param Finder $files + * @return array + * @throws FastFailException + * @throws XmlException + */ + private function findTestDependentModule(Finder $files): array + { + $testDependencies = []; + $extendedTests = []; + $extendedTestMapping = []; + foreach ($files as $filePath) { + $allEntities = []; + $filePath = $filePath->getPathname(); + $moduleName = $this->testDependencyUtil->getModuleName($filePath, $this->moduleNameToPath); + // Not a module, is either dev/tests/acceptance or loose folder with test materials + if ($moduleName == null) { + continue; + } + + $contents = file_get_contents($filePath); + preg_match_all(ActionObject::ACTION_ATTRIBUTE_VARIABLE_REGEX_PATTERN, $contents, $braceReferences); + preg_match_all(self::ACTIONGROUP_REGEX_PATTERN, $contents, $actionGroupReferences); + preg_match_all(self::EXTENDS_REGEX_PATTERN, $contents, $extendReferences); + + // Remove Duplicates + $braceReferences[0] = array_unique($braceReferences[0]); + $actionGroupReferences[1] = array_unique($actionGroupReferences[1]); + $braceReferences[1] = array_unique($braceReferences[1]); + $braceReferences[2] = array_filter(array_unique($braceReferences[2])); + + // resolve entity references + $allEntities = array_merge( + $allEntities, + $this->scriptUtil->resolveEntityReferences($braceReferences[0], $contents) + ); + + // resolve parameterized references + $allEntities = array_merge( + $allEntities, + $this->scriptUtil->resolveParametrizedReferences($braceReferences[2], $contents) + ); + + // resolve entity by names + $allEntities = array_merge( + $allEntities, + $this->scriptUtil->resolveEntityByNames($actionGroupReferences[1]) + ); + + // resolve entity by names + $allEntities = array_merge( + $allEntities, + $this->scriptUtil->resolveEntityByNames($extendReferences[1]) + ); + $modulesReferencedInTest = $this->testDependencyUtil->getModuleDependenciesFromReferences( + $allEntities, + $this->moduleNameToComposerName, + $this->moduleNameToPath + ); + if (! empty($modulesReferencedInTest)) { + $document = new \DOMDocument(); + $document->loadXML($contents); + $test_file = $document->getElementsByTagName('test')->item(0); + $test_name = $test_file->getAttribute('name'); + + # check any test extends on with this test. + $extended_test = $test_file->getAttribute('extends') ?? ""; + if (!empty($extended_test)) { + $extendedTests[] = $extended_test; + $extendedTestMapping[] = ["child_test_name" =>$test_name, "parent_test_name" =>$extended_test]; + } + + $flattenedDependencyMap = array_values( + array_unique(call_user_func_array('array_merge', array_values($modulesReferencedInTest))) + ); + $suite_name = $this->getSuiteName($test_name); + $full_name = "Magento\AcceptanceTest\_". $suite_name. "\Backend\\".$test_name."Cest.".$test_name; + $dependencyMap = [ + "file_path" => $filePath, + "full_name" => $full_name, + "test_name" => $test_name, + "test_modules" => $flattenedDependencyMap, + ]; + $testDependencies[] = $dependencyMap; + } + } + + if (!empty($extendedTests)) { + list($extendedDependencies, $tempExtendedTestMapping) = $this->getExtendedTestDependencies($extendedTests); + $testDependencies = array_merge($testDependencies, $extendedDependencies); + $extendedTestMapping = array_merge($extendedTestMapping, $tempExtendedTestMapping); + } + + return [$testDependencies, $extendedTestMapping]; + } + + /** + * Finds all extended test dependencies in given set of files + * @param array $extendedTests + * @return array + * @throws FastFailException + * @throws XmlException + */ + private function getExtendedTestDependencies(array $extendedTests): array + { + $testXmlFiles = $this->scriptUtil->getModuleXmlFilesByTestNames($extendedTests); + return $this->findTestDependentModule($testXmlFiles); + } + + /** + * Create json file of test dependencies + * @param array $array + * @return void + */ + private function array2Json(array $array) + { + $file = fopen(self::TEST_DEPENDENCY_FILE_LOCATION, 'w'); + $json = json_encode($array, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT); + fwrite($file, $json); + fclose($file); + } + + /** + * Get suite name. + * @param string $test_name + * @return integer|mixed|string + * @throws FastFailException + */ + private function getSuiteName(string $test_name) + { + $suite_name = json_decode($this->getTestAndSuiteConfiguration([$test_name]), true)["suites"] ?? "default"; + if (is_array($suite_name)) { + $suite_name = array_keys($suite_name)[0]; + } + return $suite_name; + } + /** * @param string $path * @return array diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php index 556d30d28..848b2c463 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/TestDependencyCheck.php @@ -13,6 +13,7 @@ use Symfony\Component\Finder\Finder; use Exception; use Magento\FunctionalTestingFramework\Util\Script\ScriptUtil; +use Magento\FunctionalTestingFramework\Util\Script\TestDependencyUtil; /** * Class TestDependencyCheck @@ -26,12 +27,6 @@ class TestDependencyCheck implements StaticCheckInterface const ERROR_LOG_FILENAME = 'mftf-dependency-checks'; const ERROR_LOG_MESSAGE = 'MFTF File Dependency Check'; - /** - * Array of FullModuleName => [dependencies] - * @var array - */ - private $allDependencies; - /** * Array of FullModuleName => [dependencies], including flattened dependency tree * @var array @@ -50,12 +45,6 @@ class TestDependencyCheck implements StaticCheckInterface */ private $moduleNameToComposerName; - /** - * Transactional Array to keep track of what dependencies have already been extracted. - * @var array - */ - private $alreadyExtractedDependencies; - /** * Array containing all errors found after running the execute() function. * @var array @@ -81,6 +70,11 @@ class TestDependencyCheck implements StaticCheckInterface */ private $scriptUtil; + /** + * @var TestDependencyUtil + */ + private $testDependencyUtil; + /** * Checks test dependencies, determined by references in tests versus the dependencies listed in the Magento module * @@ -91,6 +85,7 @@ class TestDependencyCheck implements StaticCheckInterface public function execute(InputInterface $input) { $this->scriptUtil = new ScriptUtil(); + $this->testDependencyUtil = new TestDependencyUtil(); $allModules = $this->scriptUtil->getAllModulePaths(); if (!class_exists('\Magento\Framework\Component\ComponentRegistrar')) { @@ -100,8 +95,13 @@ public function execute(InputInterface $input) } $registrar = new \Magento\Framework\Component\ComponentRegistrar(); $this->moduleNameToPath = $registrar->getPaths(\Magento\Framework\Component\ComponentRegistrar::MODULE); - $this->moduleNameToComposerName = $this->buildModuleNameToComposerName($this->moduleNameToPath); - $this->flattenedDependencies = $this->buildComposerDependencyList(); + $this->moduleNameToComposerName = $this->testDependencyUtil->buildModuleNameToComposerName( + $this->moduleNameToPath + ); + $this->flattenedDependencies = $this->testDependencyUtil->buildComposerDependencyList( + $this->moduleNameToPath, + $this->moduleNameToComposerName + ); $filePaths = [ DIRECTORY_SEPARATOR . 'Test' . DIRECTORY_SEPARATOR, @@ -130,7 +130,7 @@ public function execute(InputInterface $input) * Return array containing all errors found after running the execute() function. * @return array */ - public function getErrors() + public function getErrors(): array { return $this->errors; } @@ -139,7 +139,7 @@ public function getErrors() * Return string of a short human readable result of the check. For example: "No Dependency errors found." * @return string */ - public function getOutput() + public function getOutput(): string { return $this->output; } @@ -150,12 +150,12 @@ public function getOutput() * @return array * @throws XmlException */ - private function findErrorsInFileSet($files) + private function findErrorsInFileSet(Finder $files): array { $testErrors = []; foreach ($files as $filePath) { $this->allEntities = []; - $moduleName = $this->getModuleName($filePath); + $moduleName = $this->testDependencyUtil->getModuleName($filePath, $this->moduleNameToPath); // Not a module, is either dev/tests/acceptance or loose folder with test materials if ($moduleName === null) { continue; @@ -209,12 +209,16 @@ private function findErrorsInFileSet($files) * @param string $moduleName * @return array */ - private function findViolatingReferences($moduleName) + private function findViolatingReferences(string $moduleName): array { // Find Violations $violatingReferences = []; $currentModule = $this->moduleNameToComposerName[$moduleName]; - $modulesReferencedInTest = $this->getModuleDependenciesFromReferences($this->allEntities); + $modulesReferencedInTest = $this->testDependencyUtil->getModuleDependenciesFromReferences( + $this->allEntities, + $this->moduleNameToComposerName, + $this->moduleNameToPath + ); $moduleDependencies = $this->flattenedDependencies[$moduleName]; foreach ($modulesReferencedInTest as $entityName => $files) { $valid = false; @@ -235,11 +239,10 @@ private function findViolatingReferences($moduleName) /** * Builds and returns error output for violating references * - * @param array $violatingReferences - * @param string $path - * @return mixed + * @param array $violatingReferences + * @return array */ - private function setErrorOutput($violatingReferences, $path) + private function setErrorOutput(array $violatingReferences, $path): array { $testErrors = []; @@ -255,111 +258,4 @@ private function setErrorOutput($violatingReferences, $path) return $testErrors; } - - /** - * Builds and returns array of FullModuleNae => composer name - * @param array $array - * @return array - */ - private function buildModuleNameToComposerName($array) - { - $returnList = []; - foreach ($array as $moduleName => $path) { - $composerData = json_decode(file_get_contents($path . DIRECTORY_SEPARATOR . "composer.json")); - $returnList[$moduleName] = $composerData->name; - } - return $returnList; - } - - /** - * Builds and returns flattened dependency list based on composer dependencies - * @return array - */ - private function buildComposerDependencyList() - { - $flattenedDependencies = []; - - foreach ($this->moduleNameToPath as $moduleName => $pathToModule) { - $composerData = json_decode( - file_get_contents($pathToModule . DIRECTORY_SEPARATOR . "composer.json"), - true - ); - $this->allDependencies[$moduleName] = $composerData['require']; - } - foreach ($this->allDependencies as $moduleName => $dependencies) { - $this->alreadyExtractedDependencies = []; - $flattenedDependencies[$moduleName] = $this->extractSubDependencies($moduleName); - } - return $flattenedDependencies; - } - - /** - * Recursive function to fetch dependencies of given dependency, and its child dependencies - * @param string $subDependencyName - * @return array - */ - private function extractSubDependencies($subDependencyName) - { - $flattenedArray = []; - - if (array_search($subDependencyName, $this->alreadyExtractedDependencies) !== false) { - return $flattenedArray; - } - - if (isset($this->allDependencies[$subDependencyName])) { - $subDependencyArray = $this->allDependencies[$subDependencyName]; - $flattenedArray = array_merge($flattenedArray, $this->allDependencies[$subDependencyName]); - - // Keep track of dependencies that have already been used, prevents circular dependency problems - $this->alreadyExtractedDependencies[] = $subDependencyName; - foreach ($subDependencyArray as $composerDependencyName => $version) { - $subDependencyFullName = array_search($composerDependencyName, $this->moduleNameToComposerName); - $flattenedArray = array_merge( - $flattenedArray, - $this->extractSubDependencies($subDependencyFullName) - ); - } - } - return $flattenedArray; - } - - /** - * Finds unique array ofcomposer dependencies of given testObjects - * @param array $array - * @return array - */ - private function getModuleDependenciesFromReferences($array) - { - $filenames = []; - foreach ($array as $item) { - // Should it append ALL filenames, including merges? - $allFiles = explode(",", $item->getFilename()); - foreach ($allFiles as $file) { - $moduleName = $this->getModuleName($file); - if (isset($this->moduleNameToComposerName[$moduleName])) { - $composerModuleName = $this->moduleNameToComposerName[$moduleName]; - $filenames[$item->getName()][] = $composerModuleName; - } - } - } - return $filenames; - } - - /** - * Return module name for a file path - * - * @param string $filePath - * @return string|null - */ - private function getModuleName($filePath) - { - $moduleName = null; - foreach ($this->moduleNameToPath as $name => $path) { - if (strpos($filePath, $path) !== false) { - $moduleName = $name; - break; - } - } - return $moduleName; - } } diff --git a/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php b/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php index 745ab53fe..e7fb1075f 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/Script/ScriptUtil.php @@ -5,6 +5,7 @@ */ namespace Magento\FunctionalTestingFramework\Util\Script; +use Exception; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Exceptions\XmlException; @@ -40,7 +41,7 @@ class ScriptUtil * @return array * @throws TestFrameworkException */ - public function getAllModulePaths() + public function getAllModulePaths(): array { MftfApplicationConfig::create( true, @@ -60,7 +61,7 @@ public function getAllModulePaths() * @param string $message * @return string */ - public function printErrorsToFile($errors, $filePath, $message) + public function printErrorsToFile(array $errors, string $filePath, string $message): string { if (empty($errors)) { return $message . ": No errors found."; @@ -91,7 +92,7 @@ public function printErrorsToFile($errors, $filePath, $message) * @param string $scope * @return Finder|array */ - public function getModuleXmlFilesByScope($modulePaths, $scope) + public function getModuleXmlFilesByScope(array $modulePaths, string $scope) { $found = false; $scopePath = DIRECTORY_SEPARATOR . ucfirst($scope) . DIRECTORY_SEPARATOR; @@ -178,7 +179,6 @@ public function resolveEntityReferences($braceReferences, $contents, $resolveSec // trim `{{data.field}}` to `field` preg_match('/.([^.]+)}}/', $reference, $elementName); /** @var ElementObject $element */ - /** @var SectionObject $entity */ $element = $entity->getElement($elementName[1]); if ($element) { $entities[$entity->getName() . '.' . $elementName[1]] = $element; @@ -200,7 +200,7 @@ public function resolveEntityReferences($braceReferences, $contents, $resolveSec * @throws XmlException * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ - public function resolveParametrizedReferences($braceReferences, $contents, $resolveSectionElement = false) + public function resolveParametrizedReferences($braceReferences, $contents, $resolveSectionElement = false): array { $entities = []; foreach ($braceReferences as $parameterizedReference) { @@ -232,7 +232,6 @@ public function resolveParametrizedReferences($braceReferences, $contents, $reso // trim `data.field` to `field` preg_match('/.([^.]+)/', $argument, $elementName); /** @var ElementObject $element */ - /** @var SectionObject $entity */ $element = $entity->getElement($elementName[1]); if ($element) { $entities[$entity->getName() . '.' . $elementName[1]] = $element; @@ -252,7 +251,7 @@ public function resolveParametrizedReferences($braceReferences, $contents, $reso * @return array * @throws XmlException */ - public function resolveEntityByNames($references) + public function resolveEntityByNames(array $references): array { $entities = []; foreach ($references as $reference) { @@ -270,8 +269,9 @@ public function resolveEntityByNames($references) * @param string $name * @return mixed * @throws XmlException + * @throws Exception */ - public function findEntity($name) + public function findEntity(string $name) { if ($name === '_ENV' || $name === '_CREDS') { return null; @@ -293,4 +293,20 @@ public function findEntity($name) } return null; } + + /** + * Return all XML files in given test name, empty array if no path is valid + * @param array $testNames + * @return array|Finder + */ + public function getModuleXmlFilesByTestNames(array $testNames) + { + $finder = new Finder(); + array_walk($testNames, function (&$value) { + $value = $value . ".xml"; + }); + $finder->files()->followLinks()->in(MAGENTO_BP)->name($testNames)->sortByName(); + + return $finder->files() ?? []; + } } diff --git a/src/Magento/FunctionalTestingFramework/Util/Script/TestDependencyUtil.php b/src/Magento/FunctionalTestingFramework/Util/Script/TestDependencyUtil.php new file mode 100644 index 000000000..0fbf566a7 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/Script/TestDependencyUtil.php @@ -0,0 +1,184 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\FunctionalTestingFramework\Util\Script; + +/** + * TestDependencyUtil class that contains helper functions for static and upgrade scripts + * + * @package Magento\FunctionalTestingFramework\Util\Script + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class TestDependencyUtil +{ + /** + * Array of FullModuleName => [dependencies] + * @var array + */ + private $allDependencies; + + /** + * Transactional Array to keep track of what dependencies have already been extracted. + * @var array + */ + private $alreadyExtractedDependencies; + + /** + * Builds and returns array of FullModuleNae => composer name + * @param array $moduleNameToPath + * @return array + */ + public function buildModuleNameToComposerName(array $moduleNameToPath): array + { + $moduleNameToComposerName = []; + foreach ($moduleNameToPath as $moduleName => $path) { + $composerData = json_decode(file_get_contents($path . DIRECTORY_SEPARATOR . "composer.json")); + $moduleNameToComposerName[$moduleName] = $composerData->name; + } + return $moduleNameToComposerName; + } + + /** + * Builds and returns flattened dependency list based on composer dependencies + * @param array $moduleNameToPath + * @param array $moduleNameToComposerName + * @return array + */ + public function buildComposerDependencyList(array $moduleNameToPath, array $moduleNameToComposerName): array + { + $flattenedDependencies = []; + + foreach ($moduleNameToPath as $moduleName => $pathToModule) { + $composerData = json_decode( + file_get_contents($pathToModule . DIRECTORY_SEPARATOR . "composer.json"), + true + ); + $this->allDependencies[$moduleName] = $composerData['require']; + } + foreach ($this->allDependencies as $moduleName => $dependencies) { + $this->alreadyExtractedDependencies = []; + $flattenedDependencies[$moduleName] = $this->extractSubDependencies($moduleName, $moduleNameToComposerName); + } + return $flattenedDependencies; + } + + /** + * Recursive function to fetch dependencies of given dependency, and its child dependencies + * @param string $subDependencyName + * @param array $moduleNameToComposerName + * @return array + */ + private function extractSubDependencies(string $subDependencyName, array $moduleNameToComposerName): array + { + $flattenedArray = []; + + if (in_array($subDependencyName, $this->alreadyExtractedDependencies)) { + return $flattenedArray; + } + + if (isset($this->allDependencies[$subDependencyName])) { + $subDependencyArray = $this->allDependencies[$subDependencyName]; + $flattenedArray = array_merge($flattenedArray, $this->allDependencies[$subDependencyName]); + + // Keep track of dependencies that have already been used, prevents circular dependency problems + $this->alreadyExtractedDependencies[] = $subDependencyName; + foreach ($subDependencyArray as $composerDependencyName => $version) { + $subDependencyFullName = array_search($composerDependencyName, $moduleNameToComposerName); + $flattenedArray = array_merge( + $flattenedArray, + $this->extractSubDependencies($subDependencyFullName, $moduleNameToComposerName) + ); + } + } + return $flattenedArray; + } + + /** + * Finds unique array composer dependencies of given testObjects + * @param array $allEntities + * @param array $moduleComposerName + * @param array $moduleNameToPath + * @return array + */ + public function getModuleDependenciesFromReferences( + array $allEntities, + array $moduleComposerName, + array $moduleNameToPath + ): array { + $filenames = []; + foreach ($allEntities as $item) { + // Should it append ALL filenames, including merges? + $allFiles = explode(",", $item->getFilename()); + foreach ($allFiles as $file) { + $moduleName = $this->getModuleName($file, $moduleNameToPath); + if (isset($moduleComposerName[$moduleName])) { + $composerModuleName = $moduleComposerName[$moduleName]; + $filenames[$item->getName()][] = $composerModuleName; + } + } + } + return $filenames; + } + + /** + * Return module name for a file path + * + * @param string $filePath + * @param array $moduleNameToPath + * @return string|null + */ + public function getModuleName(string $filePath, array $moduleNameToPath): ?string + { + $moduleName = null; + foreach ($moduleNameToPath as $name => $path) { + if (strpos($filePath, $path. "/") !== false) { + $moduleName = $name; + break; + } + } + return $moduleName; + } + + /** + * Return array of merge test modules and file path with same test name. + * @param array $testDependencies + * @param array $extendedTestMapping + * @return array + */ + public function mergeDependenciesForExtendingTests(array $testDependencies, array $extendedTestMapping = []): array + { + $temp_array = array_reverse(array_column($testDependencies, "test_name"), true); + if (!empty($extendedTestMapping)) { + foreach ($extendedTestMapping as $value) { + $key = array_search($value["parent_test_name"], $temp_array); + if ($key !== false) { + #if parent test found merge this to child, for doing so just replace test name with child. + $testDependencies[$key]["test_name"] = $value["child_test_name"]; + } + } + } + $temp_array = []; + foreach ($testDependencies as $testDependency) { + $temp_array[$testDependency["test_name"]][] = $testDependency; + } + $testDependencies = []; + foreach ($temp_array as $testDependencyArray) { + $testDependencies[] = [ + "file_path" => array_column($testDependencyArray, 'file_path'), + "full_name" => $testDependencyArray[0]["full_name"], + "test_name" => $testDependencyArray[0]["test_name"], + "test_modules" =>array_values( + array_unique( + call_user_func_array( + 'array_merge', + array_column($testDependencyArray, 'test_modules') + ) + ) + ), + ]; + } + return $testDependencies; + } +} From ac48cf067f3fbc3006afc81d2a78dd30af5c83b5 Mon Sep 17 00:00:00 2001 From: manjusha729 <93243302+manjusha729@users.noreply.github.com> Date: Sat, 23 Apr 2022 00:27:56 +0530 Subject: [PATCH 839/888] Mqe 3371 : Added unit test for unused entity static check and added ignore tag (#180) * static check * unused entity * made changes * Added ignore tag and unit test * Added ignore tag and unit test * Updated Section in devdocs with unused entity tag Co-authored-by: Manjusha.S <manjusha.s@BLR1-LMC-N71373.local> --- .../MFTF/DevDocs/Section/ContentSection.xml | 2 + .../Util/UnusedEntityCheckTest.php | 190 ++++++++++++++++++ .../StaticCheck/UnusedEntityCheck.php | 76 +++---- 3 files changed, 218 insertions(+), 50 deletions(-) create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/Util/UnusedEntityCheckTest.php diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Section/ContentSection.xml b/dev/tests/functional/tests/MFTF/DevDocs/Section/ContentSection.xml index e0a133d51..a365c9ff5 100644 --- a/dev/tests/functional/tests/MFTF/DevDocs/Section/ContentSection.xml +++ b/dev/tests/functional/tests/MFTF/DevDocs/Section/ContentSection.xml @@ -6,6 +6,8 @@ */ --> +<!--@Ignore(Unused_Entity_Check)--> + <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="contentSection"> diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/UnusedEntityCheckTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/UnusedEntityCheckTest.php new file mode 100644 index 000000000..c7a170d86 --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/UnusedEntityCheckTest.php @@ -0,0 +1,190 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace tests\unit\Magento\FunctionalTestFramework\Util; + +use Exception; +use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; +use tests\unit\Util\MagentoTestCase; +use tests\unit\Util\TestLoggingUtil; +use Magento\FunctionalTestingFramework\StaticCheck\UnusedEntityCheck; +use Magento\FunctionalTestingFramework\Util\Script\ScriptUtil; + +class UnusedEntityCheckTest extends MagentoTestCase +{ + + public function testUnusedEntityFilesCheck() + { + $unusedEntityCheck = new UnusedEntityCheck(); + $result = $unusedEntityCheck->unusedEntities(); + $this->assertIsArray($result); + } + + public function testUnusedActiongroupFiles() + { + $unusedEntityCheck = new UnusedEntityCheck(); + $domDocument = new \DOMDocument(); + $actionGroupFiles = ['DeprecationCheckActionGroup' => + '/verification/DeprecationCheckModule/ActionGroup/DeprecationCheckActionGroup.xml', + 'ActionGroupWithMultiplePausesActionGroup'=> + '/verification/PauseCheckModule/ActionGroup/ActionGroupWithMultiplePausesActionGroup.xml', + 'ActionGroupWithNoPauseActionGroup'=> + '/verification/PauseCheckModule/ActionGroup/ActionGroupWithNoPauseActionGroup.xml']; + $result = $unusedEntityCheck->unusedActionEntity($domDocument, [], [], $actionGroupFiles, []); + $this->assertIsArray($result); + $this->assertCount(3, $result); + } + + public function testUnusedActiongroupFilesReturnedWhenActionXmlFilesAreNotEmpty() + { + $this->scriptUtil = new ScriptUtil(); + $unusedEntityCheck = new UnusedEntityCheck(); + $domDocument = new \DOMDocument(); + $modulePaths = $this->scriptUtil->getAllModulePaths(); + $actionGroupXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, "ActionGroup"); + $actionGroupFiles = ['DeprecationCheckActionGroup' => + '/verification/DeprecationCheckModule/ActionGroup/DeprecationCheckActionGroup.xml', + 'ActionGroupWithMultiplePausesActionGroup'=> + '/verification/PauseCheckModule/ActionGroup/ActionGroupWithMultiplePausesActionGroup.xml', + 'ActionGroupWithNoPauseActionGroup' => + '/verification/PauseCheckModule/ActionGroup/ActionGroupWithNoPauseActionGroup.xml']; + $result = $unusedEntityCheck->unusedActionEntity( + $domDocument, + $actionGroupXmlFiles, + [], + $actionGroupFiles, + [] + ); + $this->assertIsArray($result); + $this->assertCount(3, $result); + } + + public function testUnusedSectionFiles() + { + $unusedEntityCheck = new UnusedEntityCheck(); + $domDocument = new \DOMDocument(); + $section = [ + 'DeprecationCheckSection' => '/verification/DeprecationCheckModule/Section/DeprecationCheckSection.xml', + 'DeprecatedSection' => '/verification/TestModule/Section/DeprecatedSection.xml', + 'LocatorFunctionSection' => '/verification/TestModule/Section/LocatorFunctionSection.xml', + 'SampleSection' => '/verification/TestModuleMerged/Section/MergeSection.xml' + ]; + $result=$unusedEntityCheck->unusedSectionEntity($domDocument, [], [], [], $section, []); + $this->assertIsArray($result); + $this->assertCount(4, $result); + } + + public function testUnusedSectionFilesReturnedWhenSectionXmlFilesAreNotEmpty() + { + $unusedEntityCheck = new UnusedEntityCheck(); + $this->scriptUtil = new ScriptUtil(); + $modulePaths = $this->scriptUtil->getAllModulePaths(); + $sectionXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, "Section"); + + $domDocument = new \DOMDocument(); + $section = [ + 'DeprecationCheckSection' => '/verification/DeprecationCheckModule/Section/DeprecationCheckSection.xml', + 'DeprecatedSection' => '/verification/TestModule/Section/DeprecatedSection.xml', + 'LocatorFunctionSection' => '/verification/TestModule/Section/LocatorFunctionSection.xml', + 'SampleSection' => '/verification/TestModuleMerged/Section/MergeSection.xml' + ]; + $result = $unusedEntityCheck->unusedSectionEntity($domDocument, $sectionXmlFiles, [], [], $section, []); + $this->assertIsArray($result); + $this->assertCount(4, $result); + } + + public function testUnusedPageFiles() + { + $unusedEntityCheck = new UnusedEntityCheck(); + $domDocument = new \DOMDocument(); + $page = [ + 'DeprecationCheckPage' => '/verification/DeprecationCheckModule/Page/DeprecationCheckPage.xml', + 'DeprecatedPage' => '/verification/TestModule/Page/DeprecatedPage.xml', + 'AdminOneParamPage' => '/verification/TestModule/Page/SamplePage/AdminOneParamPage.xml', + 'AdminPage' => '/verification/TestModule/Page/SamplePage/AdminPage.xml', + 'ExternalPage' => '/verification/TestModule/Page/SamplePage/ExternalPage.xml', + 'NoParamPage' => '/verification/TestModule/Page/SamplePage/NoParamPage.xml' + ]; + $result = $unusedEntityCheck->unusedPageEntity($domDocument, [], [], $page, []); + $this->assertIsArray($result); + $this->assertCount(6, $result); + } + + public function testUnusedPageFilesReturnedWhenPageXmlFilesPassedAreNotEmpty() + { + $unusedEntityCheck = new UnusedEntityCheck(); + $domDocument = new \DOMDocument(); + $this->scriptUtil = new ScriptUtil(); + $modulePaths = $this->scriptUtil->getAllModulePaths(); + $pageXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, "Page"); + $page = [ + 'DeprecationCheckPage' => '/verification/DeprecationCheckModule/Page/DeprecationCheckPage.xml', + 'DeprecatedPage' => '/verification/TestModule/Page/DeprecatedPage.xml', + 'AdminOneParamPage' => '/verification/TestModule/Page/SamplePage/AdminOneParamPage.xml', + 'AdminPage' => '/verification/TestModule/Page/SamplePage/AdminPage.xml', + 'ExternalPage' => '/verification/TestModule/Page/SamplePage/ExternalPage.xml', + 'NoParamPage' => '/verification/TestModule/Page/SamplePage/NoParamPage.xml' + ]; + $result = $unusedEntityCheck->unusedPageEntity($domDocument, $pageXmlFiles, [], $page, []); + $this->assertIsArray($result); + $this->assertCount(6, $result); + } + + public function testUnusedData() + { + $unusedEntityCheck = new UnusedEntityCheck(); + $domDocument = new \DOMDocument(); + $data = [ + "simpleData" => + [ + "dataFilePath" => "/verification/TestModule/Data/ReplacementData.xml" + ], + + "uniqueData" => [ + + "dataFilePath" => "/verification/TestModule/Data/ReplacementData.xml" + ], + + "offset"=> + [ + "dataFilePath" => "/verification/TestModule/Data/ReplacementData.xml" + ] + ]; + $result=$unusedEntityCheck->unusedPageEntity($domDocument, [], [], $data, []); + $this->assertIsArray($result); + $this->assertCount(3, $result); + } + + public function testUnusedDataReturnedWhenCreateDataEntityAreNotEmpty() + { + $unusedEntityCheck = new UnusedEntityCheck(); + $domDocument = new \DOMDocument(); + $this->scriptUtil = new ScriptUtil(); + $modulePaths = $this->scriptUtil->getAllModulePaths(); + $dataXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, "Data"); + $data = [ + "simpleData" => + [ + "dataFilePath" => "/verification/TestModule/Data/ReplacementData.xml" + ], + + "uniqueData" => [ + + "dataFilePath" => "/verification/TestModule/Data/ReplacementData.xml" + ], + + "offset" => + [ + "dataFilePath" => "/verification/TestModule/Data/ReplacementData.xml" + ] + ]; + $result = $unusedEntityCheck->unusedPageEntity($domDocument, $dataXmlFiles, [], $data, []); + $this->assertIsArray($result); + $this->assertCount(3, $result); + } +} diff --git a/src/Magento/FunctionalTestingFramework/StaticCheck/UnusedEntityCheck.php b/src/Magento/FunctionalTestingFramework/StaticCheck/UnusedEntityCheck.php index 72c5ea801..50a348db0 100644 --- a/src/Magento/FunctionalTestingFramework/StaticCheck/UnusedEntityCheck.php +++ b/src/Magento/FunctionalTestingFramework/StaticCheck/UnusedEntityCheck.php @@ -46,24 +46,7 @@ class UnusedEntityCheck implements StaticCheckInterface */ public function execute(InputInterface $input) { - $this->scriptUtil = new ScriptUtil(); - $domDocument = new \DOMDocument(); - $modulePaths = $this->scriptUtil->getAllModulePaths(); - $testXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, "Test"); - $actionGroupXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, "ActionGroup"); - $dataXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, "Data"); - $pageXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, "Page"); - $sectionXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, "Section"); - $suiteXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, 'Suite'); - $this->errors = $this->unusedEntities( - $domDocument, - $dataXmlFiles, - $actionGroupXmlFiles, - $sectionXmlFiles, - $pageXmlFiles, - $testXmlFiles, - $suiteXmlFiles - ); + $this->errors = $this->unusedEntities(); $this->output = $this->scriptUtil->printErrorsToFile( $this->errors, StaticChecksList::getErrorFilesPath() . DIRECTORY_SEPARATOR . self::ERROR_LOG_FILENAME . '.txt', @@ -73,26 +56,19 @@ public function execute(InputInterface $input) /** * Centralized method to get unused Entities - * - * @param DOMDocument $domDocument - * @param ScriptUtil $dataXmlFiles - * @param ScriptUtil $actionGroupXmlFiles - * @param ScriptUtil $sectionXmlFiles - * @param ScriptUtil $pageXmlFiles - * @param ScriptUtil $testXmlFiles - * @param ScriptUtil $suiteXmlFiles * @return array - * @throws Exception */ - private function unusedEntities( - $domDocument, - $dataXmlFiles, - $actionGroupXmlFiles, - $sectionXmlFiles, - $pageXmlFiles, - $testXmlFiles, - $suiteXmlFiles - ) { + public function unusedEntities() + { + $this->scriptUtil = new ScriptUtil(); + $domDocument = new \DOMDocument(); + $modulePaths = $this->scriptUtil->getAllModulePaths(); + $testXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, "Test"); + $actionGroupXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, "ActionGroup"); + $dataXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, "Data"); + $pageXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, "Page"); + $sectionXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, "Section"); + $suiteXmlFiles = $this->scriptUtil->getModuleXmlFilesByScope($modulePaths, 'Suite'); foreach ($dataXmlFiles as $filePath) { $domDocument->load($filePath); $entityResult = $this->getAttributesFromDOMNodeList( @@ -101,7 +77,7 @@ private function unusedEntities( ); foreach ($entityResult as $entitiesResultData) { $dataNames[$entitiesResultData[key($entitiesResultData)]] = [ - "dataFilePath"=>StaticChecksList::getFilePath($filePath->getRealPath()) + "dataFilePath"=>$filePath->getRealPath() ]; } } @@ -112,21 +88,18 @@ private function unusedEntities( continue; } $allActionGroupFileNames[$actionGroupName ] = - StaticChecksList::getFilePath($filePath->getRealPath()); + $filePath->getRealPath(); } foreach ($sectionXmlFiles as $filePath) { $domDocument->load($filePath); $sectionName = $domDocument->getElementsByTagName("section")->item(0)->getAttribute("name"); - $sectionFileNames[$sectionName] = StaticChecksList::getFilePath($filePath->getRealPath()); + $sectionFileNames[$sectionName] = $filePath->getRealPath(); } - foreach ($pageXmlFiles as $filePath) { $domDocument->load($filePath); $pageName = $domDocument->getElementsByTagName("page")->item(0)->getAttribute("name"); - $pageFiles[$pageName] = StaticChecksList::getFilePath( - $filePath->getRealPath() - ); + $pageFiles[$pageName] = $filePath->getRealPath(); } $actionGroupReferences = $this->unusedActionEntity( $domDocument, @@ -166,6 +139,7 @@ private function unusedEntities( ) ); } + /** * Setting error message * @@ -176,9 +150,11 @@ private function setErrorOutput($unusedFilePath) { $testErrors = []; foreach ($unusedFilePath as $files) { - $errorOutput = " Unused Entity File Path "; - $errorOutput .= "\n\t".$files."\t\n"; - $testErrors[$files][] = $errorOutput; + $contents = file_get_contents($files); + $file = fopen($files, 'a'); + if (!str_contains($contents, '<!--@Ignore(Unused_Entity_Check)-->')) { + fwrite($file, '<!--@Ignore(Unused_Entity_Check)-->'); + } } return $testErrors; } @@ -194,7 +170,7 @@ private function setErrorOutput($unusedFilePath) * @return array * @throws Exception */ - private function unusedActionEntity( + public function unusedActionEntity( $domDocument, $actionGroupXmlFiles, $testXmlFiles, @@ -244,7 +220,7 @@ private function unusedActionEntity( * @return array * @throws Exception */ - private function unusedPageEntity($domDocument, $actionGroupXmlFiles, $testXmlFiles, $pageNames, $suiteXmlFiles) + public function unusedPageEntity($domDocument, $actionGroupXmlFiles, $testXmlFiles, $pageNames, $suiteXmlFiles) { foreach ($suiteXmlFiles as $filePath) { @@ -366,7 +342,7 @@ private function entityReferencePatternCheck($domDocument, $fileNames, $contents * @return array * @throws Exception */ - private function unusedSectionEntity( + public function unusedSectionEntity( $domDocument, $actionGroupXmlFiles, $testXmlFiles, @@ -504,7 +480,7 @@ private function getUnusedSectionEntitiesReferenceInActionGroupAndTestFiles( * @param DOMDocument $domDocument * @return array */ - private function unusedData( + public function unusedData( $domDocument, $actionGroupXmlFiles, $testXmlFiles, From 75b1e08d203e6075b88cd61ff95140b17b7ef339 Mon Sep 17 00:00:00 2001 From: manjusha729 <93243302+manjusha729@users.noreply.github.com> Date: Tue, 3 May 2022 20:25:09 +0530 Subject: [PATCH 840/888] MQE-3402 : Updated docs for new location of password (#188) * MQE-3402 : Updated docs for new location of password * updated doc * Updated getting started docs * MQE-3402 : Updated docs for new location of password Co-authored-by: Manjusha.S <manjusha.s@BLR1-LMC-N71373.local> Co-authored-by: Kevin Kozan <kkozan@magento.com> --- docs/credentials.md | 10 ++++++++++ docs/getting-started.md | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/docs/credentials.md b/docs/credentials.md index 0c6decb41..56f1ddbc4 100644 --- a/docs/credentials.md +++ b/docs/credentials.md @@ -53,6 +53,16 @@ magento/carriers_usps_password=Lmgxvrq89uPwECeV # Credentials for the DHL service #magento/carriers_dhl_id_us=dhl_test_user #magento/carriers_dhl_password_us=Mlgxv3dsagVeG +.... +``` +### Add key and value pair for admin password . +magento/MAGENTO_ADMIN_PASSWORD must contain the user password required for authorization in the Admin area. Example: magento/MAGENTO_ADMIN_PASSWORD=mycustompassword + +```conf +... +# Admin password +magento/MAGENTO_ADMIN_PASSWORD =123123q + .... ``` diff --git a/docs/getting-started.md b/docs/getting-started.md index ad6fa766a..f895ebe5a 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -205,8 +205,7 @@ Specify the following parameters, which are required to launch tests: - `MAGENTO_ADMIN_USERNAME` must contain the username required for authorization in the Admin area. Example: `MAGENTO_ADMIN_USERNAME=admin` -- `MAGENTO_ADMIN_PASSWORD` must contain the user password required for authorization in the Admin area. - Example: `MAGENTO_ADMIN_PASSWORD=123123q` +- `MAGENTO_ADMIN_PASSWORD` must now be set up in the credentials file. See [Credentials Page][] for details. <div class="bs-callout bs-callout-info" markdown="1"> If the `MAGENTO_BASE_URL` contains a subdirectory like `http://magento.test/magento2ce`, specify `MAGENTO_CLI_COMMAND_PATH`. @@ -366,3 +365,4 @@ allure serve dev/tests/_output/allure-results/ [Find your version]: introduction.html#find-your-mftf-version [Installation Guide docroot]: https://devdocs.magento.com/guides/v2.4/install-gde/tutorials/change-docroot-to-pub.html [Magento Two-Factor Authentication (2FA) extension]: https://devdocs.magento.com/guides/v2.4/security/two-factor-authentication.html +[Credentials Page]: https://devdocs.magento.com/mftf/docs/credentials.html From 7f8a8c3f64b39e3a27071da06cdfcda4d85c7fe7 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk <kolesnyk@adobe.com> Date: Wed, 4 May 2022 16:51:22 -0500 Subject: [PATCH 841/888] MQE-3447: Remove any remaining usages of Travis CI from MFTF Repo --- .github/CONTRIBUTING.md | 3 +-- .github/PULL_REQUEST_TEMPLATE.md | 2 +- README.md | 2 -- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 9a38dfc65..b037250ef 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -52,7 +52,7 @@ This gives Adobe permission to redistribute your contributions as part of the pr 7. For large features or changes, [open an issue][issue] to discuss first. This may prevent duplicate or unnecessary effort, and it may gain you some additional contributors. 8. To report a bug, [open an issue][issue], and follow [guidelines about bugfix issues][issue reporting]. -9. All automated tests must pass successfully (all builds on [Travis CI] must be green). +9. All automated tests must pass successfully (all builds must be green). ## Fork a repository @@ -179,4 +179,3 @@ Label| Description [Magento Contributor Agreement]: http://www.magento.com/legaldocuments/mca [MFTF repository]: https://github.com/magento/magento2-functional-testing-framework [open new issue]: https://github.com/magento/magento2-functional-testing-framework/issues/new -[Travis CI]: https://travis-ci.com/magento/magento2-functional-testing-framework/pull_requests diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 3ce27ce35..9bcc9ec2b 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -12,5 +12,5 @@ - [ ] Pull request has a meaningful description of its purpose - [ ] All commits are accompanied by meaningful commit messages - [ ] All new or changed code is covered with unit/verification tests (if applicable) - - [ ] All automated tests passed successfully (all builds on Travis CI are green) + - [ ] All automated tests passed successfully (all builds are green) - [ ] Changes to Framework doesn't have backward incompatible changes for tests or have related Pull Request with fixes to tests \ No newline at end of file diff --git a/README.md b/README.md index 5a4bbab11..02a2b0cd5 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ # Magento Functional Testing Framework (MFTF) -[![Build Status](https://travis-ci.org/magento/magento2-functional-testing-framework.svg?branch=develop)](https://travis-ci.org/magento/magento2-functional-testing-framework) [![Coverage Status](https://coveralls.io/repos/github/magento/magento2-functional-testing-framework/badge.svg?branch=develop)](https://coveralls.io/github/magento/magento2-functional-testing-framework) - ---- ## Installation From b052e802ecb8f25aa97d7475f701a2eb8ea34252 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Fri, 6 May 2022 12:50:30 +0530 Subject: [PATCH 842/888] MQE-3096 : unit tests for GenerateTestFailedCommandTest and RunTestFailedCommandTest --- .../Console/GenerateTestFailedCommandTest.php | 128 +++++++++++++++++- .../Console/RunTestFailedCommandTest.php | 79 +++++++++++ 2 files changed, 206 insertions(+), 1 deletion(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Console/GenerateTestFailedCommandTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Console/GenerateTestFailedCommandTest.php index a127ea313..cd5ed57fd 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Console/GenerateTestFailedCommandTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Console/GenerateTestFailedCommandTest.php @@ -15,7 +15,7 @@ class GenerateTestFailedCommandTest extends BaseGenerateCommandTest { - public function testSingleTestNoSuite(): void + public function testSingleTestWithNoSuite(): void { $testFileReturn = [ "tests/functional/tests/MFTF/_generated/default/SingleTestNoSuiteTest.php:SingleTestNoSuiteTest" @@ -38,4 +38,130 @@ public function testSingleTestNoSuite(): void $configuration = $stub->getFailedTestList("", ""); $this->assertEquals($expectedConfiguration, $configuration); } + + public function testMultipleTestsWithSuites(): void + { + $testFileReturn = [ + "tests/functional/tests/MFTF/_generated/SomeSpecificSuite/FirstTestSuiteTest.php:SingleTestSuiteTest", + "tests/functional/tests/MFTF/_generated/SomeSpecificSuite/SecondTestNoSuiteTest.php:SingleTestNoSuiteTest", + "tests/functional/tests/MFTF/_generated/SomeOtherSuite/SecondTestNoSuiteTest.php:SingleTestNoSuiteTest", + ]; + $expectedConfiguration = '{"tests":null,"suites":{"SomeSpecificSuite":["SingleTestSuiteTest", + "SingleTestNoSuiteTest"],"SomeOtherSuite":["SingleTestNoSuiteTest"]}}'; + + // Create a stub for the SomeClass class. + $stub = $this->getMockBuilder(GenerateTestFailedCommand::class) + ->onlyMethods(["readFailedTestFile", "writeFailedTestToFile"]) + ->getMock(); + // Configure the stub. + $stub + ->method('readFailedTestFile') + ->willReturn($testFileReturn); + $stub + ->method('writeFailedTestToFile') + ->willReturn(null); + + // Run the real code + $configuration = $stub->getFailedTestList("", ""); + $this->assertEquals($expectedConfiguration, $configuration); + } + + public function testMultipleTestFailureWithNoSuites(): void + { + $testFileReturn = [ + "tests/functional/tests/MFTF/_generated/default/SingleTestNoSuiteTest.php:SingleTestNoSuiteTest", + "tests/functional/tests/MFTF/_generated/default/FirstTestSuiteTest.php:SingleTestSuiteTest" + ]; + $expectedConfiguration = '{"tests":["SingleTestNoSuiteTest","SingleTestSuiteTest"],"suites":null}'; + + // Create a stub for the SomeClass class. + $stub = $this->getMockBuilder(GenerateTestFailedCommand::class) + ->onlyMethods(["readFailedTestFile", "writeFailedTestToFile"]) + ->getMock(); + // Configure the stub. + $stub + ->method('readFailedTestFile') + ->willReturn($testFileReturn); + $stub + ->method('writeFailedTestToFile') + ->willReturn(null); + + // Run the real code + $configuration = $stub->getFailedTestList("", ""); + $this->assertEquals($expectedConfiguration, $configuration); + } + + public function testSingleSuiteAndNoTest(): void + { + $testFileReturn = [ + "tests/functional/tests/MFTF/_generated/SomeSpecificSuite/", + ]; + $expectedConfiguration = '{"tests":null,"suites":{"SomeSpecificSuite":[null]}}'; + + // Create a stub for the SomeClass class. + $stub = $this->getMockBuilder(GenerateTestFailedCommand::class) + ->onlyMethods(["readFailedTestFile", "writeFailedTestToFile"]) + ->getMock(); + // Configure the stub. + $stub + ->method('readFailedTestFile') + ->willReturn($testFileReturn); + $stub + ->method('writeFailedTestToFile') + ->willReturn(null); + + // Run the real code + $configuration = $stub->getFailedTestList("", ""); + $this->assertEquals($expectedConfiguration, $configuration); + } + + public function testSingleSuiteWithTest(): void + { + $testFileReturn = [ + "tests/functional/tests/MFTF/_generated/SomeSpecificSuite/FirstTestSuiteTest.php:SingleTestSuiteTest", + ]; + $expectedConfiguration = '{"tests":null,"suites":{"SomeSpecificSuite":["SingleTestSuiteTest"]}}'; + + // Create a stub for the SomeClass class. + $stub = $this->getMockBuilder(GenerateTestFailedCommand::class) + ->onlyMethods(["readFailedTestFile", "writeFailedTestToFile"]) + ->getMock(); + // Configure the stub. + $stub + ->method('readFailedTestFile') + ->willReturn($testFileReturn); + $stub + ->method('writeFailedTestToFile') + ->willReturn(null); + + // Run the real code + $configuration = $stub->getFailedTestList("", ""); + $this->assertEquals($expectedConfiguration, $configuration); + } + + public function testMultipleSuitesWithNoTests(): void + { + $testFileReturn = [ + "tests/functional/tests/MFTF/_generated/SomeSpecificSuite/", + "tests/functional/tests/MFTF/_generated/SomeSpecificSuite1/", + + ]; + $expectedConfiguration = '{"tests":null,"suites":{"SomeSpecificSuite":[null],"SomeSpecificSuite1":[null]}}'; + + // Create a stub for the SomeClass class. + $stub = $this->getMockBuilder(GenerateTestFailedCommand::class) + ->onlyMethods(["readFailedTestFile", "writeFailedTestToFile"]) + ->getMock(); + // Configure the stub. + $stub + ->method('readFailedTestFile') + ->willReturn($testFileReturn); + $stub + ->method('writeFailedTestToFile') + ->willReturn(null); + + // Run the real code + $configuration = $stub->getFailedTestList("", ""); + $this->assertEquals($expectedConfiguration, $configuration); + } } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Console/RunTestFailedCommandTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Console/RunTestFailedCommandTest.php index 5bba89de1..6d85ed275 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Console/RunTestFailedCommandTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Console/RunTestFailedCommandTest.php @@ -50,4 +50,83 @@ private function invokePrivateMethod(&$object, $methodName, array $parameters = $method->setAccessible(true); return $method->invokeArgs($object, $parameters); } + + public function testSingleTestNoSuite(): void + { + $testFailedFile = [ + "tests/functional/tests/MFTF/_generated/default/SingleTestNoSuiteTest.php:SingleTestNoSuiteTest" + ]; + + $expectedResult = [ + 'tests/functional/tests/MFTF/_generated/default/SingleTestNoSuiteTest.php' + ]; + + $runFailed = new RunTestFailedCommand('run:failed'); + $filter = $this->invokePrivateMethod($runFailed, 'filterTestsForExecution', [$testFailedFile]); + $this->assertEquals($expectedResult, $filter); + } + + public function testMultipleTestNoSuite(): void + { + $testFailedFile = [ + "tests/functional/tests/MFTF/_generated/default/SingleTestNoSuiteTest.php:SingleTestNoSuiteTest", + "tests/functional/tests/MFTF/_generated/default/FirstTestSuiteTest.php:SingleTestSuiteTest" + ]; + + $expectedResult = [ + "tests/functional/tests/MFTF/_generated/default/SingleTestNoSuiteTest.php", + "tests/functional/tests/MFTF/_generated/default/FirstTestSuiteTest.php" + ]; + + $runFailed = new RunTestFailedCommand('run:failed'); + $filter = $this->invokePrivateMethod($runFailed, 'filterTestsForExecution', [$testFailedFile]); + $this->assertEquals($expectedResult, $filter); + } + + public function testSingleSuiteNoTest(): void + { + $testFailedFile = [ + "tests/functional/tests/MFTF/_generated/SomeSpecificSuite/FirstTestSuiteTest.php:SingleTestSuiteTest", + ]; + + $expectedResult = [ + "-g SomeSpecificSuite" + ]; + + $runFailed = new RunTestFailedCommand('run:failed'); + $filter = $this->invokePrivateMethod($runFailed, 'filterTestsForExecution', [$testFailedFile]); + $this->assertEquals($expectedResult, $filter); + } + + public function testSingleSuiteAndTest(): void + { + $testFailedFile = [ + "tests/functional/tests/MFTF/_generated/SomeSpecificSuite/FirstTestSuiteTest.php:SingleTestSuiteTest", + ]; + $expectedResult = [ + "-g SomeSpecificSuite", + ]; + + $runFailed = new RunTestFailedCommand('run:failed'); + $filter = $this->invokePrivateMethod($runFailed, 'filterTestsForExecution', [$testFailedFile]); + $this->assertEquals($expectedResult, $filter); + } + + public function testMultipleSuitesWithNoTest(): void + { + $testFailedFile = [ + "tests/functional/tests/MFTF/_generated/SomeSpecificSuite/", + "tests/functional/tests/MFTF/_generated/SomeSpecificSuite1/", + "tests/functional/tests/MFTF/_generated/SomeSpecificSuite2/" + ]; + $expectedResult = [ + "-g SomeSpecificSuite", + "-g SomeSpecificSuite1", + "-g SomeSpecificSuite2", + ]; + + $runFailed = new RunTestFailedCommand('run:failed'); + $filter = $this->invokePrivateMethod($runFailed, 'filterTestsForExecution', [$testFailedFile]); + $this->assertEquals($expectedResult, $filter); + } } From d4f779b520213fe5efd4edeb4333e317141ecd6c Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Fri, 6 May 2022 12:58:59 +0530 Subject: [PATCH 843/888] MQE-3096 : unit tests for GenerateTestFailedCommandTest and RunTestFailedCommandTest --- .../Console/RunTestFailedCommandTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Console/RunTestFailedCommandTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Console/RunTestFailedCommandTest.php index 6d85ed275..db0c63c61 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Console/RunTestFailedCommandTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Console/RunTestFailedCommandTest.php @@ -86,7 +86,7 @@ public function testMultipleTestNoSuite(): void public function testSingleSuiteNoTest(): void { $testFailedFile = [ - "tests/functional/tests/MFTF/_generated/SomeSpecificSuite/FirstTestSuiteTest.php:SingleTestSuiteTest", + "tests/functional/tests/MFTF/_generated/SomeSpecificSuite/", ]; $expectedResult = [ From d013074f8ccbd5edc7b7bb9328e26e4c0ec453d7 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Fri, 6 May 2022 13:02:51 +0530 Subject: [PATCH 844/888] MQE-3096 : unit tests for GenerateTestFailedCommandTest and RunTestFailedCommandTest --- .../Console/GenerateTestFailedCommandTest.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Console/GenerateTestFailedCommandTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Console/GenerateTestFailedCommandTest.php index cd5ed57fd..f1ee79128 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Console/GenerateTestFailedCommandTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Console/GenerateTestFailedCommandTest.php @@ -43,11 +43,8 @@ public function testMultipleTestsWithSuites(): void { $testFileReturn = [ "tests/functional/tests/MFTF/_generated/SomeSpecificSuite/FirstTestSuiteTest.php:SingleTestSuiteTest", - "tests/functional/tests/MFTF/_generated/SomeSpecificSuite/SecondTestNoSuiteTest.php:SingleTestNoSuiteTest", - "tests/functional/tests/MFTF/_generated/SomeOtherSuite/SecondTestNoSuiteTest.php:SingleTestNoSuiteTest", - ]; - $expectedConfiguration = '{"tests":null,"suites":{"SomeSpecificSuite":["SingleTestSuiteTest", - "SingleTestNoSuiteTest"],"SomeOtherSuite":["SingleTestNoSuiteTest"]}}'; + "tests/functional/tests/MFTF/_generated/SomeSpecificSuite/SecondTestNoSuiteTest.php:SingleTestNoSuiteTest", ]; + $expectedConfiguration = '{"tests":null,"suites":{"SomeSpecificSuite":["SingleTestSuiteTest","SingleTestNoSuiteTest"]}}'; // Create a stub for the SomeClass class. $stub = $this->getMockBuilder(GenerateTestFailedCommand::class) From 02d4bc696523cc2fe869489eae51e2c78bdd53dd Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Fri, 6 May 2022 14:09:07 +0530 Subject: [PATCH 845/888] MQE-3096 : unit tests for GenerateTestFailedCommandTest and RunTestFailedCommandTest --- .../Console/GenerateTestFailedCommandTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Console/GenerateTestFailedCommandTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Console/GenerateTestFailedCommandTest.php index f1ee79128..675fa8715 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Console/GenerateTestFailedCommandTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Console/GenerateTestFailedCommandTest.php @@ -93,7 +93,7 @@ public function testSingleSuiteAndNoTest(): void $testFileReturn = [ "tests/functional/tests/MFTF/_generated/SomeSpecificSuite/", ]; - $expectedConfiguration = '{"tests":null,"suites":{"SomeSpecificSuite":[null]}}'; + $expectedConfiguration = '{"tests":null,"suites":{"SomeSpecificSuite":[[]]}}'; // Create a stub for the SomeClass class. $stub = $this->getMockBuilder(GenerateTestFailedCommand::class) @@ -143,7 +143,7 @@ public function testMultipleSuitesWithNoTests(): void "tests/functional/tests/MFTF/_generated/SomeSpecificSuite1/", ]; - $expectedConfiguration = '{"tests":null,"suites":{"SomeSpecificSuite":[null],"SomeSpecificSuite1":[null]}}'; + $expectedConfiguration = '{"tests":null,"suites":{"SomeSpecificSuite":[[]],"SomeSpecificSuite1":[[]]}}'; // Create a stub for the SomeClass class. $stub = $this->getMockBuilder(GenerateTestFailedCommand::class) From c2b1dd021f025f62b71a97b1465ff007fbcdfef9 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Fri, 6 May 2022 14:20:23 +0530 Subject: [PATCH 846/888] fixed unit test failure --- .../Console/GenerateTestFailedCommand.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestFailedCommand.php index 7b6208bd4..6ebae7528 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestFailedCommand.php @@ -103,9 +103,12 @@ public function getFailedTestList($testsFailedFile, $testsReRunFile) if (!empty($test)) { $this->writeFailedTestToFile($test, $testsReRunFile); $testInfo = explode(DIRECTORY_SEPARATOR, $test); - $testName = explode(":", $testInfo[count($testInfo) - 1])[1]; - $suiteName = $testInfo[count($testInfo) - 2]; - + $testName = isset($testInfo[count($testInfo) - 1][1]) + ? explode(":", $testInfo[count($testInfo) - 1])[1] + : []; + $suiteName = isset($testInfo[count($testInfo) - 2]) + ? $testInfo[count($testInfo) - 2] + : []; if ($suiteName === self::DEFAULT_TEST_GROUP) { array_push($failedTestDetails['tests'], $testName); } else { From 2486bd85b52f6766bb0881179dd35f489cc0473a Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Fri, 6 May 2022 14:22:51 +0530 Subject: [PATCH 847/888] fixed unit test failure --- .../Console/GenerateTestFailedCommandTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Console/GenerateTestFailedCommandTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Console/GenerateTestFailedCommandTest.php index 675fa8715..317868300 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Console/GenerateTestFailedCommandTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Console/GenerateTestFailedCommandTest.php @@ -43,8 +43,10 @@ public function testMultipleTestsWithSuites(): void { $testFileReturn = [ "tests/functional/tests/MFTF/_generated/SomeSpecificSuite/FirstTestSuiteTest.php:SingleTestSuiteTest", - "tests/functional/tests/MFTF/_generated/SomeSpecificSuite/SecondTestNoSuiteTest.php:SingleTestNoSuiteTest", ]; - $expectedConfiguration = '{"tests":null,"suites":{"SomeSpecificSuite":["SingleTestSuiteTest","SingleTestNoSuiteTest"]}}'; + "tests/functional/tests/MFTF/_generated/SomeSpecificSuite/SecondTestNoSuiteTest.php:SingleTestNoSuiteTest" + ]; + $expectedConfiguration = + '{"tests":null,"suites":{"SomeSpecificSuite":["SingleTestSuiteTest","SingleTestNoSuiteTest"]}}'; // Create a stub for the SomeClass class. $stub = $this->getMockBuilder(GenerateTestFailedCommand::class) From 6b65074bdbdea7e08edca6a907635c67f7a9cff4 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Fri, 6 May 2022 14:31:49 +0530 Subject: [PATCH 848/888] fixed unit test failure --- .../Console/GenerateTestFailedCommand.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateTestFailedCommand.php index 6ebae7528..380270969 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateTestFailedCommand.php @@ -91,6 +91,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int * Returns a json string of tests that failed on the last run * * @return string + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function getFailedTestList($testsFailedFile, $testsReRunFile) { From bcf0d449afebdd54ac0ec1f22f158fa9155512f0 Mon Sep 17 00:00:00 2001 From: manjusha729 <93243302+manjusha729@users.noreply.github.com> Date: Fri, 6 May 2022 22:00:30 +0530 Subject: [PATCH 849/888] MQE-2233 : Support xUnit-compatible Output Format (#187) * MQE-2233 : Support xUnit-compatible Output Format * MQE-2233 : Support xUnit-compatible Output Format * modified testname in doc * added not empty condition * added not empty condition * added doc for new option + Added the right description regarding where file is moved * added doc for new option + Added the right description regarding where file is moved Co-authored-by: Manjusha.S <manjusha.s@BLR1-LMC-N71373.local> Co-authored-by: Kevin Kozan <kkozan@adobe.com> --- docs/commands/mftf.md | 6 ++- .../Console/BaseGenerateCommand.php | 25 ++++++++++++ .../Console/RunTestCommand.php | 38 ++++++++++++++----- .../Console/RunTestGroupCommand.php | 23 +++++++++-- 4 files changed, 76 insertions(+), 16 deletions(-) diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index be026cd74..4b4bb4bab 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -353,7 +353,7 @@ Generates and executes the listed groups of tests using Codeception. #### Usage ```bash -vendor/bin/mftf run:group [--skip-generate|--remove] [--] <group1> [<group2>] +vendor/bin/mftf run:group [--skip-generate|--remove|--xml] [--] <group1> [<group2>] ``` #### Options @@ -363,6 +363,7 @@ vendor/bin/mftf run:group [--skip-generate|--remove] [--] <group1> [<group2>] | `-k, --skip-generate` | Skips generating from the source XML. Instead, the command executes previously-generated groups of tests. | | `-r, --remove` | Removes previously generated suites and tests before the actual generation and run. | | `--debug` | Performs schema validations on XML files. `run:group` implicitly performs schema validation on merged files. It does not indicate the file name where the error is encountered. `--debug` performs per-file validation and returns additional debug information (such as the filename where an error occurred).| +| `--xml` | Generate JUnit XML Log (default: "report.xml") | #### Examples @@ -385,7 +386,7 @@ Generates and executes tests by name using Codeception. #### Usage ```bash -vendor/bin/mftf run:test [--skip-generate|--remove] [--] <name1> [<name2>] +vendor/bin/mftf run:test [--skip-generate|--remove|--xml] [--] <name1> [<name2>] ``` #### Options @@ -395,6 +396,7 @@ vendor/bin/mftf run:test [--skip-generate|--remove] [--] <name1> [<name2>] | `-k, --skip-generate` | Skips generating from the source XML. Instead, the command executes previously-generated groups of tests. | | `-r, --remove` | Remove previously generated suites and tests. | | `--debug` | Performs schema validations on XML files. `run:test` implicitly performs schema validation on merged files. It does not indicate the file name where the error is encountered. `--debug` performs per-file validation and returns additional debug information (such as the filename where an error occurred).| +| `--xml` | Generate JUnit XML Log (default: "report.xml") | #### Examples diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index 2d00e0abd..0c209d8f2 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -364,4 +364,29 @@ protected function applyAllFailed() } catch (TestFrameworkException $e) { } } + /** + * Codeception creates default xml file with name report.xml . + * This function renames default file name with name of the test. + * + * @param string $xml + * @param string $fileName + * @param OutputInterface $output + * @return void + * @throws \Exception + */ + public function movingXMLFileFromSourceToDestination($xml, $fileName, $output) + { + if(!empty($xml) && file_exists($this->getTestsOutputDir().'report.xml')) { + if (!file_exists($this->getTestsOutputDir().'xml')) { + mkdir($this->getTestsOutputDir().'xml' , 0777, true); + } + $fileName = str_replace("Cest.php", "",$fileName); + $existingFileName = $this->getTestsOutputDir().'report.xml'; + $newFileName = $this->getTestsOutputDir().'xml/'.$fileName.'_report.xml'; + $output->writeln( "<info>".sprintf(" report.xml file is moved to ". + $this->getTestsOutputDir().'xml/'. ' location with the new name '.$fileName.'_report.xml')."</info>") ; + rename($existingFileName , $newFileName); + } + } + } diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php index cf58bc050..95c2f563a 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php @@ -41,6 +41,12 @@ protected function configure() { $this->setName("run:test") ->setDescription("generation and execution of test(s) defined in xml") + ->addOption( + 'xml', + 'xml', + InputOption::VALUE_NONE, + "creates xml report for executed test" + ) ->addArgument( 'name', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, @@ -134,11 +140,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int $testConfigArray = json_decode($testConfiguration, true); if (isset($testConfigArray['tests'])) { - $this->runTests($testConfigArray['tests'], $output); + $this->runTests($testConfigArray['tests'], $output, $input); } if (isset($testConfigArray['suites'])) { - $this->runTestsInSuite($testConfigArray['suites'], $output); + $this->runTestsInSuite($testConfigArray['suites'], $output, $input); } // Add all failed tests in 'failed' file @@ -152,12 +158,16 @@ protected function execute(InputInterface $input, OutputInterface $output): int * * @param array $tests * @param OutputInterface $output + * @param InputInterface $input * @return void * @throws TestFrameworkException * @throws \Exception */ - private function runTests(array $tests, OutputInterface $output) + private function runTests(array $tests, OutputInterface $output, InputInterface $input) { + $xml = ($input->getOption('xml')) + ? '--xml' + : ""; if ($this->pauseEnabled()) { $codeceptionCommand = self::CODECEPT_RUN_FUNCTIONAL; } else { @@ -179,16 +189,18 @@ private function runTests(array $tests, OutputInterface $output) } if ($this->pauseEnabled()) { - $fullCommand = $codeceptionCommand . $testsDirectory . $testName . ' --verbose --steps --debug'; + $fullCommand = $codeceptionCommand . $testsDirectory . $testName . ' --verbose --steps --debug '.$xml; if ($i !== count($tests) - 1) { $fullCommand .= self::CODECEPT_RUN_OPTION_NO_EXIT; } $this->returnCode = max($this->returnCode, $this->codeceptRunTest($fullCommand, $output)); } else { - $fullCommand = $codeceptionCommand . $testsDirectory . $testName . ' --verbose --steps'; + $fullCommand = $codeceptionCommand . $testsDirectory . $testName . ' --verbose --steps '.$xml; $this->returnCode = max($this->returnCode, $this->executeTestCommand($fullCommand, $output)); } - + if (!empty($xml)) { + $this->movingXMLFileFromSourceToDestination($xml, $testName, $output); + } // Save failed tests $this->appendRunFailed(); } @@ -199,16 +211,20 @@ private function runTests(array $tests, OutputInterface $output) * * @param array $suitesConfig * @param OutputInterface $output + * @param InputInterface $input * @return void * @throws \Exception */ - private function runTestsInSuite(array $suitesConfig, OutputInterface $output) + private function runTestsInSuite(array $suitesConfig, OutputInterface $output, InputInterface $input) { + $xml = ($input->getOption('xml')) + ? '--xml' + : ""; if ($this->pauseEnabled()) { - $codeceptionCommand = self::CODECEPT_RUN_FUNCTIONAL . '--verbose --steps --debug'; + $codeceptionCommand = self::CODECEPT_RUN_FUNCTIONAL . '--verbose --steps --debug '.$xml; } else { $codeceptionCommand = realpath(PROJECT_ROOT . '/vendor/bin/codecept') - . ' run functional --verbose --steps '; + . ' run functional --verbose --steps '.$xml; } $count = count($suitesConfig); @@ -226,7 +242,9 @@ private function runTestsInSuite(array $suitesConfig, OutputInterface $output) } else { $this->returnCode = max($this->returnCode, $this->executeTestCommand($fullCommand, $output)); } - + if (!empty($xml)) { + $this->movingXMLFileFromSourceToDestination($xml, $suite, $output); + } // Save failed tests $this->appendRunFailed(); } diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php index d9a549627..38e3366d7 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php @@ -29,7 +29,15 @@ class RunTestGroupCommand extends BaseGenerateCommand protected function configure() { $this->setName('run:group') - ->setDescription('Execute a set of tests referenced via group annotations') + ->setDescription( + 'Execute a set of tests referenced via group annotations' + ) + ->addOption( + 'xml', + 'xml', + InputOption::VALUE_NONE, + "creates xml report for executed group" + ) ->addOption( 'skip-generate', 'k', @@ -58,6 +66,9 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output): int { + $xml = ($input->getOption('xml')) + ? '--xml' + : ""; $skipGeneration = $input->getOption('skip-generate'); $force = $input->getOption('force'); $groups = $input->getArgument('groups'); @@ -104,9 +115,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int } if ($this->pauseEnabled()) { - $commandString = self::CODECEPT_RUN_FUNCTIONAL . '--verbose --steps --debug'; + $commandString = self::CODECEPT_RUN_FUNCTIONAL . '--verbose --steps --debug '.$xml; } else { - $commandString = realpath(PROJECT_ROOT . '/vendor/bin/codecept') . ' run functional --verbose --steps'; + $commandString = realpath( + PROJECT_ROOT . '/vendor/bin/codecept' + ) . ' run functional --verbose --steps '.$xml; } $exitCode = -1; @@ -130,7 +143,9 @@ function ($type, $buffer) use ($output) { } ); } - + if (!empty($xml)) { + $this->movingXMLFileFromSourceToDestination($xml, $groups[$i].'_'.'group', $output); + } // Save failed tests $this->appendRunFailed(); } From cbff68a156dcec362fc07308bb673eac5ae24ec2 Mon Sep 17 00:00:00 2001 From: manjusha729 <93243302+manjusha729@users.noreply.github.com> Date: Mon, 9 May 2022 20:41:56 +0530 Subject: [PATCH 850/888] MQE-3300 : Show credentials in allure report for suite (#186) * MQE-3300 : Show credentials in allure report for suite * MQE-3300 : Show credentials in allure report for suite * fixed verification test failure * fixed verification test failure * fixed verification test failure * added deleted line back * remove new line space from creds * get credentials for hook actions * fix psr * MQE-3300 : Show credentials in allure report for suite - Small change to secret message Co-authored-by: Manjusha.S <manjusha.s@BLR1-LMC-N71373.local> Co-authored-by: Kevin Kozan <kkozan@magento.com> Co-authored-by: Kevin Kozan <kkozan@adobe.com> --- .../Test/Objects/ActionGroupObjectTest.php | 118 ++++++++++++++---- .../Test/Objects/ActionObjectTest.php | 53 +++++--- .../Test/Util/ActionMergeUtilTest.php | 22 ++-- .../Resources/BasicFunctionalTest.txt | 2 +- .../Test/Objects/ActionObject.php | 17 +++ .../Test/Objects/TestObject.php | 23 ++++ .../Util/TestGenerator.php | 36 ++++-- 7 files changed, 211 insertions(+), 60 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionGroupObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionGroupObjectTest.php index a6df01937..c66303ba6 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionGroupObjectTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionGroupObjectTest.php @@ -49,7 +49,7 @@ public function testGetStepsWithDefaultCase(): void $this->setEntityObjectHandlerReturn($entity); $actionGroupUnderTest = (new ActionGroupObjectBuilder())->build(); $steps = $actionGroupUnderTest->getSteps(null, self::ACTION_GROUP_MERGE_KEY); - $this->assertOnMergeKeyAndActionValue($steps, ['userInput' => 'literal']); + $this->assertOnMergeKeyAndActionValue($steps, ['userInput' => 'literal', 'requiredCredentials' => '']); } /** @@ -67,30 +67,48 @@ public function testGetStepsWithCustomArgs(): void }); $actionGroupUnderTest = (new ActionGroupObjectBuilder()) - ->withActionObjects([new ActionObject('action1', 'testAction', ['userInput' => '{{arg1.field2}}'])]) - ->withArguments([new ArgumentObject('arg1', null, 'entity')]) - ->build(); + ->withActionObjects([new ActionObject( + 'action1', + 'testAction', + [ + 'userInput' => '{{arg1.field2}}','requiredCredentials' => '' + ] + )]) + ->withArguments([new ArgumentObject('arg1', null, 'entity')]) + ->build(); $steps = $actionGroupUnderTest->getSteps(['arg1' => 'data2'], self::ACTION_GROUP_MERGE_KEY); - $this->assertOnMergeKeyAndActionValue($steps, ['userInput' => 'testValue2']); + $this->assertOnMergeKeyAndActionValue($steps, ['userInput' => 'testValue2','requiredCredentials' => '']); // entity.field as argument $actionGroupUnderTest = (new ActionGroupObjectBuilder()) - ->withActionObjects([new ActionObject('action1', 'testAction', ['userInput' => '{{arg1}}'])]) + ->withActionObjects([new ActionObject( + 'action1', + 'testAction', + ['userInput' => '{{arg1}}', + 'requiredCredentials' => '' + ] + )]) ->withArguments([new ArgumentObject('arg1', null, 'entity')]) ->build(); $steps = $actionGroupUnderTest->getSteps(['arg1' => 'data2.field2'], self::ACTION_GROUP_MERGE_KEY); - $this->assertOnMergeKeyAndActionValue($steps, ['userInput' => 'testValue2']); + $this->assertOnMergeKeyAndActionValue($steps, ['userInput' => 'testValue2', 'requiredCredentials' => '']); // String Data $actionGroupUnderTest = (new ActionGroupObjectBuilder()) - ->withActionObjects([new ActionObject('action1', 'testAction', ['userInput' => '{{simple}}'])]) + ->withActionObjects([new ActionObject( + 'action1', + 'testAction', + ['userInput' => '{{simple}}', + 'requiredCredentials' => '' + ] + )]) ->withArguments([new ArgumentObject('simple', null, 'string')]) ->build(); $steps = $actionGroupUnderTest->getSteps(['simple' => 'override'], self::ACTION_GROUP_MERGE_KEY); - $this->assertOnMergeKeyAndActionValue($steps, ['userInput' => 'override']); + $this->assertOnMergeKeyAndActionValue($steps, ['userInput' => 'override', 'requiredCredentials' => '']); } /** @@ -102,21 +120,32 @@ public function testGetStepsWithCustomArgs(): void public function testGetStepsWithPersistedArgs(): void { $actionGroupUnderTest = (new ActionGroupObjectBuilder()) - ->withActionObjects([new ActionObject('action1', 'testAction', ['userInput' => '{{arg1.field2}}'])]) + ->withActionObjects([new ActionObject( + 'action1', + 'testAction', + ['userInput' => '{{arg1.field2}}', + 'requiredCredentials' => ''] + )]) ->withArguments([new ArgumentObject('arg1', null, 'entity')]) ->build(); $steps = $actionGroupUnderTest->getSteps(['arg1' => '$data3$'], self::ACTION_GROUP_MERGE_KEY); - $this->assertOnMergeKeyAndActionValue($steps, ['userInput' => '$data3.field2$']); + $this->assertOnMergeKeyAndActionValue($steps, ['userInput' => '$data3.field2$','requiredCredentials' => '']); // Simple Data $actionGroupUnderTest = (new ActionGroupObjectBuilder()) - ->withActionObjects([new ActionObject('action1', 'testAction', ['userInput' => '{{simple}}'])]) + ->withActionObjects([new ActionObject( + 'action1', + 'testAction', + ['userInput' => '{{simple}}', + 'requiredCredentials' => '' + ] + )]) ->withArguments([new ArgumentObject('simple', null, 'string')]) ->build(); $steps = $actionGroupUnderTest->getSteps(['simple' => '$data3.field2$'], self::ACTION_GROUP_MERGE_KEY); - $this->assertOnMergeKeyAndActionValue($steps, ['userInput' => '$data3.field2$']); + $this->assertOnMergeKeyAndActionValue($steps, ['userInput' => '$data3.field2$','requiredCredentials' => '']); } /** @@ -134,12 +163,18 @@ public function testGetStepsWithNoFieldArg(): void }); $actionGroupUnderTest = (new ActionGroupObjectBuilder()) - ->withActionObjects([new ActionObject('action1', 'testAction', ['userInput' => '{{arg1}}'])]) + ->withActionObjects([new ActionObject( + 'action1', + 'testAction', + ['userInput' => '{{arg1}}', + 'requiredCredentials' => '' + ] + )]) ->withArguments([new ArgumentObject('arg1', null, 'entity')]) ->build(); $steps = $actionGroupUnderTest->getSteps(['arg1' => 'data2.field2'], self::ACTION_GROUP_MERGE_KEY); - $this->assertOnMergeKeyAndActionValue($steps, ['userInput' => 'testValue2']); + $this->assertOnMergeKeyAndActionValue($steps, ['userInput' => 'testValue2','requiredCredentials' => '']); } /** @@ -157,11 +192,17 @@ public function testGetStepsWithNoArgs(): void }); $actionGroupUnderTest = (new ActionGroupObjectBuilder()) - ->withActionObjects([new ActionObject('action1', 'testAction', ['userInput' => '{{data1.field1}}'])]) + ->withActionObjects([new ActionObject( + 'action1', + 'testAction', + ['userInput' => '{{data1.field1}}', + 'requiredCredentials' => '' + ] + )]) ->build(); $steps = $actionGroupUnderTest->getSteps(null, self::ACTION_GROUP_MERGE_KEY); - $this->assertOnMergeKeyAndActionValue($steps, ['userInput' => 'testValue']); + $this->assertOnMergeKeyAndActionValue($steps, ['userInput' => 'testValue','requiredCredentials' => '']); } /** @@ -199,11 +240,22 @@ public function testGetStepsWithParameterizedArg(): void // XML Data $steps = $actionGroupUnderTest->getSteps(['arg1' => 'data2'], self::ACTION_GROUP_MERGE_KEY); - $this->assertOnMergeKeyAndActionValue($steps, ['selector' => '.selector testValue2']); + $this->assertOnMergeKeyAndActionValue($steps, [ + 'selector' => '.selector testValue2', + 'requiredCredentials' => '' + ]); // Persisted Data - $steps = $actionGroupUnderTest->getSteps(['arg1' => '$data2$'], self::ACTION_GROUP_MERGE_KEY); - $this->assertOnMergeKeyAndActionValue($steps, ['selector' => '.selector $data2.field2$']); + $steps = $actionGroupUnderTest->getSteps( + ['arg1' => '$data2$'], + self::ACTION_GROUP_MERGE_KEY + ); + $this->assertOnMergeKeyAndActionValue( + $steps, + ['selector' => '.selector $data2.field2$', + 'requiredCredentials' => '' + ] + ); } /** @@ -242,15 +294,28 @@ public function testGetStepsWithParameterizedSimpleArg(): void // String Literal $steps = $actionGroupUnderTest->getSteps(['simple' => 'stringLiteral'], self::ACTION_GROUP_MERGE_KEY); - $this->assertOnMergeKeyAndActionValue($steps, ['selector' => '.selector stringLiteral']); + $this->assertOnMergeKeyAndActionValue($steps, [ + 'selector' => '.selector stringLiteral', + 'requiredCredentials' => '' + ]); // String Literal w/ data-like structure $steps = $actionGroupUnderTest->getSteps(['simple' => 'data2.field2'], self::ACTION_GROUP_MERGE_KEY); - $this->assertOnMergeKeyAndActionValue($steps, ['selector' => '.selector data2.field2']); + $this->assertOnMergeKeyAndActionValue( + $steps, + ['selector' => '.selector data2.field2', + 'requiredCredentials' => '' + ] + ); // Persisted Data $steps = $actionGroupUnderTest->getSteps(['simple' => '$someData.field1$'], self::ACTION_GROUP_MERGE_KEY); - $this->assertOnMergeKeyAndActionValue($steps, ['selector' => '.selector $someData.field1$']); + $this->assertOnMergeKeyAndActionValue( + $steps, + ['selector' => '.selector $someData.field1$', + 'requiredCredentials' => '' + ] + ); } /** @@ -267,7 +332,12 @@ public function testGetStepsWithOuterScopePersistence(): void ->build(); $steps = $actionGroupUnderTest->getSteps(['arg1' => '$$someData$$'], self::ACTION_GROUP_MERGE_KEY); - $this->assertOnMergeKeyAndActionValue($steps, ['userInput' => '$$someData.field1$$']); + $this->assertOnMergeKeyAndActionValue( + $steps, + ['userInput' => '$$someData.field1$$', + 'requiredCredentials' => '' + ] + ); } /** diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php index f3c75a073..d64de1cac 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php @@ -71,7 +71,8 @@ public function testResolveElementInSelector(): void // Set up mocks $actionObject = new ActionObject('merge123', 'fillField', [ 'selector' => '{{SectionObject.elementObject}}', - 'userInput' => 'Hello world' + 'userInput' => 'Hello world', + 'requiredCredentials' => '' ]); $elementObject = new ElementObject('elementObject', 'button', '#replacementSelector', null, '42', false); $this->mockSectionHandlerWithElement($elementObject); @@ -82,7 +83,8 @@ public function testResolveElementInSelector(): void // Verify $expected = [ 'selector' => '#replacementSelector', - 'userInput' => 'Hello world' + 'userInput' => 'Hello world', + 'requiredCredentials' => '' ]; $this->assertEquals($expected, $actionObject->getCustomActionAttributes()); } @@ -98,7 +100,8 @@ public function testResolveSelectorWithOneStringLiteral(): void { $actionObject = new ActionObject('key123', 'fillField', [ 'selector' => "{{SectionObject.elementObject('stringliteral')}}", - 'userInput' => 'Input' + 'userInput' => 'Input', + 'requiredCredentials' => '' ]); $elementObject = new ElementObject('elementObject', 'button', '#{{var1}}', null, '42', true); $this->mockSectionHandlerWithElement($elementObject); @@ -109,7 +112,8 @@ public function testResolveSelectorWithOneStringLiteral(): void // Verify $expected = [ 'selector' => '#stringliteral', - 'userInput' => 'Input' + 'userInput' => 'Input', + 'requiredCredentials' => '' ]; $this->assertEquals($expected, $actionObject->getCustomActionAttributes()); } @@ -125,7 +129,8 @@ public function testResolveSelectorWithOneDataReference(): void { $actionObject = new ActionObject('key123', 'fillField', [ 'selector' => "{{SectionObject.elementObject(dataObject.key)}}", - 'userInput' => 'Input' + 'userInput' => 'Input', + 'requiredCredentials' => '' ]); // Mock SectionHandler @@ -142,7 +147,8 @@ public function testResolveSelectorWithOneDataReference(): void // Verify $expected = [ 'selector' => '#myValue', - 'userInput' => 'Input' + 'userInput' => 'Input', + 'requiredCredentials' => '' ]; $this->assertEquals($expected, $actionObject->getCustomActionAttributes()); } @@ -158,7 +164,8 @@ public function testResolveSelectorWithOnePersistedReference(): void { $actionObject = new ActionObject('key123', 'fillField', [ 'selector' => '{{SectionObject.elementObject($data.key$)}}', - 'userInput' => 'Input' + 'userInput' => 'Input', + 'requiredCredentials' => '' ]); // Mock SectionHandler @@ -171,7 +178,8 @@ public function testResolveSelectorWithOnePersistedReference(): void // Verify $expected = [ 'selector' => '#$data.key$', - 'userInput' => 'Input' + 'userInput' => 'Input', + 'requiredCredentials' => '' ]; $this->assertEquals($expected, $actionObject->getCustomActionAttributes()); } @@ -204,7 +212,8 @@ public function testResolveSelectorWithManyParams(): void // Verify $expected = [ 'selector' => '#stringLiteral[myValue,$data.key$]', - 'userInput' => 'Input' + 'userInput' => 'Input', + 'requiredCredentials' => '' ]; $this->assertEquals($expected, $actionObject->getCustomActionAttributes()); } @@ -260,7 +269,7 @@ public function testResolveUrl(): void // Verify $expected = [ - 'url' => '/replacement/url.html' + 'url' => '/replacement/url.html','requiredCredentials' => '' ]; $this->assertEquals($expected, $actionObject->getCustomActionAttributes()); } @@ -330,7 +339,8 @@ public function testResolveDataInUserInput(): void // Set up mocks $actionObject = new ActionObject('merge123', 'fillField', [ 'selector' => '#selector', - 'userInput' => '{{EntityDataObject.key}}' + 'userInput' => '{{EntityDataObject.key}}', + 'requiredCredentials' => '' ]); $entityDataObject = new EntityDataObject('EntityDataObject', 'test', [ 'key' => 'replacementData' @@ -343,7 +353,8 @@ public function testResolveDataInUserInput(): void // Verify $expected = [ 'selector' => '#selector', - 'userInput' => 'replacementData' + 'userInput' => 'replacementData', + 'requiredCredentials' => '' ]; $this->assertEquals($expected, $actionObject->getCustomActionAttributes()); } @@ -360,7 +371,8 @@ public function testResolveArrayData(): void // Set up mocks $actionObject = new ActionObject('merge123', 'fillField', [ 'selector' => '#selector', - 'userInput' => '{{EntityDataObject.values}}' + 'userInput' => '{{EntityDataObject.values}}', + 'requiredCredentials' => '' ]); $entityDataObject = new EntityDataObject('EntityDataObject', 'test', [ 'values' => [ @@ -373,11 +385,11 @@ public function testResolveArrayData(): void // Call the method under test $actionObject->resolveReferences(); - - // Verify + //Verify $expected = [ 'selector' => '#selector', - 'userInput' => '["value1","value2","\"My\" Value"]' + 'userInput' => '["value1","value2","\"My\" Value"]', + 'requiredCredentials' => '' ]; $this->assertEquals($expected, $actionObject->getCustomActionAttributes()); } @@ -395,7 +407,8 @@ public function testTooFewArgumentException(): void $actionObject = new ActionObject('key123', 'fillField', [ 'selector' => "{{SectionObject.elementObject('arg1')}}", - 'userInput' => 'Input' + 'userInput' => 'Input', + 'requiredCredentials' => '' ]); $elementObject = new ElementObject('elementObject', 'button', '#{{var1}} {{var2}}', null, '42', true); $this->mockSectionHandlerWithElement($elementObject); @@ -417,7 +430,8 @@ public function testTooManyArgumentException(): void $actionObject = new ActionObject('key123', 'fillField', [ 'selector' => "{{SectionObject.elementObject('arg1', 'arg2', 'arg3')}}", - 'userInput' => 'Input' + 'userInput' => 'Input', + 'requiredCredentials' => '' ]); $elementObject = new ElementObject('elementObject', 'button', '#{{var1}}', null, '42', true); $this->mockSectionHandlerWithElement($elementObject); @@ -438,7 +452,8 @@ public function testInvalidTimezoneException(): void $this->expectException(TestReferenceException::class); $actionObject = new ActionObject('key123', 'generateDate', [ - 'timezone' => "INVALID_TIMEZONE" + 'timezone' => "INVALID_TIMEZONE", + 'requiredCredentials' => '' ]); // Call the method under test diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php index 56bb0f0c5..99152b8f0 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php @@ -126,7 +126,7 @@ public function testResolveActionStepEntityData(): void $property->setValue($mockDOHInstance, $mockDOHInstance); // Create test object and action object - $actionAttributes = [$userInputKey => $userInputValue]; + $actionAttributes = [$userInputKey => $userInputValue,'requiredCredentials'=>'']; $actions[$actionName] = new ActionObject($actionName, $actionType, $actionAttributes); $this->assertEquals($userInputValue, $actions[$actionName]->getCustomActionAttributes()[$userInputKey]); @@ -198,7 +198,7 @@ public function testValidFillFieldSecretFunction(): void $actionObjectOne = new ActionObject( 'actionKey1', 'fillField', - ['userInput' => '{{_CREDS.username}}'] + ['userInput' => '{{_CREDS.username}}', 'requiredCredentials' => 'username'] ); $actionObject = [$actionObjectOne]; @@ -208,7 +208,7 @@ public function testValidFillFieldSecretFunction(): void $expectedValue = new ActionObject( 'actionKey1', 'fillSecretField', - ['userInput' => '{{_CREDS.username}}'] + ['userInput' => '{{_CREDS.username}}','requiredCredentials' => 'username'] ); $this->assertEquals($expectedValue, $result['actionKey1']); } @@ -225,7 +225,10 @@ public function testValidMagentoCLISecretFunction(): void $actionObjectOne = new ActionObject( 'actionKey1', 'magentoCLI', - ['command' => 'config:set cms/wysiwyg/enabled {{_CREDS.payment_authorizenet_login}}'] + ['command' => + 'config:set cms/wysiwyg/enabled {{_CREDS.payment_authorizenet_login}}', + 'requiredCredentials' => '' + ] ); $actionObject = [$actionObjectOne]; @@ -235,7 +238,10 @@ public function testValidMagentoCLISecretFunction(): void $expectedValue = new ActionObject( 'actionKey1', 'magentoCLISecret', - ['command' => 'config:set cms/wysiwyg/enabled {{_CREDS.payment_authorizenet_login}}'] + ['command' => + 'config:set cms/wysiwyg/enabled {{_CREDS.payment_authorizenet_login}}', + 'requiredCredentials' => '' + ] ); $this->assertEquals($expectedValue, $result['actionKey1']); } @@ -252,7 +258,7 @@ public function testValidCreateDataSecretFunction(): void $actionObjectOne = new ActionObject( 'actionKey1', 'field', - ['value' => '{{_CREDS.payment_authorizenet_login}}'] + ['value' => '{{_CREDS.payment_authorizenet_login}}','requiredCredentials' => ''] ); $actionObject = [$actionObjectOne]; @@ -262,7 +268,7 @@ public function testValidCreateDataSecretFunction(): void $expectedValue = new ActionObject( 'actionKey1', 'field', - ['value' => '{{_CREDS.payment_authorizenet_login}}'] + ['value' => '{{_CREDS.payment_authorizenet_login}}','requiredCredentials' => ''] ); $this->assertEquals($expectedValue, $result['actionKey1']); } @@ -284,7 +290,7 @@ public function testInvalidSecretFunctions(): void $actionObjectOne = new ActionObject( 'actionKey1', 'click', - ['userInput' => '{{_CREDS.username}}'] + ['userInput' => '{{_CREDS.username}}','requiredCredentials' => 'username'] ); $actionObject = [$actionObjectOne]; diff --git a/dev/tests/verification/Resources/BasicFunctionalTest.txt b/dev/tests/verification/Resources/BasicFunctionalTest.txt index e30f50c34..97403a39a 100644 --- a/dev/tests/verification/Resources/BasicFunctionalTest.txt +++ b/dev/tests/verification/Resources/BasicFunctionalTest.txt @@ -151,7 +151,7 @@ class BasicFunctionalTestCest $I->moveForward(); // stepKey: moveForwardKey1 $I->moveMouseOver(".functionalTestSelector"); // stepKey: moveMouseOverKey1 $I->openNewTab(); // stepKey: openNewTabKey1 - $I->pause(); // stepKey: pauseKey1 + $I->pause(true); // stepKey: pauseKey1 $I->pressKey("#page", "a"); // stepKey: pressKey1 $I->pressKey("#page", ['ctrl', 'a'],'new'); // stepKey: pressKey2 $I->pressKey("#page", ['shift', '111'],'1','x'); // stepKey: pressKey3 diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php index aec38c9a5..451b58aa0 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php @@ -289,6 +289,7 @@ public function resolveReferences() $this->resolveSelectorReferenceAndTimeout(); $this->resolveUrlReference(); $this->resolveDataInputReferences(); + $this->detectCredentials(); $this->validateTimezoneAttribute(); if ($this->getType() === 'deleteData') { $this->validateMutuallyExclusiveAttributes(self::DELETE_DATA_MUTUAL_EXCLUSIVE_ATTRIBUTES); @@ -417,6 +418,22 @@ private function resolveSelectorReferenceAndTimeout() } } } + /** + * Sets requiredCredentials property + * + * @return void + * @throws TestReferenceException + */ + public function detectCredentials() + { + $requiredCredentials = ""; + $attributes = $this->getCustomActionAttributes(); + if (isset($attributes['userInput']) && stristr($attributes['userInput'], '_CREDS') == true) { + $credentials = explode(".", trim($attributes['userInput'], '{}')); + $requiredCredentials = $credentials[1]; + } + $this->resolvedCustomAttributes['requiredCredentials'] = $requiredCredentials; + } /** * Look up the url for SomePageName and set it, with MAGENTO_BASE_URL prepended, as the url attribute in the diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php index 9da9191cd..86b33285d 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/TestObject.php @@ -259,6 +259,29 @@ public function getEstimatedDuration() } } + /** + * Function to return credentials + * @return array + */ + public function getCredentials() + { + $requiredCredentials = []; + foreach ($this->hooks as $hookObject) { + foreach ($hookObject->getActions() as $action) { + if (isset($action->getCustomActionAttributes()['requiredCredentials']) + && !empty($action->getCustomActionAttributes()['requiredCredentials'])) { + $requiredCredentials[] = $action->getCustomActionAttributes()['requiredCredentials']; + } + } + } + foreach ($this->getOrderedActions() as $action) { + if (isset($action->getCustomActionAttributes()['requiredCredentials']) + && !empty($action->getCustomActionAttributes()['requiredCredentials'])) { + $requiredCredentials[] = $action->getCustomActionAttributes()['requiredCredentials']; + } + } + return array_unique($requiredCredentials); + } /** * Function which takes a set of actions and estimates time for completion based on action type. * diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 0c47036f0..00e58da61 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -273,7 +273,7 @@ public function assembleTestPhp($testObject) } catch (TestReferenceException $e) { throw new TestReferenceException($e->getMessage() . "\n" . $testObject->getFilename()); } - $classAnnotationsPhp = $this->generateAnnotationsPhp($testObject->getAnnotations()); + $classAnnotationsPhp = $this->generateAnnotationsPhp($testObject); $cestPhp = "<?php\n"; $cestPhp .= "namespace Magento\AcceptanceTest\\_" . $this->exportDirName . "\Backend;\n\n"; @@ -449,12 +449,13 @@ private function generateUseStatementsPhp() /** * Generates Annotations PHP for given object, using given scope to determine indentation and additional output. * - * @param array $annotationsObject + * @param array $testObject * @param boolean $isMethod * @return string */ - private function generateAnnotationsPhp($annotationsObject, $isMethod = false) + private function generateAnnotationsPhp($testObject, $isMethod = false) { + $annotationsObject = $testObject->getAnnotations(); //TODO: Refactor to deal with PHPMD.CyclomaticComplexity if ($isMethod) { $indent = "\t"; @@ -470,7 +471,7 @@ private function generateAnnotationsPhp($annotationsObject, $isMethod = false) continue; } if (!$isMethod) { - $annotationsPhp .= $this->generateClassAnnotations($annotationType, $annotationName); + $annotationsPhp .= $this->generateClassAnnotations($annotationType, $annotationName, $testObject); } else { $annotationsPhp .= $this->generateMethodAnnotations($annotationType, $annotationName); } @@ -536,19 +537,39 @@ private function generateMethodAnnotations($annotationType = null, $annotationNa return $annotationToAppend; } + /** + * Returs required credentials to configure + * + * @param TestObject $testObject + * @return string + */ + public function requiredCredentials($testObject) + { + $requiredCredentials = (!empty($testObject->getCredentials())) + ? implode(",", $testObject->getCredentials()) + : ""; + + return $requiredCredentials; + } /** * Method which return formatted class level annotations based on type and name(s). * * @param string $annotationType * @param array $annotationName + * @param array $testObject * @return null|string * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ - private function generateClassAnnotations($annotationType, $annotationName) + private function generateClassAnnotations($annotationType, $annotationName, $testObject) { $annotationToAppend = null; - + $requiredCredentialsMessage = $this->requiredCredentials($testObject); + $credMsg = "\n\n"."This test uses the following credentials:"."\n"; + if (!empty($requiredCredentialsMessage) && !empty($annotationName['main'])) { + $annotationName = ['main'=>$annotationName['main'].', '.$credMsg.''.$requiredCredentialsMessage, + 'test_files'=> "\n".$annotationName['test_files'], 'deprecated'=>$annotationName['deprecated']]; + } switch ($annotationType) { case "title": $annotationToAppend = sprintf(" * @Title(\"%s\")\n", $annotationName[0]); @@ -773,7 +794,6 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $selector = $this->addUniquenessFunctionCall($customActionAttributes['selector']); $selector = $this->resolveLocatorFunctionInAttribute($selector); } - if (isset($customActionAttributes['count'])) { $countClickValue = $customActionAttributes['count']; $countValue = $this->addUniquenessFunctionCall($countClickValue); @@ -1855,7 +1875,7 @@ private function generateTestPhp($test) $testName = $test->getName(); $testName = str_replace(' ', '', $testName); - $testAnnotations = $this->generateAnnotationsPhp($test->getAnnotations(), true); + $testAnnotations = $this->generateAnnotationsPhp($test, true); $dependencies = 'AcceptanceTester $I'; if (!$test->isSkipped() || MftfApplicationConfig::getConfig()->allowSkipped()) { try { From 8321d7d6a767320e00173ece557d372e7dc64fe4 Mon Sep 17 00:00:00 2001 From: "Mohit.k.Sharma" <mohit.k.sharma@BLR1-LMC-N71405.local> Date: Mon, 16 May 2022 20:03:31 +0530 Subject: [PATCH 851/888] MQE-2953 | Get Cookie Expiry in mftf --- dev/.credentials | 1 + docs/test/actions.md | 29 ++++++++++++++++ etc/di.xml | 2 +- .../Module/MagentoWebDriver.php | 33 +++++++++++++++++++ .../Test/Objects/ActionGroupObject.php | 1 + .../Test/etc/Actions/grabActions.xsd | 18 +++++++++- .../Util/TestGenerator.php | 2 ++ 7 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 dev/.credentials diff --git a/dev/.credentials b/dev/.credentials new file mode 100644 index 000000000..50c0c05bf --- /dev/null +++ b/dev/.credentials @@ -0,0 +1 @@ +magento/MAGENTO_ADMIN_PASSWORD=Admin@123456 diff --git a/docs/test/actions.md b/docs/test/actions.md index 993a9ff84..73e3da0d6 100644 --- a/docs/test/actions.md +++ b/docs/test/actions.md @@ -144,6 +144,7 @@ The following test actions return a variable: * [grabAttributeFrom](#grabattributefrom) * [grabCookie](#grabcookie) +* [grabCookieAttributes](#grabCookieAttributes) * [grabFromCurrentUrl](#grabfromcurrenturl) * [grabMultiple](#grabmultiple) * [grabPageSource](#grabpagesource) @@ -1158,6 +1159,34 @@ To access this value, use `{$grabCookieExampleDomain}` in later actions. --> <grabCookie userInput="cookie1" parameterArray="['domainName' => '.example.com']" stepKey="grabCookieExampleDomain"/> ``` +### grabCookieAttributes + +See [grabCookieAttributes docs on codeception.com](http://codeception.com/docs/modules/WebDriver#grabCookieAttributes). + +Attribute|Type|Use|Description +---|---|---|--- +`userInput`|string|optional| Name of the cookie to grab. +`parameterArray`|string|optional| Array of cookie parameters to grab. +`stepKey`|string|required| A unique identifier of the action. +`before`|string|optional| `stepKey` of action that must be executed next. +`after`|string|optional| `stepKey` of preceding action. + +#### Examples + +```xml +<!-- Grab the cookie attributes with the given name `cookie1`. +To access these values, use `{$grabCookie1}` in later actions. --> +<grabCookieAttributes userInput="cookie1" stepKey="grabCookie1"/> +``` + +```xml +<!-- Grab the cookie attributes with the given name `cookie1` from the domain `www.example.com`. +To access these values, use `{$grabCookieExampleDomain}` in later actions. +To access expiry date, use `{$grabCookieExampleDomain.expiry}` in later actions. +--> +<grabCookieAttributes userInput="cookie1" parameterArray="['domainName' => '.example.com']" stepKey="grabCookieExampleDomain"/> +``` + ### grabFromCurrentUrl See [grabFromCurrentUrl docs on codeception.com](http://codeception.com/docs/modules/WebDriver#grabFromCurrentUrl).. diff --git a/etc/di.xml b/etc/di.xml index f5184808c..586158286 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -8,7 +8,7 @@ <!-- Entity value gets replaced in Dom.php before reading $xml --> <!DOCTYPE config [ - <!ENTITY commonTestActions "acceptPopup|actionGroup|amOnPage|amOnUrl|amOnSubdomain|appendField|assertArrayIsSortasserted|assertElementContainsAttribute|attachFile|cancelPopup|checkOption|clearField|click|clickWithLeftButton|clickWithRightButton|closeAdminNotification|closeTab|comment|conditionalClick|createData|deleteData|updateData|getData|dontSee|dontSeeJsError|dontSeeCheckboxIsChecked|dontSeeCookie|dontSeeCurrentUrlEquals|dontSeeCurrentUrlMatches|dontSeeElement|dontSeeElementInDOM|dontSeeInCurrentUrl|dontSeeInField|dontSeeInFormFields|dontSeeInPageSource|dontSeeInSource|dontSeeInTitle|dontSeeLink|dontSeeOptionIsSelected|doubleClick|dragAndDrop|entity|executeJS|fillField|formatCurrency|generateDate|getOTP|grabAttributeFrom|grabCookie|grabFromCurrentUrl|grabMultiple|grabPageSource|grabTextFrom|grabValueFrom|return|loadSessionSnapshot|loginAsAdmin|magentoCLI|magentoCron|makeScreenshot|maximizeWindow|moveBack|moveForward|moveMouseOver|mSetLocale|mResetLocale|openNewTab|pause|parseFloat|pressKey|reloadPage|resetCookie|submitForm|resizeWindow|saveSessionSnapshot|scrollTo|scrollToTopOfPage|searchAndMultiSelectOption|see|seeCheckboxIsChecked|seeCookie|seeCurrentUrlEquals|seeCurrentUrlMatches|seeElement|seeElementInDOM|seeInCurrentUrl|seeInField|seeInFormFields|seeInPageSource|seeInPopup|seeInSource|seeInTitle|seeLink|seeNumberOfElements|seeOptionIsSelected|selectOption|setCookie|submitForm|switchToIFrame|switchToNextTab|switchToPreviousTab|switchToWindow|typeInPopup|uncheckOption|unselectOption|wait|waitForAjaxLoad|waitForElement|waitForElementChange|waitForElementNotVisible|waitForElementVisible|waitForPwaElementNotVisible|waitForPwaElementVisible|waitForJS|waitForLoadingMaskToDisappear|waitForPageLoad|waitForText|assertArrayHasKey|assertArrayNotHasKey|assertContains|assertStringContainsString|assertStringContainsStringIgnoringCase|assertCount|assertEmpty|assertEquals|assertFalse|assertFileExists|assertFileNotExists|assertGreaterOrEquals|assertGreaterThan|assertGreaterThanOrEqual|assertInstanceOf|assertIsEmpty|assertLessOrEquals|assertLessThan|assertLessThanOrEqual|assertNotContains|assertStringNotContainsString|assertStringNotContainsStringIgnoringCase|assertNotEmpty|assertNotEquals|assertNotInstanceOf|assertNotNull|assertNotRegExp|assertNotSame|assertNull|assertRegExp|assertSame|assertStringStartsNotWith|assertStringStartsWith|assertTrue|expectException|fail|dontSeeFullUrlEquals|dontSee|dontSeeFullUrlMatches|dontSeeInFullUrl|seeFullUrlEquals|seeFullUrlMatches|seeInFullUrl|grabFromFullUrl|helper|assertEqualsWithDelta|assertEqualsCanonicalizing|assertEqualsIgnoringCase|assertNotEqualsWithDelta|assertNotEqualsCanonicalizing|assertNotEqualsIgnoringCase"> + <!ENTITY commonTestActions "acceptPopup|actionGroup|amOnPage|amOnUrl|amOnSubdomain|appendField|assertArrayIsSortasserted|assertElementContainsAttribute|attachFile|cancelPopup|checkOption|clearField|click|clickWithLeftButton|clickWithRightButton|closeAdminNotification|closeTab|comment|conditionalClick|createData|deleteData|updateData|getData|dontSee|dontSeeJsError|dontSeeCheckboxIsChecked|dontSeeCookie|dontSeeCurrentUrlEquals|dontSeeCurrentUrlMatches|dontSeeElement|dontSeeElementInDOM|dontSeeInCurrentUrl|dontSeeInField|dontSeeInFormFields|dontSeeInPageSource|dontSeeInSource|dontSeeInTitle|dontSeeLink|dontSeeOptionIsSelected|doubleClick|dragAndDrop|entity|executeJS|fillField|formatCurrency|generateDate|getOTP|grabAttributeFrom|grabCookie|grabCookieAttributes|grabFromCurrentUrl|grabMultiple|grabPageSource|grabTextFrom|grabValueFrom|return|loadSessionSnapshot|loginAsAdmin|magentoCLI|magentoCron|makeScreenshot|maximizeWindow|moveBack|moveForward|moveMouseOver|mSetLocale|mResetLocale|openNewTab|pause|parseFloat|pressKey|reloadPage|resetCookie|submitForm|resizeWindow|saveSessionSnapshot|scrollTo|scrollToTopOfPage|searchAndMultiSelectOption|see|seeCheckboxIsChecked|seeCookie|seeCurrentUrlEquals|seeCurrentUrlMatches|seeElement|seeElementInDOM|seeInCurrentUrl|seeInField|seeInFormFields|seeInPageSource|seeInPopup|seeInSource|seeInTitle|seeLink|seeNumberOfElements|seeOptionIsSelected|selectOption|setCookie|submitForm|switchToIFrame|switchToNextTab|switchToPreviousTab|switchToWindow|typeInPopup|uncheckOption|unselectOption|wait|waitForAjaxLoad|waitForElement|waitForElementChange|waitForElementNotVisible|waitForElementVisible|waitForPwaElementNotVisible|waitForPwaElementVisible|waitForJS|waitForLoadingMaskToDisappear|waitForPageLoad|waitForText|assertArrayHasKey|assertArrayNotHasKey|assertContains|assertStringContainsString|assertStringContainsStringIgnoringCase|assertCount|assertEmpty|assertEquals|assertFalse|assertFileExists|assertFileNotExists|assertGreaterOrEquals|assertGreaterThan|assertGreaterThanOrEqual|assertInstanceOf|assertIsEmpty|assertLessOrEquals|assertLessThan|assertLessThanOrEqual|assertNotContains|assertStringNotContainsString|assertStringNotContainsStringIgnoringCase|assertNotEmpty|assertNotEquals|assertNotInstanceOf|assertNotNull|assertNotRegExp|assertNotSame|assertNull|assertRegExp|assertSame|assertStringStartsNotWith|assertStringStartsWith|assertTrue|expectException|fail|dontSeeFullUrlEquals|dontSee|dontSeeFullUrlMatches|dontSeeInFullUrl|seeFullUrlEquals|seeFullUrlMatches|seeInFullUrl|grabFromFullUrl|helper|assertEqualsWithDelta|assertEqualsCanonicalizing|assertEqualsIgnoringCase|assertNotEqualsWithDelta|assertNotEqualsCanonicalizing|assertNotEqualsIgnoringCase"> ]> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../src/Magento/FunctionalTestingFramework/ObjectManager/etc/config.xsd"> diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index e6276ba10..851543889 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -808,6 +808,39 @@ public function rapidClick($selector, $count) } } + /** + * Grabs a cookie attributes value. + * You can set additional cookie params like `domain`, `path` in array passed as last argument. + * If the cookie is set by an ajax request (XMLHttpRequest), + * there might be some delay caused by the browser, so try `$I->wait(0.1)`. + * @param string $cookie + * @param array $params + * @return mixed + */ + public function grabCookieAttributes(string $cookie, array $params = []): array + { + $params['name'] = $cookie; + $cookieArrays = $this->filterCookies($this->webDriver->manage()->getCookies(), $params); + if (is_array($cookieArrays)) { // Microsoft Edge returns null if there are no cookies... + $cookieAttributes = []; + foreach ($cookieArrays as $cookieArray) { + if ($cookieArray->getName() === $cookie) { + $cookieAttributes['name'] = $cookieArray->getValue(); + $cookieAttributes['path'] = $cookieArray->getPath(); + $cookieAttributes['domain'] = $cookieArray->getDomain(); + $cookieAttributes['secure'] = $cookieArray->isSecure(); + $cookieAttributes['httpOnly'] = $cookieArray->isHttpOnly(); + $cookieAttributes['sameSite'] = $cookieArray->getSameSite(); + $cookieAttributes['expiry'] = date('d/m/Y', $cookieArray->getExpiry()); + + return $cookieAttributes; + } + } + } + + return []; + } + /** * Function used to fill sensitive credentials with user data, data is decrypted immediately prior to fill to avoid * exposure in console or log. diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php index b608a4846..593320d44 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php @@ -31,6 +31,7 @@ class ActionGroupObject "createData", "grabAttributeFrom", "grabCookie", + "grabCookieAttributes", "grabFromCurrentUrl", "grabMultiple", "grabPageSource", diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/grabActions.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/grabActions.xsd index 9109489aa..993657a86 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/grabActions.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/grabActions.xsd @@ -13,6 +13,7 @@ <xs:choice> <xs:element type="grabAttributeFromType" name="grabAttributeFrom" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="grabCookieType" name="grabCookie" minOccurs="0" maxOccurs="unbounded"/> + <xs:element type="grabCookieAttributesType" name="grabCookieAttributes" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="grabFromCurrentUrlType" name="grabFromCurrentUrl" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="grabMultipleType" name="grabMultiple" minOccurs="0" maxOccurs="unbounded"/> <xs:element type="grabPageSourceType" name="grabPageSource" minOccurs="0" maxOccurs="unbounded"/> @@ -53,6 +54,21 @@ </xs:simpleContent> </xs:complexType> + <xs:complexType name="grabCookieAttributesType"> + <xs:annotation> + <xs:documentation> + Grabs a cookie attributes value. + </xs:documentation> + </xs:annotation> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute ref="userInput"/> + <xs:attribute ref="parameterArray"/> + <xs:attributeGroup ref="commonActionAttributes"/> + </xs:extension> + </xs:simpleContent> + </xs:complexType> + <xs:complexType name="grabFromCurrentUrlType"> <xs:annotation> <xs:documentation> @@ -129,4 +145,4 @@ </xs:extension> </xs:simpleContent> </xs:complexType> -</xs:schema> \ No newline at end of file +</xs:schema> diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 0c47036f0..8128f8893 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1100,6 +1100,7 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato $parameterArray ); break; + case "grabCookieAttributes": case "grabCookie": $testSteps .= $this->wrapFunctionCallWithReturnValue( $stepKey, @@ -2371,6 +2372,7 @@ private function validateXmlAttributesMutuallyExclusive($key, $tagName, $attribu 'excludes' => [ 'dontSeeCookie', 'grabCookie', + 'grabCookieAttributes', 'resetCookie', 'seeCookie', 'setCookie', From 9c60f95eeec448026c49cfa6f995ba8effe0c5fb Mon Sep 17 00:00:00 2001 From: "Mohit.k.Sharma" <mohit.k.sharma@BLR1-LMC-N71405.local> Date: Mon, 16 May 2022 20:06:04 +0530 Subject: [PATCH 852/888] MQE-2953 | Get Cookie Expiry in mftf --- dev/.credentials | 1 - 1 file changed, 1 deletion(-) delete mode 100644 dev/.credentials diff --git a/dev/.credentials b/dev/.credentials deleted file mode 100644 index 50c0c05bf..000000000 --- a/dev/.credentials +++ /dev/null @@ -1 +0,0 @@ -magento/MAGENTO_ADMIN_PASSWORD=Admin@123456 From 9842d5e750b82a3acd03a2f91fba0fe354c8af0d Mon Sep 17 00:00:00 2001 From: "Mohit.k.Sharma" <mohit.k.sharma@BLR1-LMC-N71405.local> Date: Tue, 17 May 2022 08:30:59 +0530 Subject: [PATCH 853/888] MQE-2953 | Verification Test Added --- .../Resources/ActionGroupWithStepKeyReferences.txt | 1 + dev/tests/verification/Resources/BasicFunctionalTest.txt | 1 + .../FunctionActionGroupWithStepKeyReferencesActionGroup.xml | 1 + .../TestModule/ActionGroup/XmlDuplicateActionGroup.xml | 2 ++ .../Test/BasicFunctionalTest/BasicFunctionalTest.xml | 1 + .../TestModule/Test/XmlDuplicateTest/XmlDuplicateTest.xml | 6 ++++++ 6 files changed, 12 insertions(+) diff --git a/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt b/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt index 04195a1da..0d62a57e3 100644 --- a/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt +++ b/dev/tests/verification/Resources/ActionGroupWithStepKeyReferences.txt @@ -67,6 +67,7 @@ class ActionGroupWithStepKeyReferencesCest $action14ActionGroup = $I->grabMultiple($action14ActionGroup); // stepKey: action14ActionGroup $action15ActionGroup = $I->grabTextFrom($action15ActionGroup); // stepKey: action15ActionGroup $action16ActionGroup = $I->grabValueFrom($action16ActionGroup); // stepKey: action16ActionGroup + $action17ActionGroup = $I->grabCookieAttributes($action17ActionGroup, ['domain' => 'www.google.com']); // stepKey: action17ActionGroup $I->comment("Exiting Action Group [actionGroup] FunctionActionGroupWithStepKeyReferences"); } diff --git a/dev/tests/verification/Resources/BasicFunctionalTest.txt b/dev/tests/verification/Resources/BasicFunctionalTest.txt index e30f50c34..dd78781ba 100644 --- a/dev/tests/verification/Resources/BasicFunctionalTest.txt +++ b/dev/tests/verification/Resources/BasicFunctionalTest.txt @@ -127,6 +127,7 @@ class BasicFunctionalTestCest $getOtpWithInput = $I->getOTP("someInput"); // stepKey: getOtpWithInput $grabAttributeFromKey1 = $I->grabAttributeFrom(".functionalTestSelector", "someInput"); // stepKey: grabAttributeFromKey1 $grabCookieKey1 = $I->grabCookie("grabCookieInput", ['domain' => 'www.google.com']); // stepKey: grabCookieKey1 + $grabCookieAttributesKey1 = $I->grabCookieAttributes("grabCookieAttributesInput", ['domain' => 'www.google.com']); // stepKey: grabCookieAttributesKey1 $grabFromCurrentUrlKey1 = $I->grabFromCurrentUrl("/grabCurrentUrl"); // stepKey: grabFromCurrentUrlKey1 $grabMultipleKey1 = $I->grabMultiple(".functionalTestSelector"); // stepKey: grabMultipleKey1 $grabTextFromKey1 = $I->grabTextFrom(".functionalTestSelector"); // stepKey: grabTextFromKey1 diff --git a/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionActionGroupWithStepKeyReferencesActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionActionGroupWithStepKeyReferencesActionGroup.xml index 205e32b3a..97f40bafd 100644 --- a/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionActionGroupWithStepKeyReferencesActionGroup.xml +++ b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionActionGroupWithStepKeyReferencesActionGroup.xml @@ -28,5 +28,6 @@ <grabMultiple selector="{$action14}" stepKey="action14"/> <grabTextFrom selector="{$action15}" stepKey="action15"/> <grabValueFrom selector="{$action16}" stepKey="action16"/> + <grabCookieAttributes userInput="{$action17}" parameterArray="['domain' => 'www.google.com']" stepKey="$action17"/> </actionGroup> </actionGroups> diff --git a/dev/tests/verification/TestModule/ActionGroup/XmlDuplicateActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/XmlDuplicateActionGroup.xml index 6eefdaf51..14cbd836f 100644 --- a/dev/tests/verification/TestModule/ActionGroup/XmlDuplicateActionGroup.xml +++ b/dev/tests/verification/TestModule/ActionGroup/XmlDuplicateActionGroup.xml @@ -90,6 +90,8 @@ <grabAttributeFrom selector="1" stepKey="grabattribute12"/> <grabCookie stepKey="grabcookie1"/> <grabCookie stepKey="grabcookie12"/> + <grabCookieAttributes stepKey="grabcookieattributes1"/> + <grabCookieAttributes stepKey="grabcookieattributes12"/> <grabFromCurrentUrl stepKey="grabfromcurl1"/> <grabFromCurrentUrl stepKey="grabfromcurl12"/> <grabMultiple selector="1" stepKey="grabmulti1"/> diff --git a/dev/tests/verification/TestModule/Test/BasicFunctionalTest/BasicFunctionalTest.xml b/dev/tests/verification/TestModule/Test/BasicFunctionalTest/BasicFunctionalTest.xml index 53bd1f7ef..fa2b5e247 100644 --- a/dev/tests/verification/TestModule/Test/BasicFunctionalTest/BasicFunctionalTest.xml +++ b/dev/tests/verification/TestModule/Test/BasicFunctionalTest/BasicFunctionalTest.xml @@ -72,6 +72,7 @@ <getOTP stepKey="getOtpWithInput" userInput="someInput"/> <grabAttributeFrom selector=".functionalTestSelector" userInput="someInput" stepKey="grabAttributeFromKey1" /> <grabCookie userInput="grabCookieInput" parameterArray="['domain' => 'www.google.com']" stepKey="grabCookieKey1" /> + <grabCookieAttributes userInput="grabCookieAttributesInput" parameterArray="['domain' => 'www.google.com']" stepKey="grabCookieAttributesKey1" /> <grabFromCurrentUrl regex="/grabCurrentUrl" stepKey="grabFromCurrentUrlKey1" /> <grabMultiple selector=".functionalTestSelector" stepKey="grabMultipleKey1" /> <grabTextFrom selector=".functionalTestSelector" stepKey="grabTextFromKey1" /> diff --git a/dev/tests/verification/TestModule/Test/XmlDuplicateTest/XmlDuplicateTest.xml b/dev/tests/verification/TestModule/Test/XmlDuplicateTest/XmlDuplicateTest.xml index b24bac3b5..01d7bc88c 100644 --- a/dev/tests/verification/TestModule/Test/XmlDuplicateTest/XmlDuplicateTest.xml +++ b/dev/tests/verification/TestModule/Test/XmlDuplicateTest/XmlDuplicateTest.xml @@ -93,6 +93,8 @@ <grabAttributeFrom selector="1" stepKey="grabattribute12"/> <grabCookie stepKey="grabcookie1"/> <grabCookie stepKey="grabcookie12"/> + <grabCookieAttributes stepKey="grabcookieattributes1"/> + <grabCookieAttributes stepKey="grabcookieattributes12"/> <grabFromCurrentUrl stepKey="grabfromcurl1"/> <grabFromCurrentUrl stepKey="grabfromcurl12"/> <grabMultiple selector="1" stepKey="grabmulti1"/> @@ -305,6 +307,8 @@ <grabAttributeFrom selector="1" stepKey="grabattribute12"/> <grabCookie stepKey="grabcookie1"/> <grabCookie stepKey="grabcookie12"/> + <grabCookieAttributes stepKey="grabcookieattributes1"/> + <grabCookieAttributes stepKey="grabcookieattributes12"/> <grabFromCurrentUrl stepKey="grabfromcurl1"/> <grabFromCurrentUrl stepKey="grabfromcurl12"/> <grabMultiple selector="1" stepKey="grabmulti1"/> @@ -516,6 +520,8 @@ <grabAttributeFrom selector="1" stepKey="grabattribute12"/> <grabCookie stepKey="grabcookie1"/> <grabCookie stepKey="grabcookie12"/> + <grabCookieAttributes stepKey="grabcookieattributes1"/> + <grabCookieAttributes stepKey="grabcookieattributes12"/> <grabFromCurrentUrl stepKey="grabfromcurl1"/> <grabFromCurrentUrl stepKey="grabfromcurl12"/> <grabMultiple selector="1" stepKey="grabmulti1"/> From 71a13bb7e3875fdbaa7face9b9a7f11937b47bfe Mon Sep 17 00:00:00 2001 From: "Mohit.k.Sharma" <mohit.k.sharma@BLR1-LMC-N71405.local> Date: Tue, 17 May 2022 08:36:19 +0530 Subject: [PATCH 854/888] MQE-2953 | Verification Test FIX --- .../FunctionActionGroupWithStepKeyReferencesActionGroup.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionActionGroupWithStepKeyReferencesActionGroup.xml b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionActionGroupWithStepKeyReferencesActionGroup.xml index 97f40bafd..a9275c23b 100644 --- a/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionActionGroupWithStepKeyReferencesActionGroup.xml +++ b/dev/tests/verification/TestModule/ActionGroup/FunctionalActionGroup/FunctionActionGroupWithStepKeyReferencesActionGroup.xml @@ -28,6 +28,6 @@ <grabMultiple selector="{$action14}" stepKey="action14"/> <grabTextFrom selector="{$action15}" stepKey="action15"/> <grabValueFrom selector="{$action16}" stepKey="action16"/> - <grabCookieAttributes userInput="{$action17}" parameterArray="['domain' => 'www.google.com']" stepKey="$action17"/> + <grabCookieAttributes userInput="{$action17}" parameterArray="['domain' => 'www.google.com']" stepKey="action17"/> </actionGroup> </actionGroups> From 4082762101fffbd82a42e09b03b99b5e5b6d05ec Mon Sep 17 00:00:00 2001 From: "Mohit.k.Sharma" <mohit.k.sharma@BLR1-LMC-N71405.local> Date: Wed, 18 May 2022 10:56:25 +0530 Subject: [PATCH 855/888] MQE-2953 | Fix Code Review Points --- .../FunctionalTestingFramework/Module/MagentoWebDriver.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 851543889..4f240a3bd 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -821,8 +821,8 @@ public function grabCookieAttributes(string $cookie, array $params = []): array { $params['name'] = $cookie; $cookieArrays = $this->filterCookies($this->webDriver->manage()->getCookies(), $params); + $cookieAttributes = []; if (is_array($cookieArrays)) { // Microsoft Edge returns null if there are no cookies... - $cookieAttributes = []; foreach ($cookieArrays as $cookieArray) { if ($cookieArray->getName() === $cookie) { $cookieAttributes['name'] = $cookieArray->getValue(); @@ -838,7 +838,7 @@ public function grabCookieAttributes(string $cookie, array $params = []): array } } - return []; + return $cookieAttributes; } /** From 7b039e4efae9b3f61aaa63d4618543ec35373fec Mon Sep 17 00:00:00 2001 From: Ji Lu <jilu1@adobe.com> Date: Mon, 6 Jun 2022 23:15:49 -0500 Subject: [PATCH 856/888] MQE-3520: improve error handling for better error message in ModuleResolver. --- .../FunctionalTestingFramework/Util/ModuleResolver.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index 434a1cdc3..b330ac84b 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -7,6 +7,7 @@ namespace Magento\FunctionalTestingFramework\Util; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Exceptions\FastFailException; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Util\ModuleResolver\ModuleResolverService; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; @@ -168,6 +169,7 @@ private function __construct() * * @return array * @throws TestFrameworkException + * @throws FastFailException */ public function getEnabledModules() { @@ -201,7 +203,7 @@ public function getEnabledModules() "MAGENTO_ADMIN_USERNAME" => getenv("MAGENTO_ADMIN_USERNAME"), "MAGENTO_ADMIN_PASSWORD" => getenv("MAGENTO_ADMIN_PASSWORD"), ]; - throw new TestFrameworkException($message, $context); + throw new FastFailException($message, $context); } $this->enabledModules = json_decode($response); @@ -215,6 +217,7 @@ public function getEnabledModules() * @param boolean $verbosePath * @return array * @throws TestFrameworkException + * @throws FastFailException */ public function getModulesPath($verbosePath = false) { From 97f1e5ed0fa025f48e88964cae4d6d706e79aef0 Mon Sep 17 00:00:00 2001 From: Sergiy Vasiutynskyi <s.vasiutynskyi@atwix.com> Date: Tue, 7 Jun 2022 21:43:47 +0300 Subject: [PATCH 857/888] AC-2749 updated 'symfony/console' and 'symfony/process' constraints to support 5.4v, removed PHP 7.3 & PHP 8.0 compatibility --- composer.json | 6 +++--- composer.lock | 6 +++--- etc/config/command.php | 2 +- .../Console/BuildProjectCommand.php | 11 +++++++---- .../Console/CleanProjectCommand.php | 8 ++++++-- .../Console/GenerateDevUrnCommand.php | 13 ++++++++----- .../Console/RunManifestCommand.php | 2 +- .../Console/RunTestCommand.php | 2 +- .../Console/RunTestFailedCommand.php | 7 +------ .../Console/RunTestGroupCommand.php | 6 ++---- .../Console/SetupEnvCommand.php | 8 ++++++-- .../Console/UpgradeTestsCommand.php | 8 ++++++-- 12 files changed, 45 insertions(+), 34 deletions(-) diff --git a/composer.json b/composer.json index 7bd0d3c66..133c8c8e3 100755 --- a/composer.json +++ b/composer.json @@ -12,10 +12,10 @@ "php": ">7.3", "ext-curl": "*", "ext-dom": "*", + "ext-iconv": "*", "ext-intl": "*", "ext-json": "*", "ext-openssl": "*", - "ext-iconv": "*", "allure-framework/allure-codeception": "^1.4", "aws/aws-sdk-php": "^3.132", "codeception/codeception": "^4.1", @@ -31,12 +31,12 @@ "nikic/php-parser": "^4.4", "php-webdriver/webdriver": "^1.9.0", "spomky-labs/otphp": "^10.0", - "symfony/console": "^4.4", + "symfony/console": "^4.4||^5.4", "symfony/dotenv": "^5.3", "symfony/finder": "^5.0", "symfony/http-foundation": "^5.0", "symfony/mime": "^5.0", - "symfony/process": "^4.4", + "symfony/process": "^4.4||^5.4", "weew/helpers-array": "^1.3" }, "require-dev": { diff --git a/composer.lock b/composer.lock index e2834f7ba..12e3144f5 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "40786b066af41372e12e5af07aeeaf0b", + "content-hash": "69a3d90dcac080bbeb28b46e4533dadb", "packages": [ { "name": "allure-framework/allure-codeception", @@ -7886,10 +7886,10 @@ "php": ">7.3", "ext-curl": "*", "ext-dom": "*", + "ext-iconv": "*", "ext-intl": "*", "ext-json": "*", - "ext-openssl": "*", - "ext-iconv": "*" + "ext-openssl": "*" }, "platform-dev": [], "plugin-api-version": "1.1.0" diff --git a/etc/config/command.php b/etc/config/command.php index 72c6f1a42..0d8fc7997 100644 --- a/etc/config/command.php +++ b/etc/config/command.php @@ -24,7 +24,7 @@ $valid = validateCommand($magentoBinary, $command); if ($valid) { $fullCommand = escapeshellcmd($magentoBinary . " $command" . " $arguments"); - $process = new Symfony\Component\Process\Process($fullCommand); + $process = Symfony\Component\Process\Process::fromShellCommandline($fullCommand); $process->setIdleTimeout($timeout); $process->setTimeout(0); $idleTimeout = false; diff --git a/src/Magento/FunctionalTestingFramework/Console/BuildProjectCommand.php b/src/Magento/FunctionalTestingFramework/Console/BuildProjectCommand.php index afeacaad3..33cc4bc71 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BuildProjectCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BuildProjectCommand.php @@ -28,7 +28,8 @@ */ class BuildProjectCommand extends Command { - const DEFAULT_YAML_INLINE_DEPTH = 10; + private const SUCCESS_EXIT_CODE = 0; + public const DEFAULT_YAML_INLINE_DEPTH = 10; /** * Env processor manages .env files. @@ -65,11 +66,11 @@ protected function configure() * * @param InputInterface $input * @param OutputInterface $output - * @return void + * @return integer * @throws \Exception * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $resetCommand = new CleanProjectCommand(); $resetOptions = new ArrayInput([]); @@ -91,7 +92,7 @@ protected function execute(InputInterface $input, OutputInterface $output) // TODO can we just import the codecept symfony command? $codeceptBuildCommand = realpath(PROJECT_ROOT . '/vendor/bin/codecept') . ' build'; - $process = new Process($codeceptBuildCommand); + $process = Process::fromShellCommandline($codeceptBuildCommand); $process->setWorkingDirectory(TESTS_BP); $process->setIdleTimeout(600); $process->setTimeout(0); @@ -112,6 +113,8 @@ function ($type, $buffer) use ($output) { $upgradeOptions = new ArrayInput([]); $upgradeCommand->run($upgradeOptions, $output); } + + return self::SUCCESS_EXIT_CODE; } /** diff --git a/src/Magento/FunctionalTestingFramework/Console/CleanProjectCommand.php b/src/Magento/FunctionalTestingFramework/Console/CleanProjectCommand.php index 641cfe1ed..6517d3ab1 100644 --- a/src/Magento/FunctionalTestingFramework/Console/CleanProjectCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/CleanProjectCommand.php @@ -18,6 +18,8 @@ class CleanProjectCommand extends Command { + private const SUCCESS_EXIT_CODE = 0; + /** * Configures the current command. * @@ -37,11 +39,11 @@ protected function configure() * * @param InputInterface $input * @param OutputInterface $output - * @return void + * @return integer * @throws \Symfony\Component\Console\Exception\LogicException * @throws TestFrameworkException */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $configFiles = [ // codeception.yml file for top level config @@ -97,5 +99,7 @@ protected function execute(InputInterface $input, OutputInterface $output) } $output->writeln('mftf files removed from filesystem.'); + + return self::SUCCESS_EXIT_CODE; } } diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateDevUrnCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateDevUrnCommand.php index 034e6f516..72529158b 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateDevUrnCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateDevUrnCommand.php @@ -19,13 +19,14 @@ class GenerateDevUrnCommand extends Command { + private const SUCCESS_EXIT_CODE = 0; /** * Argument for the path to IDE config file */ - const IDE_FILE_PATH_ARGUMENT = 'path'; + public const IDE_FILE_PATH_ARGUMENT = 'path'; - const PROJECT_PATH_IDENTIFIER = '$PROJECT_DIR$'; - const MFTF_SRC_PATH = 'src/Magento/FunctionalTestingFramework/'; + public const PROJECT_PATH_IDENTIFIER = '$PROJECT_DIR$'; + public const MFTF_SRC_PATH = 'src/Magento/FunctionalTestingFramework/'; /** * Configures the current command. @@ -54,10 +55,10 @@ protected function configure() * * @param InputInterface $input * @param OutputInterface $output - * @return void + * @return int * @throws \Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $miscXmlFilePath = $input->getArgument(self::IDE_FILE_PATH_ARGUMENT); $miscXmlFile = realpath($miscXmlFilePath); @@ -117,6 +118,8 @@ protected function execute(InputInterface $input, OutputInterface $output) //Save output $dom->save($miscXmlFile); $output->writeln("MFTF URN mapping successfully added to {$miscXmlFile}."); + + return self::SUCCESS_EXIT_CODE; } /** diff --git a/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php index fbabc5282..3b75cbb87 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php @@ -131,7 +131,7 @@ private function runManifestLine($manifestLine, $output, $exit = false) . " run functional --verbose --steps " . $manifestLine; // run the codecept command in a sub process - $process = new Process($codeceptionCommand); + $process = Process::fromShellCommandline($codeceptionCommand); $process->setWorkingDirectory(TESTS_BP); $process->setIdleTimeout(600); $process->setTimeout(0); diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php index 95c2f563a..02e721ae3 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php @@ -261,7 +261,7 @@ private function runTestsInSuite(array $suitesConfig, OutputInterface $output, I */ private function executeTestCommand(string $command, OutputInterface $output) { - $process = new Process($command); + $process = Process::fromShellCommandline($command); $process->setWorkingDirectory(TESTS_BP); $process->setIdleTimeout(600); $process->setTimeout(0); diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php index 96b376247..55834ad9b 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php @@ -7,14 +7,9 @@ namespace Magento\FunctionalTestingFramework\Console; -use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; -use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; -use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Process\Process; -use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; -use Symfony\Component\Console\Input\InputOption; class RunTestFailedCommand extends BaseGenerateCommand { @@ -78,7 +73,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $codeceptionCommand = realpath(PROJECT_ROOT . '/vendor/bin/codecept') . ' run functional '; $codeceptionCommand .= $testManifestList[$i]; - $process = new Process($codeceptionCommand); + $process = Process::fromShellCommandline($codeceptionCommand); $process->setWorkingDirectory(TESTS_BP); $process->setIdleTimeout(600); $process->setTimeout(0); diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php index 38e3366d7..fefbe08f8 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestGroupCommand.php @@ -7,9 +7,8 @@ namespace Magento\FunctionalTestingFramework\Console; -use Magento\FunctionalTestingFramework\Suite\Handlers\SuiteObjectHandler; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; -use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Util\GenerationErrorHandler; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Input\InputArgument; @@ -17,7 +16,6 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Process\Process; -use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; class RunTestGroupCommand extends BaseGenerateCommand { @@ -133,7 +131,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } $returnCodes[] = $this->codeceptRunTest($codeceptionCommandString, $output); } else { - $process = new Process($codeceptionCommandString); + $process = Process::fromShellCommandline($codeceptionCommandString); $process->setWorkingDirectory(TESTS_BP); $process->setIdleTimeout(600); $process->setTimeout(0); diff --git a/src/Magento/FunctionalTestingFramework/Console/SetupEnvCommand.php b/src/Magento/FunctionalTestingFramework/Console/SetupEnvCommand.php index 65e8c61e7..258e905d5 100644 --- a/src/Magento/FunctionalTestingFramework/Console/SetupEnvCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/SetupEnvCommand.php @@ -18,6 +18,8 @@ class SetupEnvCommand extends Command { + private const SUCCESS_EXIT_CODE = 0; + /** * Env processor manages .env files. * @@ -47,10 +49,10 @@ protected function configure() * * @param InputInterface $input * @param OutputInterface $output - * @return void + * @return integer * @throws \Symfony\Component\Console\Exception\LogicException */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $config = $this->envProcessor->getEnv(); $userEnv = []; @@ -62,5 +64,7 @@ protected function execute(InputInterface $input, OutputInterface $output) } $this->envProcessor->putEnvFile($userEnv); $output->writeln(".env configuration successfully applied."); + + return self::SUCCESS_EXIT_CODE; } } diff --git a/src/Magento/FunctionalTestingFramework/Console/UpgradeTestsCommand.php b/src/Magento/FunctionalTestingFramework/Console/UpgradeTestsCommand.php index 526ab4903..06284605d 100644 --- a/src/Magento/FunctionalTestingFramework/Console/UpgradeTestsCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/UpgradeTestsCommand.php @@ -17,6 +17,8 @@ class UpgradeTestsCommand extends Command { + private const SUCCESS_EXIT_CODE = 0; + /** * Pool of upgrade scripts to run * @@ -46,10 +48,10 @@ protected function configure() * * @param InputInterface $input * @param OutputInterface $output - * @return int|null|void + * @return int * @throws \Exception */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { /** @var \Magento\FunctionalTestingFramework\Upgrade\UpgradeInterface[] $upgradeScriptObjects */ $upgradeScriptObjects = $this->upgradeScriptsList->getUpgradeScripts(); @@ -59,5 +61,7 @@ protected function execute(InputInterface $input, OutputInterface $output) LoggingUtil::getInstance()->getLogger(get_class($upgradeScriptObject))->info($upgradeOutput); $output->writeln($upgradeOutput . PHP_EOL); } + + return self::SUCCESS_EXIT_CODE; } } From 62eb19b69ee491299dc6ba6478ff4ebb7e34f5da Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Wed, 22 Jun 2022 13:28:37 +0530 Subject: [PATCH 858/888] 3.10-RC : 3.10 Change log, version bump to develop --- CHANGELOG.md | 10 ++++++++++ composer.json | 2 +- composer.lock | 12 ++++++++++-- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9688654fb..8ae172d42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ Magento Functional Testing Framework Changelog ================================================ + +3.10 +--------- + +### Enhancements +* Updated symfony/console and symfony/process constraints to support latest Symfony LTS (5.4v) +* Updated Symfony related code to support latest Symfony LTS (5.4v). +* Removed PHP 8.0 & PHP 7.3 compatibility. + + 3.9.0 --------- diff --git a/composer.json b/composer.json index 133c8c8e3..0d67f4738 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "3.9.0", + "version": "3.10", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index 12e3144f5..ad4950066 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "69a3d90dcac080bbeb28b46e4533dadb", + "content-hash": "592c7edd765aa0e619fc5e5e52e57971", "packages": [ { "name": "allure-framework/allure-codeception", @@ -2224,6 +2224,14 @@ "psr-17", "psr-7" ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-diactoros/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-diactoros/issues", + "rss": "https://github.com/laminas/laminas-diactoros/releases.atom", + "source": "https://github.com/laminas/laminas-diactoros" + }, "funding": [ { "url": "https://funding.communitybridge.org/projects/laminas-project", @@ -7892,5 +7900,5 @@ "ext-openssl": "*" }, "platform-dev": [], - "plugin-api-version": "1.1.0" + "plugin-api-version": "2.1.0" } From 1fb434938bf22588c09cff11ec4454ea41eeadc1 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Wed, 22 Jun 2022 13:45:15 +0530 Subject: [PATCH 859/888] Updated CHANGELOG.md --- CHANGELOG.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ae172d42..1b1d7801f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,19 @@ Magento Functional Testing Framework Changelog 3.10 --------- +### Fixes +* Hashicorp Vault PHP lib being instantiated with wrong params + ### Enhancements * Updated symfony/console and symfony/process constraints to support latest Symfony LTS (5.4v) * Updated Symfony related code to support latest Symfony LTS (5.4v). * Removed PHP 8.0 & PHP 7.3 compatibility. - +* Implement rapid times X clicks on UI element in MFTF +* Log MFTF test dependencies +* Unused entity static check +* Updated docs for new location of password +* Remove any remaining usages of Travis CI from MFTF Repo +* Unit tests for GenerateTestFailedCommandTest and RunTestFailedCommandTest 3.9.0 --------- From f832547f53b0374a14d94d2286d99a41e04b5274 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Thu, 23 Jun 2022 11:08:50 +0530 Subject: [PATCH 860/888] updated mftf version with right format and placed enhancements above fixes in changelog.md file --- CHANGELOG.md | 7 +++---- composer.json | 2 +- composer.lock | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b1d7801f..f3ebe41b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,13 +4,9 @@ Magento Functional Testing Framework Changelog 3.10 --------- -### Fixes -* Hashicorp Vault PHP lib being instantiated with wrong params - ### Enhancements * Updated symfony/console and symfony/process constraints to support latest Symfony LTS (5.4v) * Updated Symfony related code to support latest Symfony LTS (5.4v). -* Removed PHP 8.0 & PHP 7.3 compatibility. * Implement rapid times X clicks on UI element in MFTF * Log MFTF test dependencies * Unused entity static check @@ -18,6 +14,9 @@ Magento Functional Testing Framework Changelog * Remove any remaining usages of Travis CI from MFTF Repo * Unit tests for GenerateTestFailedCommandTest and RunTestFailedCommandTest +### Fixes +* Hashicorp Vault PHP lib being instantiated with wrong params + 3.9.0 --------- diff --git a/composer.json b/composer.json index 0d67f4738..2835da162 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "3.10", + "version": "3.10.0", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index ad4950066..3bdb5f12f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "592c7edd765aa0e619fc5e5e52e57971", + "content-hash": "fd34c83cd0fc786e9d8d892d1e25b18d", "packages": [ { "name": "allure-framework/allure-codeception", From 9f78ed44e8460d6da05b5b8c1fa9c0fa13b6e50c Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Thu, 23 Jun 2022 11:10:14 +0530 Subject: [PATCH 861/888] updated mftf version with right format and placed enhancements above fixes in changelog.md file --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3ebe41b1..5d75be840 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ Magento Functional Testing Framework Changelog ================================================ -3.10 +3.10.0 --------- ### Enhancements From 400e84b244c0727057351cce0d5f36ba8a77a776 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Thu, 23 Jun 2022 20:32:05 +0530 Subject: [PATCH 862/888] removed extra space --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d75be840..cbc6086a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ Magento Functional Testing Framework Changelog --------- ### Enhancements -* Updated symfony/console and symfony/process constraints to support latest Symfony LTS (5.4v) +* Updated symfony/console and symfony/process constraints to support latest Symfony LTS (5.4v) * Updated Symfony related code to support latest Symfony LTS (5.4v). * Implement rapid times X clicks on UI element in MFTF * Log MFTF test dependencies From 2ff53e7dde573e4278e9516b18fd68759158ac37 Mon Sep 17 00:00:00 2001 From: Faizan Shaikh <glo88465@adobe.com> Date: Thu, 14 Jul 2022 11:31:46 +0530 Subject: [PATCH 863/888] AC-5897:Allure reports are not generated for composer builds when running from repo - Updated composer json --- composer.json | 2 +- composer.lock | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/composer.json b/composer.json index 133c8c8e3..052510251 100755 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "codeception/module-asserts": "^1.1", "codeception/module-sequence": "^1.0", "codeception/module-webdriver": "^1.0", - "composer/composer": "^1.9||^2.0", + "composer/composer": "^1.9 || ^2.0, !=2.2.16", "csharpru/vault-php": "^4.2.1", "guzzlehttp/guzzle": "^7.3.0", "laminas/laminas-diactoros": "^2.8", diff --git a/composer.lock b/composer.lock index 12e3144f5..19db070e5 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "69a3d90dcac080bbeb28b46e4533dadb", + "content-hash": "212125f806b6d909aa92f02c3e9d52e9", "packages": [ { "name": "allure-framework/allure-codeception", @@ -2224,6 +2224,14 @@ "psr-17", "psr-7" ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-diactoros/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-diactoros/issues", + "rss": "https://github.com/laminas/laminas-diactoros/releases.atom", + "source": "https://github.com/laminas/laminas-diactoros" + }, "funding": [ { "url": "https://funding.communitybridge.org/projects/laminas-project", @@ -2459,9 +2467,6 @@ "require": { "php": "^7.1 || ^8.0" }, - "replace": { - "myclabs/deep-copy": "self.version" - }, "require-dev": { "doctrine/collections": "^1.0", "doctrine/common": "^2.6", @@ -7892,5 +7897,5 @@ "ext-openssl": "*" }, "platform-dev": [], - "plugin-api-version": "1.1.0" + "plugin-api-version": "2.3.0" } From c05551b638acdba67700429afc876f1086c4df2c Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Mon, 25 Jul 2022 20:34:03 +0530 Subject: [PATCH 864/888] resolved conflicts --- composer.lock | 4 ---- 1 file changed, 4 deletions(-) diff --git a/composer.lock b/composer.lock index 0ae5ab861..1a8a0b9f3 100644 --- a/composer.lock +++ b/composer.lock @@ -7897,9 +7897,5 @@ "ext-openssl": "*" }, "platform-dev": [], -<<<<<<< HEAD - "plugin-api-version": "2.1.0" -======= "plugin-api-version": "2.3.0" ->>>>>>> 23a85f5a6150fbeec38817a50dc13d0e865b73d8 } From 6d94d58d67d55bad6e496a976e0f4f2025525b86 Mon Sep 17 00:00:00 2001 From: Dmytro Shevtsov <shevtsov@adobe.com> Date: Mon, 1 Aug 2022 16:43:54 -0500 Subject: [PATCH 865/888] Fix links in docs --- docs/configuration.md | 2 +- docs/data.md | 2 +- docs/getting-started.md | 4 +- docs/reporting.md | 2 +- docs/section/locator-functions.md | 2 +- docs/test/actions.md | 180 +++++++++++++++--------------- docs/test/annotations.md | 4 +- 7 files changed, 98 insertions(+), 98 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index bd48d1554..501b1d5e9 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -443,4 +443,4 @@ MAGENTO_ADMIN_WEBAPI_TOKEN_LIFETIME=10800 [`MAGENTO_CLI_COMMAND_PATH`]: #magento_cli_command_path [generateDate]: test/actions.md#generatedate [mftf]: commands/mftf.md -[timezones]: http://php.net/manual/en/timezones.php +[timezones]: https://php.net/manual/en/timezones.php diff --git a/docs/data.md b/docs/data.md index 100b95317..721f94a7e 100644 --- a/docs/data.md +++ b/docs/data.md @@ -340,6 +340,6 @@ Attributes|Type|Use|Description [`<required-entities>`]: #requiredentity-tag [`<var>`]: #var-tag [Actions]: ./test/actions.md -[category creation]: http://docs.magento.com/m2/ce/user_guide/catalog/category-create.html +[category creation]: https://docs.magento.com/user-guide/catalog/category-create.html [Credentials]: ./credentials.md [test actions]: ./test/actions.md#actions-returning-a-variable diff --git a/docs/getting-started.md b/docs/getting-started.md index f895ebe5a..87cb04f79 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -347,7 +347,7 @@ allure serve dev/tests/_output/allure-results/ [`MAGENTO_BP`]: configuration.html#magento_bp [`mftf`]: commands/mftf.html [allure docs]: https://docs.qameta.io/allure/ -[Allure Framework]: http://allure.qatools.ru/ +[Allure Framework]: https://github.com/allure-framework [basic configuration]: configuration.html#basic-configuration [chrome driver]: https://sites.google.com/a/chromium.org/chromedriver/downloads [Codeception Test execution]: https://blog.jetbrains.com/phpstorm/2017/03/codeception-support-comes-to-phpstorm-2017-1/ @@ -355,7 +355,7 @@ allure serve dev/tests/_output/allure-results/ [Configuration]: configuration.html [contributing]: https://github.com/magento/magento2-functional-testing-framework/blob/develop/.github/CONTRIBUTING.md [install Allure]: https://github.com/allure-framework/allure2#download -[java]: http://www.oracle.com/technetwork/java/javase/downloads/index.html +[java]: https://www.oracle.com/java/technologies/downloads/ [mftf tests]: introduction.html#mftf-tests [php]: https://devdocs.magento.com/guides/v2.4/install-gde/system-requirements.html [PhpStorm]: https://www.jetbrains.com/phpstorm/ diff --git a/docs/reporting.md b/docs/reporting.md index 629c3cfd8..225890fcb 100644 --- a/docs/reporting.md +++ b/docs/reporting.md @@ -305,7 +305,7 @@ Refer to the [Reporting section][] for more Allure CLI details. [`run:group`]: commands/mftf.md#rungroup [`run:test`]: commands/mftf.md#runtest [Allure Framework]: https://docs.qameta.io/allure/ -[Allure Test Report]: http://allure.qatools.ru/ +[Allure Test Report]: https://github.com/allure-framework [codecept]: commands/codeception.md [codeception]: https://codeception.com/docs/reference/Commands [mftf]: commands/mftf.md diff --git a/docs/section/locator-functions.md b/docs/section/locator-functions.md index d2dc9924c..141afc9e6 100644 --- a/docs/section/locator-functions.md +++ b/docs/section/locator-functions.md @@ -40,6 +40,6 @@ Given the above element definitions, you call the elements in a test just like a <!-- {% endraw %} --> <!-- Link Definitions --> -[Locator functions]: http://codeception.com/docs/reference/Locator +[Locator functions]: https://codeception.com/docs/reference/Locator [section]: ../section.md [parameterized selectors]: ./parameterized-selectors.md \ No newline at end of file diff --git a/docs/test/actions.md b/docs/test/actions.md index 73e3da0d6..94db9c989 100644 --- a/docs/test/actions.md +++ b/docs/test/actions.md @@ -1,7 +1,7 @@ # Test actions Actions in the MFTF allow you to automate different scenarios of Magento user's actions. -They are mostly XML implementations of [Codeception actions](http://codeception.com/docs/modules/WebDriver#Actions). +They are mostly XML implementations of [Codeception actions](https://codeception.com/docs/modules/WebDriver#Actions). Some actions drive browser elements, while others use REST APIs. ## Common attributes @@ -144,7 +144,7 @@ The following test actions return a variable: * [grabAttributeFrom](#grabattributefrom) * [grabCookie](#grabcookie) -* [grabCookieAttributes](#grabCookieAttributes) +* [grabCookieAttributes](#grabcookieattributes) * [grabFromCurrentUrl](#grabfromcurrenturl) * [grabMultiple](#grabmultiple) * [grabPageSource](#grabpagesource) @@ -188,7 +188,7 @@ If the description of an element does not include a link to Codeception analogue Accepts the current popup visible on the page. -See [acceptPopup docs on codeception.com](http://codeception.com/docs/modules/WebDriver#acceptPopup). +See [acceptPopup docs on codeception.com](https://codeception.com/docs/modules/WebDriver#acceptPopup). Attribute|Type|Use|Description ---|---|---|--- @@ -207,7 +207,7 @@ Attribute|Type|Use|Description Opens the page by the URL relative to the one set in the `MAGENTO_BASE_URL` configuration variable. -See [amOnPage docs on codeception.com](http://codeception.com/docs/modules/WebDriver#amOnPage). +See [amOnPage docs on codeception.com](https://codeception.com/docs/modules/WebDriver#amOnPage). Attribute|Type|Use|Description ---|---|---|--- @@ -227,7 +227,7 @@ Attribute|Type|Use|Description Takes the base URL and changes the subdomain. -See [amOnSubdomain docs on codeception.com](http://codeception.com/docs/modules/WebDriver#amOnSubdomain). +See [amOnSubdomain docs on codeception.com](https://codeception.com/docs/modules/WebDriver#amOnSubdomain). Attribute|Type|Use|Description ---|---|---|--- @@ -251,7 +251,7 @@ Pre-condition: the current base URL is `https://www.magento.com`. Opens a page by the absolute URL. -See [amOnUrl docs on codeception.com](http://codeception.com/docs/modules/WebDriver#amOnUrl). +See [amOnUrl docs on codeception.com](https://codeception.com/docs/modules/WebDriver#amOnUrl). Attribute|Type|Use|Description ---|---|---|--- @@ -269,7 +269,7 @@ Attribute|Type|Use|Description ### appendField -See [appendField docs on codeception.com](http://codeception.com/docs/modules/WebDriver#appendField). +See [appendField docs on codeception.com](https://codeception.com/docs/modules/WebDriver#appendField). Attribute|Type|Use|Description ---|---|---|--- @@ -288,7 +288,7 @@ Attribute|Type|Use|Description ### attachFile -See [attachFile docs on codeception.com](http://codeception.com/docs/modules/WebDriver#attachFile). +See [attachFile docs on codeception.com](https://codeception.com/docs/modules/WebDriver#attachFile). Attribute|Type|Use|Description ---|---|---|--- @@ -307,7 +307,7 @@ Attribute|Type|Use|Description ### cancelPopup -See [cancelPopup docs on codeception.com](http://codeception.com/docs/modules/WebDriver#cancelPopup). +See [cancelPopup docs on codeception.com](https://codeception.com/docs/modules/WebDriver#cancelPopup). Attribute|Type|Use|Description ---|---|---|--- @@ -324,7 +324,7 @@ Attribute|Type|Use|Description ### checkOption -See [checkOption docs on codeception.com](http://codeception.com/docs/modules/WebDriver#checkOption). +See [checkOption docs on codeception.com](https://codeception.com/docs/modules/WebDriver#checkOption). Attribute|Type|Use|Description ---|---|---|--- @@ -361,12 +361,12 @@ Attribute|Type|Use|Description ### click -See [click docs on codeception.com](http://codeception.com/docs/modules/WebDriver#click). +See [click docs on codeception.com](https://codeception.com/docs/modules/WebDriver#click). Attribute|Type|Use|Description ---|---|---|--- `selector`|string|optional| The selector identifying the corresponding HTML element. -`selectorArray`|string|optional| Selects an element as a key value array. See [strict locator](http://codeception.com/docs/modules/WebDriver#locating-elements). +`selectorArray`|string|optional| Selects an element as a key value array. See [strict locator](https://codeception.com/docs/modules/WebDriver#locating-elements). `userInput`|string|optional| Data to be sent with the click. `stepKey`|string|required| A unique identifier of the action. `before`|string|optional| `stepKey` of action that must be executed next. @@ -386,7 +386,7 @@ Attribute|Type|Use|Description ### clickWithLeftButton -See [clickWithLeftButton docs on codeception.com](http://codeception.com/docs/modules/WebDriver#clickWithLeftButton). +See [clickWithLeftButton docs on codeception.com](https://codeception.com/docs/modules/WebDriver#clickWithLeftButton). Attribute|Type|Use|Description ---|---|---|--- @@ -417,7 +417,7 @@ Attribute|Type|Use|Description ### clickWithRightButton -See [clickWithRightButton docs on codeception.com](http://codeception.com/docs/modules/WebDriver#clickWithRightButton). +See [clickWithRightButton docs on codeception.com](https://codeception.com/docs/modules/WebDriver#clickWithRightButton). Attribute|Type|Use|Description ---|---|---|--- @@ -465,7 +465,7 @@ Attribute|Type|Use|Description ### closeTab -See [closeTab docs on codeception.com](http://codeception.com/docs/modules/WebDriver#closeTab). +See [closeTab docs on codeception.com](https://codeception.com/docs/modules/WebDriver#closeTab). Attribute|Type|Use|Description ---|---|---|--- @@ -623,7 +623,7 @@ Delete an entity using [REST API](https://devdocs.magento.com/redoc/2.3/) reques ### dontSee -See [the codeception.com documentation for more information about this action](http://codeception.com/docs/modules/WebDriver#dontSee). +See [the codeception.com documentation for more information about this action](https://codeception.com/docs/modules/WebDriver#dontSee). Attribute|Type|Use|Description ---|---|---|--- @@ -643,7 +643,7 @@ Attribute|Type|Use|Description ### dontSeeCheckboxIsChecked -See [dontSeeCheckboxIsChecked docs on codeception.com](http://codeception.com/docs/modules/WebDriver#dontSeeCheckboxIsChecked). +See [dontSeeCheckboxIsChecked docs on codeception.com](https://codeception.com/docs/modules/WebDriver#dontSeeCheckboxIsChecked). Attribute|Type|Use|Description ---|---|---|--- @@ -661,7 +661,7 @@ Attribute|Type|Use|Description ### dontSeeCookie -See [dontSeeCookie docs on codeception.com](http://codeception.com/docs/modules/WebDriver#dontSeeCookie). +See [dontSeeCookie docs on codeception.com](https://codeception.com/docs/modules/WebDriver#dontSeeCookie). Attribute|Type|Use|Description ---|---|---|--- @@ -685,7 +685,7 @@ Attribute|Type|Use|Description ### dontSeeCurrentUrlEquals -See [dontSeeCurrentUrlEquals docs on codeception.com](http://codeception.com/docs/modules/WebDriver#dontSeeCurrentUrlEquals). +See [dontSeeCurrentUrlEquals docs on codeception.com](https://codeception.com/docs/modules/WebDriver#dontSeeCurrentUrlEquals). Attribute|Type|Use|Description ---|---|---|--- @@ -703,7 +703,7 @@ Attribute|Type|Use|Description ### dontSeeCurrentUrlMatches -See [dontSeeCurrentUrlMatches docs on codeception.com](http://codeception.com/docs/modules/WebDriver#dontSeeCurrentUrlMatches) +See [dontSeeCurrentUrlMatches docs on codeception.com](https://codeception.com/docs/modules/WebDriver#dontSeeCurrentUrlMatches) Attribute|Type|Use|Description ---|---|---|--- @@ -721,7 +721,7 @@ Attribute|Type|Use|Description ### dontSeeElement -See [dontSeeElement docs on codeception.com](http://codeception.com/docs/modules/WebDriver#dontSeeElement). +See [dontSeeElement docs on codeception.com](https://codeception.com/docs/modules/WebDriver#dontSeeElement). Attribute|Type|Use|Description ---|---|---|--- @@ -740,7 +740,7 @@ Attribute|Type|Use|Description ### dontSeeElementInDOM -See [dontSeeElementInDOM docs on codeception.com](http://codeception.com/docs/modules/WebDriver#dontSeeElementInDOM). +See [dontSeeElementInDOM docs on codeception.com](https://codeception.com/docs/modules/WebDriver#dontSeeElementInDOM). Attribute|Type|Use|Description ---|---|---|--- @@ -759,7 +759,7 @@ Attribute|Type|Use|Description ### dontSeeInCurrentUrl -See [dontSeeInCurrentUrl docs on codeception.com](http://codeception.com/docs/modules/WebDriver#dontSeeInCurrentUrl). +See [dontSeeInCurrentUrl docs on codeception.com](https://codeception.com/docs/modules/WebDriver#dontSeeInCurrentUrl). Attribute|Type|Use|Description ---|---|---|--- @@ -777,7 +777,7 @@ Attribute|Type|Use|Description ### dontSeeInField -See [dontSeeInField docs on codeception.com](http://codeception.com/docs/modules/WebDriver#dontSeeInField). +See [dontSeeInField docs on codeception.com](https://codeception.com/docs/modules/WebDriver#dontSeeInField). Attribute|Type|Use|Description ---|---|---|--- @@ -797,7 +797,7 @@ Attribute|Type|Use|Description ### dontSeeInFormFields -See [dontSeeInFormFields docs on codeception.com](http://codeception.com/docs/modules/WebDriver#dontSeeInFormFields). +See [dontSeeInFormFields docs on codeception.com](https://codeception.com/docs/modules/WebDriver#dontSeeInFormFields). Attribute|Type|Use|Description ---|---|---|--- @@ -816,7 +816,7 @@ Attribute|Type|Use|Description ### dontSeeInPageSource -See [dontSeeInPageSource docs on codeception.com](http://codeception.com/docs/modules/WebDriver#dontSeeInPageSource). +See [dontSeeInPageSource docs on codeception.com](https://codeception.com/docs/modules/WebDriver#dontSeeInPageSource). Attribute|Type|Use|Description ---|---|---|--- @@ -834,7 +834,7 @@ Attribute|Type|Use|Description ### dontSeeInSource -See [dontSeeInSource docs on codeception.com](http://codeception.com/docs/modules/WebDriver#dontSeeInSource). +See [dontSeeInSource docs on codeception.com](https://codeception.com/docs/modules/WebDriver#dontSeeInSource). Attribute|Type|Use|Description ---|---|---|--- @@ -854,7 +854,7 @@ You must encode the `html` using a tool such as [CyberChef](https://gchq.github. ### dontSeeInTitle -See [dontSeeInTitle docs on codeception.com](http://codeception.com/docs/modules/WebDriver#dontSeeInTitle). +See [dontSeeInTitle docs on codeception.com](https://codeception.com/docs/modules/WebDriver#dontSeeInTitle). Attribute|Type|Use|Description ---|---|---|--- @@ -889,7 +889,7 @@ Attribute|Type|Use|Description ### dontSeeLink -See [dontSeeLink docs on codeception.com](http://codeception.com/docs/modules/WebDriver#dontSeeLink). +See [dontSeeLink docs on codeception.com](https://codeception.com/docs/modules/WebDriver#dontSeeLink). Attribute|Type|Use|Description ---|---|---|--- @@ -913,7 +913,7 @@ Attribute|Type|Use|Description ### dontSeeOptionIsSelected -See [dontSeeOptionIsSelected docs on codeception.com](http://codeception.com/docs/modules/WebDriver#dontSeeOptionIsSelected). +See [dontSeeOptionIsSelected docs on codeception.com](https://codeception.com/docs/modules/WebDriver#dontSeeOptionIsSelected). Attribute|Type|Use|Description ---|---|---|--- @@ -932,7 +932,7 @@ Attribute|Type|Use|Description ### doubleClick -See [doubleClick docs on codeception.com](http://codeception.com/docs/modules/WebDriver#doubleClick). +See [doubleClick docs on codeception.com](https://codeception.com/docs/modules/WebDriver#doubleClick). Attribute|Type|Use|Description ---|---|---|--- @@ -950,7 +950,7 @@ Attribute|Type|Use|Description ### dragAndDrop -See [dragAndDrop docs on codeception.com](http://codeception.com/docs/modules/WebDriver#dragAndDrop). +See [dragAndDrop docs on codeception.com](https://codeception.com/docs/modules/WebDriver#dragAndDrop). Attribute|Type|Use|Description ---|---|---|--- @@ -976,7 +976,7 @@ Attribute|Type|Use|Description ### rapidClick -See [rapidClick docs on codeception.com](http://codeception.com/docs/modules/WebDriver#rapidClick). +See [rapidClick docs on codeception.com](https://codeception.com/docs/modules/WebDriver#rapidClick). | Attribute | Type | Use | Description | |------------|--------|----------|-------------------------------------------------| @@ -995,7 +995,7 @@ See [rapidClick docs on codeception.com](http://codeception.com/docs/modules/Web ### executeJS -See [executeJS docs on codeception.com](http://codeception.com/docs/modules/WebDriver#executeJS). +See [executeJS docs on codeception.com](https://codeception.com/docs/modules/WebDriver#executeJS). Attribute|Type|Use|Description ---|---|---|--- @@ -1016,7 +1016,7 @@ To access this value you would use `{$returnTime}` in later actions. ### fillField -See [fillField docs on codeception.com](http://codeception.com/docs/modules/WebDriver#fillField). +See [fillField docs on codeception.com](https://codeception.com/docs/modules/WebDriver#fillField). Attribute|Type|Use|Description ---|---|---|--- @@ -1115,7 +1115,7 @@ Attribute|Type|Use|Description ### grabAttributeFrom -See [grabAttributeFrom docs on codeception.com](http://codeception.com/docs/modules/WebDriver#grabAttributeFrom). +See [grabAttributeFrom docs on codeception.com](https://codeception.com/docs/modules/WebDriver#grabAttributeFrom). Attribute|Type|Use|Description ---|---|---|--- @@ -1135,7 +1135,7 @@ To access this value, use `{$grabAttributeFromInput}` in later actions. --> ### grabCookie -See [grabCookie docs on codeception.com](http://codeception.com/docs/modules/WebDriver#grabCookie). +See [grabCookie docs on codeception.com](https://codeception.com/docs/modules/WebDriver#grabCookie). Attribute|Type|Use|Description ---|---|---|--- @@ -1161,7 +1161,7 @@ To access this value, use `{$grabCookieExampleDomain}` in later actions. --> ### grabCookieAttributes -See [grabCookieAttributes docs on codeception.com](http://codeception.com/docs/modules/WebDriver#grabCookieAttributes). +See [grabCookieAttributes docs on codeception.com](https://codeception.com/docs/modules/WebDriver#grabCookieAttributes). Attribute|Type|Use|Description ---|---|---|--- @@ -1189,7 +1189,7 @@ To access expiry date, use `{$grabCookieExampleDomain.expiry}` in later actions ### grabFromCurrentUrl -See [grabFromCurrentUrl docs on codeception.com](http://codeception.com/docs/modules/WebDriver#grabFromCurrentUrl).. +See [grabFromCurrentUrl docs on codeception.com](https://codeception.com/docs/modules/WebDriver#grabFromCurrentUrl).. Attribute|Type|Use|Description ---|---|---|--- @@ -1208,7 +1208,7 @@ To access this value, use `{$grabFromCurrentUrl}` in later actions. --> ### grabMultiple -See [grabMultiple docs on codeception.com](http://codeception.com/docs/modules/WebDriver#grabMultiple).. +See [grabMultiple docs on codeception.com](https://codeception.com/docs/modules/WebDriver#grabMultiple).. Attribute|Type|Use|Description ---|---|---|--- @@ -1234,7 +1234,7 @@ To access this value, use `{$grabAllLinks}` in later actions. --> ### grabPageSource -See [grabPageSource docs on codeception.com](http://codeception.com/docs/modules/WebDriver#grabPageSource). +See [grabPageSource docs on codeception.com](https://codeception.com/docs/modules/WebDriver#grabPageSource). Attribute|Type|Use|Description ---|---|---|--- @@ -1252,7 +1252,7 @@ To access this value, use `{$grabPageSource}` in later actions. --> ### grabTextFrom -See [grabTextFrom docs on codeception.com](http://codeception.com/docs/modules/WebDriver#grabTextFrom). +See [grabTextFrom docs on codeception.com](https://codeception.com/docs/modules/WebDriver#grabTextFrom). Attribute|Type|Use|Description ---|---|---|--- @@ -1307,7 +1307,7 @@ Attribute|Type|Use|Description ### loadSessionSnapshot -See [loadSessionSnapshot docs on codeception.com](http://codeception.com/docs/modules/WebDriver#loadSessionSnapshot). +See [loadSessionSnapshot docs on codeception.com](https://codeception.com/docs/modules/WebDriver#loadSessionSnapshot). Attribute|Type|Use|Description ---|---|---|--- @@ -1368,7 +1368,7 @@ Attribute|Type|Use|Description ### makeScreenshot -See [makeScreenshot docs on codeception.com](http://codeception.com/docs/modules/WebDriver#makeScreenshot). +See [makeScreenshot docs on codeception.com](https://codeception.com/docs/modules/WebDriver#makeScreenshot). Attribute|Type|Use|Description ---|---|---|--- @@ -1391,7 +1391,7 @@ This action does not add a screenshot to the Allure [report](../reporting.md).</ ### maximizeWindow -See [maximizeWindow docs on codeception.com](http://codeception.com/docs/modules/WebDriver#maximizeWindow). +See [maximizeWindow docs on codeception.com](https://codeception.com/docs/modules/WebDriver#maximizeWindow). Attribute|Type|Use|Description ---|---|---|--- @@ -1408,7 +1408,7 @@ Attribute|Type|Use|Description ### moveBack -See [moveBack docs on codeception.com](http://codeception.com/docs/modules/WebDriver#moveBack). +See [moveBack docs on codeception.com](https://codeception.com/docs/modules/WebDriver#moveBack). Attribute|Type|Use|Description ---|---|---|--- @@ -1425,7 +1425,7 @@ Attribute|Type|Use|Description ### moveForward -See [moveForward docs on codeception.com](http://codeception.com/docs/modules/WebDriver#moveForward).. +See [moveForward docs on codeception.com](https://codeception.com/docs/modules/WebDriver#moveForward).. Attribute|Type|Use|Description ---|---|---|--- @@ -1440,7 +1440,7 @@ Attribute|Type|Use|Description ### moveMouseOver -See [moveMouseOver docs on codeception.com](http://codeception.com/docs/modules/WebDriver#moveMouseOver). +See [moveMouseOver docs on codeception.com](https://codeception.com/docs/modules/WebDriver#moveMouseOver). Attribute|Type|Use|Description ---|---|---|--- @@ -1484,7 +1484,7 @@ Attribute|Type|Use|Description ### openNewTab -See [openNewTab docs on codeception.com](http://codeception.com/docs/modules/WebDriver#openNewTab). +See [openNewTab docs on codeception.com](https://codeception.com/docs/modules/WebDriver#openNewTab). Attribute|Type|Use|Description ---|---|---|--- @@ -1529,7 +1529,7 @@ Attribute|Type|Use|Description ### pressKey -See [pressKey docs on codeception.com](http://codeception.com/docs/modules/WebDriver#pressKey). +See [pressKey docs on codeception.com](https://codeception.com/docs/modules/WebDriver#pressKey). Attribute|Type|Use|Description ---|---|---|--- @@ -1557,7 +1557,7 @@ To press more than one key at a time, wrap the keys in secondary `[]`. ### reloadPage -See [reloadPage docs on codeception.com](http://codeception.com/docs/modules/WebDriver#reloadPage). +See [reloadPage docs on codeception.com](https://codeception.com/docs/modules/WebDriver#reloadPage). Attribute|Type|Use|Description ---|---|---|--- @@ -1589,7 +1589,7 @@ Attribute|Type|Use|Description ### resetCookie -See [resetCookie docs on codeception.com](http://codeception.com/docs/modules/WebDriver#resetCookie). +See [resetCookie docs on codeception.com](https://codeception.com/docs/modules/WebDriver#resetCookie). Attribute|Type|Use|Description ---|---|---|--- @@ -1613,7 +1613,7 @@ Attribute|Type|Use|Description ### resizeWindow -See [resizeWindow docs on codeception.com](http://codeception.com/docs/modules/WebDriver#resizeWindow). +See [resizeWindow docs on codeception.com](https://codeception.com/docs/modules/WebDriver#resizeWindow). Attribute|Type|Use|Description ---|---|---|--- @@ -1632,7 +1632,7 @@ Attribute|Type|Use|Description ### saveSessionSnapshot -See [saveSessionSnapshot docs on codeception.com](http://codeception.com/docs/modules/WebDriver#saveSessionSnapshot). +See [saveSessionSnapshot docs on codeception.com](https://codeception.com/docs/modules/WebDriver#saveSessionSnapshot). Attribute|Type|Use|Description ---|---|---|--- @@ -1650,7 +1650,7 @@ Attribute|Type|Use|Description ### scrollTo -See [scrollTo docs on codeception.com](http://codeception.com/docs/modules/WebDriver#scrollTo). +See [scrollTo docs on codeception.com](https://codeception.com/docs/modules/WebDriver#scrollTo). Attribute|Type|Use|Description ---|---|---|--- @@ -1723,7 +1723,7 @@ On this test step the MFTF: ### see -See [see docs on codeception.com](http://codeception.com/docs/modules/WebDriver#see). +See [see docs on codeception.com](https://codeception.com/docs/modules/WebDriver#see). Attribute|Type|Use|Description ---|---|---|--- @@ -1743,7 +1743,7 @@ Attribute|Type|Use|Description ### seeCheckboxIsChecked -See [seeCheckboxIsChecked docs on codeception.com](http://codeception.com/docs/modules/WebDriver#seeCheckboxIsChecked). +See [seeCheckboxIsChecked docs on codeception.com](https://codeception.com/docs/modules/WebDriver#seeCheckboxIsChecked). Attribute|Type|Use|Description ---|---|---|--- @@ -1761,7 +1761,7 @@ Attribute|Type|Use|Description ### seeCookie -See [seeCookie docs on codeception.com](http://codeception.com/docs/modules/WebDriver#seeCookie). +See [seeCookie docs on codeception.com](https://codeception.com/docs/modules/WebDriver#seeCookie). Attribute|Type|Use|Description ---|---|---|--- @@ -1785,7 +1785,7 @@ Attribute|Type|Use|Description ### seeCurrentUrlEquals -See [seeCurrentUrlEquals docs on codeception.com](http://codeception.com/docs/modules/WebDriver#seeCurrentUrlEquals). +See [seeCurrentUrlEquals docs on codeception.com](https://codeception.com/docs/modules/WebDriver#seeCurrentUrlEquals). Attribute|Type|Use|Description ---|---|---|--- @@ -1803,7 +1803,7 @@ Attribute|Type|Use|Description ### seeCurrentUrlMatches -See [seeCurrentUrlMatches docs on codeception.com](http://codeception.com/docs/modules/WebDriver#seeCurrentUrlMatches). +See [seeCurrentUrlMatches docs on codeception.com](https://codeception.com/docs/modules/WebDriver#seeCurrentUrlMatches). Attribute|Type|Use|Description ---|---|---|--- @@ -1821,7 +1821,7 @@ Attribute|Type|Use|Description ### seeElement -See [seeElement docs on codeception.com](http://codeception.com/docs/modules/WebDriver#seeElement). +See [seeElement docs on codeception.com](https://codeception.com/docs/modules/WebDriver#seeElement). Attribute|Type|Use|Description ---|---|---|--- @@ -1841,7 +1841,7 @@ Attribute|Type|Use|Description ### seeElementInDOM -See [seeElementInDOM docs on codeception.com](http://codeception.com/docs/modules/WebDriver#seeElementInDOM). +See [seeElementInDOM docs on codeception.com](https://codeception.com/docs/modules/WebDriver#seeElementInDOM). Attribute|Type|Use|Description ---|---|---|--- @@ -1860,7 +1860,7 @@ Attribute|Type|Use|Description ### seeInCurrentUrl -See [seeInCurrentUrl docs on codeception.com](http://codeception.com/docs/modules/WebDriver#seeInCurrentUrl). +See [seeInCurrentUrl docs on codeception.com](https://codeception.com/docs/modules/WebDriver#seeInCurrentUrl). Attribute|Type|Use|Description ---|---|---|--- @@ -1878,7 +1878,7 @@ Attribute|Type|Use|Description ### seeInField -See [seeInField docs on codeception.com](http://codeception.com/docs/modules/WebDriver#seeInField). +See [seeInField docs on codeception.com](https://codeception.com/docs/modules/WebDriver#seeInField). Attribute|Type|Use|Description ---|---|---|--- @@ -1898,7 +1898,7 @@ Attribute|Type|Use|Description ### seeInFormFields -See [seeInFormFields docs on codeception.com](http://codeception.com/docs/modules/WebDriver#seeInFormFields). +See [seeInFormFields docs on codeception.com](https://codeception.com/docs/modules/WebDriver#seeInFormFields). Attribute|Type|Use|Description ---|---|---|--- @@ -1917,7 +1917,7 @@ Attribute|Type|Use|Description ### seeInPageSource -See [seeInPageSource docs on codeception.com](http://codeception.com/docs/modules/WebDriver#seeInPageSource). +See [seeInPageSource docs on codeception.com](https://codeception.com/docs/modules/WebDriver#seeInPageSource). Attribute|Type|Use|Description ---|---|---|--- @@ -1937,7 +1937,7 @@ You must encode the `html` using a tool such as [CyberChef](https://gchq.github. ### seeInPopup -See [seeInPopup docs on codeception.com](http://codeception.com/docs/modules/WebDriver#seeInPopup). +See [seeInPopup docs on codeception.com](https://codeception.com/docs/modules/WebDriver#seeInPopup). Attribute|Type|Use|Description ---|---|---|--- @@ -1955,7 +1955,7 @@ Attribute|Type|Use|Description ### seeInSource -See [seeInSource docs on codeception.com](http://codeception.com/docs/modules/WebDriver#seeInSource). +See [seeInSource docs on codeception.com](https://codeception.com/docs/modules/WebDriver#seeInSource). Attribute|Type|Use|Description ---|---|---|--- @@ -1975,7 +1975,7 @@ You must encode the `html` using a tool such as [CyberChef](https://gchq.github. ### seeInTitle -See [seeInTitle docs on codeception.com](http://codeception.com/docs/modules/WebDriver#seeInTitle). +See [seeInTitle docs on codeception.com](https://codeception.com/docs/modules/WebDriver#seeInTitle). Attribute|Type|Use|Description ---|---|---|--- @@ -1993,7 +1993,7 @@ Attribute|Type|Use|Description ### seeLink -See [seeLink docs on codeception.com](http://codeception.com/docs/modules/WebDriver#seeLink). +See [seeLink docs on codeception.com](https://codeception.com/docs/modules/WebDriver#seeLink). Attribute|Type|Use|Description ---|---|---|--- @@ -2017,7 +2017,7 @@ Attribute|Type|Use|Description ### seeNumberOfElements -See [seeNumberOfElements docs on codeception.com](http://codeception.com/docs/modules/WebDriver#seeNumberOfElements). +See [seeNumberOfElements docs on codeception.com](https://codeception.com/docs/modules/WebDriver#seeNumberOfElements). Attribute|Type|Use|Description ---|---|---|--- @@ -2042,7 +2042,7 @@ Attribute|Type|Use|Description ### seeOptionIsSelected -See [seeOptionIsSelected docs on codeception.com](http://codeception.com/docs/modules/WebDriver#seeOptionIsSelected). +See [seeOptionIsSelected docs on codeception.com](https://codeception.com/docs/modules/WebDriver#seeOptionIsSelected). Attribute|Type|Use|Description ---|---|---|--- @@ -2061,7 +2061,7 @@ Attribute|Type|Use|Description ### selectOption -See [selectOption docs on codeception.com](http://codeception.com/docs/modules/WebDriver#selectOption). +See [selectOption docs on codeception.com](https://codeception.com/docs/modules/WebDriver#selectOption). Attribute|Type|Use|Description ---|---|---|--- @@ -2104,7 +2104,7 @@ It contains a child element `<array>` where you specify the options that must be ### setCookie -See [setCookie docs on codeception.com](http://codeception.com/docs/modules/WebDriver#setCookie). +See [setCookie docs on codeception.com](https://codeception.com/docs/modules/WebDriver#setCookie). Attribute|Type|Use|Description ---|---|---|--- @@ -2124,7 +2124,7 @@ Attribute|Type|Use|Description ### submitForm -See [submitForm docs on codeception.com](http://codeception.com/docs/modules/WebDriver#submitForm). +See [submitForm docs on codeception.com](https://codeception.com/docs/modules/WebDriver#submitForm). Attribute|Type|Use|Description ---|---|---|--- @@ -2144,7 +2144,7 @@ Attribute|Type|Use|Description ### switchToIFrame -See [switchToIFrame docs on codeception.com](http://codeception.com/docs/modules/WebDriver#switchToIFrame). +See [switchToIFrame docs on codeception.com](https://codeception.com/docs/modules/WebDriver#switchToIFrame). Attribute|Type|Use|Description ---|---|---|--- @@ -2163,7 +2163,7 @@ Attribute|Type|Use|Description ### switchToNextTab -See [switchToNextTab docs on codeception.com](http://codeception.com/docs/modules/WebDriver#switchToNextTab). +See [switchToNextTab docs on codeception.com](https://codeception.com/docs/modules/WebDriver#switchToNextTab). Attribute|Type|Use|Description ---|---|---|--- @@ -2186,7 +2186,7 @@ Attribute|Type|Use|Description ### switchToPreviousTab -See [switchToPreviousTab docs on codeception.com](http://codeception.com/docs/modules/WebDriver#switchToPreviousTab). +See [switchToPreviousTab docs on codeception.com](https://codeception.com/docs/modules/WebDriver#switchToPreviousTab). Attribute|Type|Use|Description ---|---|---|--- @@ -2209,7 +2209,7 @@ Attribute|Type|Use|Description ### switchToWindow -See [switchToWindow docs on codeception.com](http://codeception.com/docs/modules/WebDriver#switchToWindow). +See [switchToWindow docs on codeception.com](https://codeception.com/docs/modules/WebDriver#switchToWindow). Attribute|Type|Use|Description ---|---|---|--- @@ -2227,7 +2227,7 @@ Attribute|Type|Use|Description ### typeInPopup -See [typeInPopup docs on codeception.com](http://codeception.com/docs/modules/WebDriver#typeInPopup). +See [typeInPopup docs on codeception.com](https://codeception.com/docs/modules/WebDriver#typeInPopup). Attribute|Type|Use|Description ---|---|---|--- @@ -2245,7 +2245,7 @@ Attribute|Type|Use|Description ### uncheckOption -See [uncheckOption docs on codeception.com](http://codeception.com/docs/modules/WebDriver#uncheckOption). +See [uncheckOption docs on codeception.com](https://codeception.com/docs/modules/WebDriver#uncheckOption). Attribute|Type|Use|Description ---|---|---|--- @@ -2263,7 +2263,7 @@ Attribute|Type|Use|Description ### unselectOption -See [unselectOption docs on codeception.com](http://codeception.com/docs/modules/WebDriver#unselectOption). +See [unselectOption docs on codeception.com](https://codeception.com/docs/modules/WebDriver#unselectOption). Attribute|Type|Use|Description ---|---|---|--- @@ -2315,7 +2315,7 @@ This action can optionally contain one or more [requiredEntity](#requiredentity) ### wait -See [wait docs on codeception.com](http://codeception.com/docs/modules/WebDriver#wait). +See [wait docs on codeception.com](https://codeception.com/docs/modules/WebDriver#wait). Attribute|Type|Use|Description ---|---|---|--- @@ -2351,7 +2351,7 @@ Attribute|Type|Use|Description ### waitForElementChange -See [waitForElementChange docs on codeception.com](http://codeception.com/docs/modules/WebDriver#waitForElementChange). +See [waitForElementChange docs on codeception.com](https://codeception.com/docs/modules/WebDriver#waitForElementChange). Attribute|Type|Use|Description ---|---|---|--- @@ -2371,7 +2371,7 @@ Attribute|Type|Use|Description ### waitForElement -See [waitForElement docs on codeception.com](http://codeception.com/docs/modules/WebDriver#waitForElement). +See [waitForElement docs on codeception.com](https://codeception.com/docs/modules/WebDriver#waitForElement). Attribute|Type|Use|Description ---|---|---|--- @@ -2390,7 +2390,7 @@ Attribute|Type|Use|Description ### waitForElementNotVisible -See [waitForElementNotVisible docs on codeception.com](http://codeception.com/docs/modules/WebDriver#waitForElementNotVisible). +See [waitForElementNotVisible docs on codeception.com](https://codeception.com/docs/modules/WebDriver#waitForElementNotVisible). Attribute|Type|Use|Description ---|---|---|--- @@ -2409,7 +2409,7 @@ Attribute|Type|Use|Description ### waitForElementVisible -See [waitForElementVisible docs on codeception.com](http://codeception.com/docs/modules/WebDriver#waitForElementVisible). +See [waitForElementVisible docs on codeception.com](https://codeception.com/docs/modules/WebDriver#waitForElementVisible). Attribute|Type|Use|Description ---|---|---|--- @@ -2427,7 +2427,7 @@ Attribute|Type|Use|Description ### waitForElementClickable -See [waitForElementClickable docs on codeception.com](http://codeception.com/docs/modules/WebDriver#waitForElementClickable). +See [waitForElementClickable docs on codeception.com](https://codeception.com/docs/modules/WebDriver#waitForElementClickable). Attribute|Type|Use|Description ---|---|---|--- @@ -2446,7 +2446,7 @@ Attribute|Type|Use|Description ### waitForJS -See [waitForJS docs on codeception.com](http://codeception.com/docs/modules/WebDriver#waitForJS). +See [waitForJS docs on codeception.com](https://codeception.com/docs/modules/WebDriver#waitForJS). Attribute|Type|Use|Description ---|---|---|--- @@ -2552,7 +2552,7 @@ Attribute|Type|Use|Description ### waitForText -See [waitForText docs on codeception.com](http://codeception.com/docs/modules/WebDriver#waitForText). +See [waitForText docs on codeception.com](https://codeception.com/docs/modules/WebDriver#waitForText). Attribute|Type|Use|Description ---|---|---|--- diff --git a/docs/test/annotations.md b/docs/test/annotations.md index 79cc00e80..cd3a672a1 100644 --- a/docs/test/annotations.md +++ b/docs/test/annotations.md @@ -225,8 +225,8 @@ Attribute|Type|Use [`@Description`]: https://github.com/allure-framework/allure-phpunit#extended-test-class-or-test-method-description [`@Features`]: https://github.com/allure-framework/allure-phpunit#map-test-classes-and-test-methods-to-features-and-stories -[`@group`]: http://codeception.com/docs/07-AdvancedUsage#Groups -[`@return`]: http://codeception.com/docs/07-AdvancedUsage#Examples +[`@group`]: https://codeception.com/docs/07-AdvancedUsage#Groups +[`@return`]: https://codeception.com/docs/07-AdvancedUsage#Examples [`@Severity`]: https://github.com/allure-framework/allure-phpunit#set-test-severity [`@Stories`]: https://github.com/allure-framework/allure-phpunit#map-test-classes-and-test-methods-to-features-and-stories [`@TestCaseId`]: https://github.com/allure-framework/allure1/wiki/Test-Case-ID From b6ca8a19a97294bb63b965f58b5910df956a17eb Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Sat, 30 Jul 2022 19:27:42 +0530 Subject: [PATCH 866/888] MQE-3840 : Fixed allure report not generating issue --- src/Magento/FunctionalTestingFramework/Util/TestGenerator.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index adaf4a356..2f0959296 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -564,9 +564,9 @@ public function requiredCredentials($testObject) private function generateClassAnnotations($annotationType, $annotationName, $testObject) { $annotationToAppend = null; - $requiredCredentialsMessage = $this->requiredCredentials($testObject); - $credMsg = "\n\n"."This test uses the following credentials:"."\n"; if (!empty($requiredCredentialsMessage) && !empty($annotationName['main'])) { + $requiredCredentialsMessage = $this->requiredCredentials($testObject); + $credMsg = "\n\n"."This test uses the following credentials:"."\n"; $annotationName = ['main'=>$annotationName['main'].', '.$credMsg.''.$requiredCredentialsMessage, 'test_files'=> "\n".$annotationName['test_files'], 'deprecated'=>$annotationName['deprecated']]; } From b6ac740387d846a523a9be5b485d3abea43e824f Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Mon, 1 Aug 2022 10:09:09 +0530 Subject: [PATCH 867/888] MQE-3840 : fixed issue --- src/Magento/FunctionalTestingFramework/Util/TestGenerator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 2f0959296..1032b9317 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -564,7 +564,7 @@ public function requiredCredentials($testObject) private function generateClassAnnotations($annotationType, $annotationName, $testObject) { $annotationToAppend = null; - if (!empty($requiredCredentialsMessage) && !empty($annotationName['main'])) { + if (!empty($annotationName['main'])) { $requiredCredentialsMessage = $this->requiredCredentials($testObject); $credMsg = "\n\n"."This test uses the following credentials:"."\n"; $annotationName = ['main'=>$annotationName['main'].', '.$credMsg.''.$requiredCredentialsMessage, From 8ba093c9493bc11e82e40574b74811fb70bdb299 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Mon, 1 Aug 2022 10:17:22 +0530 Subject: [PATCH 868/888] fixed issue --- .../FunctionalTestingFramework/Util/TestGenerator.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 1032b9317..d95526676 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -564,11 +564,13 @@ public function requiredCredentials($testObject) private function generateClassAnnotations($annotationType, $annotationName, $testObject) { $annotationToAppend = null; - if (!empty($annotationName['main'])) { + if (!$testObject->isSkipped() && !empty($annotationName['main'])) { $requiredCredentialsMessage = $this->requiredCredentials($testObject); $credMsg = "\n\n"."This test uses the following credentials:"."\n"; - $annotationName = ['main'=>$annotationName['main'].', '.$credMsg.''.$requiredCredentialsMessage, - 'test_files'=> "\n".$annotationName['test_files'], 'deprecated'=>$annotationName['deprecated']]; + $annotationName = (!empty($requiredCredentialsMessage)) ? + ['main'=>$annotationName['main'].', '.$credMsg.''.$requiredCredentialsMessage, + 'test_files'=> "\n".$annotationName['test_files'], 'deprecated'=>$annotationName['deprecated']] + : $annotationName; } switch ($annotationType) { case "title": From 57d643bd5ff174e9da3050fa03659dbb1b76cead Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Mon, 1 Aug 2022 11:31:08 +0530 Subject: [PATCH 869/888] verification test --- ...ssueMustGetSkippedWithoutErrorExitCode.txt | 39 +++++++++++++++++++ ...ssueMustGetSkippedWithoutErrorExitCode.xml | 32 +++++++++++++++ .../Tests/SkippedGenerationTest.php | 11 ++++++ 3 files changed, 82 insertions(+) create mode 100644 dev/tests/verification/Resources/SkippedTestWithIssueMustGetSkippedWithoutErrorExitCode.txt create mode 100644 dev/tests/verification/TestModule/Test/SkippedTest/SkippedTestWithIssueMustGetSkippedWithoutErrorExitCode.xml diff --git a/dev/tests/verification/Resources/SkippedTestWithIssueMustGetSkippedWithoutErrorExitCode.txt b/dev/tests/verification/Resources/SkippedTestWithIssueMustGetSkippedWithoutErrorExitCode.txt new file mode 100644 index 000000000..f35d7ca74 --- /dev/null +++ b/dev/tests/verification/Resources/SkippedTestWithIssueMustGetSkippedWithoutErrorExitCode.txt @@ -0,0 +1,39 @@ +<?php +namespace Magento\AcceptanceTest\_default\Backend; + +use Magento\FunctionalTestingFramework\AcceptanceTester; +use \Codeception\Util\Locator; +use Yandex\Allure\Adapter\Annotation\Features; +use Yandex\Allure\Adapter\Annotation\Stories; +use Yandex\Allure\Adapter\Annotation\Title; +use Yandex\Allure\Adapter\Annotation\Description; +use Yandex\Allure\Adapter\Annotation\Parameter; +use Yandex\Allure\Adapter\Annotation\Severity; +use Yandex\Allure\Adapter\Model\SeverityLevel; +use Yandex\Allure\Adapter\Annotation\TestCaseId; + +/** + * @Title("[NO TESTCASEID]: skippedTest") + * @Description("<h3>Test files</h3>verification/TestModule/Test/SkippedTest/SkippedTestWithIssueMustGetSkippedWithoutErrorExitCode.xml<br>") + */ +class SkippedTestWithIssueMustGetSkippedWithoutErrorExitCodeCest +{ + /** + * @var bool + */ + private $isSuccess = false; + + /** + * @Stories({"skipped"}) + * @Severity(level = SeverityLevel::MINOR) + * @Features({"TestModule"}) + * @param AcceptanceTester $I + * @return void + * @throws \Exception + */ + public function SkippedTestWithIssueMustGetSkippedWithoutErrorExitCode(AcceptanceTester $I, \Codeception\Scenario $scenario) + { + unlink(__FILE__); + $scenario->skip("This test is skipped due to the following issues:\nSkippedValue"); + } +} diff --git a/dev/tests/verification/TestModule/Test/SkippedTest/SkippedTestWithIssueMustGetSkippedWithoutErrorExitCode.xml b/dev/tests/verification/TestModule/Test/SkippedTest/SkippedTestWithIssueMustGetSkippedWithoutErrorExitCode.xml new file mode 100644 index 000000000..b44cd6d81 --- /dev/null +++ b/dev/tests/verification/TestModule/Test/SkippedTest/SkippedTestWithIssueMustGetSkippedWithoutErrorExitCode.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="SkippedTestWithIssueMustGetSkippedWithoutErrorExitCode"> + <annotations> + <stories value="skipped"/> + <title value="skippedTest"/> + <description value=""/> + <severity value="AVERAGE"/> + <skip> + <issueId value="SkippedValue"/> + </skip> + </annotations> + <before> + <createData entity="ReplacementPerson" stepKey="createPersonParam"/> + <actionGroup ref="FunctionalActionGroup" stepKey="beforeGroup"/> + </before> + <createData entity="DefaultPerson" stepKey="createPerson"/> + <actionGroup ref="FunctionalActionGroupWithData" stepKey="actionGroupWithPersistedData1"> + <argument name="person" value="$createPerson$"/> + </actionGroup> + <after> + <actionGroup ref="FunctionalActionGroup" stepKey="afterGroup" after ="notFound"/> + </after> + </test> +</tests> diff --git a/dev/tests/verification/Tests/SkippedGenerationTest.php b/dev/tests/verification/Tests/SkippedGenerationTest.php index 2bc73986a..bfcc5bcc4 100644 --- a/dev/tests/verification/Tests/SkippedGenerationTest.php +++ b/dev/tests/verification/Tests/SkippedGenerationTest.php @@ -41,4 +41,15 @@ public function testMultipleSkippedIssuesGeneration() { $this->generateAndCompareTest('SkippedTestTwoIssues'); } + + /** + * Tests skipped test with multiple issues generation. + * + * @throws \Exception + * @throws \Magento\FunctionalTestingFramework\Exceptions\TestReferenceException + */ + public function testSkippedTestMustNotFailToGenerateWithErrorWhenThereIsIssueWithAnyOfTheStepsAsTheTestIsSkipped() + { + $this->generateAndCompareTest('SkippedTestWithIssueMustGetSkippedWithoutErrorExitCode'); + } } From 8b97663478d587fa86fdc833ac7def12702304b1 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Mon, 1 Aug 2022 12:17:10 +0530 Subject: [PATCH 870/888] verification test --- dev/tests/verification/Tests/SkippedGenerationTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/tests/verification/Tests/SkippedGenerationTest.php b/dev/tests/verification/Tests/SkippedGenerationTest.php index bfcc5bcc4..b2d1c8fdc 100644 --- a/dev/tests/verification/Tests/SkippedGenerationTest.php +++ b/dev/tests/verification/Tests/SkippedGenerationTest.php @@ -42,8 +42,8 @@ public function testMultipleSkippedIssuesGeneration() $this->generateAndCompareTest('SkippedTestTwoIssues'); } - /** - * Tests skipped test with multiple issues generation. + /** + * Tests skipped test doesnt fail to generate when there is issue in test * * @throws \Exception * @throws \Magento\FunctionalTestingFramework\Exceptions\TestReferenceException From ad1a2e9f708b0ed6cd46a2827c02f39eb0360d02 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Mon, 1 Aug 2022 20:16:55 +0530 Subject: [PATCH 871/888] 3.10.1-RC : 3.10.1 Release --- CHANGELOG.md | 8 ++++++++ composer.json | 2 +- composer.lock | 5 ++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cbc6086a0..163e71085 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ Magento Functional Testing Framework Changelog ================================================ +3.10.1 +--------- + +### Fixes + +* Fixed Allure reports are not generated for composer builds when running from repo +* Fixed All MFTF scheduled build isn't h + 3.10.0 --------- diff --git a/composer.json b/composer.json index 1149253c2..e731e9685 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "3.10.0", + "version": "3.10.1", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index 1a8a0b9f3..5b52e5956 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "fd34c83cd0fc786e9d8d892d1e25b18d", + "content-hash": "b504d7cfd0bf4111f83579996edb79ef", "packages": [ { "name": "allure-framework/allure-codeception", @@ -2467,6 +2467,9 @@ "require": { "php": "^7.1 || ^8.0" }, + "replace": { + "myclabs/deep-copy": "self.version" + }, "require-dev": { "doctrine/collections": "^1.0", "doctrine/common": "^2.6", From c02cb597bc4fb776817da9283514e1cdb6ab42b2 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Mon, 1 Aug 2022 20:37:38 +0530 Subject: [PATCH 872/888] 3.10.1-RC : 3.10.1 Release --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 163e71085..cdd015d32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,8 @@ Magento Functional Testing Framework Changelog ### Fixes -* Fixed Allure reports are not generated for composer builds when running from repo -* Fixed All MFTF scheduled build isn't h +* Fixed Allure reports not generated for composer builds. +* Fixed All MFTF scheduled build isn't generating allure report. 3.10.0 --------- From 8d7db5616c39c6fd44f8b401c091e3090ed26f2f Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Mon, 1 Aug 2022 20:38:33 +0530 Subject: [PATCH 873/888] 3.10.1-RC : 3.10.1 Release --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cdd015d32..f893ba79c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,8 @@ Magento Functional Testing Framework Changelog ### Fixes -* Fixed Allure reports not generated for composer builds. -* Fixed All MFTF scheduled build isn't generating allure report. +* Fixed allure reports not generating for composer builds. +* Fixed all MFTF scheduled build not generating allure report. 3.10.0 --------- From a8082a145db0d13e6d30994c6e9fe9ef6a1090a5 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Thu, 11 Aug 2022 12:34:42 +0530 Subject: [PATCH 874/888] Merging 3.10.1 master back to develop | Admin Credentials being output to console in WebAPIAuth --- .../DataTransport/Auth/WebApiAuth.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php b/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php index be29a7e19..f80ffc105 100644 --- a/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php +++ b/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php @@ -119,8 +119,6 @@ public static function getAdminToken($username = null, $password = null) $message .= Tfa::isEnabled() ? ' and 2FA settings:' : ':' . PHP_EOL; } catch (TestFrameworkException $e) { } - $message .= "username: {$login}" . PHP_EOL; - $message .= "password: {$password}" . PHP_EOL; $message .= $errMessage; $context = ['url' => $authUrl]; throw new FastFailException($message, $context); From 6c5a0dc88be2f247650477fd0b93a789d226271b Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Thu, 11 Aug 2022 12:37:30 +0530 Subject: [PATCH 875/888] Merging 3.10.1 master back to develop | Admin Credentials being output to console in WebAPIAuth --- .../DataTransport/Auth/WebApiAuth.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php b/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php index f80ffc105..bc4e52571 100644 --- a/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php +++ b/src/Magento/FunctionalTestingFramework/DataTransport/Auth/WebApiAuth.php @@ -113,7 +113,7 @@ public static function getAdminToken($username = null, $password = null) $errMessage = $e->getMessage(); } - $message = 'Cannot retrieve API token with credentials. Please check the following configurations'; + $message = 'Cannot retrieve API token with credentials.'; try { // No exception will ever throw from here $message .= Tfa::isEnabled() ? ' and 2FA settings:' : ':' . PHP_EOL; From 6241ed1bc0f1b7a456c9023dc3a7a085de58a54a Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Tue, 23 Aug 2022 14:42:53 +0530 Subject: [PATCH 876/888] 3.10.2-RC : mftf deployment --- CHANGELOG.md | 8 ++++++++ composer.json | 2 +- composer.lock | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f893ba79c..c92fa924f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ Magento Functional Testing Framework Changelog ================================================ +3.10.2 +--------- + +### Fixes + +* Fixed admin credentials being output to console in WebAPIAuth + + 3.10.1 --------- diff --git a/composer.json b/composer.json index e731e9685..0161b4883 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "magento/magento2-functional-testing-framework", "description": "Magento2 Functional Testing Framework", "type": "library", - "version": "3.10.1", + "version": "3.10.2", "license": "AGPL-3.0", "keywords": ["magento", "automation", "functional", "testing"], "config": { diff --git a/composer.lock b/composer.lock index 5b52e5956..1f79506a8 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b504d7cfd0bf4111f83579996edb79ef", + "content-hash": "075f7ef8a19879334ba1e0443f4e9679", "packages": [ { "name": "allure-framework/allure-codeception", From 8905e2a9050012aeb1a213ec56d75de5230fa4ba Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Tue, 23 Aug 2022 14:45:40 +0530 Subject: [PATCH 877/888] 3.10.2-RC : mftf deployment --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c92fa924f..3566f8718 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,6 @@ Magento Functional Testing Framework Changelog * Fixed admin credentials being output to console in WebAPIAuth - 3.10.1 --------- From 8f6167a02be91c856ad5447cbc01bcacea2d97de Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Wed, 24 Aug 2022 16:59:51 +0530 Subject: [PATCH 878/888] updated lock --- composer.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.lock b/composer.lock index 1f79506a8..40205fb9d 100644 --- a/composer.lock +++ b/composer.lock @@ -7755,6 +7755,7 @@ "symfony/polyfill-php80": "^1.16", "symfony/service-contracts": "^1.1.6|^2" }, + "conflict": { "ext-psr": "<1.1|>=2", "symfony/config": "<5.3", From 393a99e0533dff7fe69c8fe9a7b2e99fc351f317 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Wed, 24 Aug 2022 17:36:20 +0530 Subject: [PATCH 879/888] updated changelog.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3566f8718..071f59887 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ Magento Functional Testing Framework Changelog ### Fixes * Fixed admin credentials being output to console in WebAPIAuth +* Fixed links in docs + 3.10.1 --------- From a35b728e4bc4102a951db0ec9013ace4df8c8bed Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Wed, 24 Aug 2022 20:13:50 +0530 Subject: [PATCH 880/888] fix --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 071f59887..2319ee48c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ Magento Functional Testing Framework Changelog * Fixed links in docs + 3.10.1 --------- From 46a70c74cd0a347d08c53d60abc0fae1e265c222 Mon Sep 17 00:00:00 2001 From: "Manjusha.S" <manjusha.s@BLR1-LMC-N71373.local> Date: Wed, 24 Aug 2022 20:18:00 +0530 Subject: [PATCH 881/888] removed unwanted file --- composer.lock | 1 - 1 file changed, 1 deletion(-) diff --git a/composer.lock b/composer.lock index 40205fb9d..1f79506a8 100644 --- a/composer.lock +++ b/composer.lock @@ -7755,7 +7755,6 @@ "symfony/polyfill-php80": "^1.16", "symfony/service-contracts": "^1.1.6|^2" }, - "conflict": { "ext-psr": "<1.1|>=2", "symfony/config": "<5.3", From f89a7da98945d6207c4cd50699f2594c81cf2304 Mon Sep 17 00:00:00 2001 From: Jeff Matthews <matthews.jeffery@gmail.com> Date: Tue, 30 Aug 2022 10:52:24 -0500 Subject: [PATCH 882/888] Added migration metadata to docs --- docs/backward-incompatible-changes.md | 5 +++++ docs/best-practices.md | 7 +++++- docs/commands/codeception.md | 5 +++++ docs/commands/mftf.md | 5 +++++ docs/configuration.md | 5 +++++ docs/configure-2fa.md | 5 +++++ docs/credentials.md | 5 +++++ docs/custom-helpers.md | 7 +++++- docs/data.md | 5 +++++ docs/debugging.md | 5 +++++ docs/extending.md | 5 +++++ docs/getting-started.md | 5 +++++ docs/guides/action-groups.md | 5 +++++ docs/guides/cicd.md | 5 +++++ docs/guides/git-vs-composer-install.md | 5 +++++ docs/guides/selectors.md | 9 ++++++-- docs/guides/test-isolation.md | 5 +++++ docs/guides/test-modularity.md | 5 +++++ docs/guides/using-suites.md | 5 +++++ docs/interactive-pause.md | 5 +++++ docs/introduction.md | 5 +++++ docs/merge_points/extend-action-groups.md | 5 +++++ docs/merge_points/extend-data.md | 5 +++++ docs/merge_points/extend-tests.md | 5 +++++ docs/merge_points/introduction.md | 5 +++++ docs/merge_points/merge-action-groups.md | 5 +++++ docs/merge_points/merge-data.md | 5 +++++ docs/merge_points/merge-pages.md | 5 +++++ docs/merge_points/merge-sections.md | 5 +++++ docs/merge_points/merge-tests.md | 5 +++++ docs/merging.md | 5 +++++ docs/metadata.md | 5 +++++ docs/mftf-tests-packaging.md | 5 +++++ docs/page.md | 5 +++++ docs/reporting.md | 5 +++++ docs/section.md | 5 +++++ docs/section/locator-functions.md | 5 +++++ docs/section/parameterized-selectors.md | 5 +++++ docs/selectors.md | 5 +++++ docs/suite.md | 5 +++++ docs/test-prep.md | 17 +++++++++----- docs/test.md | 5 +++++ docs/test/action-groups.md | 5 +++++ docs/test/actions.md | 7 +++++- docs/test/annotations.md | 5 +++++ docs/test/assertions.md | 27 ++++++++++++++--------- docs/tips-tricks.md | 5 +++++ docs/troubleshooting.md | 5 +++++ docs/update.md | 5 +++++ docs/versioning.md | 5 +++++ 50 files changed, 272 insertions(+), 22 deletions(-) diff --git a/docs/backward-incompatible-changes.md b/docs/backward-incompatible-changes.md index 5ddf1c9cb..4000ccb34 100644 --- a/docs/backward-incompatible-changes.md +++ b/docs/backward-incompatible-changes.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/backward-incompatible-changes/ +layout: migrated +--- + # MFTF 3.0.0 backward incompatible changes This page highlights backward incompatible changes between releases that have a major impact and require detailed explanation and special instructions to ensure third-party tests continue working with Magento core tests. diff --git a/docs/best-practices.md b/docs/best-practices.md index 1f3a25e02..d320dba16 100644 --- a/docs/best-practices.md +++ b/docs/best-practices.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/best-practices/ +layout: migrated +--- + # Best practices Check out our best practices below to ensure you are getting the absolute most out of the Magento Functional Testing Framework. @@ -85,7 +90,7 @@ The following pattern is used when merging with `extends`: Use a corresponding [`<deleteData>`] test step in your [`<after>`] block when using a [`<createData>`] action in a [`<before>`] block. 2. Make specific data entries under test to be unique. Enable data uniqueness where data values are required to be unique in a database by test design. - Use `unique=”suffix”` or `unique=”prefix”` to append or prepend a unique value to the [entity] attribute. + Use `unique="suffix"` or `unique="prefix"` to append or prepend a unique value to the [entity] attribute. This ensures that tests using the entity can be repeated. 3. Do not modify existing data entity fields or merge additional data fields without complete understanding and verifying the usage of existing data in tests. Create a new data entity for your test if you are not sure. diff --git a/docs/commands/codeception.md b/docs/commands/codeception.md index 8e6d76c11..2f112c25d 100644 --- a/docs/commands/codeception.md +++ b/docs/commands/codeception.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/commands/codeception/ +layout: migrated +--- + # CLI commands: vendor/bin/codecept <div class="bs-callout bs-callout-warning" markdown="1"> diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index 4b4bb4bab..a9c242a69 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/commands/mftf/ +layout: migrated +--- + # CLI commands: vendor/bin/mftf The Magento Functional Testing Framework (MFTF) introduces the command line interface (CLI) tool `vendor/bin/mftf` to facilitate your interaction with the framework. diff --git a/docs/configuration.md b/docs/configuration.md index 501b1d5e9..c17c2d9af 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/configuration/ +layout: migrated +--- + # Configuration The `*.env` file provides additional configuration for the Magento Functional Testing Framework (MFTF). diff --git a/docs/configure-2fa.md b/docs/configure-2fa.md index 7b01913b9..08b3d9273 100644 --- a/docs/configure-2fa.md +++ b/docs/configure-2fa.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/two-factor-authentication/ +layout: migrated +--- + # Configuring MFTF for Two-Factor Authentication (2FA) Using two-factor authentication (2FA) with MFTF is possible with some configurations settings in Magento. diff --git a/docs/credentials.md b/docs/credentials.md index 56f1ddbc4..bd71550be 100644 --- a/docs/credentials.md +++ b/docs/credentials.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/credentials/ +layout: migrated +--- + # Credentials When you test functionality that involves external services such as UPS, FedEx, PayPal, or SignifyD, diff --git a/docs/custom-helpers.md b/docs/custom-helpers.md index bf1ebc572..b0aba01c3 100644 --- a/docs/custom-helpers.md +++ b/docs/custom-helpers.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/custom-helpers/ +layout: migrated +--- + # Custom Helpers <div class="bs-callout-warning"> @@ -37,7 +42,7 @@ This functionality is used to select text on the page and cannot be accomplished ```php <?php /** - * Copyright © Magento, Inc. All rights reserved. + * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/docs/data.md b/docs/data.md index 721f94a7e..7247577a7 100644 --- a/docs/data.md +++ b/docs/data.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/data/ +layout: migrated +--- + # Input testing data MFTF enables you to specify and use `<data>` entities defined in XML. Default `<data>` entities are provided for use and as templates for entity creation and manipulation. diff --git a/docs/debugging.md b/docs/debugging.md index be17e952a..b4dbde2b3 100644 --- a/docs/debugging.md +++ b/docs/debugging.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/debugging/ +layout: migrated +--- + # Debugging Debugging within the Magento Functional Testing Framework is helpful in identifying test bugs by allowing you to pause execution so that you may: diff --git a/docs/extending.md b/docs/extending.md index 576bfdb24..a901249f4 100644 --- a/docs/extending.md +++ b/docs/extending.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/extending/ +layout: migrated +--- + # Extending There are cases when you need to create many tests that are very similar to each other. diff --git a/docs/getting-started.md b/docs/getting-started.md index 87cb04f79..f8644f92d 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/getting-started/ +layout: migrated +--- + # Getting started <div class="bs-callout bs-callout-info" markdown="1"> diff --git a/docs/guides/action-groups.md b/docs/guides/action-groups.md index 30c531e4e..fe635b4dd 100644 --- a/docs/guides/action-groups.md +++ b/docs/guides/action-groups.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/action-group-best-practices/ +layout: migrated +--- + # Action Group Best Practices We strive to write tests using only action groups. Fortunately, we have built up a large set of action groups to get started. We can make use of them and extend them for our own specific needs. In some cases, we may never even need to write action groups of our own. We may be able to simply chain together calls to existing action groups to implement our new test case. diff --git a/docs/guides/cicd.md b/docs/guides/cicd.md index 80cf134d8..1933a9da3 100644 --- a/docs/guides/cicd.md +++ b/docs/guides/cicd.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/cicd/ +layout: migrated +--- + # How to use MFTF in CICD To integrate MFTF tests into your CICD pipeline, it is best to start with the conceptual flow of the pipeline code. diff --git a/docs/guides/git-vs-composer-install.md b/docs/guides/git-vs-composer-install.md index fd9006cc1..61b9f882b 100644 --- a/docs/guides/git-vs-composer-install.md +++ b/docs/guides/git-vs-composer-install.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/git-vs-composer-install/ +layout: migrated +--- + # Git vs Composer installation of Magento with MFTF Depending on how you plan to use Magnto code, there are different options for installing Magento. diff --git a/docs/guides/selectors.md b/docs/guides/selectors.md index d1441865a..98dadba9a 100644 --- a/docs/guides/selectors.md +++ b/docs/guides/selectors.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/selectors/ +layout: migrated +--- + # How To write good selectors Selectors are the atomic unit of test writing. They fit into the hierarchy like this: MFTF tests make use of action groups > which are made up of actions > which interact with page objects > which contain elements > which are specified by selectors. Because they are fundamental building blocks, we must take care when writing them. @@ -213,7 +218,7 @@ Similarly, the relative XPath selector is a double forward slash `//`. It is use Example: ```xpath -//div[@class=’form-group’]//input[@id='user-message'] +//div[@class='form-group']//input[@id='user-message'] ``` In the `GOOD` example above, all `<div class='form-group'/>` elements in the DOM are matched first. Then all `<input id='user-message'/>` with `<div class='form-group'/>` as one of its parents are matched. The parent does not have to immediately precede it since it uses another double forward slash `//`. @@ -247,7 +252,7 @@ Given this HTML: ```html <tr> <td> - <a href=“#”>Edit</a> + <a href="#">Edit</a> </td> <td> <div>Unique Value</div> diff --git a/docs/guides/test-isolation.md b/docs/guides/test-isolation.md index 474867ff2..1841b1df3 100644 --- a/docs/guides/test-isolation.md +++ b/docs/guides/test-isolation.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/test-isolation/ +layout: migrated +--- + # Test Isolation Because MFTF is a framework for testing a highly customizable and ever changing application, MFTF tests need to be properly isolated. diff --git a/docs/guides/test-modularity.md b/docs/guides/test-modularity.md index ed182313e..c6ddfbf50 100644 --- a/docs/guides/test-modularity.md +++ b/docs/guides/test-modularity.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/test-modularity/ +layout: migrated +--- + # Test Modularity One of MFTF's most distinguishing functionalities is the framework's modularity. diff --git a/docs/guides/using-suites.md b/docs/guides/using-suites.md index 99413cb78..265aabcfb 100644 --- a/docs/guides/using-suites.md +++ b/docs/guides/using-suites.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/using-suites/ +layout: migrated +--- + # Using suites With an increasing number of MFTF tests, it is important to have a mechanism to organize and consolidate them for ease-of-use. diff --git a/docs/interactive-pause.md b/docs/interactive-pause.md index 5914c6339..8d20d6e45 100644 --- a/docs/interactive-pause.md +++ b/docs/interactive-pause.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/interactive-pause/ +layout: migrated +--- + # Interactive Pause It can be difficut to write a successful test on the first attempt. You will need to try different commands, with different arguments, before you find the correct path. diff --git a/docs/introduction.md b/docs/introduction.md index 73b068ba0..c2dfcf3bb 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/ +layout: migrated +--- + # Introduction to the Magento Functional Testing Framework <div class="bs-callout bs-callout-info" markdown="1"> diff --git a/docs/merge_points/extend-action-groups.md b/docs/merge_points/extend-action-groups.md index 6e7a54d70..fc988b075 100644 --- a/docs/merge_points/extend-action-groups.md +++ b/docs/merge_points/extend-action-groups.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/extend-action-groups/ +layout: migrated +--- + # Extend action groups Extending an action group doesn't affect the existing action group. diff --git a/docs/merge_points/extend-data.md b/docs/merge_points/extend-data.md index 91d2a67bb..0ac84d4e6 100644 --- a/docs/merge_points/extend-data.md +++ b/docs/merge_points/extend-data.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/extend-data/ +layout: migrated +--- + # Extend data entities Extending a data entity does not affect the existing data entity. diff --git a/docs/merge_points/extend-tests.md b/docs/merge_points/extend-tests.md index 763977049..1c06948d2 100644 --- a/docs/merge_points/extend-tests.md +++ b/docs/merge_points/extend-tests.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/extend-tests/ +layout: migrated +--- + # Extend tests Tests can be extended to cover the needs of your extension. diff --git a/docs/merge_points/introduction.md b/docs/merge_points/introduction.md index af03dade6..e62785b54 100644 --- a/docs/merge_points/introduction.md +++ b/docs/merge_points/introduction.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/ +layout: migrated +--- + # Merge Points for testing extensions in MFTF The Magento Functional Testing Framework (MFTF) allows great flexibility when writing XML tests for extensions. diff --git a/docs/merge_points/merge-action-groups.md b/docs/merge_points/merge-action-groups.md index ca6d20e68..4eecd5c32 100644 --- a/docs/merge_points/merge-action-groups.md +++ b/docs/merge_points/merge-action-groups.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/merge-action-groups/ +layout: migrated +--- + # Merge action groups An action group is a set of individual actions working together as a group. diff --git a/docs/merge_points/merge-data.md b/docs/merge_points/merge-data.md index b3342cc46..083fce236 100644 --- a/docs/merge_points/merge-data.md +++ b/docs/merge_points/merge-data.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/merge-data/ +layout: migrated +--- + # Merge data Data objects can be merged to cover the needs of your extension. diff --git a/docs/merge_points/merge-pages.md b/docs/merge_points/merge-pages.md index c7a3e8fa8..e9c86475c 100644 --- a/docs/merge_points/merge-pages.md +++ b/docs/merge_points/merge-pages.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/merge-pages/ +layout: migrated +--- + # Merge pages Sections can be merged into pages to cover your extension. diff --git a/docs/merge_points/merge-sections.md b/docs/merge_points/merge-sections.md index 135b3f7d8..13226b150 100644 --- a/docs/merge_points/merge-sections.md +++ b/docs/merge_points/merge-sections.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/merge-sections/ +layout: migrated +--- + # Merge sections Sections can be merged together to cover your extension. diff --git a/docs/merge_points/merge-tests.md b/docs/merge_points/merge-tests.md index b9e50d296..6555c2803 100644 --- a/docs/merge_points/merge-tests.md +++ b/docs/merge_points/merge-tests.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/merge-tests/ +layout: migrated +--- + # Merge tests Tests can be merged to create a new test that covers new extension capabilities. diff --git a/docs/merging.md b/docs/merging.md index d8436492e..fcda9c45e 100644 --- a/docs/merging.md +++ b/docs/merging.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merging/ +layout: migrated +--- + # Merging MFTF allows you to merge test components defined in XML files, such as: diff --git a/docs/metadata.md b/docs/metadata.md index 414f4bc04..ae7e0878a 100644 --- a/docs/metadata.md +++ b/docs/metadata.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/metadata/ +layout: migrated +--- + # Metadata In this topic we talk about handling entities that you need in your tests (such as categories, products, wish lists, and similar) using MFTF. diff --git a/docs/mftf-tests-packaging.md b/docs/mftf-tests-packaging.md index 8a37b8013..59b36a068 100644 --- a/docs/mftf-tests-packaging.md +++ b/docs/mftf-tests-packaging.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/mftf-tests-packaging/ +layout: migrated +--- + <style> .mftf-dl { margin-bottom: 2.5em; diff --git a/docs/page.md b/docs/page.md index fd03cfd58..121229faf 100644 --- a/docs/page.md +++ b/docs/page.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/page/ +layout: migrated +--- + # Page structure MFTF uses a modified concept of [PageObjects], which models the testing areas of your page as objects within the code. diff --git a/docs/reporting.md b/docs/reporting.md index 225890fcb..defefa2a5 100644 --- a/docs/reporting.md +++ b/docs/reporting.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/reporting/ +layout: migrated +--- + # Reporting The Magento Functional Testing Framework provides two types of reporting: diff --git a/docs/section.md b/docs/section.md index 68a6507af..926dee41d 100644 --- a/docs/section.md +++ b/docs/section.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/section/ +layout: migrated +--- + # Section structure A `<section>` is a reusable part of a [`<page>`](./page.html) and is the standard file for defining UI elements on a page used in a test. diff --git a/docs/section/locator-functions.md b/docs/section/locator-functions.md index 141afc9e6..91af37be9 100644 --- a/docs/section/locator-functions.md +++ b/docs/section/locator-functions.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/section/locator-functions/ +layout: migrated +--- + # Locator functions ## Define Locator::functions in elements diff --git a/docs/section/parameterized-selectors.md b/docs/section/parameterized-selectors.md index 58227948f..7c9f02ac5 100644 --- a/docs/section/parameterized-selectors.md +++ b/docs/section/parameterized-selectors.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/section/parameterized-selectors/ +layout: migrated +--- + # Parameterized selectors Use the following examples to create and use parameterized selectors in the MFTF. diff --git a/docs/selectors.md b/docs/selectors.md index 376140819..7a0332882 100644 --- a/docs/selectors.md +++ b/docs/selectors.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/selectors/ +layout: migrated +--- + ## Selectors These guidelines should help you to write high quality selectors. diff --git a/docs/suite.md b/docs/suite.md index 9f623f276..85127ba57 100644 --- a/docs/suite.md +++ b/docs/suite.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/suite/ +layout: migrated +--- + # Suites Suites are essentially groups of tests that run in specific conditions (preconditions and postconditions). diff --git a/docs/test-prep.md b/docs/test-prep.md index b344fcf9f..c44dff168 100644 --- a/docs/test-prep.md +++ b/docs/test-prep.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/test-prep/ +layout: migrated +--- + # Preparing a test for MFTF This tutorial demonstrates the process of converting a raw functional test into a properly abstracted test file, ready for publishing. @@ -47,7 +52,7 @@ For our example, we have a test that creates a simple product. Note the hardcode <?xml version="1.0" encoding="UTF-8"?> <!-- /** - * Copyright © Magento, Inc. All rights reserved. + * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> @@ -112,7 +117,7 @@ In this example `AdminProductFormSection` refers to the `<section>` in the XML f <?xml version="1.0" encoding="UTF-8"?> <!-- /** - * Copyright © Magento, Inc. All rights reserved. + * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> @@ -176,7 +181,7 @@ Here we are interested in `<section name="AdminProductFormSection">`, where we a <?xml version="1.0" encoding="UTF-8"?> <!-- /** - * Copyright © Magento, Inc. All rights reserved. + * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> @@ -211,7 +216,7 @@ We replace the hardcoded values with variables and the MFTF will do the variable <?xml version="1.0" encoding="UTF-8"?> <!-- /** - * Copyright © Magento, Inc. All rights reserved. + * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> @@ -316,7 +321,7 @@ To create an action group, take the steps and put them within an `<actionGroup>` <?xml version="1.0" encoding="UTF-8"?> <!-- /** - * Copyright © Magento, Inc. All rights reserved. + * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> @@ -347,7 +352,7 @@ Now we can reference this action group within our test (and any other test). <?xml version="1.0" encoding="UTF-8"?> <!-- /** - * Copyright © Magento, Inc. All rights reserved. + * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> diff --git a/docs/test.md b/docs/test.md index 4a77016f1..9fb5201fc 100644 --- a/docs/test.md +++ b/docs/test.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/ +layout: migrated +--- + # Test Test cases in the Magento Functional Testing Framework (MFTF) are defined in XML as [`<tests>`]. diff --git a/docs/test/action-groups.md b/docs/test/action-groups.md index 05adf795e..66ce81f34 100644 --- a/docs/test/action-groups.md +++ b/docs/test/action-groups.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/action-groups/ +layout: migrated +--- + # Action groups In the MFTF, you can re-use a group of [actions][], such as logging in as an administrator or a customer, declared in an XML file when you need to perform the same sequence of actions multiple times. diff --git a/docs/test/actions.md b/docs/test/actions.md index 94db9c989..f4199159b 100644 --- a/docs/test/actions.md +++ b/docs/test/actions.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/actions/ +layout: migrated +--- + # Test actions Actions in the MFTF allow you to automate different scenarios of Magento user's actions. @@ -2440,7 +2445,7 @@ Attribute|Type|Use|Description #### Example ```xml -<!-- Waits up to $timeout seconds for the given element to be clickable. If element doesn’t become clickable, a timeout exception is thrown. --> +<!-- Waits up to $timeout seconds for the given element to be clickable. If element doesn't become clickable, a timeout exception is thrown. --> <waitForElementClickable selector="#changedElement" stepKey="waitForElementClickable"/> ``` diff --git a/docs/test/annotations.md b/docs/test/annotations.md index cd3a672a1..9641df45a 100644 --- a/docs/test/annotations.md +++ b/docs/test/annotations.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/annotations/ +layout: migrated +--- + # Annotations diff --git a/docs/test/assertions.md b/docs/test/assertions.md index a3e97cf51..eb2696747 100644 --- a/docs/test/assertions.md +++ b/docs/test/assertions.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/assertions/ +layout: migrated +--- + # Assertions Assertions serve to pass or fail the [test](../test.md#test-tag) if a condition is not met. These assertions will look familiar to you if you've used any other testing framework, like PHPUnit. @@ -287,8 +292,8 @@ Example: ```xml <assertGreaterOrEquals stepKey="checkStatusSortOrderAsc" after="getOrderStatusSecondRow"> - <actualResult type="const">$getOrderStatusSecondRow</actualResult> - <expectedResult type="const">$getOrderStatusFirstRow</expectedResult> + <actualResult type="const">$getOrderStatusSecondRow</actualResult> + <expectedResult type="const">$getOrderStatusFirstRow</expectedResult> </assertGreaterOrEquals> ``` @@ -307,8 +312,8 @@ Example: ```xml <assertGreaterThan stepKey="checkQuantityWasChanged"> - <actualResult type="const">$grabEndQuantity</actualResult> - <expectedResult type="const">$grabStartQuantity</expectedResult> + <actualResult type="const">$grabEndQuantity</actualResult> + <expectedResult type="const">$grabStartQuantity</expectedResult> </assertGreaterThan> ``` @@ -327,8 +332,8 @@ Example: ```xml <assertGreaterThanOrEqual stepKey="checkStatusSortOrderAsc" after="getOrderStatusSecondRow"> - <actualResult type="const">$getOrderStatusSecondRow</actualResult> - <expectedResult type="const">$getOrderStatusFirstRow</expectedResult> + <actualResult type="const">$getOrderStatusSecondRow</actualResult> + <expectedResult type="const">$getOrderStatusFirstRow</expectedResult> </assertGreaterThanOrEqual> ``` @@ -489,7 +494,7 @@ Example: ```xml <assertNotEmpty stepKey="checkSwatchFieldForAdmin"> - <actualResult type="const">$grabSwatchForAdmin</actualResult> + <actualResult type="const">$grabSwatchForAdmin</actualResult> </assertNotEmpty> ``` @@ -508,8 +513,8 @@ Example: ```xml <assertNotEquals stepKey="assertNotEquals"> - <actualResult type="string">{$grabTotalAfter}</actualResult> - <expectedResult type="string">{$grabTotalBefore}</expectedResult> + <actualResult type="string">{$grabTotalAfter}</actualResult> + <expectedResult type="string">{$grabTotalBefore}</expectedResult> </assertNotEquals> ``` @@ -584,8 +589,8 @@ Example: ```xml <assertNotRegExp stepKey="simpleThumbnailIsNotDefault"> - <actualResult type="const">$getSimpleProductThumbnail</actualResult> - <expectedResult type="const">'/placeholder\/thumbnail\.jpg/'</expectedResult> + <actualResult type="const">$getSimpleProductThumbnail</actualResult> + <expectedResult type="const">'/placeholder\/thumbnail\.jpg/'</expectedResult> </assertNotRegExp> ``` diff --git a/docs/tips-tricks.md b/docs/tips-tricks.md index a2300c3bf..b5259320e 100644 --- a/docs/tips-tricks.md +++ b/docs/tips-tricks.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/tips-tricks/ +layout: migrated +--- + # Tips and Tricks Sometimes, little changes can make a big difference in your project. Here are some test writing tips to keep everything running smoothly. diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index d2a7dcabe..c58132695 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/troubleshooting/ +layout: migrated +--- + # Troubleshooting Having a little trouble with the MFTF? See some common errors and fixes below. diff --git a/docs/update.md b/docs/update.md index 284730430..29aaeef9a 100644 --- a/docs/update.md +++ b/docs/update.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/update/ +layout: migrated +--- + # Update the Magento Functional Testing Framework <div class="bs-callout bs-callout-info" markdown="1"> diff --git a/docs/versioning.md b/docs/versioning.md index 3cb51e405..6635e7581 100644 --- a/docs/versioning.md +++ b/docs/versioning.md @@ -1,3 +1,8 @@ +--- +migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/versioning/ +layout: migrated +--- + # MFTF versioning schema This document describes the versioning policy for the Magento Functional Testing Framework (MFTF), including the version numbering schema. From d25a667436c1d43bf6fd9c3918dec83a2bcc7ba4 Mon Sep 17 00:00:00 2001 From: Jeff Matthews <matthews.jeffery@gmail.com> Date: Tue, 30 Aug 2022 11:13:54 -0500 Subject: [PATCH 883/888] Added required metadata for devdocs log generator --- docs/backward-incompatible-changes.md | 1 + docs/best-practices.md | 1 + docs/commands/codeception.md | 1 + docs/commands/mftf.md | 1 + docs/configuration.md | 1 + docs/configure-2fa.md | 1 + docs/credentials.md | 1 + docs/custom-helpers.md | 1 + docs/data.md | 1 + docs/debugging.md | 1 + docs/extending.md | 1 + docs/getting-started.md | 1 + docs/guides/action-groups.md | 1 + docs/guides/cicd.md | 1 + docs/guides/git-vs-composer-install.md | 1 + docs/guides/selectors.md | 1 + docs/guides/test-isolation.md | 1 + docs/guides/test-modularity.md | 1 + docs/guides/using-suites.md | 1 + docs/interactive-pause.md | 1 + docs/introduction.md | 1 + docs/merge_points/extend-action-groups.md | 1 + docs/merge_points/extend-data.md | 1 + docs/merge_points/extend-tests.md | 1 + docs/merge_points/introduction.md | 1 + docs/merge_points/merge-action-groups.md | 1 + docs/merge_points/merge-data.md | 1 + docs/merge_points/merge-pages.md | 1 + docs/merge_points/merge-sections.md | 1 + docs/merge_points/merge-tests.md | 1 + docs/merging.md | 1 + docs/metadata.md | 1 + docs/mftf-tests-packaging.md | 1 + docs/page.md | 1 + docs/reporting.md | 1 + docs/section.md | 1 + docs/section/locator-functions.md | 1 + docs/section/parameterized-selectors.md | 1 + docs/selectors.md | 1 + docs/suite.md | 1 + docs/test-prep.md | 1 + docs/test.md | 1 + docs/test/action-groups.md | 1 + docs/test/actions.md | 1 + docs/test/annotations.md | 1 + docs/test/assertions.md | 1 + docs/tips-tricks.md | 1 + docs/troubleshooting.md | 1 + docs/update.md | 1 + docs/versioning.md | 1 + 50 files changed, 50 insertions(+) diff --git a/docs/backward-incompatible-changes.md b/docs/backward-incompatible-changes.md index 4000ccb34..3f74ef351 100644 --- a/docs/backward-incompatible-changes.md +++ b/docs/backward-incompatible-changes.md @@ -1,4 +1,5 @@ --- +title: MFTF 3.0.0 backward incompatible changes migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/backward-incompatible-changes/ layout: migrated --- diff --git a/docs/best-practices.md b/docs/best-practices.md index d320dba16..c9482a561 100644 --- a/docs/best-practices.md +++ b/docs/best-practices.md @@ -1,4 +1,5 @@ --- +title: Best practices migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/best-practices/ layout: migrated --- diff --git a/docs/commands/codeception.md b/docs/commands/codeception.md index 2f112c25d..e29751578 100644 --- a/docs/commands/codeception.md +++ b/docs/commands/codeception.md @@ -1,4 +1,5 @@ --- +title: CLI commands - vendor/bin/codecept migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/commands/codeception/ layout: migrated --- diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index a9c242a69..c14985431 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -1,4 +1,5 @@ --- +title: CLI commands - vendor/bin/mftf migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/commands/mftf/ layout: migrated --- diff --git a/docs/configuration.md b/docs/configuration.md index c17c2d9af..9da2912aa 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1,4 +1,5 @@ --- +title: Configuration migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/configuration/ layout: migrated --- diff --git a/docs/configure-2fa.md b/docs/configure-2fa.md index 08b3d9273..0d2c80758 100644 --- a/docs/configure-2fa.md +++ b/docs/configure-2fa.md @@ -1,4 +1,5 @@ --- +title: Configuring MFTF for two-factor authentication (2FA) migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/two-factor-authentication/ layout: migrated --- diff --git a/docs/credentials.md b/docs/credentials.md index bd71550be..0221ce98e 100644 --- a/docs/credentials.md +++ b/docs/credentials.md @@ -1,4 +1,5 @@ --- +title: Credentials migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/credentials/ layout: migrated --- diff --git a/docs/custom-helpers.md b/docs/custom-helpers.md index b0aba01c3..ae638aba9 100644 --- a/docs/custom-helpers.md +++ b/docs/custom-helpers.md @@ -1,4 +1,5 @@ --- +title: Custom helpers migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/custom-helpers/ layout: migrated --- diff --git a/docs/data.md b/docs/data.md index 7247577a7..447d855ed 100644 --- a/docs/data.md +++ b/docs/data.md @@ -1,4 +1,5 @@ --- +title: Input testing data migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/data/ layout: migrated --- diff --git a/docs/debugging.md b/docs/debugging.md index b4dbde2b3..aa3941766 100644 --- a/docs/debugging.md +++ b/docs/debugging.md @@ -1,4 +1,5 @@ --- +title: Debugging migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/debugging/ layout: migrated --- diff --git a/docs/extending.md b/docs/extending.md index a901249f4..2e1f103b5 100644 --- a/docs/extending.md +++ b/docs/extending.md @@ -1,4 +1,5 @@ --- +title: Extending migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/extending/ layout: migrated --- diff --git a/docs/getting-started.md b/docs/getting-started.md index f8644f92d..e6c0011ac 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -1,4 +1,5 @@ --- +title: Getting started migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/getting-started/ layout: migrated --- diff --git a/docs/guides/action-groups.md b/docs/guides/action-groups.md index fe635b4dd..af2eee1d4 100644 --- a/docs/guides/action-groups.md +++ b/docs/guides/action-groups.md @@ -1,4 +1,5 @@ --- +title: Action group best practices migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/action-group-best-practices/ layout: migrated --- diff --git a/docs/guides/cicd.md b/docs/guides/cicd.md index 1933a9da3..c660007a8 100644 --- a/docs/guides/cicd.md +++ b/docs/guides/cicd.md @@ -1,4 +1,5 @@ --- +title: How to use MFTF in CICD migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/cicd/ layout: migrated --- diff --git a/docs/guides/git-vs-composer-install.md b/docs/guides/git-vs-composer-install.md index 61b9f882b..4f9d7b170 100644 --- a/docs/guides/git-vs-composer-install.md +++ b/docs/guides/git-vs-composer-install.md @@ -1,4 +1,5 @@ --- +title: Git vs Composer installation of Magento with MFTF migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/git-vs-composer-install/ layout: migrated --- diff --git a/docs/guides/selectors.md b/docs/guides/selectors.md index 98dadba9a..b56ebb052 100644 --- a/docs/guides/selectors.md +++ b/docs/guides/selectors.md @@ -1,4 +1,5 @@ --- +title: How to write good selectors migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/selectors/ layout: migrated --- diff --git a/docs/guides/test-isolation.md b/docs/guides/test-isolation.md index 1841b1df3..37140610d 100644 --- a/docs/guides/test-isolation.md +++ b/docs/guides/test-isolation.md @@ -1,4 +1,5 @@ --- +title: Test isolation migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/test-isolation/ layout: migrated --- diff --git a/docs/guides/test-modularity.md b/docs/guides/test-modularity.md index c6ddfbf50..907512794 100644 --- a/docs/guides/test-modularity.md +++ b/docs/guides/test-modularity.md @@ -1,4 +1,5 @@ --- +title: Test modularity migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/test-modularity/ layout: migrated --- diff --git a/docs/guides/using-suites.md b/docs/guides/using-suites.md index 265aabcfb..89247fb65 100644 --- a/docs/guides/using-suites.md +++ b/docs/guides/using-suites.md @@ -1,4 +1,5 @@ --- +title: Using suites migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/using-suites/ layout: migrated --- diff --git a/docs/interactive-pause.md b/docs/interactive-pause.md index 8d20d6e45..49788dba1 100644 --- a/docs/interactive-pause.md +++ b/docs/interactive-pause.md @@ -1,4 +1,5 @@ --- +title: Interactive pause migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/interactive-pause/ layout: migrated --- diff --git a/docs/introduction.md b/docs/introduction.md index c2dfcf3bb..d8026f91d 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -1,4 +1,5 @@ --- +title: Introduction to the Magento Functional Testing Framework migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/ layout: migrated --- diff --git a/docs/merge_points/extend-action-groups.md b/docs/merge_points/extend-action-groups.md index fc988b075..5fb31af00 100644 --- a/docs/merge_points/extend-action-groups.md +++ b/docs/merge_points/extend-action-groups.md @@ -1,4 +1,5 @@ --- +title: Extend action groups migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/extend-action-groups/ layout: migrated --- diff --git a/docs/merge_points/extend-data.md b/docs/merge_points/extend-data.md index 0ac84d4e6..e803a387a 100644 --- a/docs/merge_points/extend-data.md +++ b/docs/merge_points/extend-data.md @@ -1,4 +1,5 @@ --- +title: Extend data entities migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/extend-data/ layout: migrated --- diff --git a/docs/merge_points/extend-tests.md b/docs/merge_points/extend-tests.md index 1c06948d2..265a3c0dd 100644 --- a/docs/merge_points/extend-tests.md +++ b/docs/merge_points/extend-tests.md @@ -1,4 +1,5 @@ --- +title: Extend tests migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/extend-tests/ layout: migrated --- diff --git a/docs/merge_points/introduction.md b/docs/merge_points/introduction.md index e62785b54..15f93fa5d 100644 --- a/docs/merge_points/introduction.md +++ b/docs/merge_points/introduction.md @@ -1,4 +1,5 @@ --- +title: Merge points for testing extensions in MFTF migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/ layout: migrated --- diff --git a/docs/merge_points/merge-action-groups.md b/docs/merge_points/merge-action-groups.md index 4eecd5c32..8ceeafefc 100644 --- a/docs/merge_points/merge-action-groups.md +++ b/docs/merge_points/merge-action-groups.md @@ -1,4 +1,5 @@ --- +title: Merge action groups migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/merge-action-groups/ layout: migrated --- diff --git a/docs/merge_points/merge-data.md b/docs/merge_points/merge-data.md index 083fce236..bcdab55c4 100644 --- a/docs/merge_points/merge-data.md +++ b/docs/merge_points/merge-data.md @@ -1,4 +1,5 @@ --- +title: Merge data migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/merge-data/ layout: migrated --- diff --git a/docs/merge_points/merge-pages.md b/docs/merge_points/merge-pages.md index e9c86475c..ac034b3eb 100644 --- a/docs/merge_points/merge-pages.md +++ b/docs/merge_points/merge-pages.md @@ -1,4 +1,5 @@ --- +title: Merge pages migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/merge-pages/ layout: migrated --- diff --git a/docs/merge_points/merge-sections.md b/docs/merge_points/merge-sections.md index 13226b150..84ad44f7c 100644 --- a/docs/merge_points/merge-sections.md +++ b/docs/merge_points/merge-sections.md @@ -1,4 +1,5 @@ --- +title: Merge sections migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/merge-sections/ layout: migrated --- diff --git a/docs/merge_points/merge-tests.md b/docs/merge_points/merge-tests.md index 6555c2803..c71f0a2fb 100644 --- a/docs/merge_points/merge-tests.md +++ b/docs/merge_points/merge-tests.md @@ -1,4 +1,5 @@ --- +title: Merge tests migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/merge-tests/ layout: migrated --- diff --git a/docs/merging.md b/docs/merging.md index fcda9c45e..c01fc4d88 100644 --- a/docs/merging.md +++ b/docs/merging.md @@ -1,4 +1,5 @@ --- +title: Merging migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merging/ layout: migrated --- diff --git a/docs/metadata.md b/docs/metadata.md index ae7e0878a..90098261c 100644 --- a/docs/metadata.md +++ b/docs/metadata.md @@ -1,4 +1,5 @@ --- +title: Metadata migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/metadata/ layout: migrated --- diff --git a/docs/mftf-tests-packaging.md b/docs/mftf-tests-packaging.md index 59b36a068..d73e2ede3 100644 --- a/docs/mftf-tests-packaging.md +++ b/docs/mftf-tests-packaging.md @@ -1,4 +1,5 @@ --- +title: MFTF functional test modules and packaging migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/mftf-tests-packaging/ layout: migrated --- diff --git a/docs/page.md b/docs/page.md index 121229faf..4fc20e576 100644 --- a/docs/page.md +++ b/docs/page.md @@ -1,4 +1,5 @@ --- +title: Page structure migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/page/ layout: migrated --- diff --git a/docs/reporting.md b/docs/reporting.md index defefa2a5..402d8b21b 100644 --- a/docs/reporting.md +++ b/docs/reporting.md @@ -1,4 +1,5 @@ --- +title: Reporting migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/reporting/ layout: migrated --- diff --git a/docs/section.md b/docs/section.md index 926dee41d..31037af97 100644 --- a/docs/section.md +++ b/docs/section.md @@ -1,4 +1,5 @@ --- +title: Section structure migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/section/ layout: migrated --- diff --git a/docs/section/locator-functions.md b/docs/section/locator-functions.md index 91af37be9..992417e6d 100644 --- a/docs/section/locator-functions.md +++ b/docs/section/locator-functions.md @@ -1,4 +1,5 @@ --- +title: Locator functions migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/section/locator-functions/ layout: migrated --- diff --git a/docs/section/parameterized-selectors.md b/docs/section/parameterized-selectors.md index 7c9f02ac5..4b072698e 100644 --- a/docs/section/parameterized-selectors.md +++ b/docs/section/parameterized-selectors.md @@ -1,4 +1,5 @@ --- +title: Parameterized selectors migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/section/parameterized-selectors/ layout: migrated --- diff --git a/docs/selectors.md b/docs/selectors.md index 7a0332882..d6cdc8090 100644 --- a/docs/selectors.md +++ b/docs/selectors.md @@ -1,4 +1,5 @@ --- +title: Selectors migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/selectors/ layout: migrated --- diff --git a/docs/suite.md b/docs/suite.md index 85127ba57..75615aafa 100644 --- a/docs/suite.md +++ b/docs/suite.md @@ -1,4 +1,5 @@ --- +title: Suites migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/suite/ layout: migrated --- diff --git a/docs/test-prep.md b/docs/test-prep.md index c44dff168..b905b028f 100644 --- a/docs/test-prep.md +++ b/docs/test-prep.md @@ -1,4 +1,5 @@ --- +title: Preparing a test for MFTF migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/test-prep/ layout: migrated --- diff --git a/docs/test.md b/docs/test.md index 9fb5201fc..2372a7737 100644 --- a/docs/test.md +++ b/docs/test.md @@ -1,4 +1,5 @@ --- +title: Test migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/ layout: migrated --- diff --git a/docs/test/action-groups.md b/docs/test/action-groups.md index 66ce81f34..041966b0b 100644 --- a/docs/test/action-groups.md +++ b/docs/test/action-groups.md @@ -1,4 +1,5 @@ --- +title: Action groups migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/action-groups/ layout: migrated --- diff --git a/docs/test/actions.md b/docs/test/actions.md index f4199159b..286a42359 100644 --- a/docs/test/actions.md +++ b/docs/test/actions.md @@ -1,4 +1,5 @@ --- +title: Test actions migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/actions/ layout: migrated --- diff --git a/docs/test/annotations.md b/docs/test/annotations.md index 9641df45a..45a66c21c 100644 --- a/docs/test/annotations.md +++ b/docs/test/annotations.md @@ -1,4 +1,5 @@ --- +title: Annotations migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/annotations/ layout: migrated --- diff --git a/docs/test/assertions.md b/docs/test/assertions.md index eb2696747..fc95b80b8 100644 --- a/docs/test/assertions.md +++ b/docs/test/assertions.md @@ -1,4 +1,5 @@ --- +title: Assertions migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/assertions/ layout: migrated --- diff --git a/docs/tips-tricks.md b/docs/tips-tricks.md index b5259320e..a0cba8301 100644 --- a/docs/tips-tricks.md +++ b/docs/tips-tricks.md @@ -1,4 +1,5 @@ --- +title: Tips and tricks migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/tips-tricks/ layout: migrated --- diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index c58132695..8c56402b5 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -1,4 +1,5 @@ --- +title: Troubleshooting migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/troubleshooting/ layout: migrated --- diff --git a/docs/update.md b/docs/update.md index 29aaeef9a..617e61141 100644 --- a/docs/update.md +++ b/docs/update.md @@ -1,4 +1,5 @@ --- +title: Update the Magento Functional Testing Framework migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/update/ layout: migrated --- diff --git a/docs/versioning.md b/docs/versioning.md index 6635e7581..121a93368 100644 --- a/docs/versioning.md +++ b/docs/versioning.md @@ -1,4 +1,5 @@ --- +title: MFTF versioning schema migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/versioning/ layout: migrated --- From 5f19d27c3bc17c656744eec7a94ede4c8168c58b Mon Sep 17 00:00:00 2001 From: Jeff Matthews <matthews.jeffery@gmail.com> Date: Wed, 7 Dec 2022 12:49:14 -0600 Subject: [PATCH 884/888] COMDOX-365: Added redirects --- docs/backward-incompatible-changes.md | 2 +- docs/best-practices.md | 2 +- docs/commands/codeception.md | 2 +- docs/commands/mftf.md | 2 +- docs/configuration.md | 2 +- docs/configure-2fa.md | 2 +- docs/credentials.md | 2 +- docs/custom-helpers.md | 2 +- docs/data.md | 2 +- docs/debugging.md | 2 +- docs/extending.md | 2 +- docs/getting-started.md | 2 +- docs/guides/action-groups.md | 2 +- docs/guides/cicd.md | 2 +- docs/guides/git-vs-composer-install.md | 2 +- docs/guides/selectors.md | 2 +- docs/guides/test-isolation.md | 2 +- docs/guides/test-modularity.md | 2 +- docs/guides/using-suites.md | 2 +- docs/interactive-pause.md | 2 +- docs/introduction.md | 2 +- docs/merge_points/extend-action-groups.md | 2 +- docs/merge_points/extend-data.md | 2 +- docs/merge_points/extend-tests.md | 2 +- docs/merge_points/introduction.md | 2 +- docs/merge_points/merge-action-groups.md | 2 +- docs/merge_points/merge-data.md | 2 +- docs/merge_points/merge-pages.md | 2 +- docs/merge_points/merge-sections.md | 2 +- docs/merge_points/merge-tests.md | 2 +- docs/merging.md | 2 +- docs/metadata.md | 2 +- docs/mftf-tests-packaging.md | 2 +- docs/page.md | 2 +- docs/reporting.md | 2 +- docs/section.md | 2 +- docs/section/locator-functions.md | 2 +- docs/section/parameterized-selectors.md | 2 +- docs/selectors.md | 2 +- docs/suite.md | 2 +- docs/test-prep.md | 2 +- docs/test.md | 2 +- docs/test/action-groups.md | 2 +- docs/test/actions.md | 2 +- docs/test/annotations.md | 2 +- docs/test/assertions.md | 2 +- docs/tips-tricks.md | 2 +- docs/troubleshooting.md | 2 +- docs/update.md | 2 +- docs/versioning.md | 2 +- 50 files changed, 50 insertions(+), 50 deletions(-) diff --git a/docs/backward-incompatible-changes.md b/docs/backward-incompatible-changes.md index 3f74ef351..9f447e6f4 100644 --- a/docs/backward-incompatible-changes.md +++ b/docs/backward-incompatible-changes.md @@ -1,6 +1,6 @@ --- title: MFTF 3.0.0 backward incompatible changes -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/backward-incompatible-changes/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/backward-incompatible-changes/ layout: migrated --- diff --git a/docs/best-practices.md b/docs/best-practices.md index c9482a561..32b15dff2 100644 --- a/docs/best-practices.md +++ b/docs/best-practices.md @@ -1,6 +1,6 @@ --- title: Best practices -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/best-practices/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/best-practices/ layout: migrated --- diff --git a/docs/commands/codeception.md b/docs/commands/codeception.md index e29751578..65484e555 100644 --- a/docs/commands/codeception.md +++ b/docs/commands/codeception.md @@ -1,6 +1,6 @@ --- title: CLI commands - vendor/bin/codecept -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/commands/codeception/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/commands/codeception/ layout: migrated --- diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index c14985431..c673ef94e 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -1,6 +1,6 @@ --- title: CLI commands - vendor/bin/mftf -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/commands/mftf/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/commands/mftf/ layout: migrated --- diff --git a/docs/configuration.md b/docs/configuration.md index 9da2912aa..bf86dccfe 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1,6 +1,6 @@ --- title: Configuration -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/configuration/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/configuration/ layout: migrated --- diff --git a/docs/configure-2fa.md b/docs/configure-2fa.md index 0d2c80758..04290c71e 100644 --- a/docs/configure-2fa.md +++ b/docs/configure-2fa.md @@ -1,6 +1,6 @@ --- title: Configuring MFTF for two-factor authentication (2FA) -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/two-factor-authentication/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/two-factor-authentication/ layout: migrated --- diff --git a/docs/credentials.md b/docs/credentials.md index 0221ce98e..cef52e7f0 100644 --- a/docs/credentials.md +++ b/docs/credentials.md @@ -1,6 +1,6 @@ --- title: Credentials -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/credentials/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/credentials/ layout: migrated --- diff --git a/docs/custom-helpers.md b/docs/custom-helpers.md index ae638aba9..dfad00ecd 100644 --- a/docs/custom-helpers.md +++ b/docs/custom-helpers.md @@ -1,6 +1,6 @@ --- title: Custom helpers -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/custom-helpers/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/custom-helpers/ layout: migrated --- diff --git a/docs/data.md b/docs/data.md index 447d855ed..1578ab8d4 100644 --- a/docs/data.md +++ b/docs/data.md @@ -1,6 +1,6 @@ --- title: Input testing data -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/data/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/data/ layout: migrated --- diff --git a/docs/debugging.md b/docs/debugging.md index aa3941766..9ac6408a2 100644 --- a/docs/debugging.md +++ b/docs/debugging.md @@ -1,6 +1,6 @@ --- title: Debugging -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/debugging/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/debugging/ layout: migrated --- diff --git a/docs/extending.md b/docs/extending.md index 2e1f103b5..0099de622 100644 --- a/docs/extending.md +++ b/docs/extending.md @@ -1,6 +1,6 @@ --- title: Extending -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/extending/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/extending/ layout: migrated --- diff --git a/docs/getting-started.md b/docs/getting-started.md index e6c0011ac..f96bf18ec 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -1,6 +1,6 @@ --- title: Getting started -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/getting-started/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/getting-started/ layout: migrated --- diff --git a/docs/guides/action-groups.md b/docs/guides/action-groups.md index af2eee1d4..4cb35bbc5 100644 --- a/docs/guides/action-groups.md +++ b/docs/guides/action-groups.md @@ -1,6 +1,6 @@ --- title: Action group best practices -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/action-group-best-practices/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/action-group-best-practices/ layout: migrated --- diff --git a/docs/guides/cicd.md b/docs/guides/cicd.md index c660007a8..552233923 100644 --- a/docs/guides/cicd.md +++ b/docs/guides/cicd.md @@ -1,6 +1,6 @@ --- title: How to use MFTF in CICD -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/cicd/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/cicd/ layout: migrated --- diff --git a/docs/guides/git-vs-composer-install.md b/docs/guides/git-vs-composer-install.md index 4f9d7b170..2052cf32f 100644 --- a/docs/guides/git-vs-composer-install.md +++ b/docs/guides/git-vs-composer-install.md @@ -1,6 +1,6 @@ --- title: Git vs Composer installation of Magento with MFTF -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/git-vs-composer-install/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/git-vs-composer-install/ layout: migrated --- diff --git a/docs/guides/selectors.md b/docs/guides/selectors.md index b56ebb052..9f2622b81 100644 --- a/docs/guides/selectors.md +++ b/docs/guides/selectors.md @@ -1,6 +1,6 @@ --- title: How to write good selectors -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/selectors/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/selectors/ layout: migrated --- diff --git a/docs/guides/test-isolation.md b/docs/guides/test-isolation.md index 37140610d..60c4dae47 100644 --- a/docs/guides/test-isolation.md +++ b/docs/guides/test-isolation.md @@ -1,6 +1,6 @@ --- title: Test isolation -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/test-isolation/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/test-isolation/ layout: migrated --- diff --git a/docs/guides/test-modularity.md b/docs/guides/test-modularity.md index 907512794..2e88b279a 100644 --- a/docs/guides/test-modularity.md +++ b/docs/guides/test-modularity.md @@ -1,6 +1,6 @@ --- title: Test modularity -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/test-modularity/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/test-modularity/ layout: migrated --- diff --git a/docs/guides/using-suites.md b/docs/guides/using-suites.md index 89247fb65..682c8490f 100644 --- a/docs/guides/using-suites.md +++ b/docs/guides/using-suites.md @@ -1,6 +1,6 @@ --- title: Using suites -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/using-suites/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/using-suites/ layout: migrated --- diff --git a/docs/interactive-pause.md b/docs/interactive-pause.md index 49788dba1..b32355653 100644 --- a/docs/interactive-pause.md +++ b/docs/interactive-pause.md @@ -1,6 +1,6 @@ --- title: Interactive pause -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/interactive-pause/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/interactive-pause/ layout: migrated --- diff --git a/docs/introduction.md b/docs/introduction.md index d8026f91d..56dd39254 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -1,6 +1,6 @@ --- title: Introduction to the Magento Functional Testing Framework -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/ layout: migrated --- diff --git a/docs/merge_points/extend-action-groups.md b/docs/merge_points/extend-action-groups.md index 5fb31af00..09ae46330 100644 --- a/docs/merge_points/extend-action-groups.md +++ b/docs/merge_points/extend-action-groups.md @@ -1,6 +1,6 @@ --- title: Extend action groups -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/extend-action-groups/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/extend-action-groups/ layout: migrated --- diff --git a/docs/merge_points/extend-data.md b/docs/merge_points/extend-data.md index e803a387a..a17f32cf1 100644 --- a/docs/merge_points/extend-data.md +++ b/docs/merge_points/extend-data.md @@ -1,6 +1,6 @@ --- title: Extend data entities -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/extend-data/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/extend-data/ layout: migrated --- diff --git a/docs/merge_points/extend-tests.md b/docs/merge_points/extend-tests.md index 265a3c0dd..b87ad35d8 100644 --- a/docs/merge_points/extend-tests.md +++ b/docs/merge_points/extend-tests.md @@ -1,6 +1,6 @@ --- title: Extend tests -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/extend-tests/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/extend-tests/ layout: migrated --- diff --git a/docs/merge_points/introduction.md b/docs/merge_points/introduction.md index 15f93fa5d..2fb379a26 100644 --- a/docs/merge_points/introduction.md +++ b/docs/merge_points/introduction.md @@ -1,6 +1,6 @@ --- title: Merge points for testing extensions in MFTF -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/ layout: migrated --- diff --git a/docs/merge_points/merge-action-groups.md b/docs/merge_points/merge-action-groups.md index 8ceeafefc..80b533559 100644 --- a/docs/merge_points/merge-action-groups.md +++ b/docs/merge_points/merge-action-groups.md @@ -1,6 +1,6 @@ --- title: Merge action groups -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/merge-action-groups/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/merge-action-groups/ layout: migrated --- diff --git a/docs/merge_points/merge-data.md b/docs/merge_points/merge-data.md index bcdab55c4..b392197c7 100644 --- a/docs/merge_points/merge-data.md +++ b/docs/merge_points/merge-data.md @@ -1,6 +1,6 @@ --- title: Merge data -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/merge-data/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/merge-data/ layout: migrated --- diff --git a/docs/merge_points/merge-pages.md b/docs/merge_points/merge-pages.md index ac034b3eb..1d46383df 100644 --- a/docs/merge_points/merge-pages.md +++ b/docs/merge_points/merge-pages.md @@ -1,6 +1,6 @@ --- title: Merge pages -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/merge-pages/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/merge-pages/ layout: migrated --- diff --git a/docs/merge_points/merge-sections.md b/docs/merge_points/merge-sections.md index 84ad44f7c..fcd6a3726 100644 --- a/docs/merge_points/merge-sections.md +++ b/docs/merge_points/merge-sections.md @@ -1,6 +1,6 @@ --- title: Merge sections -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/merge-sections/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/merge-sections/ layout: migrated --- diff --git a/docs/merge_points/merge-tests.md b/docs/merge_points/merge-tests.md index c71f0a2fb..f30ef0cfd 100644 --- a/docs/merge_points/merge-tests.md +++ b/docs/merge_points/merge-tests.md @@ -1,6 +1,6 @@ --- title: Merge tests -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/merge-tests/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/merge-tests/ layout: migrated --- diff --git a/docs/merging.md b/docs/merging.md index c01fc4d88..7ee786ad1 100644 --- a/docs/merging.md +++ b/docs/merging.md @@ -1,6 +1,6 @@ --- title: Merging -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merging/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merging/ layout: migrated --- diff --git a/docs/metadata.md b/docs/metadata.md index 90098261c..17b466c11 100644 --- a/docs/metadata.md +++ b/docs/metadata.md @@ -1,6 +1,6 @@ --- title: Metadata -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/metadata/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/metadata/ layout: migrated --- diff --git a/docs/mftf-tests-packaging.md b/docs/mftf-tests-packaging.md index d73e2ede3..e30b6aefc 100644 --- a/docs/mftf-tests-packaging.md +++ b/docs/mftf-tests-packaging.md @@ -1,6 +1,6 @@ --- title: MFTF functional test modules and packaging -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/mftf-tests-packaging/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/mftf-tests-packaging/ layout: migrated --- diff --git a/docs/page.md b/docs/page.md index 4fc20e576..ddcfceb9d 100644 --- a/docs/page.md +++ b/docs/page.md @@ -1,6 +1,6 @@ --- title: Page structure -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/page/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/page/ layout: migrated --- diff --git a/docs/reporting.md b/docs/reporting.md index 402d8b21b..dd71be158 100644 --- a/docs/reporting.md +++ b/docs/reporting.md @@ -1,6 +1,6 @@ --- title: Reporting -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/reporting/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/reporting/ layout: migrated --- diff --git a/docs/section.md b/docs/section.md index 31037af97..8b1fb0106 100644 --- a/docs/section.md +++ b/docs/section.md @@ -1,6 +1,6 @@ --- title: Section structure -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/section/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/section/ layout: migrated --- diff --git a/docs/section/locator-functions.md b/docs/section/locator-functions.md index 992417e6d..190cc965c 100644 --- a/docs/section/locator-functions.md +++ b/docs/section/locator-functions.md @@ -1,6 +1,6 @@ --- title: Locator functions -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/section/locator-functions/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/section/locator-functions/ layout: migrated --- diff --git a/docs/section/parameterized-selectors.md b/docs/section/parameterized-selectors.md index 4b072698e..982ae9565 100644 --- a/docs/section/parameterized-selectors.md +++ b/docs/section/parameterized-selectors.md @@ -1,6 +1,6 @@ --- title: Parameterized selectors -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/section/parameterized-selectors/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/section/parameterized-selectors/ layout: migrated --- diff --git a/docs/selectors.md b/docs/selectors.md index d6cdc8090..d9e34cde1 100644 --- a/docs/selectors.md +++ b/docs/selectors.md @@ -1,6 +1,6 @@ --- title: Selectors -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/selectors/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/selectors/ layout: migrated --- diff --git a/docs/suite.md b/docs/suite.md index 75615aafa..74527edba 100644 --- a/docs/suite.md +++ b/docs/suite.md @@ -1,6 +1,6 @@ --- title: Suites -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/suite/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/suite/ layout: migrated --- diff --git a/docs/test-prep.md b/docs/test-prep.md index b905b028f..c94f62a5f 100644 --- a/docs/test-prep.md +++ b/docs/test-prep.md @@ -1,6 +1,6 @@ --- title: Preparing a test for MFTF -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/test-prep/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/test-prep/ layout: migrated --- diff --git a/docs/test.md b/docs/test.md index 2372a7737..a47305d1f 100644 --- a/docs/test.md +++ b/docs/test.md @@ -1,6 +1,6 @@ --- title: Test -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/ layout: migrated --- diff --git a/docs/test/action-groups.md b/docs/test/action-groups.md index 041966b0b..bd5b47288 100644 --- a/docs/test/action-groups.md +++ b/docs/test/action-groups.md @@ -1,6 +1,6 @@ --- title: Action groups -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/action-groups/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/action-groups/ layout: migrated --- diff --git a/docs/test/actions.md b/docs/test/actions.md index 286a42359..1dc25a112 100644 --- a/docs/test/actions.md +++ b/docs/test/actions.md @@ -1,6 +1,6 @@ --- title: Test actions -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/actions/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/actions/ layout: migrated --- diff --git a/docs/test/annotations.md b/docs/test/annotations.md index 45a66c21c..213911981 100644 --- a/docs/test/annotations.md +++ b/docs/test/annotations.md @@ -1,6 +1,6 @@ --- title: Annotations -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/annotations/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/annotations/ layout: migrated --- diff --git a/docs/test/assertions.md b/docs/test/assertions.md index fc95b80b8..cafd52872 100644 --- a/docs/test/assertions.md +++ b/docs/test/assertions.md @@ -1,6 +1,6 @@ --- title: Assertions -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/assertions/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/assertions/ layout: migrated --- diff --git a/docs/tips-tricks.md b/docs/tips-tricks.md index a0cba8301..5b27511df 100644 --- a/docs/tips-tricks.md +++ b/docs/tips-tricks.md @@ -1,6 +1,6 @@ --- title: Tips and tricks -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/tips-tricks/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/tips-tricks/ layout: migrated --- diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 8c56402b5..409ad9584 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -1,6 +1,6 @@ --- title: Troubleshooting -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/troubleshooting/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/troubleshooting/ layout: migrated --- diff --git a/docs/update.md b/docs/update.md index 617e61141..28be390fa 100644 --- a/docs/update.md +++ b/docs/update.md @@ -1,6 +1,6 @@ --- title: Update the Magento Functional Testing Framework -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/update/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/update/ layout: migrated --- diff --git a/docs/versioning.md b/docs/versioning.md index 121a93368..80e89924c 100644 --- a/docs/versioning.md +++ b/docs/versioning.md @@ -1,6 +1,6 @@ --- title: MFTF versioning schema -migrated_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/versioning/ +redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/versioning/ layout: migrated --- From 5af32e4c89753e7c3ef47d76823dd8e15f70182b Mon Sep 17 00:00:00 2001 From: Dmytro Shevtsov <shevtsov@adobe.com> Date: Thu, 15 Dec 2022 13:55:28 -0600 Subject: [PATCH 885/888] Update migrated pages Replace 'layout' with 'status' --- docs/backward-incompatible-changes.md | 2 +- docs/best-practices.md | 2 +- docs/commands/codeception.md | 2 +- docs/commands/mftf.md | 2 +- docs/configuration.md | 2 +- docs/configure-2fa.md | 2 +- docs/credentials.md | 2 +- docs/custom-helpers.md | 2 +- docs/data.md | 2 +- docs/debugging.md | 2 +- docs/extending.md | 2 +- docs/getting-started.md | 2 +- docs/guides/action-groups.md | 2 +- docs/guides/cicd.md | 2 +- docs/guides/git-vs-composer-install.md | 2 +- docs/guides/selectors.md | 2 +- docs/guides/test-isolation.md | 2 +- docs/guides/test-modularity.md | 2 +- docs/guides/using-suites.md | 2 +- docs/interactive-pause.md | 2 +- docs/introduction.md | 2 +- docs/merge_points/extend-action-groups.md | 2 +- docs/merge_points/extend-data.md | 2 +- docs/merge_points/extend-tests.md | 2 +- docs/merge_points/introduction.md | 2 +- docs/merge_points/merge-action-groups.md | 2 +- docs/merge_points/merge-data.md | 2 +- docs/merge_points/merge-pages.md | 2 +- docs/merge_points/merge-sections.md | 2 +- docs/merge_points/merge-tests.md | 2 +- docs/merging.md | 2 +- docs/metadata.md | 2 +- docs/mftf-tests-packaging.md | 2 +- docs/page.md | 2 +- docs/reporting.md | 2 +- docs/section.md | 2 +- docs/section/locator-functions.md | 2 +- docs/section/parameterized-selectors.md | 2 +- docs/selectors.md | 2 +- docs/suite.md | 2 +- docs/test-prep.md | 2 +- docs/test.md | 2 +- docs/test/action-groups.md | 2 +- docs/test/actions.md | 2 +- docs/test/annotations.md | 2 +- docs/test/assertions.md | 2 +- docs/tips-tricks.md | 2 +- docs/troubleshooting.md | 2 +- docs/update.md | 2 +- docs/versioning.md | 2 +- 50 files changed, 50 insertions(+), 50 deletions(-) diff --git a/docs/backward-incompatible-changes.md b/docs/backward-incompatible-changes.md index 9f447e6f4..5ee285941 100644 --- a/docs/backward-incompatible-changes.md +++ b/docs/backward-incompatible-changes.md @@ -1,7 +1,7 @@ --- title: MFTF 3.0.0 backward incompatible changes redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/backward-incompatible-changes/ -layout: migrated +status: migrated --- # MFTF 3.0.0 backward incompatible changes diff --git a/docs/best-practices.md b/docs/best-practices.md index 32b15dff2..ec6237b1c 100644 --- a/docs/best-practices.md +++ b/docs/best-practices.md @@ -1,7 +1,7 @@ --- title: Best practices redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/best-practices/ -layout: migrated +status: migrated --- # Best practices diff --git a/docs/commands/codeception.md b/docs/commands/codeception.md index 65484e555..1905d7a1e 100644 --- a/docs/commands/codeception.md +++ b/docs/commands/codeception.md @@ -1,7 +1,7 @@ --- title: CLI commands - vendor/bin/codecept redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/commands/codeception/ -layout: migrated +status: migrated --- # CLI commands: vendor/bin/codecept diff --git a/docs/commands/mftf.md b/docs/commands/mftf.md index c673ef94e..4cfbdab93 100644 --- a/docs/commands/mftf.md +++ b/docs/commands/mftf.md @@ -1,7 +1,7 @@ --- title: CLI commands - vendor/bin/mftf redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/commands/mftf/ -layout: migrated +status: migrated --- # CLI commands: vendor/bin/mftf diff --git a/docs/configuration.md b/docs/configuration.md index bf86dccfe..fff885e1f 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1,7 +1,7 @@ --- title: Configuration redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/configuration/ -layout: migrated +status: migrated --- # Configuration diff --git a/docs/configure-2fa.md b/docs/configure-2fa.md index 04290c71e..783e9e360 100644 --- a/docs/configure-2fa.md +++ b/docs/configure-2fa.md @@ -1,7 +1,7 @@ --- title: Configuring MFTF for two-factor authentication (2FA) redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/two-factor-authentication/ -layout: migrated +status: migrated --- # Configuring MFTF for Two-Factor Authentication (2FA) diff --git a/docs/credentials.md b/docs/credentials.md index cef52e7f0..dc77cdb39 100644 --- a/docs/credentials.md +++ b/docs/credentials.md @@ -1,7 +1,7 @@ --- title: Credentials redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/credentials/ -layout: migrated +status: migrated --- # Credentials diff --git a/docs/custom-helpers.md b/docs/custom-helpers.md index dfad00ecd..d6647705f 100644 --- a/docs/custom-helpers.md +++ b/docs/custom-helpers.md @@ -1,7 +1,7 @@ --- title: Custom helpers redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/custom-helpers/ -layout: migrated +status: migrated --- # Custom Helpers diff --git a/docs/data.md b/docs/data.md index 1578ab8d4..c555e2df1 100644 --- a/docs/data.md +++ b/docs/data.md @@ -1,7 +1,7 @@ --- title: Input testing data redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/data/ -layout: migrated +status: migrated --- # Input testing data diff --git a/docs/debugging.md b/docs/debugging.md index 9ac6408a2..ad4fe33ee 100644 --- a/docs/debugging.md +++ b/docs/debugging.md @@ -1,7 +1,7 @@ --- title: Debugging redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/debugging/ -layout: migrated +status: migrated --- # Debugging diff --git a/docs/extending.md b/docs/extending.md index 0099de622..9672c0732 100644 --- a/docs/extending.md +++ b/docs/extending.md @@ -1,7 +1,7 @@ --- title: Extending redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/extending/ -layout: migrated +status: migrated --- # Extending diff --git a/docs/getting-started.md b/docs/getting-started.md index f96bf18ec..efdd16dbc 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -1,7 +1,7 @@ --- title: Getting started redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/getting-started/ -layout: migrated +status: migrated --- # Getting started diff --git a/docs/guides/action-groups.md b/docs/guides/action-groups.md index 4cb35bbc5..354ae707d 100644 --- a/docs/guides/action-groups.md +++ b/docs/guides/action-groups.md @@ -1,7 +1,7 @@ --- title: Action group best practices redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/action-group-best-practices/ -layout: migrated +status: migrated --- # Action Group Best Practices diff --git a/docs/guides/cicd.md b/docs/guides/cicd.md index 552233923..985a5123f 100644 --- a/docs/guides/cicd.md +++ b/docs/guides/cicd.md @@ -1,7 +1,7 @@ --- title: How to use MFTF in CICD redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/cicd/ -layout: migrated +status: migrated --- # How to use MFTF in CICD diff --git a/docs/guides/git-vs-composer-install.md b/docs/guides/git-vs-composer-install.md index 2052cf32f..bf24ed219 100644 --- a/docs/guides/git-vs-composer-install.md +++ b/docs/guides/git-vs-composer-install.md @@ -1,7 +1,7 @@ --- title: Git vs Composer installation of Magento with MFTF redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/git-vs-composer-install/ -layout: migrated +status: migrated --- # Git vs Composer installation of Magento with MFTF diff --git a/docs/guides/selectors.md b/docs/guides/selectors.md index 9f2622b81..cdbfa5fcc 100644 --- a/docs/guides/selectors.md +++ b/docs/guides/selectors.md @@ -1,7 +1,7 @@ --- title: How to write good selectors redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/selectors/ -layout: migrated +status: migrated --- # How To write good selectors diff --git a/docs/guides/test-isolation.md b/docs/guides/test-isolation.md index 60c4dae47..64a04a152 100644 --- a/docs/guides/test-isolation.md +++ b/docs/guides/test-isolation.md @@ -1,7 +1,7 @@ --- title: Test isolation redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/test-isolation/ -layout: migrated +status: migrated --- # Test Isolation diff --git a/docs/guides/test-modularity.md b/docs/guides/test-modularity.md index 2e88b279a..e9a407c3b 100644 --- a/docs/guides/test-modularity.md +++ b/docs/guides/test-modularity.md @@ -1,7 +1,7 @@ --- title: Test modularity redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/test-modularity/ -layout: migrated +status: migrated --- # Test Modularity diff --git a/docs/guides/using-suites.md b/docs/guides/using-suites.md index 682c8490f..ea5f4c924 100644 --- a/docs/guides/using-suites.md +++ b/docs/guides/using-suites.md @@ -1,7 +1,7 @@ --- title: Using suites redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/using-suites/ -layout: migrated +status: migrated --- # Using suites diff --git a/docs/interactive-pause.md b/docs/interactive-pause.md index b32355653..19a8e5681 100644 --- a/docs/interactive-pause.md +++ b/docs/interactive-pause.md @@ -1,7 +1,7 @@ --- title: Interactive pause redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/interactive-pause/ -layout: migrated +status: migrated --- # Interactive Pause diff --git a/docs/introduction.md b/docs/introduction.md index 56dd39254..c92083afe 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -1,7 +1,7 @@ --- title: Introduction to the Magento Functional Testing Framework redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/ -layout: migrated +status: migrated --- # Introduction to the Magento Functional Testing Framework diff --git a/docs/merge_points/extend-action-groups.md b/docs/merge_points/extend-action-groups.md index 09ae46330..c8fefade4 100644 --- a/docs/merge_points/extend-action-groups.md +++ b/docs/merge_points/extend-action-groups.md @@ -1,7 +1,7 @@ --- title: Extend action groups redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/extend-action-groups/ -layout: migrated +status: migrated --- # Extend action groups diff --git a/docs/merge_points/extend-data.md b/docs/merge_points/extend-data.md index a17f32cf1..d2150fc61 100644 --- a/docs/merge_points/extend-data.md +++ b/docs/merge_points/extend-data.md @@ -1,7 +1,7 @@ --- title: Extend data entities redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/extend-data/ -layout: migrated +status: migrated --- # Extend data entities diff --git a/docs/merge_points/extend-tests.md b/docs/merge_points/extend-tests.md index b87ad35d8..90e2c8b95 100644 --- a/docs/merge_points/extend-tests.md +++ b/docs/merge_points/extend-tests.md @@ -1,7 +1,7 @@ --- title: Extend tests redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/extend-tests/ -layout: migrated +status: migrated --- # Extend tests diff --git a/docs/merge_points/introduction.md b/docs/merge_points/introduction.md index 2fb379a26..d0c75f784 100644 --- a/docs/merge_points/introduction.md +++ b/docs/merge_points/introduction.md @@ -1,7 +1,7 @@ --- title: Merge points for testing extensions in MFTF redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/ -layout: migrated +status: migrated --- # Merge Points for testing extensions in MFTF diff --git a/docs/merge_points/merge-action-groups.md b/docs/merge_points/merge-action-groups.md index 80b533559..b4e2c4273 100644 --- a/docs/merge_points/merge-action-groups.md +++ b/docs/merge_points/merge-action-groups.md @@ -1,7 +1,7 @@ --- title: Merge action groups redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/merge-action-groups/ -layout: migrated +status: migrated --- # Merge action groups diff --git a/docs/merge_points/merge-data.md b/docs/merge_points/merge-data.md index b392197c7..9bb64c692 100644 --- a/docs/merge_points/merge-data.md +++ b/docs/merge_points/merge-data.md @@ -1,7 +1,7 @@ --- title: Merge data redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/merge-data/ -layout: migrated +status: migrated --- # Merge data diff --git a/docs/merge_points/merge-pages.md b/docs/merge_points/merge-pages.md index 1d46383df..2c4248744 100644 --- a/docs/merge_points/merge-pages.md +++ b/docs/merge_points/merge-pages.md @@ -1,7 +1,7 @@ --- title: Merge pages redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/merge-pages/ -layout: migrated +status: migrated --- # Merge pages diff --git a/docs/merge_points/merge-sections.md b/docs/merge_points/merge-sections.md index fcd6a3726..3061eb265 100644 --- a/docs/merge_points/merge-sections.md +++ b/docs/merge_points/merge-sections.md @@ -1,7 +1,7 @@ --- title: Merge sections redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/merge-sections/ -layout: migrated +status: migrated --- # Merge sections diff --git a/docs/merge_points/merge-tests.md b/docs/merge_points/merge-tests.md index f30ef0cfd..6051d6808 100644 --- a/docs/merge_points/merge-tests.md +++ b/docs/merge_points/merge-tests.md @@ -1,7 +1,7 @@ --- title: Merge tests redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merge-points/merge-tests/ -layout: migrated +status: migrated --- # Merge tests diff --git a/docs/merging.md b/docs/merging.md index 7ee786ad1..01d6b6163 100644 --- a/docs/merging.md +++ b/docs/merging.md @@ -1,7 +1,7 @@ --- title: Merging redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/merging/ -layout: migrated +status: migrated --- # Merging diff --git a/docs/metadata.md b/docs/metadata.md index 17b466c11..2bae0c116 100644 --- a/docs/metadata.md +++ b/docs/metadata.md @@ -1,7 +1,7 @@ --- title: Metadata redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/metadata/ -layout: migrated +status: migrated --- # Metadata diff --git a/docs/mftf-tests-packaging.md b/docs/mftf-tests-packaging.md index e30b6aefc..961e1425c 100644 --- a/docs/mftf-tests-packaging.md +++ b/docs/mftf-tests-packaging.md @@ -1,7 +1,7 @@ --- title: MFTF functional test modules and packaging redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/mftf-tests-packaging/ -layout: migrated +status: migrated --- <style> diff --git a/docs/page.md b/docs/page.md index ddcfceb9d..89f50b634 100644 --- a/docs/page.md +++ b/docs/page.md @@ -1,7 +1,7 @@ --- title: Page structure redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/page/ -layout: migrated +status: migrated --- # Page structure diff --git a/docs/reporting.md b/docs/reporting.md index dd71be158..a70835309 100644 --- a/docs/reporting.md +++ b/docs/reporting.md @@ -1,7 +1,7 @@ --- title: Reporting redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/reporting/ -layout: migrated +status: migrated --- # Reporting diff --git a/docs/section.md b/docs/section.md index 8b1fb0106..7e8645d7e 100644 --- a/docs/section.md +++ b/docs/section.md @@ -1,7 +1,7 @@ --- title: Section structure redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/section/ -layout: migrated +status: migrated --- # Section structure diff --git a/docs/section/locator-functions.md b/docs/section/locator-functions.md index 190cc965c..8a9424aac 100644 --- a/docs/section/locator-functions.md +++ b/docs/section/locator-functions.md @@ -1,7 +1,7 @@ --- title: Locator functions redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/section/locator-functions/ -layout: migrated +status: migrated --- # Locator functions diff --git a/docs/section/parameterized-selectors.md b/docs/section/parameterized-selectors.md index 982ae9565..99c1f7c98 100644 --- a/docs/section/parameterized-selectors.md +++ b/docs/section/parameterized-selectors.md @@ -1,7 +1,7 @@ --- title: Parameterized selectors redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/section/parameterized-selectors/ -layout: migrated +status: migrated --- # Parameterized selectors diff --git a/docs/selectors.md b/docs/selectors.md index d9e34cde1..4a28bdb31 100644 --- a/docs/selectors.md +++ b/docs/selectors.md @@ -1,7 +1,7 @@ --- title: Selectors redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/selectors/ -layout: migrated +status: migrated --- ## Selectors diff --git a/docs/suite.md b/docs/suite.md index 74527edba..97f2c9603 100644 --- a/docs/suite.md +++ b/docs/suite.md @@ -1,7 +1,7 @@ --- title: Suites redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/suite/ -layout: migrated +status: migrated --- # Suites diff --git a/docs/test-prep.md b/docs/test-prep.md index c94f62a5f..8a54c3682 100644 --- a/docs/test-prep.md +++ b/docs/test-prep.md @@ -1,7 +1,7 @@ --- title: Preparing a test for MFTF redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/test-prep/ -layout: migrated +status: migrated --- # Preparing a test for MFTF diff --git a/docs/test.md b/docs/test.md index a47305d1f..f759432cd 100644 --- a/docs/test.md +++ b/docs/test.md @@ -1,7 +1,7 @@ --- title: Test redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/ -layout: migrated +status: migrated --- # Test diff --git a/docs/test/action-groups.md b/docs/test/action-groups.md index bd5b47288..0950b6cd8 100644 --- a/docs/test/action-groups.md +++ b/docs/test/action-groups.md @@ -1,7 +1,7 @@ --- title: Action groups redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/action-groups/ -layout: migrated +status: migrated --- # Action groups diff --git a/docs/test/actions.md b/docs/test/actions.md index 1dc25a112..3c63d504f 100644 --- a/docs/test/actions.md +++ b/docs/test/actions.md @@ -1,7 +1,7 @@ --- title: Test actions redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/actions/ -layout: migrated +status: migrated --- # Test actions diff --git a/docs/test/annotations.md b/docs/test/annotations.md index 213911981..c51e09923 100644 --- a/docs/test/annotations.md +++ b/docs/test/annotations.md @@ -1,7 +1,7 @@ --- title: Annotations redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/annotations/ -layout: migrated +status: migrated --- # Annotations diff --git a/docs/test/assertions.md b/docs/test/assertions.md index cafd52872..dedca2e74 100644 --- a/docs/test/assertions.md +++ b/docs/test/assertions.md @@ -1,7 +1,7 @@ --- title: Assertions redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test/assertions/ -layout: migrated +status: migrated --- # Assertions diff --git a/docs/tips-tricks.md b/docs/tips-tricks.md index 5b27511df..8ef00f888 100644 --- a/docs/tips-tricks.md +++ b/docs/tips-tricks.md @@ -1,7 +1,7 @@ --- title: Tips and tricks redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/test-writing/tips-tricks/ -layout: migrated +status: migrated --- # Tips and Tricks diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 409ad9584..cf27a049e 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -1,7 +1,7 @@ --- title: Troubleshooting redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/troubleshooting/ -layout: migrated +status: migrated --- # Troubleshooting diff --git a/docs/update.md b/docs/update.md index 28be390fa..311875b6d 100644 --- a/docs/update.md +++ b/docs/update.md @@ -1,7 +1,7 @@ --- title: Update the Magento Functional Testing Framework redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/update/ -layout: migrated +status: migrated --- # Update the Magento Functional Testing Framework diff --git a/docs/versioning.md b/docs/versioning.md index 80e89924c..ff76ab867 100644 --- a/docs/versioning.md +++ b/docs/versioning.md @@ -1,7 +1,7 @@ --- title: MFTF versioning schema redirect_to: https://developer.adobe.com/commerce/testing/functional-testing-framework/versioning/ -layout: migrated +status: migrated --- # MFTF versioning schema From 0ebf9e7537a49b5e598255f12afe6779aaced876 Mon Sep 17 00:00:00 2001 From: Dmitry Shevtsov <12731225+dshevtsov@users.noreply.github.com> Date: Thu, 15 Dec 2022 15:12:49 -0600 Subject: [PATCH 886/888] Update main.yml Disable checks for docs updates --- .github/workflows/main.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4a567c7c4..36ddf7855 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -3,7 +3,9 @@ name: CI -on: [pull_request] +on: + pull_request: + paths-ignore: docs/** jobs: unit-tests: From 771e594a090e94eae8fc9ce66aeecd07c73fef4a Mon Sep 17 00:00:00 2001 From: Dmitry Shevtsov <12731225+dshevtsov@users.noreply.github.com> Date: Thu, 15 Dec 2022 15:15:10 -0600 Subject: [PATCH 887/888] Update main.yml Fix syntax --- .github/workflows/main.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 36ddf7855..f54e1b395 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -5,7 +5,8 @@ name: CI on: pull_request: - paths-ignore: docs/** + paths-ignore: + - 'docs/**' jobs: unit-tests: From dd2b1a6ef1960f0bf6cda34dc60ce0c6ebe5cdb0 Mon Sep 17 00:00:00 2001 From: ImgBotApp <ImgBotHelp@gmail.com> Date: Tue, 21 May 2024 22:27:38 +0000 Subject: [PATCH 888/888] [ImgBot] Optimize images *Total -- 99.09kb -> 60.05kb (39.39%) /docs/img/page-dia.svg -- 7.05kb -> 3.78kb (46.39%) /docs/img/action-groups-dia.svg -- 12.82kb -> 7.48kb (41.7%) /docs/img/data-dia.svg -- 12.56kb -> 7.63kb (39.25%) /docs/img/test-dia.svg -- 30.08kb -> 18.34kb (39.02%) /docs/img/metadata-dia.svg -- 26.91kb -> 16.58kb (38.38%) /docs/img/section-dia.svg -- 9.67kb -> 6.25kb (35.39%) Signed-off-by: ImgBotApp <ImgBotHelp@gmail.com> --- docs/img/action-groups-dia.svg | 517 +------------- docs/img/data-dia.svg | 490 +------------ docs/img/metadata-dia.svg | 1051 +-------------------------- docs/img/page-dia.svg | 291 +------- docs/img/section-dia.svg | 297 +------- docs/img/test-dia.svg | 1229 +------------------------------- 6 files changed, 6 insertions(+), 3869 deletions(-) diff --git a/docs/img/action-groups-dia.svg b/docs/img/action-groups-dia.svg index 853420d54..9fbe68886 100644 --- a/docs/img/action-groups-dia.svg +++ b/docs/img/action-groups-dia.svg @@ -1,516 +1 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="643" - height="114" - version="1.1" - id="svg152" - sodipodi:docname="action-groups-dia.svg" - inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"> - <metadata - id="metadata158"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <defs - id="defs156" /> - <sodipodi:namedview - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1" - objecttolerance="10" - gridtolerance="10" - guidetolerance="10" - inkscape:pageopacity="0" - inkscape:pageshadow="2" - inkscape:window-width="1920" - inkscape:window-height="1017" - id="namedview154" - showgrid="false" - inkscape:zoom="1.2492586" - inkscape:cx="149.25073" - inkscape:cy="58.965954" - inkscape:window-x="3278" - inkscape:window-y="-8" - inkscape:window-maximized="1" - inkscape:current-layer="svg152" /> - <a - href="actions.html" - title="any actions" - id="a3851"> - <g - id="g242"> - <path - d="M404 25 L498 25 L504 31 L504 41 L498 47 L404 47 L398 41 L398 31 Z" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="path2" /> - <text - x="451" - y="36" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text4">actionTypeTags</text> - <line - x1="401" - y1="44" - x2="404" - y2="41" - style="stroke:rgb(0,0,0);stroke-width:2" - id="line6" /> - <path - d="M404 41 L406 43 L407 38 L402 39 L404 41 Z" - style="fill:rgb(0,0,0)" - id="path8" /> - <rect - x="499" - y="31" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect10" /> - <line - x1="501" - y1="36" - x2="507" - y2="36" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line12" /> - <line - x1="504" - y1="33" - x2="504" - y2="39" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line14" /> - </g> - </a> - <a - id="a3924" - href="#argument-tag" - title="zero or more <argument> elements"> - <g - id="g233"> - <rect - x="566" - y="80" - width="70" - height="22" - style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-dasharray:4, 1" - id="rect16" /> - <rect - x="563" - y="77" - width="70" - height="22" - style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-dasharray:4, 1" - id="rect18" /> - <text - x="598" - y="88" - style="font-weight:bold;font-size:10.66666698px;font-family:Arial;dominant-baseline:central;text-anchor:middle;fill:#000000" - id="text20">argument</text> - <text - x="623" - y="109" - style="font-size:9.59999943px;font-family:Arial;dominant-baseline:central;text-anchor:end;fill:#000000" - id="text22">0..∞</text> - </g> - </a> - <line - x1="543" - y1="88" - x2="563" - y2="88" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line24" /> - <a - id="a3914" - title="contains a sequence of"> - <g - id="g227"> - <path - d="M509 78 L532 78 L538 84 L538 92 L532 98 L509 98 L503 92 L503 84 Z" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="path26" /> - <line - x1="506" - y1="88" - x2="535" - y2="88" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line28" /> - <ellipse - cx="515" - cy="88" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse30" /> - <ellipse - cx="520" - cy="88" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse32" /> - <ellipse - cx="525" - cy="88" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse34" /> - <rect - x="533" - y="83" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect36" /> - <line - x1="535" - y1="88" - x2="541" - y2="88" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line38" /> - </g> - </a> - <line - x1="483" - y1="88" - x2="503" - y2="88" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line40" /> - <a - id="a3907" - href="#arguments-tag" - title="wrapping element <arguments>"> - <g - id="g218"> - <rect - x="398" - y="77" - width="80" - height="22" - style="fill:#ffffff;stroke:#000000;stroke-width:1" - id="rect42" /> - <text - x="438" - y="88" - style="font-weight:bold;font-size:10.66666698px;font-family:Arial;dominant-baseline:central;text-anchor:middle;fill:#000000" - id="text44">arguments</text> - <rect - x="473" - y="83" - width="10" - height="10" - style="fill:#ffffff;stroke:#000000;stroke-width:1" - id="rect46" /> - <line - x1="475" - y1="88" - x2="481" - y2="88" - style="stroke:#000000;stroke-width:1" - id="line48" /> - </g> - </a> - <line - x1="388" - y1="36" - x2="398" - y2="36" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line50" /> - <line - x1="388" - y1="88" - x2="398" - y2="88" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line52" /> - <line - x1="388" - y1="36" - x2="388" - y2="88" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line54" /> - <a - id="a3833" - title="optionally contains muiliple times one of the following nodes"> - <g - id="g212"> - <line - x1="378" - y1="62" - x2="388" - y2="62" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line56" /> - <path - d="M347 55 L370 55 L376 61 L376 69 L370 75 L347 75 L341 69 L341 61 Z" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="path58" /> - <path - d="M344 52 L367 52 L373 58 L373 66 L367 72 L344 72 L338 66 L338 58 Z" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="path60" /> - <line - x1="343" - y1="62" - x2="347" - y2="62" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line62" /> - <line - x1="347" - y1="62" - x2="351" - y2="58" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line64" /> - <line - x1="359" - y1="58" - x2="363" - y2="58" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line66" /> - <line - x1="359" - y1="62" - x2="367" - y2="62" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line68" /> - <line - x1="359" - y1="66" - x2="363" - y2="66" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line70" /> - <line - x1="363" - y1="58" - x2="363" - y2="66" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line72" /> - <ellipse - cx="355" - cy="58" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse74" /> - <ellipse - cx="355" - cy="62" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse76" /> - <ellipse - cx="355" - cy="66" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse78" /> - <text - x="368" - y="82" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - id="text80">0..∞</text> - <rect - x="368" - y="57" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect82" /> - <line - x1="370" - y1="62" - x2="376" - y2="62" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line84" /> - </g> - </a> - <line - x1="318" - y1="62" - x2="338" - y2="62" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line86" /> - <a - id="a82" - href="#actiongroup-tag" - title="one or more <actionGroup> elements"> - <g - id="g195"> - <rect - x="227" - y="54" - width="89" - height="22" - style="fill:#ffffff;stroke:#000000;stroke-width:1" - id="rect88" /> - <rect - x="224" - y="51" - width="89" - height="22" - style="fill:#ffffff;stroke:#000000;stroke-width:1" - id="rect90" /> - <text - x="268.5" - y="62" - style="font-weight:bold;font-size:10.66666698px;font-family:Arial;dominant-baseline:central;text-anchor:middle;fill:#000000" - id="text92">actionGroup</text> - <text - x="308" - y="83" - style="font-size:9.59999943px;font-family:Arial;dominant-baseline:central;text-anchor:end;fill:#000000" - id="text94">1..∞</text> - <rect - x="308" - y="57" - width="10" - height="10" - style="fill:#ffffff;stroke:#000000;stroke-width:1" - id="rect96" /> - <line - x1="310" - y1="62" - x2="316" - y2="62" - style="stroke:#000000;stroke-width:1" - id="line98" /> - </g> - </a> - <line - x1="204" - y1="62" - x2="224" - y2="62" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line100" /> - <line - x1="146.40559" - y1="62" - x2="166.40559" - y2="62" - style="stroke:#000000;stroke-width:1;stroke-linecap:round" - id="line126" /> - <a - id="a106" - title="Root element <actionGroups>" - href="#actiongroups-tag"> - <g - transform="translate(-10)" - id="g104"> - <line - x1="124.97701" - y1="62" - x2="146.40559" - y2="62" - style="stroke:#000000;stroke-width:1.03509831;stroke-linecap:round" - id="line142" /> - <rect - x="59.977016" - y="51" - width="95.357147" - height="22" - style="fill:#ffffff;stroke:#000000;stroke-width:1.03509831" - id="rect144" /> - <text - x="102.44111" - y="63.59021" - style="font-weight:bold;font-size:11.041049px;font-family:Arial;dominant-baseline:central;text-anchor:middle;fill:#000000;stroke-width:1.03509831" - id="text146" - transform="scale(1.0350984,0.96609173)">actionGroups</text> - <rect - x="147.83417" - y="57" - width="10.714286" - height="10" - style="fill:#ffffff;stroke:#000000;stroke-width:1.03509831" - id="rect148" /> - <line - x1="149.97702" - y1="62" - x2="156.40558" - y2="62" - style="stroke:#000000;stroke-width:1.03509831" - id="line150" /> - </g> - </a> - <a - id="a3823" - title="contains a sequence of"> - <g - id="g227-6" - transform="translate(-339.59441,-26)"> - <path - d="m 509,78 h 23 l 6,6 v 8 l -6,6 h -23 l -6,-6 v -8 z" - style="fill:#ffffff;stroke:#000000;stroke-width:1" - id="path26-0" - inkscape:connector-curvature="0" /> - <line - x1="506" - y1="88" - x2="535" - y2="88" - style="stroke:#000000;stroke-width:1" - id="line28-3" /> - <circle - cx="515" - cy="88" - id="ellipse30-8" - r="2" /> - <circle - cx="520" - cy="88" - id="ellipse32-3" - r="2" /> - <circle - cx="525" - cy="88" - id="ellipse34-4" - r="2" /> - <rect - x="533" - y="83" - width="10" - height="10" - style="fill:#ffffff;stroke:#000000;stroke-width:1" - id="rect36-0" /> - <line - x1="535" - y1="88" - x2="541" - y2="88" - style="stroke:#000000;stroke-width:1" - id="line38-2" /> - </g> - </a> -</svg> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="svg152" width="643" height="114" version="1.1"><metadata id="metadata158"/><a id="a3851" href="actions.html" title="any actions"><g id="g242"><path d="M404 25 L498 25 L504 31 L504 41 L498 47 L404 47 L398 41 L398 31 Z" style="fill:#fff;stroke:#000;stroke-width:1" id="path2"/><text x="451" y="36" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text4">actionTypeTags</text><line id="line6" x1="401" x2="404" y1="44" y2="41" style="stroke:#000;stroke-width:2"/><path d="M404 41 L406 43 L407 38 L402 39 L404 41 Z" style="fill:#000" id="path8"/><rect id="rect10" width="10" height="10" x="499" y="31" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line12" x1="501" x2="507" y1="36" y2="36" style="stroke:#000;stroke-width:1"/><line id="line14" x1="504" x2="504" y1="33" y2="39" style="stroke:#000;stroke-width:1"/></g></a><a id="a3924" href="#argument-tag" title="zero or more <argument> elements"><g id="g233"><rect id="rect16" width="70" height="22" x="566" y="80" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><rect id="rect18" width="70" height="22" x="563" y="77" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><text x="598" y="88" style="font-weight:700;font-size:10.66666698px;font-family:Arial;dominant-baseline:central;text-anchor:middle;fill:#000" id="text20">argument</text><text x="623" y="109" style="font-size:9.59999943px;font-family:Arial;dominant-baseline:central;text-anchor:end;fill:#000" id="text22">0..∞</text></g></a><line id="line24" x1="543" x2="563" y1="88" y2="88" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a3914" title="contains a sequence of"><g id="g227"><path d="M509 78 L532 78 L538 84 L538 92 L532 98 L509 98 L503 92 L503 84 Z" style="fill:#fff;stroke:#000;stroke-width:1" id="path26"/><line id="line28" x1="506" x2="535" y1="88" y2="88" style="stroke:#000;stroke-width:1"/><ellipse id="ellipse30" cx="515" cy="88" rx="2" ry="2"/><ellipse id="ellipse32" cx="520" cy="88" rx="2" ry="2"/><ellipse id="ellipse34" cx="525" cy="88" rx="2" ry="2"/><rect id="rect36" width="10" height="10" x="533" y="83" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line38" x1="535" x2="541" y1="88" y2="88" style="stroke:#000;stroke-width:1"/></g></a><line id="line40" x1="483" x2="503" y1="88" y2="88" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a3907" href="#arguments-tag" title="wrapping element <arguments>"><g id="g218"><rect id="rect42" width="80" height="22" x="398" y="77" style="fill:#fff;stroke:#000;stroke-width:1"/><text x="438" y="88" style="font-weight:700;font-size:10.66666698px;font-family:Arial;dominant-baseline:central;text-anchor:middle;fill:#000" id="text44">arguments</text><rect id="rect46" width="10" height="10" x="473" y="83" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line48" x1="475" x2="481" y1="88" y2="88" style="stroke:#000;stroke-width:1"/></g></a><line id="line50" x1="388" x2="398" y1="36" y2="36" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><line id="line52" x1="388" x2="398" y1="88" y2="88" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><line id="line54" x1="388" x2="388" y1="36" y2="88" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a3833" title="optionally contains muiliple times one of the following nodes"><g id="g212"><line id="line56" x1="378" x2="388" y1="62" y2="62" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><path d="M347 55 L370 55 L376 61 L376 69 L370 75 L347 75 L341 69 L341 61 Z" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1" id="path58"/><path d="M344 52 L367 52 L373 58 L373 66 L367 72 L344 72 L338 66 L338 58 Z" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1" id="path60"/><line id="line62" x1="343" x2="347" y1="62" y2="62" style="stroke:#000;stroke-width:1"/><line id="line64" x1="347" x2="351" y1="62" y2="58" style="stroke:#000;stroke-width:1"/><line id="line66" x1="359" x2="363" y1="58" y2="58" style="stroke:#000;stroke-width:1"/><line id="line68" x1="359" x2="367" y1="62" y2="62" style="stroke:#000;stroke-width:1"/><line id="line70" x1="359" x2="363" y1="66" y2="66" style="stroke:#000;stroke-width:1"/><line id="line72" x1="363" x2="363" y1="58" y2="66" style="stroke:#000;stroke-width:1"/><ellipse id="ellipse74" cx="355" cy="58" rx="2" ry="2"/><ellipse id="ellipse76" cx="355" cy="62" rx="2" ry="2"/><ellipse id="ellipse78" cx="355" cy="66" rx="2" ry="2"/><text x="368" y="82" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" id="text80">0..∞</text><rect id="rect82" width="10" height="10" x="368" y="57" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line84" x1="370" x2="376" y1="62" y2="62" style="stroke:#000;stroke-width:1"/></g></a><line id="line86" x1="318" x2="338" y1="62" y2="62" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a82" href="#actiongroup-tag" title="one or more <actionGroup> elements"><g id="g195"><rect id="rect88" width="89" height="22" x="227" y="54" style="fill:#fff;stroke:#000;stroke-width:1"/><rect id="rect90" width="89" height="22" x="224" y="51" style="fill:#fff;stroke:#000;stroke-width:1"/><text x="268.5" y="62" style="font-weight:700;font-size:10.66666698px;font-family:Arial;dominant-baseline:central;text-anchor:middle;fill:#000" id="text92">actionGroup</text><text x="308" y="83" style="font-size:9.59999943px;font-family:Arial;dominant-baseline:central;text-anchor:end;fill:#000" id="text94">1..∞</text><rect id="rect96" width="10" height="10" x="308" y="57" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line98" x1="310" x2="316" y1="62" y2="62" style="stroke:#000;stroke-width:1"/></g></a><line id="line100" x1="204" x2="224" y1="62" y2="62" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><line id="line126" x1="146.406" x2="166.406" y1="62" y2="62" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a106" href="#actiongroups-tag" title="Root element <actionGroups>"><g id="g104" transform="translate(-10)"><line id="line142" x1="124.977" x2="146.406" y1="62" y2="62" style="stroke:#000;stroke-width:1.03509831;stroke-linecap:round"/><rect id="rect144" width="95.357" height="22" x="59.977" y="51" style="fill:#fff;stroke:#000;stroke-width:1.03509831"/><text x="102.441" y="63.59" style="font-weight:700;font-size:11.041049px;font-family:Arial;dominant-baseline:central;text-anchor:middle;fill:#000;stroke-width:1.03509831" id="text146" transform="scale(1.0350984,0.96609173)">actionGroups</text><rect id="rect148" width="10.714" height="10" x="147.834" y="57" style="fill:#fff;stroke:#000;stroke-width:1.03509831"/><line id="line150" x1="149.977" x2="156.406" y1="62" y2="62" style="stroke:#000;stroke-width:1.03509831"/></g></a><a id="a3823" title="contains a sequence of"><g id="g227-6" transform="translate(-339.59441,-26)"><path d="m 509,78 h 23 l 6,6 v 8 l -6,6 h -23 l -6,-6 v -8 z" style="fill:#fff;stroke:#000;stroke-width:1" id="path26-0"/><line id="line28-3" x1="506" x2="535" y1="88" y2="88" style="stroke:#000;stroke-width:1"/><circle id="ellipse30-8" cx="515" cy="88" r="2"/><circle id="ellipse32-3" cx="520" cy="88" r="2"/><circle id="ellipse34-4" cx="525" cy="88" r="2"/><rect id="rect36-0" width="10" height="10" x="533" y="83" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line38-2" x1="535" x2="541" y1="88" y2="88" style="stroke:#000;stroke-width:1"/></g></a></svg> \ No newline at end of file diff --git a/docs/img/data-dia.svg b/docs/img/data-dia.svg index fbaf7d8ec..1b2c315e7 100644 --- a/docs/img/data-dia.svg +++ b/docs/img/data-dia.svg @@ -1,489 +1 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="496" - height="218" - version="1.1" - id="svg176" - sodipodi:docname="data-dia.svg" - inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"> - <metadata - id="metadata182"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <defs - id="defs180" /> - <sodipodi:namedview - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1" - objecttolerance="10" - gridtolerance="10" - guidetolerance="10" - inkscape:pageopacity="0" - inkscape:pageshadow="2" - inkscape:window-width="1920" - inkscape:window-height="1017" - id="namedview178" - showgrid="false" - inkscape:zoom="1.6195026" - inkscape:cx="156.50572" - inkscape:cy="97.15766" - inkscape:window-x="3278" - inkscape:window-y="-8" - inkscape:window-maximized="1" - inkscape:current-layer="svg176" /> - <text - x="338" - y="57" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - id="text8">0..∞</text> - <a - id="a3925" - href="#data-tag" - title="zero or more <data> elements"> - <g - id="g195"> - <rect - x="307" - y="28" - width="44" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect2" /> - <rect - x="304" - y="25" - width="44" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect4" /> - <text - x="326" - y="36" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text6">data</text> - </g> - </a> - <text - x="332" - y="109" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - id="text24">0..∞</text> - <a - id="a3935" - href="#var-tag" - title="zero or more <var> elements"> - <g - id="g204"> - <rect - x="307" - y="80" - width="38" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect18" /> - <rect - x="304" - y="77" - width="38" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect20" /> - <text - x="323" - y="88" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text22">var</text> - </g> - </a> - <text - x="389" - y="161" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - id="text40">0..∞</text> - <a - id="a3945" - href="#requiredentity-tag" - title="zero or more <requiredEntity> elements"> - <g - id="g213"> - <rect - x="307" - y="132" - width="95" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect34" /> - <rect - x="304" - y="129" - width="95" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect36" /> - <text - x="351.5" - y="140" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text38">requiredEntity</text> - </g> - </a> - <text - x="476" - y="213" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - id="text56">0..∞</text> - <a - id="a3963" - href="#item-tag" - title="zero or more <item> elements"> - <g - id="g229"> - <rect - x="445" - y="184" - width="44" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect50" /> - <rect - x="442" - y="181" - width="44" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect52" /> - <text - x="464" - y="192" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text54">item</text> - </g> - </a> - <line - x1="417.84494" - y1="192" - x2="442" - y2="192" - style="stroke:#000000;stroke-width:1.09897804;stroke-linecap:round" - id="line66" /> - <a - id="a3968" - title="a sequence of the following elements"> - <g - id="g3966"> - <path - inkscape:connector-curvature="0" - d="m 388,182 h 23 l 6,6 v 8 l -6,6 h -23 l -6,-6 v -8 z" - style="fill:#ffffff;stroke:#000000;stroke-width:1" - id="path68" /> - <line - x1="385" - y1="192" - x2="414" - y2="192" - style="stroke:#000000;stroke-width:1" - id="line70" /> - <circle - r="2" - cx="394" - cy="192" - id="ellipse72" /> - <circle - r="2" - cx="399" - cy="192" - id="ellipse74" /> - <circle - r="2" - cx="404" - cy="192" - id="ellipse76" /> - </g> - </a> - <line - x1="360.46375" - y1="192" - x2="382" - y2="192" - style="stroke:#000000;stroke-width:1.03769612;stroke-linecap:round" - id="line82" /> - <text - x="352" - y="213" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - id="text90">0..∞</text> - <a - id="a99" - href="#array-tag" - title="zero or more <array> elements"> - <g - id="g3864"> - <rect - x="307" - y="184" - width="53" - height="22" - style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-dasharray:4, 1" - id="rect84" /> - <rect - x="304" - y="181" - width="53" - height="22" - style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-dasharray:4, 1" - id="rect86" /> - <text - x="330.5" - y="192" - style="font-weight:bold;font-size:10.66666698px;font-family:Arial;dominant-baseline:central;text-anchor:middle;fill:#000000" - id="text88">array</text> - </g> - </a> - <line - x1="294" - y1="36" - x2="304" - y2="36" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line96" /> - <line - x1="294" - y1="88" - x2="304" - y2="88" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line98" /> - <line - x1="294" - y1="140" - x2="304" - y2="140" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line100" /> - <line - x1="294" - y1="192" - x2="304" - y2="192" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line102" /> - <line - x1="294" - y1="36" - x2="294" - y2="192" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line104" /> - <line - x1="282.8219" - y1="114" - x2="294" - y2="114" - style="stroke:#000000;stroke-width:1.05726469;stroke-linecap:round" - id="line106" /> - <a - id="a3984" - title="that contains one of the following nodes one or times"> - <g - id="g3959"> - <g - id="g3922"> - <path - inkscape:connector-curvature="0" - id="path110" - style="fill:#ffffff;stroke:#000000;stroke-width:1" - d="m 250,104 h 23 l 6,6 v 8 l -6,6 h -23 l -6,-6 v -8 z" /> - <path - id="path108" - style="fill:#ffffff;stroke:#000000;stroke-width:1" - d="m 253,107 h 23 l 6,6 v 8 l -6,6 h -23 l -6,-6 v -8 z" - inkscape:connector-curvature="0" /> - <line - id="line112" - style="stroke:#000000;stroke-width:1" - y2="114" - x2="253" - y1="114" - x1="249" /> - <line - id="line114" - style="stroke:#000000;stroke-width:1" - y2="110" - x2="257" - y1="114" - x1="253" /> - <line - id="line116" - style="stroke:#000000;stroke-width:1" - y2="110" - x2="269" - y1="110" - x1="265" /> - <line - id="line118" - style="stroke:#000000;stroke-width:1" - y2="114" - x2="273" - y1="114" - x1="265" /> - <line - id="line120" - style="stroke:#000000;stroke-width:1" - y2="118" - x2="269" - y1="118" - x1="265" /> - <line - id="line122" - style="stroke:#000000;stroke-width:1" - y2="118" - x2="269" - y1="110" - x1="269" /> - <circle - id="ellipse124" - cy="110" - cx="261" - r="2" /> - <circle - id="ellipse126" - cy="114" - cx="261" - r="2" /> - <circle - id="ellipse128" - cy="118" - cx="261" - r="2" /> - <text - id="text130" - style="font-size:9.59999943px;font-family:Arial;dominant-baseline:central;text-anchor:end;fill:#000000" - y="134" - x="274">1..∞</text> - </g> - </g> - </a> - <line - x1="222.68196" - y1="114" - x2="244" - y2="114" - style="stroke:#000000;stroke-width:1.03242517;stroke-linecap:round" - id="line136" /> - <rect - x="167" - y="106" - width="55" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect138" /> - <a - id="a231" - href="#entity-tag" - title="zero or more <entity> elements"> - <g - id="g186"> - <rect - x="164" - y="103" - width="55" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect140" /> - <text - x="191.5" - y="114" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text142">entity</text> - </g> - </a> - <text - x="214" - y="135" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - id="text144">0..∞</text> - <line - x1="136" - y1="114" - x2="164" - y2="114" - style="stroke:#000000;stroke-width:1.18321598;stroke-linecap:round" - id="line150" /> - <a - id="a3976" - title="that contains a sequence of"> - <g - id="g3944"> - <path - d="m 110,104 h 23 l 6,6 v 8 l -6,6 h -23 l -6,-6 v -8 z" - style="fill:#ffffff;stroke:#000000;stroke-width:1" - id="path152" - inkscape:connector-curvature="0" /> - <line - x1="107" - y1="114" - x2="136" - y2="114" - style="stroke:#000000;stroke-width:1" - id="line154" /> - <circle - cx="116" - cy="114" - id="ellipse156" - r="2" /> - <circle - cx="121" - cy="114" - id="ellipse158" - r="2" /> - <circle - cx="126" - cy="114" - id="ellipse160" - r="2" /> - </g> - </a> - <line - x1="79.899483" - y1="114" - x2="104" - y2="114" - style="stroke:#000000;stroke-width:1.09773672;stroke-linecap:round" - id="line166" /> - <a - id="a104" - title="Root element <entities>" - href="#entities-tag"> - <g - id="g102"> - <rect - x="20" - y="103" - width="59" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect168" /> - <text - x="49.5" - y="114" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text170">entities</text> - </g> - </a> -</svg> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="svg176" width="496" height="218" version="1.1"><metadata id="metadata182"/><text x="338" y="57" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" id="text8">0..∞</text><a id="a3925" href="#data-tag" title="zero or more <data> elements"><g id="g195"><rect id="rect2" width="44" height="22" x="307" y="28" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><rect id="rect4" width="44" height="22" x="304" y="25" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><text x="326" y="36" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text6">data</text></g></a><text x="332" y="109" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" id="text24">0..∞</text><a id="a3935" href="#var-tag" title="zero or more <var> elements"><g id="g204"><rect id="rect18" width="38" height="22" x="307" y="80" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><rect id="rect20" width="38" height="22" x="304" y="77" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><text x="323" y="88" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text22">var</text></g></a><text x="389" y="161" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" id="text40">0..∞</text><a id="a3945" href="#requiredentity-tag" title="zero or more <requiredEntity> elements"><g id="g213"><rect id="rect34" width="95" height="22" x="307" y="132" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><rect id="rect36" width="95" height="22" x="304" y="129" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><text x="351.5" y="140" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text38">requiredEntity</text></g></a><text x="476" y="213" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" id="text56">0..∞</text><a id="a3963" href="#item-tag" title="zero or more <item> elements"><g id="g229"><rect id="rect50" width="44" height="22" x="445" y="184" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><rect id="rect52" width="44" height="22" x="442" y="181" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><text x="464" y="192" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text54">item</text></g></a><line id="line66" x1="417.845" x2="442" y1="192" y2="192" style="stroke:#000;stroke-width:1.09897804;stroke-linecap:round"/><a id="a3968" title="a sequence of the following elements"><g id="g3966"><path d="m 388,182 h 23 l 6,6 v 8 l -6,6 h -23 l -6,-6 v -8 z" style="fill:#fff;stroke:#000;stroke-width:1" id="path68"/><line id="line70" x1="385" x2="414" y1="192" y2="192" style="stroke:#000;stroke-width:1"/><circle id="ellipse72" cx="394" cy="192" r="2"/><circle id="ellipse74" cx="399" cy="192" r="2"/><circle id="ellipse76" cx="404" cy="192" r="2"/></g></a><line id="line82" x1="360.464" x2="382" y1="192" y2="192" style="stroke:#000;stroke-width:1.03769612;stroke-linecap:round"/><text x="352" y="213" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" id="text90">0..∞</text><a id="a99" href="#array-tag" title="zero or more <array> elements"><g id="g3864"><rect id="rect84" width="53" height="22" x="307" y="184" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><rect id="rect86" width="53" height="22" x="304" y="181" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><text x="330.5" y="192" style="font-weight:700;font-size:10.66666698px;font-family:Arial;dominant-baseline:central;text-anchor:middle;fill:#000" id="text88">array</text></g></a><line id="line96" x1="294" x2="304" y1="36" y2="36" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><line id="line98" x1="294" x2="304" y1="88" y2="88" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><line id="line100" x1="294" x2="304" y1="140" y2="140" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><line id="line102" x1="294" x2="304" y1="192" y2="192" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><line id="line104" x1="294" x2="294" y1="36" y2="192" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><line id="line106" x1="282.822" x2="294" y1="114" y2="114" style="stroke:#000;stroke-width:1.05726469;stroke-linecap:round"/><a id="a3984" title="that contains one of the following nodes one or times"><g id="g3959"><g id="g3922"><path id="path110" style="fill:#fff;stroke:#000;stroke-width:1" d="m 250,104 h 23 l 6,6 v 8 l -6,6 h -23 l -6,-6 v -8 z"/><path id="path108" style="fill:#fff;stroke:#000;stroke-width:1" d="m 253,107 h 23 l 6,6 v 8 l -6,6 h -23 l -6,-6 v -8 z"/><line id="line112" style="stroke:#000;stroke-width:1" x1="249" x2="253" y1="114" y2="114"/><line id="line114" style="stroke:#000;stroke-width:1" x1="253" x2="257" y1="114" y2="110"/><line id="line116" style="stroke:#000;stroke-width:1" x1="265" x2="269" y1="110" y2="110"/><line id="line118" style="stroke:#000;stroke-width:1" x1="265" x2="273" y1="114" y2="114"/><line id="line120" style="stroke:#000;stroke-width:1" x1="265" x2="269" y1="118" y2="118"/><line id="line122" style="stroke:#000;stroke-width:1" x1="269" x2="269" y1="110" y2="118"/><circle id="ellipse124" cx="261" cy="110" r="2"/><circle id="ellipse126" cx="261" cy="114" r="2"/><circle id="ellipse128" cx="261" cy="118" r="2"/><text id="text130" style="font-size:9.59999943px;font-family:Arial;dominant-baseline:central;text-anchor:end;fill:#000" x="274" y="134">1..∞</text></g></g></a><line id="line136" x1="222.682" x2="244" y1="114" y2="114" style="stroke:#000;stroke-width:1.03242517;stroke-linecap:round"/><rect id="rect138" width="55" height="22" x="167" y="106" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><a id="a231" href="#entity-tag" title="zero or more <entity> elements"><g id="g186"><rect id="rect140" width="55" height="22" x="164" y="103" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><text x="191.5" y="114" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text142">entity</text></g></a><text x="214" y="135" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" id="text144">0..∞</text><line id="line150" x1="136" x2="164" y1="114" y2="114" style="stroke:#000;stroke-width:1.18321598;stroke-linecap:round"/><a id="a3976" title="that contains a sequence of"><g id="g3944"><path d="m 110,104 h 23 l 6,6 v 8 l -6,6 h -23 l -6,-6 v -8 z" style="fill:#fff;stroke:#000;stroke-width:1" id="path152"/><line id="line154" x1="107" x2="136" y1="114" y2="114" style="stroke:#000;stroke-width:1"/><circle id="ellipse156" cx="116" cy="114" r="2"/><circle id="ellipse158" cx="121" cy="114" r="2"/><circle id="ellipse160" cx="126" cy="114" r="2"/></g></a><line id="line166" x1="79.899" x2="104" y1="114" y2="114" style="stroke:#000;stroke-width:1.09773672;stroke-linecap:round"/><a id="a104" href="#entities-tag" title="Root element <entities>"><g id="g102"><rect id="rect168" width="59" height="22" x="20" y="103" style="fill:#fff;stroke:#000;stroke-width:1"/><text x="49.5" y="114" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text170">entities</text></g></a></svg> \ No newline at end of file diff --git a/docs/img/metadata-dia.svg b/docs/img/metadata-dia.svg index 0ce0fc27a..9e898be3b 100644 --- a/docs/img/metadata-dia.svg +++ b/docs/img/metadata-dia.svg @@ -1,1050 +1 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="561" - height="478" - version="1.1" - id="svg318" - sodipodi:docname="metadata-dia.svg" - inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"> - <metadata - id="metadata324"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <defs - id="defs322" /> - <sodipodi:namedview - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1" - objecttolerance="10" - gridtolerance="10" - guidetolerance="10" - inkscape:pageopacity="0" - inkscape:pageshadow="2" - inkscape:window-width="1920" - inkscape:window-height="1017" - id="namedview320" - showgrid="false" - inkscape:zoom="1.3964619" - inkscape:cx="235.1642" - inkscape:cy="256.75664" - inkscape:window-x="3278" - inkscape:window-y="-8" - inkscape:window-maximized="1" - inkscape:current-layer="svg318" /> - <a - id="a4301" - href="#field-tag" - title="zero or more <field> elements"> - <g - id="g417"> - <rect - x="491" - y="28" - width="44" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect2" /> - <rect - x="488" - y="25" - width="44" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect4" /> - <text - x="510" - y="36" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text6">field</text> - <text - x="522" - y="57" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - id="text8">0..∞</text> - </g> - </a> - <a - id="a4308" - title="zero or more <array> elements" - href="#array-tag"> - <g - id="g442"> - <rect - x="491" - y="80" - width="53" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect18" /> - <rect - x="488" - y="77" - width="53" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect20" /> - <text - x="514.5" - y="88" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text22">array</text> - <text - x="536" - y="109" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - id="text24">0..∞</text> - <rect - x="536" - y="83" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect26" /> - <line - x1="538" - y1="88" - x2="544" - y2="88" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line28" /> - <line - x1="541" - y1="85" - x2="541" - y2="91" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line30" /> - </g> - </a> - <line - x1="478" - y1="36" - x2="488" - y2="36" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line46" /> - <line - x1="478" - y1="88" - x2="488" - y2="88" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line48" /> - <a - id="a4318" - href="#object-tag" - title="zero or more <object> elements"> - <g - id="g452"> - <rect - x="491" - y="132" - width="58" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect32" /> - <rect - x="488" - y="129" - width="58" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect34" /> - <text - x="517" - y="140" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text36">object</text> - <text - x="541" - y="161" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - id="text38">0..∞</text> - <rect - x="541" - y="135" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect40" /> - <line - x1="543" - y1="140" - x2="549" - y2="140" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line42" /> - <line - x1="546" - y1="137" - x2="546" - y2="143" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line44" /> - <line - x1="478" - y1="140" - x2="488" - y2="140" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line50" /> - </g> - </a> - <line - x1="478" - y1="36" - x2="478" - y2="140" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line52" /> - <line - x1="468" - y1="88" - x2="478" - y2="88" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line54" /> - <a - id="a4284" - title="that may contain zero or more times one of the following nodes"> - <g - id="g433"> - <path - d="M437 81 L460 81 L466 87 L466 95 L460 101 L437 101 L431 95 L431 87 Z" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="path56" /> - <path - d="M434 78 L457 78 L463 84 L463 92 L457 98 L434 98 L428 92 L428 84 Z" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="path58" /> - <line - x1="433" - y1="88" - x2="437" - y2="88" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line60" /> - <line - x1="437" - y1="88" - x2="441" - y2="84" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line62" /> - <line - x1="449" - y1="84" - x2="453" - y2="84" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line64" /> - <line - x1="449" - y1="88" - x2="457" - y2="88" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line66" /> - <line - x1="449" - y1="92" - x2="453" - y2="92" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line68" /> - <line - x1="453" - y1="84" - x2="453" - y2="92" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line70" /> - <ellipse - cx="445" - cy="84" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse72" /> - <ellipse - cx="445" - cy="88" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse74" /> - <ellipse - cx="445" - cy="92" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse76" /> - <text - x="458" - y="108" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - id="text78">0..∞</text> - <rect - x="458" - y="83" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect80" /> - <line - x1="460" - y1="88" - x2="466" - y2="88" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line82" /> - </g> - </a> - <line - x1="408" - y1="88" - x2="428" - y2="88" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line84" /> - <a - id="a4227" - title="zero or more <field> elements" - href="#field-tag"> - <g - id="g387"> - <rect - x="348" - y="184" - width="44" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect98" /> - <rect - x="345" - y="181" - width="44" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect100" /> - <text - x="367" - y="192" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text102">field</text> - <text - x="379" - y="213" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - id="text104">0..∞</text> - </g> - </a> - <a - id="a4262" - title="zero or one <value> element" - href="#value-tag"> - <g - id="g466"> - <rect - x="483" - y="285" - width="49" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect128" /> - <text - x="507.5" - y="296" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text130">value</text> - </g> - </a> - <a - id="a4329" - title="zero or more <object> elements" - href="#object-tag"> - <g - id="g462"> - <rect - x="486" - y="236" - width="58" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect114" /> - <rect - x="483" - y="233" - width="58" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect116" /> - <text - x="512" - y="244" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text118">object</text> - <text - x="536" - y="265" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - id="text120">0..∞</text> - <rect - x="536" - y="239" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect122" /> - <line - x1="538" - y1="244" - x2="544" - y2="244" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line124" /> - <line - x1="541" - y1="241" - x2="541" - y2="247" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line126" /> - <line - x1="473" - y1="244" - x2="483" - y2="244" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line140" /> - </g> - </a> - <line - x1="473" - y1="296" - x2="483" - y2="296" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line142" /> - <line - x1="473" - y1="244" - x2="473" - y2="296" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line144" /> - <line - x1="463" - y1="270" - x2="473" - y2="270" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line146" /> - <a - id="a4267" - title="that may contain zero or more times one of the following nodes"> - <g - id="g482"> - <path - d="M432 263 L455 263 L461 269 L461 277 L455 283 L432 283 L426 277 L426 269 Z" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="path148" /> - <path - d="M429 260 L452 260 L458 266 L458 274 L452 280 L429 280 L423 274 L423 266 Z" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="path150" /> - <line - x1="428" - y1="270" - x2="432" - y2="270" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line152" /> - <line - x1="432" - y1="270" - x2="436" - y2="266" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line154" /> - <line - x1="444" - y1="266" - x2="448" - y2="266" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line156" /> - <line - x1="444" - y1="270" - x2="452" - y2="270" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line158" /> - <line - x1="444" - y1="274" - x2="448" - y2="274" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line160" /> - <line - x1="448" - y1="266" - x2="448" - y2="274" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line162" /> - <ellipse - cx="440" - cy="266" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse164" /> - <ellipse - cx="440" - cy="270" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse166" /> - <ellipse - cx="440" - cy="274" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse168" /> - <text - x="453" - y="290" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - id="text170">0..∞</text> - <rect - x="453" - y="265" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect172" /> - <line - x1="455" - y1="270" - x2="461" - y2="270" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line174" /> - </g> - </a> - <line - x1="403" - y1="270" - x2="423" - y2="270" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line176" /> - <a - id="a4234" - title="zero or more <array> elements" - href="#array-tag"> - <g - id="g395"> - <rect - x="348" - y="262" - width="53" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect178" /> - <rect - x="345" - y="259" - width="53" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect180" /> - <text - x="371.5" - y="270" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text182">array</text> - <text - x="393" - y="291" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - id="text184">0..∞</text> - <rect - x="393" - y="265" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect186" /> - <line - x1="395" - y1="270" - x2="401" - y2="270" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line188" /> - </g> - </a> - <a - id="a4243" - href="#header-tag" - title="zero or more <header> elements"> - <g - id="g400"> - <rect - x="348" - y="340" - width="57" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect190" /> - <rect - x="345" - y="337" - width="57" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect192" /> - <text - x="373.5" - y="348" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text194">header</text> - </g> - </a> - <text - x="392" - y="369" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - id="text196">0..∞</text> - <a - id="a4249" - title="zero or more <param> elements" - href="#param-tag"> - <g - id="g406"> - <rect - x="348" - y="392" - width="54" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect206" /> - <rect - x="345" - y="389" - width="54" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect208" /> - <text - x="372" - y="400" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text210">param</text> - <text - x="389" - y="421" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - id="text212">0..∞</text> - </g> - </a> - <a - id="a4216" - href="#object-tag" - title="zero or more <object> elements"> - <g - id="g381"> - <g - id="g346"> - <rect - id="rect86" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - height="22" - width="58" - y="80" - x="348" /> - <rect - id="rect88" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - height="22" - width="58" - y="77" - x="345" /> - <text - id="text90" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - y="88" - x="374">object</text> - <text - id="text92" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - y="109" - x="398">0..∞</text> - <rect - id="rect94" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - height="10" - width="10" - y="83" - x="398" /> - <line - id="line96" - style="stroke:rgb(0,0,0);stroke-width:1" - y2="88" - x2="406" - y1="88" - x1="400" /> - </g> - <line - x1="335" - y1="88" - x2="345" - y2="88" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line234" /> - </g> - </a> - <line - x1="335" - y1="192" - x2="345" - y2="192" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line236" /> - <line - x1="335" - y1="270" - x2="345" - y2="270" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line238" /> - <line - x1="335" - y1="348" - x2="345" - y2="348" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line240" /> - <line - x1="335" - y1="400" - x2="345" - y2="400" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line242" /> - <a - id="a4256" - title="one <contentType> element" - href="#contentType-tag"> - <g - id="g411"> - <rect - x="345" - y="441" - width="84" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect222" /> - <text - x="387" - y="452" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text224">contentType</text> - <line - x1="335" - y1="452" - x2="345" - y2="452" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line244" /> - </g> - </a> - <line - x1="335" - y1="88" - x2="335" - y2="452" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line246" /> - <line - x1="325" - y1="244" - x2="335" - y2="244" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line248" /> - <a - id="a4199" - title="that may contain zero or more times one of the following nodes"> - <g - id="g371"> - <path - d="M294 237 L317 237 L323 243 L323 251 L317 257 L294 257 L288 251 L288 243 Z" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="path250" /> - <path - d="M291 234 L314 234 L320 240 L320 248 L314 254 L291 254 L285 248 L285 240 Z" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="path252" /> - <line - x1="290" - y1="244" - x2="294" - y2="244" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line254" /> - <line - x1="294" - y1="244" - x2="298" - y2="240" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line256" /> - <line - x1="306" - y1="240" - x2="310" - y2="240" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line258" /> - <line - x1="306" - y1="244" - x2="314" - y2="244" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line260" /> - <line - x1="306" - y1="248" - x2="310" - y2="248" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line262" /> - <line - x1="310" - y1="240" - x2="310" - y2="248" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line264" /> - <ellipse - cx="302" - cy="240" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse266" /> - <ellipse - cx="302" - cy="244" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse268" /> - <ellipse - cx="302" - cy="248" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse270" /> - <text - x="315" - y="264" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - id="text272">0..∞</text> - <rect - x="315" - y="239" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect274" /> - <line - x1="317" - y1="244" - x2="323" - y2="244" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line276" /> - </g> - </a> - <line - x1="265" - y1="244" - x2="285" - y2="244" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line278" /> - <a - id="a4190" - title="zero or more <operation> elements" - href="#operation-tag"> - <g - id="g338"> - <rect - x="188" - y="236" - width="75" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect280" /> - <rect - x="185" - y="233" - width="75" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect282" /> - <text - x="222.5" - y="244" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text284">operation</text> - <text - x="255" - y="265" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - id="text286">0..∞</text> - <rect - x="255" - y="239" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect288" /> - <line - x1="257" - y1="244" - x2="263" - y2="244" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line290" /> - </g> - </a> - <line - x1="165" - y1="244" - x2="185" - y2="244" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line292" /> - <a - id="a4180" - title="that contains a sequence of"> - <g - id="g355"> - <path - d="M131 234 L154 234 L160 240 L160 248 L154 254 L131 254 L125 248 L125 240 Z" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="path294" /> - <line - x1="128" - y1="244" - x2="157" - y2="244" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line296" /> - <ellipse - cx="137" - cy="244" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse298" /> - <ellipse - cx="142" - cy="244" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse300" /> - <ellipse - cx="147" - cy="244" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse302" /> - <rect - x="155" - y="239" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect304" /> - <line - x1="157" - y1="244" - x2="163" - y2="244" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line306" /> - </g> - </a> - <line - x1="105" - y1="244" - x2="125" - y2="244" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line308" /> - <a - id="a484" - href="#operations-tag" - xlink:arcrole="The <operations> element"> - <g - id="g330"> - <rect - x="20" - y="233" - width="80" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect310" /> - <text - x="60" - y="244" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text312">operations</text> - <rect - x="95" - y="239" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect314" /> - <line - x1="97" - y1="244" - x2="103" - y2="244" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line316" /> - </g> - </a> -</svg> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="svg318" width="561" height="478" version="1.1"><metadata id="metadata324"/><a id="a4301" href="#field-tag" title="zero or more <field> elements"><g id="g417"><rect id="rect2" width="44" height="22" x="491" y="28" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><rect id="rect4" width="44" height="22" x="488" y="25" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><text x="510" y="36" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text6">field</text><text x="522" y="57" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" id="text8">0..∞</text></g></a><a id="a4308" href="#array-tag" title="zero or more <array> elements"><g id="g442"><rect id="rect18" width="53" height="22" x="491" y="80" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><rect id="rect20" width="53" height="22" x="488" y="77" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><text x="514.5" y="88" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text22">array</text><text x="536" y="109" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" id="text24">0..∞</text><rect id="rect26" width="10" height="10" x="536" y="83" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line28" x1="538" x2="544" y1="88" y2="88" style="stroke:#000;stroke-width:1"/><line id="line30" x1="541" x2="541" y1="85" y2="91" style="stroke:#000;stroke-width:1"/></g></a><line id="line46" x1="478" x2="488" y1="36" y2="36" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><line id="line48" x1="478" x2="488" y1="88" y2="88" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a4318" href="#object-tag" title="zero or more <object> elements"><g id="g452"><rect id="rect32" width="58" height="22" x="491" y="132" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><rect id="rect34" width="58" height="22" x="488" y="129" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><text x="517" y="140" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text36">object</text><text x="541" y="161" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" id="text38">0..∞</text><rect id="rect40" width="10" height="10" x="541" y="135" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line42" x1="543" x2="549" y1="140" y2="140" style="stroke:#000;stroke-width:1"/><line id="line44" x1="546" x2="546" y1="137" y2="143" style="stroke:#000;stroke-width:1"/><line id="line50" x1="478" x2="488" y1="140" y2="140" style="stroke:#000;stroke-width:1;stroke-linecap:round"/></g></a><line id="line52" x1="478" x2="478" y1="36" y2="140" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><line id="line54" x1="468" x2="478" y1="88" y2="88" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a4284" title="that may contain zero or more times one of the following nodes"><g id="g433"><path d="M437 81 L460 81 L466 87 L466 95 L460 101 L437 101 L431 95 L431 87 Z" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1" id="path56"/><path d="M434 78 L457 78 L463 84 L463 92 L457 98 L434 98 L428 92 L428 84 Z" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1" id="path58"/><line id="line60" x1="433" x2="437" y1="88" y2="88" style="stroke:#000;stroke-width:1"/><line id="line62" x1="437" x2="441" y1="88" y2="84" style="stroke:#000;stroke-width:1"/><line id="line64" x1="449" x2="453" y1="84" y2="84" style="stroke:#000;stroke-width:1"/><line id="line66" x1="449" x2="457" y1="88" y2="88" style="stroke:#000;stroke-width:1"/><line id="line68" x1="449" x2="453" y1="92" y2="92" style="stroke:#000;stroke-width:1"/><line id="line70" x1="453" x2="453" y1="84" y2="92" style="stroke:#000;stroke-width:1"/><ellipse id="ellipse72" cx="445" cy="84" rx="2" ry="2"/><ellipse id="ellipse74" cx="445" cy="88" rx="2" ry="2"/><ellipse id="ellipse76" cx="445" cy="92" rx="2" ry="2"/><text x="458" y="108" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" id="text78">0..∞</text><rect id="rect80" width="10" height="10" x="458" y="83" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line82" x1="460" x2="466" y1="88" y2="88" style="stroke:#000;stroke-width:1"/></g></a><line id="line84" x1="408" x2="428" y1="88" y2="88" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a4227" href="#field-tag" title="zero or more <field> elements"><g id="g387"><rect id="rect98" width="44" height="22" x="348" y="184" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><rect id="rect100" width="44" height="22" x="345" y="181" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><text x="367" y="192" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text102">field</text><text x="379" y="213" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" id="text104">0..∞</text></g></a><a id="a4262" href="#value-tag" title="zero or one <value> element"><g id="g466"><rect id="rect128" width="49" height="22" x="483" y="285" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><text x="507.5" y="296" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text130">value</text></g></a><a id="a4329" href="#object-tag" title="zero or more <object> elements"><g id="g462"><rect id="rect114" width="58" height="22" x="486" y="236" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><rect id="rect116" width="58" height="22" x="483" y="233" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><text x="512" y="244" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text118">object</text><text x="536" y="265" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" id="text120">0..∞</text><rect id="rect122" width="10" height="10" x="536" y="239" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line124" x1="538" x2="544" y1="244" y2="244" style="stroke:#000;stroke-width:1"/><line id="line126" x1="541" x2="541" y1="241" y2="247" style="stroke:#000;stroke-width:1"/><line id="line140" x1="473" x2="483" y1="244" y2="244" style="stroke:#000;stroke-width:1;stroke-linecap:round"/></g></a><line id="line142" x1="473" x2="483" y1="296" y2="296" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><line id="line144" x1="473" x2="473" y1="244" y2="296" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><line id="line146" x1="463" x2="473" y1="270" y2="270" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a4267" title="that may contain zero or more times one of the following nodes"><g id="g482"><path d="M432 263 L455 263 L461 269 L461 277 L455 283 L432 283 L426 277 L426 269 Z" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1" id="path148"/><path d="M429 260 L452 260 L458 266 L458 274 L452 280 L429 280 L423 274 L423 266 Z" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1" id="path150"/><line id="line152" x1="428" x2="432" y1="270" y2="270" style="stroke:#000;stroke-width:1"/><line id="line154" x1="432" x2="436" y1="270" y2="266" style="stroke:#000;stroke-width:1"/><line id="line156" x1="444" x2="448" y1="266" y2="266" style="stroke:#000;stroke-width:1"/><line id="line158" x1="444" x2="452" y1="270" y2="270" style="stroke:#000;stroke-width:1"/><line id="line160" x1="444" x2="448" y1="274" y2="274" style="stroke:#000;stroke-width:1"/><line id="line162" x1="448" x2="448" y1="266" y2="274" style="stroke:#000;stroke-width:1"/><ellipse id="ellipse164" cx="440" cy="266" rx="2" ry="2"/><ellipse id="ellipse166" cx="440" cy="270" rx="2" ry="2"/><ellipse id="ellipse168" cx="440" cy="274" rx="2" ry="2"/><text x="453" y="290" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" id="text170">0..∞</text><rect id="rect172" width="10" height="10" x="453" y="265" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line174" x1="455" x2="461" y1="270" y2="270" style="stroke:#000;stroke-width:1"/></g></a><line id="line176" x1="403" x2="423" y1="270" y2="270" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a4234" href="#array-tag" title="zero or more <array> elements"><g id="g395"><rect id="rect178" width="53" height="22" x="348" y="262" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><rect id="rect180" width="53" height="22" x="345" y="259" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><text x="371.5" y="270" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text182">array</text><text x="393" y="291" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" id="text184">0..∞</text><rect id="rect186" width="10" height="10" x="393" y="265" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line188" x1="395" x2="401" y1="270" y2="270" style="stroke:#000;stroke-width:1"/></g></a><a id="a4243" href="#header-tag" title="zero or more <header> elements"><g id="g400"><rect id="rect190" width="57" height="22" x="348" y="340" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><rect id="rect192" width="57" height="22" x="345" y="337" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><text x="373.5" y="348" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text194">header</text></g></a><text x="392" y="369" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" id="text196">0..∞</text><a id="a4249" href="#param-tag" title="zero or more <param> elements"><g id="g406"><rect id="rect206" width="54" height="22" x="348" y="392" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><rect id="rect208" width="54" height="22" x="345" y="389" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><text x="372" y="400" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text210">param</text><text x="389" y="421" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" id="text212">0..∞</text></g></a><a id="a4216" href="#object-tag" title="zero or more <object> elements"><g id="g381"><g id="g346"><rect id="rect86" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1" width="58" height="22" x="348" y="80"/><rect id="rect88" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1" width="58" height="22" x="345" y="77"/><text id="text90" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" x="374" y="88">object</text><text id="text92" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" x="398" y="109">0..∞</text><rect id="rect94" style="fill:#fff;stroke:#000;stroke-width:1" width="10" height="10" x="398" y="83"/><line id="line96" style="stroke:#000;stroke-width:1" x1="400" x2="406" y1="88" y2="88"/></g><line id="line234" x1="335" x2="345" y1="88" y2="88" style="stroke:#000;stroke-width:1;stroke-linecap:round"/></g></a><line id="line236" x1="335" x2="345" y1="192" y2="192" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><line id="line238" x1="335" x2="345" y1="270" y2="270" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><line id="line240" x1="335" x2="345" y1="348" y2="348" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><line id="line242" x1="335" x2="345" y1="400" y2="400" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a4256" href="#contentType-tag" title="one <contentType> element"><g id="g411"><rect id="rect222" width="84" height="22" x="345" y="441" style="fill:#fff;stroke:#000;stroke-width:1"/><text x="387" y="452" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text224">contentType</text><line id="line244" x1="335" x2="345" y1="452" y2="452" style="stroke:#000;stroke-width:1;stroke-linecap:round"/></g></a><line id="line246" x1="335" x2="335" y1="88" y2="452" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><line id="line248" x1="325" x2="335" y1="244" y2="244" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a4199" title="that may contain zero or more times one of the following nodes"><g id="g371"><path d="M294 237 L317 237 L323 243 L323 251 L317 257 L294 257 L288 251 L288 243 Z" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1" id="path250"/><path d="M291 234 L314 234 L320 240 L320 248 L314 254 L291 254 L285 248 L285 240 Z" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1" id="path252"/><line id="line254" x1="290" x2="294" y1="244" y2="244" style="stroke:#000;stroke-width:1"/><line id="line256" x1="294" x2="298" y1="244" y2="240" style="stroke:#000;stroke-width:1"/><line id="line258" x1="306" x2="310" y1="240" y2="240" style="stroke:#000;stroke-width:1"/><line id="line260" x1="306" x2="314" y1="244" y2="244" style="stroke:#000;stroke-width:1"/><line id="line262" x1="306" x2="310" y1="248" y2="248" style="stroke:#000;stroke-width:1"/><line id="line264" x1="310" x2="310" y1="240" y2="248" style="stroke:#000;stroke-width:1"/><ellipse id="ellipse266" cx="302" cy="240" rx="2" ry="2"/><ellipse id="ellipse268" cx="302" cy="244" rx="2" ry="2"/><ellipse id="ellipse270" cx="302" cy="248" rx="2" ry="2"/><text x="315" y="264" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" id="text272">0..∞</text><rect id="rect274" width="10" height="10" x="315" y="239" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line276" x1="317" x2="323" y1="244" y2="244" style="stroke:#000;stroke-width:1"/></g></a><line id="line278" x1="265" x2="285" y1="244" y2="244" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a4190" href="#operation-tag" title="zero or more <operation> elements"><g id="g338"><rect id="rect280" width="75" height="22" x="188" y="236" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><rect id="rect282" width="75" height="22" x="185" y="233" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><text x="222.5" y="244" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text284">operation</text><text x="255" y="265" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" id="text286">0..∞</text><rect id="rect288" width="10" height="10" x="255" y="239" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line290" x1="257" x2="263" y1="244" y2="244" style="stroke:#000;stroke-width:1"/></g></a><line id="line292" x1="165" x2="185" y1="244" y2="244" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a4180" title="that contains a sequence of"><g id="g355"><path d="M131 234 L154 234 L160 240 L160 248 L154 254 L131 254 L125 248 L125 240 Z" style="fill:#fff;stroke:#000;stroke-width:1" id="path294"/><line id="line296" x1="128" x2="157" y1="244" y2="244" style="stroke:#000;stroke-width:1"/><ellipse id="ellipse298" cx="137" cy="244" rx="2" ry="2"/><ellipse id="ellipse300" cx="142" cy="244" rx="2" ry="2"/><ellipse id="ellipse302" cx="147" cy="244" rx="2" ry="2"/><rect id="rect304" width="10" height="10" x="155" y="239" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line306" x1="157" x2="163" y1="244" y2="244" style="stroke:#000;stroke-width:1"/></g></a><line id="line308" x1="105" x2="125" y1="244" y2="244" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a484" href="#operations-tag" xlink:arcrole="The <operations> element"><g id="g330"><rect id="rect310" width="80" height="22" x="20" y="233" style="fill:#fff;stroke:#000;stroke-width:1"/><text x="60" y="244" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text312">operations</text><rect id="rect314" width="10" height="10" x="95" y="239" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line316" x1="97" x2="103" y1="244" y2="244" style="stroke:#000;stroke-width:1"/></g></a></svg> \ No newline at end of file diff --git a/docs/img/page-dia.svg b/docs/img/page-dia.svg index 668891db0..10f014328 100644 --- a/docs/img/page-dia.svg +++ b/docs/img/page-dia.svg @@ -1,290 +1 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="370" - height="62" - version="1.1" - id="svg78" - sodipodi:docname="page-dia.svg" - inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"> - <metadata - id="metadata84"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <defs - id="defs82" /> - <sodipodi:namedview - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1" - objecttolerance="10" - gridtolerance="10" - guidetolerance="10" - inkscape:pageopacity="0" - inkscape:pageshadow="2" - inkscape:window-width="1920" - inkscape:window-height="1017" - id="namedview80" - showgrid="false" - inkscape:zoom="1.5351351" - inkscape:cx="91.410446" - inkscape:cy="18.181373" - inkscape:window-x="3278" - inkscape:window-y="-8" - inkscape:window-maximized="1" - inkscape:current-layer="svg78" /> - <rect - x="304" - y="28" - width="59" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect2" /> - <a - href="#section-tag" - id="a8" - title="zero or more <secion> elements"> - <rect - x="301" - y="25" - width="59" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect4" /> - <text - x="330.5" - y="36" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text6">section</text> - </a> - <text - x="350" - y="57" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - id="text10">0..∞</text> - <line - x1="281" - y1="36" - x2="301" - y2="36" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line16" /> - <a - id="a3770" - title="that contains a sequence of"> - <g - id="g3768"> - <path - d="M247 26 L270 26 L276 32 L276 40 L270 46 L247 46 L241 40 L241 32 Z" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="path18" /> - <line - x1="244" - y1="36" - x2="273" - y2="36" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line20" /> - <ellipse - cx="253" - cy="36" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse22" /> - <ellipse - cx="258" - cy="36" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse24" /> - <ellipse - cx="263" - cy="36" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse26" /> - <rect - x="271" - y="31" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect28" /> - <line - x1="273" - y1="36" - x2="279" - y2="36" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line30" /> - </g> - </a> - <line - x1="221" - y1="36" - x2="241" - y2="36" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line32" /> - <rect - x="167" - y="28" - width="52" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect34" /> - <a - href="#page-tag" - id="a40" - title="one or more <page> elements"> - <rect - x="164" - y="25" - width="52" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect36" /> - <text - x="190" - y="36" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text38">page</text> - </a> - <text - x="211" - y="57" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - id="text42">1..∞</text> - <rect - x="211" - y="31" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect48" /> - <line - x1="213" - y1="36" - x2="219" - y2="36" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line50" /> - <line - x1="144" - y1="36" - x2="164" - y2="36" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line52" /> - <a - id="a3751" - title="that contains a sequence of"> - <g - id="g3749"> - <path - d="M110 26 L133 26 L139 32 L139 40 L133 46 L110 46 L104 40 L104 32 Z" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="path54" /> - <line - x1="107" - y1="36" - x2="136" - y2="36" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line56" /> - <ellipse - cx="116" - cy="36" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse58" /> - <ellipse - cx="121" - cy="36" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse60" /> - <ellipse - cx="126" - cy="36" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse62" /> - <rect - x="134" - y="31" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect64" /> - <line - x1="136" - y1="36" - x2="142" - y2="36" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line66" /> - </g> - </a> - <line - x1="84" - y1="36" - x2="104" - y2="36" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line68" /> - <a - id="a46" - href="#pages-tag" - title="Root element <pages>"> - <g - id="g44"> - <rect - x="20" - y="25" - width="59" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect70" /> - <text - x="49.5" - y="36" - style="font-weight:bold;font-size:10.66666698px;font-family:Arial;dominant-baseline:central;text-anchor:middle;fill:#000000" - id="text72">pages</text> - <rect - x="74" - y="31" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect74" /> - <line - x1="76" - y1="36" - x2="82" - y2="36" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line76" /> - </g> - </a> -</svg> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="svg78" width="370" height="62" version="1.1"><metadata id="metadata84"/><rect id="rect2" width="59" height="22" x="304" y="28" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><a id="a8" href="#section-tag" title="zero or more <secion> elements"><rect id="rect4" width="59" height="22" x="301" y="25" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><text x="330.5" y="36" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text6">section</text></a><text x="350" y="57" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" id="text10">0..∞</text><line id="line16" x1="281" x2="301" y1="36" y2="36" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a3770" title="that contains a sequence of"><g id="g3768"><path d="M247 26 L270 26 L276 32 L276 40 L270 46 L247 46 L241 40 L241 32 Z" style="fill:#fff;stroke:#000;stroke-width:1" id="path18"/><line id="line20" x1="244" x2="273" y1="36" y2="36" style="stroke:#000;stroke-width:1"/><ellipse id="ellipse22" cx="253" cy="36" rx="2" ry="2"/><ellipse id="ellipse24" cx="258" cy="36" rx="2" ry="2"/><ellipse id="ellipse26" cx="263" cy="36" rx="2" ry="2"/><rect id="rect28" width="10" height="10" x="271" y="31" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line30" x1="273" x2="279" y1="36" y2="36" style="stroke:#000;stroke-width:1"/></g></a><line id="line32" x1="221" x2="241" y1="36" y2="36" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><rect id="rect34" width="52" height="22" x="167" y="28" style="fill:#fff;stroke:#000;stroke-width:1"/><a id="a40" href="#page-tag" title="one or more <page> elements"><rect id="rect36" width="52" height="22" x="164" y="25" style="fill:#fff;stroke:#000;stroke-width:1"/><text x="190" y="36" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text38">page</text></a><text x="211" y="57" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" id="text42">1..∞</text><rect id="rect48" width="10" height="10" x="211" y="31" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line50" x1="213" x2="219" y1="36" y2="36" style="stroke:#000;stroke-width:1"/><line id="line52" x1="144" x2="164" y1="36" y2="36" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a3751" title="that contains a sequence of"><g id="g3749"><path d="M110 26 L133 26 L139 32 L139 40 L133 46 L110 46 L104 40 L104 32 Z" style="fill:#fff;stroke:#000;stroke-width:1" id="path54"/><line id="line56" x1="107" x2="136" y1="36" y2="36" style="stroke:#000;stroke-width:1"/><ellipse id="ellipse58" cx="116" cy="36" rx="2" ry="2"/><ellipse id="ellipse60" cx="121" cy="36" rx="2" ry="2"/><ellipse id="ellipse62" cx="126" cy="36" rx="2" ry="2"/><rect id="rect64" width="10" height="10" x="134" y="31" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line66" x1="136" x2="142" y1="36" y2="36" style="stroke:#000;stroke-width:1"/></g></a><line id="line68" x1="84" x2="104" y1="36" y2="36" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a46" href="#pages-tag" title="Root element <pages>"><g id="g44"><rect id="rect70" width="59" height="22" x="20" y="25" style="fill:#fff;stroke:#000;stroke-width:1"/><text x="49.5" y="36" style="font-weight:700;font-size:10.66666698px;font-family:Arial;dominant-baseline:central;text-anchor:middle;fill:#000" id="text72">pages</text><rect id="rect74" width="10" height="10" x="74" y="31" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line76" x1="76" x2="82" y1="36" y2="36" style="stroke:#000;stroke-width:1"/></g></a></svg> \ No newline at end of file diff --git a/docs/img/section-dia.svg b/docs/img/section-dia.svg index 1ee7611af..5eb80bbb4 100644 --- a/docs/img/section-dia.svg +++ b/docs/img/section-dia.svg @@ -1,296 +1 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="385" - height="62" - version="1.1" - id="svg74" - sodipodi:docname="section-dia.svg" - inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"> - <metadata - id="metadata80"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <defs - id="defs78" /> - <sodipodi:namedview - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1" - objecttolerance="10" - gridtolerance="10" - guidetolerance="10" - inkscape:pageopacity="0" - inkscape:pageshadow="2" - inkscape:window-width="1920" - inkscape:window-height="1017" - id="namedview76" - showgrid="false" - inkscape:zoom="2.0864242" - inkscape:cx="154.86083" - inkscape:cy="15.327771" - inkscape:window-x="3278" - inkscape:window-y="-8" - inkscape:window-maximized="1" - inkscape:current-layer="svg74" /> - <rect - x="316" - y="28" - width="62" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect2" /> - <a - id="a3803" - href="#element-tag" - title="one or more <element> elements"> - <g - id="g88"> - <rect - x="313" - y="25" - width="62" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect4" /> - <text - x="344" - y="36" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text6">element</text> - </g> - </a> - <text - x="365" - y="57" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - id="text8">1..∞</text> - <line - x1="293" - y1="36" - x2="313" - y2="36" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line14" /> - <a - id="a3777" - title="that contains a sequence of"> - <g - id="g3775"> - <path - d="M259 26 L282 26 L288 32 L288 40 L282 46 L259 46 L253 40 L253 32 Z" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="path16" /> - <line - x1="256" - y1="36" - x2="285" - y2="36" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line18" /> - <ellipse - cx="265" - cy="36" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse20" /> - <ellipse - cx="270" - cy="36" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse22" /> - <ellipse - cx="275" - cy="36" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse24" /> - <rect - x="283" - y="31" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect26" /> - <line - x1="285" - y1="36" - x2="291" - y2="36" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line28" /> - </g> - </a> - <line - x1="233" - y1="36" - x2="253" - y2="36" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line30" /> - <rect - x="167" - y="28" - width="64" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect32" /> - <a - id="a109" - href="#section-tag" - title="one or more <section> elements"> - <g - id="g84"> - <path - inkscape:connector-curvature="0" - id="rect34" - d="m 164,25 c 21.33333,0 42.66667,0 64,0 0,7.333333 0,14.666667 0,22 -21.33333,0 -42.66667,0 -64,0 0,-7.333333 0,-14.666667 0,-22 z" - style="fill:#ffffff;stroke:#000000;stroke-width:1" /> - <path - inkscape:connector-curvature="0" - id="text36" - d="m 177.5625,37.363255 c 1.52529,-0.935044 2.52281,1.779504 3.69792,0.04687 -1.41244,-0.537747 -5.23048,-1.866312 -2.60417,-3.849609 1.13374,-1.247589 5.42381,0.888062 2.93622,1.363663 -0.52908,-0.06221 -2.59658,-1.343691 -2.32164,0.136988 1.91588,0.03374 5.07512,1.94106 2.46713,3.697591 -1.42333,0.629818 -3.75169,0.397163 -4.17546,-1.395508 z m 9.65625,-0.182291 c 2.44842,-0.276007 0.71062,2.155886 -0.94792,1.885417 -2.98868,0.278515 -3.66937,-4.498438 -1.14974,-5.585938 1.95032,-1.411312 4.8677,2.271182 3.08252,3.117187 -1.03835,0 -2.07671,0 -3.11507,0 -0.18497,1.277388 1.81333,2.021528 2.13021,0.583334 z m 0.0833,-1.479167 c 0.38377,-2.44698 -3.53646,-0.483165 -1.6359,0 0.5453,0 1.0906,0 1.6359,0 z m 7.47396,-0.65625 c -1.52854,0.994728 -2.51116,-1.881488 -3.55989,0.273438 -0.96483,1.83752 1.70256,3.656455 2.33125,1.525753 2.64318,-0.225852 0.0544,2.909802 -1.55668,2.20968 -3.17146,-0.115705 -3.1548,-5.664414 0.0212,-5.757325 1.21388,-0.172487 2.50213,0.483367 2.76416,1.748454 z m 3.65104,-1.635417 c 0.4678,1.281947 -0.63769,0.990621 -1,1.442464 0.17471,0.96121 -0.40103,2.406694 0.40625,3.000245 1.95951,0.06826 -0.55728,2.393732 -1.625,0.739583 -0.45945,-1.271518 -0.16723,-2.680854 -0.25,-4.015625 -0.97874,0.476369 -0.99812,-1.649412 0,-1.166667 -0.31505,-1.053184 0.48134,-1.467007 1.31127,-1.861536 0.54105,-0.0085 -0.30244,1.868393 0.43328,1.861536 0.2414,0 0.4828,0 0.7242,0 z m 1.02604,-0.75 c -0.20685,-1.071939 0.0909,-1.639223 1.24109,-1.354166 0.51629,0.342671 0.34899,1.883179 -0.74283,1.354166 -0.16609,0 -0.33217,0 -0.49826,0 z m 0,6.281251 c 0,-1.843751 0,-3.687501 0,-5.531251 0.96324,-0.107657 1.81965,-0.108492 1.46355,1.103188 0,1.476021 0,2.952042 0,4.428063 -0.48785,0 -0.9757,0 -1.46355,0 z m 2.6198,-2.843751 c -0.18497,-2.633509 3.5807,-3.821658 5.09424,-1.784912 1.49262,1.743986 0.16168,4.91742 -2.23487,4.753663 -1.65062,0.06716 -2.99523,-1.308404 -2.85937,-2.968751 z m 1.5,0.07813 c -0.0314,3.170045 4.26045,0.891586 2.3125,-1.260416 -0.96403,-1.094803 -2.49485,0.0058 -2.3125,1.260416 z m 10.39062,2.765626 c -0.96323,0.107657 -1.81964,0.108491 -1.46354,-1.103189 -0.16753,-1.109612 0.46733,-2.707337 -0.63151,-3.396812 -1.96808,-0.190926 -1.40078,2.230498 -1.48307,3.511676 0.38258,1.199876 -0.60098,1.033596 -1.46354,0.988325 0,-1.843751 0,-3.687501 0,-5.531251 1.63308,-0.62997 1.077,1.516748 2.17708,0.109375 2.22452,-1.125947 3.22655,1.30944 2.86458,3.087564 0,0.778104 0,1.556208 0,2.334312 z" - style="font-weight:bold;font-size:10.66666698px;font-family:Arial;dominant-baseline:central;text-anchor:middle;fill:#000000" /> - </g> - </a> - <text - x="223" - y="57" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - id="text38">1..∞</text> - <rect - x="223" - y="31" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect44" /> - <line - x1="225" - y1="36" - x2="231" - y2="36" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line46" /> - <line - x1="144" - y1="36" - x2="164" - y2="36" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line48" /> - <a - id="a3757" - title="that contains a sequence of"> - <g - id="g3755"> - <path - d="M110 26 L133 26 L139 32 L139 40 L133 46 L110 46 L104 40 L104 32 Z" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="path50" /> - <line - x1="107" - y1="36" - x2="136" - y2="36" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line52" /> - <ellipse - cx="116" - cy="36" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse54" /> - <ellipse - cx="121" - cy="36" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse56" /> - <a - id="a3744"> - <ellipse - id="ellipse58" - style="rgb(0,0,0)" - ry="2" - rx="2" - cy="36" - cx="126" /> - </a> - <rect - x="134" - y="31" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect60" /> - <line - x1="136" - y1="36" - x2="142" - y2="36" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line62" /> - </g> - </a> - <line - x1="84" - y1="36" - x2="104" - y2="36" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line64" /> - <a - id="a48" - title="Root element <sections>"> - <g - id="g46"> - <rect - x="20" - y="25" - width="59" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect66" /> - <text - x="49.5" - y="36" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text68">sections</text> - <rect - x="74" - y="31" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect70" /> - <line - x1="76" - y1="36" - x2="82" - y2="36" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line72" /> - </g> - </a> -</svg> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="svg74" width="385" height="62" version="1.1"><metadata id="metadata80"/><rect id="rect2" width="62" height="22" x="316" y="28" style="fill:#fff;stroke:#000;stroke-width:1"/><a id="a3803" href="#element-tag" title="one or more <element> elements"><g id="g88"><rect id="rect4" width="62" height="22" x="313" y="25" style="fill:#fff;stroke:#000;stroke-width:1"/><text x="344" y="36" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text6">element</text></g></a><text x="365" y="57" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" id="text8">1..∞</text><line id="line14" x1="293" x2="313" y1="36" y2="36" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a3777" title="that contains a sequence of"><g id="g3775"><path d="M259 26 L282 26 L288 32 L288 40 L282 46 L259 46 L253 40 L253 32 Z" style="fill:#fff;stroke:#000;stroke-width:1" id="path16"/><line id="line18" x1="256" x2="285" y1="36" y2="36" style="stroke:#000;stroke-width:1"/><ellipse id="ellipse20" cx="265" cy="36" rx="2" ry="2"/><ellipse id="ellipse22" cx="270" cy="36" rx="2" ry="2"/><ellipse id="ellipse24" cx="275" cy="36" rx="2" ry="2"/><rect id="rect26" width="10" height="10" x="283" y="31" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line28" x1="285" x2="291" y1="36" y2="36" style="stroke:#000;stroke-width:1"/></g></a><line id="line30" x1="233" x2="253" y1="36" y2="36" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><rect id="rect32" width="64" height="22" x="167" y="28" style="fill:#fff;stroke:#000;stroke-width:1"/><a id="a109" href="#section-tag" title="one or more <section> elements"><g id="g84"><path id="rect34" d="m 164,25 c 21.33333,0 42.66667,0 64,0 0,7.333333 0,14.666667 0,22 -21.33333,0 -42.66667,0 -64,0 0,-7.333333 0,-14.666667 0,-22 z" style="fill:#fff;stroke:#000;stroke-width:1"/><path id="text36" d="m 177.5625,37.363255 c 1.52529,-0.935044 2.52281,1.779504 3.69792,0.04687 -1.41244,-0.537747 -5.23048,-1.866312 -2.60417,-3.849609 1.13374,-1.247589 5.42381,0.888062 2.93622,1.363663 -0.52908,-0.06221 -2.59658,-1.343691 -2.32164,0.136988 1.91588,0.03374 5.07512,1.94106 2.46713,3.697591 -1.42333,0.629818 -3.75169,0.397163 -4.17546,-1.395508 z m 9.65625,-0.182291 c 2.44842,-0.276007 0.71062,2.155886 -0.94792,1.885417 -2.98868,0.278515 -3.66937,-4.498438 -1.14974,-5.585938 1.95032,-1.411312 4.8677,2.271182 3.08252,3.117187 -1.03835,0 -2.07671,0 -3.11507,0 -0.18497,1.277388 1.81333,2.021528 2.13021,0.583334 z m 0.0833,-1.479167 c 0.38377,-2.44698 -3.53646,-0.483165 -1.6359,0 0.5453,0 1.0906,0 1.6359,0 z m 7.47396,-0.65625 c -1.52854,0.994728 -2.51116,-1.881488 -3.55989,0.273438 -0.96483,1.83752 1.70256,3.656455 2.33125,1.525753 2.64318,-0.225852 0.0544,2.909802 -1.55668,2.20968 -3.17146,-0.115705 -3.1548,-5.664414 0.0212,-5.757325 1.21388,-0.172487 2.50213,0.483367 2.76416,1.748454 z m 3.65104,-1.635417 c 0.4678,1.281947 -0.63769,0.990621 -1,1.442464 0.17471,0.96121 -0.40103,2.406694 0.40625,3.000245 1.95951,0.06826 -0.55728,2.393732 -1.625,0.739583 -0.45945,-1.271518 -0.16723,-2.680854 -0.25,-4.015625 -0.97874,0.476369 -0.99812,-1.649412 0,-1.166667 -0.31505,-1.053184 0.48134,-1.467007 1.31127,-1.861536 0.54105,-0.0085 -0.30244,1.868393 0.43328,1.861536 0.2414,0 0.4828,0 0.7242,0 z m 1.02604,-0.75 c -0.20685,-1.071939 0.0909,-1.639223 1.24109,-1.354166 0.51629,0.342671 0.34899,1.883179 -0.74283,1.354166 -0.16609,0 -0.33217,0 -0.49826,0 z m 0,6.281251 c 0,-1.843751 0,-3.687501 0,-5.531251 0.96324,-0.107657 1.81965,-0.108492 1.46355,1.103188 0,1.476021 0,2.952042 0,4.428063 -0.48785,0 -0.9757,0 -1.46355,0 z m 2.6198,-2.843751 c -0.18497,-2.633509 3.5807,-3.821658 5.09424,-1.784912 1.49262,1.743986 0.16168,4.91742 -2.23487,4.753663 -1.65062,0.06716 -2.99523,-1.308404 -2.85937,-2.968751 z m 1.5,0.07813 c -0.0314,3.170045 4.26045,0.891586 2.3125,-1.260416 -0.96403,-1.094803 -2.49485,0.0058 -2.3125,1.260416 z m 10.39062,2.765626 c -0.96323,0.107657 -1.81964,0.108491 -1.46354,-1.103189 -0.16753,-1.109612 0.46733,-2.707337 -0.63151,-3.396812 -1.96808,-0.190926 -1.40078,2.230498 -1.48307,3.511676 0.38258,1.199876 -0.60098,1.033596 -1.46354,0.988325 0,-1.843751 0,-3.687501 0,-5.531251 1.63308,-0.62997 1.077,1.516748 2.17708,0.109375 2.22452,-1.125947 3.22655,1.30944 2.86458,3.087564 0,0.778104 0,1.556208 0,2.334312 z" style="font-weight:700;font-size:10.66666698px;font-family:Arial;dominant-baseline:central;text-anchor:middle;fill:#000"/></g></a><text x="223" y="57" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" id="text38">1..∞</text><rect id="rect44" width="10" height="10" x="223" y="31" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line46" x1="225" x2="231" y1="36" y2="36" style="stroke:#000;stroke-width:1"/><line id="line48" x1="144" x2="164" y1="36" y2="36" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a3757" title="that contains a sequence of"><g id="g3755"><path d="M110 26 L133 26 L139 32 L139 40 L133 46 L110 46 L104 40 L104 32 Z" style="fill:#fff;stroke:#000;stroke-width:1" id="path50"/><line id="line52" x1="107" x2="136" y1="36" y2="36" style="stroke:#000;stroke-width:1"/><ellipse id="ellipse54" cx="116" cy="36" rx="2" ry="2"/><ellipse id="ellipse56" cx="121" cy="36" rx="2" ry="2"/><a id="a3744"><ellipse id="ellipse58" cx="126" cy="36" rx="2" ry="2"/></a><rect id="rect60" width="10" height="10" x="134" y="31" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line62" x1="136" x2="142" y1="36" y2="36" style="stroke:#000;stroke-width:1"/></g></a><line id="line64" x1="84" x2="104" y1="36" y2="36" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a48" title="Root element <sections>"><g id="g46"><rect id="rect66" width="59" height="22" x="20" y="25" style="fill:#fff;stroke:#000;stroke-width:1"/><text x="49.5" y="36" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text68">sections</text><rect id="rect70" width="10" height="10" x="74" y="31" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line72" x1="76" x2="82" y1="36" y2="36" style="stroke:#000;stroke-width:1"/></g></a></svg> \ No newline at end of file diff --git a/docs/img/test-dia.svg b/docs/img/test-dia.svg index fcf2628da..47439dbb0 100644 --- a/docs/img/test-dia.svg +++ b/docs/img/test-dia.svg @@ -1,1228 +1 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="601" - height="322" - version="1.1" - id="svg330" - sodipodi:docname="test-dia.svg" - inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"> - <metadata - id="metadata336"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <defs - id="defs334" /> - <sodipodi:namedview - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1" - objecttolerance="10" - gridtolerance="10" - guidetolerance="10" - inkscape:pageopacity="0" - inkscape:pageshadow="2" - inkscape:window-width="1920" - inkscape:window-height="1017" - id="namedview332" - showgrid="false" - inkscape:zoom="1.890183" - inkscape:cx="272.85453" - inkscape:cy="165.81687" - inkscape:window-x="3278" - inkscape:window-y="-8" - inkscape:window-maximized="1" - inkscape:current-layer="svg330" /> - <g - id="g398"> - <path - id="path2" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - d="M354 25 L436 25 L442 31 L442 41 L436 47 L354 47 L348 41 L348 31 Z" /> - <text - id="text4" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - y="36" - x="395">testTypeTags</text> - <line - id="line6" - style="stroke:rgb(0,0,0);stroke-width:2" - y2="41" - x2="354" - y1="44" - x1="351" /> - <path - id="path8" - style="fill:rgb(0,0,0)" - d="M354 41 L356 43 L357 38 L352 39 L354 41 Z" /> - <rect - id="rect10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - height="10" - width="10" - y="31" - x="437" /> - <line - id="line12" - style="stroke:rgb(0,0,0);stroke-width:1" - y2="36" - x2="445" - y1="36" - x1="439" /> - <line - id="line14" - style="stroke:rgb(0,0,0);stroke-width:1" - y2="39" - x2="442" - y1="33" - x1="442" /> - </g> - <g - id="g429"> - <path - id="path16" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - d="M498 77 L580 77 L586 83 L586 93 L580 99 L498 99 L492 93 L492 83 Z" /> - <text - id="text18" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - y="88" - x="539">testTypeTags</text> - <line - id="line20" - style="stroke:rgb(0,0,0);stroke-width:2" - y2="93" - x2="498" - y1="96" - x1="495" /> - <path - id="path22" - style="fill:rgb(0,0,0)" - d="M498 93 L500 95 L501 90 L496 91 L498 93 Z" /> - <rect - id="rect24" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - height="10" - width="10" - y="83" - x="581" /> - <line - id="line26" - style="stroke:rgb(0,0,0);stroke-width:1" - y2="88" - x2="589" - y1="88" - x1="583" /> - <line - id="line28" - style="stroke:rgb(0,0,0);stroke-width:1" - y2="91" - x2="586" - y1="85" - x1="586" /> - </g> - <line - x1="472" - y1="88" - x2="492" - y2="88" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line30" /> - <a - id="a4301" - title="that may contain any number of the following nodes in any order"> - <g - id="g420"> - <path - d="M441 81 L464 81 L470 87 L470 95 L464 101 L441 101 L435 95 L435 87 Z" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="path32" /> - <path - d="M438 78 L461 78 L467 84 L467 92 L461 98 L438 98 L432 92 L432 84 Z" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="path34" /> - <line - x1="437" - y1="88" - x2="441" - y2="88" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line36" /> - <line - x1="441" - y1="88" - x2="445" - y2="84" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line38" /> - <line - x1="453" - y1="84" - x2="457" - y2="84" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line40" /> - <line - x1="453" - y1="88" - x2="461" - y2="88" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line42" /> - <line - x1="453" - y1="92" - x2="457" - y2="92" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line44" /> - <line - x1="457" - y1="84" - x2="457" - y2="92" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line46" /> - <ellipse - cx="449" - cy="84" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse48" /> - <ellipse - cx="449" - cy="88" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse50" /> - <ellipse - cx="449" - cy="92" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse52" /> - <text - x="462" - y="108" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - id="text54">0..∞</text> - <rect - x="462" - y="83" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect56" /> - <line - x1="464" - y1="88" - x2="470" - y2="88" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line58" /> - </g> - </a> - <line - x1="412" - y1="88" - x2="432" - y2="88" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line60" /> - <a - id="a4270" - href="#before-tag" - title="zero or one <before> element"> - <g - id="g404"> - <rect - x="348" - y="77" - width="59" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect62" /> - <text - x="377.5" - y="88" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text64">before</text> - <rect - x="402" - y="83" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect66" /> - <line - x1="404" - y1="88" - x2="410" - y2="88" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line68" /> - </g> - </a> - <g - id="g438"> - <path - id="path70" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - d="M489 129 L571 129 L577 135 L577 145 L571 151 L489 151 L483 145 L483 135 Z" /> - <text - id="text72" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - y="140" - x="530">testTypeTags</text> - <line - id="line74" - style="stroke:rgb(0,0,0);stroke-width:2" - y2="145" - x2="489" - y1="148" - x1="486" /> - <path - id="path76" - style="fill:rgb(0,0,0)" - d="M489 145 L491 147 L492 142 L487 143 L489 145 Z" /> - <rect - id="rect78" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - height="10" - width="10" - y="135" - x="572" /> - <line - id="line80" - style="stroke:rgb(0,0,0);stroke-width:1" - y2="140" - x2="580" - y1="140" - x1="574" /> - <line - id="line82" - style="stroke:rgb(0,0,0);stroke-width:1" - y2="143" - x2="577" - y1="137" - x1="577" /> - </g> - <line - x1="463" - y1="140" - x2="483" - y2="140" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line84" /> - <a - id="a4318" - title="that may contain any number of the following nodes in any order"> - <g - id="g460"> - <path - d="M432 133 L455 133 L461 139 L461 147 L455 153 L432 153 L426 147 L426 139 Z" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="path86" /> - <path - d="M429 130 L452 130 L458 136 L458 144 L452 150 L429 150 L423 144 L423 136 Z" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="path88" /> - <line - x1="428" - y1="140" - x2="432" - y2="140" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line90" /> - <line - x1="432" - y1="140" - x2="436" - y2="136" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line92" /> - <line - x1="444" - y1="136" - x2="448" - y2="136" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line94" /> - <line - x1="444" - y1="140" - x2="452" - y2="140" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line96" /> - <line - x1="444" - y1="144" - x2="448" - y2="144" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line98" /> - <line - x1="448" - y1="136" - x2="448" - y2="144" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line100" /> - <ellipse - cx="440" - cy="136" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse102" /> - <ellipse - cx="440" - cy="140" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse104" /> - <ellipse - cx="440" - cy="144" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse106" /> - <text - x="453" - y="160" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - id="text108">0..∞</text> - <rect - x="453" - y="135" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect110" /> - <line - x1="455" - y1="140" - x2="461" - y2="140" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line112" /> - </g> - </a> - <line - x1="403" - y1="140" - x2="423" - y2="140" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line114" /> - <a - id="a4277" - href="#after-tag" - title="zero or one <after> element"> - <g - id="g444"> - <rect - x="348" - y="129" - width="50" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect116" /> - <text - x="373" - y="140" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text118">after</text> - <rect - x="393" - y="135" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect120" /> - <line - x1="395" - y1="140" - x2="401" - y2="140" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line122" /> - </g> - </a> - <a - id="a4335" - title="zero or one <annotations> element" - href="#annotations-tag"> - <g - id="g467"> - <rect - x="348" - y="181" - width="86" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect124" /> - <text - x="391" - y="192" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text126">annotations</text> - <rect - x="429" - y="187" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect128" /> - <line - x1="431" - y1="192" - x2="437" - y2="192" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line130" /> - <line - x1="434" - y1="189" - x2="434" - y2="195" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line132" /> - </g> - </a> - <line - x1="338" - y1="36" - x2="348" - y2="36" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line134" /> - <line - x1="338" - y1="88" - x2="348" - y2="88" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line136" /> - <line - x1="338" - y1="140" - x2="348" - y2="140" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line138" /> - <line - x1="338" - y1="192" - x2="348" - y2="192" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line140" /> - <line - x1="338" - y1="36" - x2="338" - y2="192" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line142" /> - <line - x1="328" - y1="114" - x2="338" - y2="114" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line144" /> - <a - id="a4284" - title="that may contain any number of the following nodes in any order"> - <g - id="g389"> - <path - d="M297 107 L320 107 L326 113 L326 121 L320 127 L297 127 L291 121 L291 113 Z" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="path146" /> - <path - d="M294 104 L317 104 L323 110 L323 118 L317 124 L294 124 L288 118 L288 110 Z" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="path148" /> - <line - x1="293" - y1="114" - x2="297" - y2="114" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line150" /> - <line - x1="297" - y1="114" - x2="301" - y2="110" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line152" /> - <line - x1="309" - y1="110" - x2="313" - y2="110" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line154" /> - <line - x1="309" - y1="114" - x2="317" - y2="114" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line156" /> - <line - x1="309" - y1="118" - x2="313" - y2="118" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line158" /> - <line - x1="313" - y1="110" - x2="313" - y2="118" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line160" /> - <ellipse - cx="305" - cy="110" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse162" /> - <ellipse - cx="305" - cy="114" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse164" /> - <ellipse - cx="305" - cy="118" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse166" /> - <text - x="318" - y="134" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - id="text168">0..∞</text> - <rect - x="318" - y="109" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect170" /> - <line - x1="320" - y1="114" - x2="326" - y2="114" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line172" /> - </g> - </a> - <line - x1="268" - y1="114" - x2="288" - y2="114" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line174" /> - <a - id="a4261" - title="one or more <test> elements" - href="#test-tag"> - <g - id="g373"> - <rect - x="220" - y="106" - width="46" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect176" /> - <rect - x="217" - y="103" - width="46" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect178" /> - <text - x="240" - y="114" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text180">test</text> - <text - x="258" - y="135" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - id="text182">1..∞</text> - <rect - x="258" - y="109" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect184" /> - <line - x1="260" - y1="114" - x2="266" - y2="114" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line186" /> - </g> - </a> - <line - x1="197" - y1="114" - x2="217" - y2="114" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line188" /> - <a - id="a4205" - title="that contains one of the following nodes"> - <g - id="g365"> - <path - d="M163 104 L186 104 L192 110 L192 118 L186 124 L163 124 L157 118 L157 110 Z" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="path190" /> - <line - x1="162" - y1="114" - x2="166" - y2="114" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line192" /> - <line - x1="166" - y1="114" - x2="170" - y2="110" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line194" /> - <line - x1="178" - y1="110" - x2="182" - y2="110" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line196" /> - <line - x1="178" - y1="114" - x2="186" - y2="114" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line198" /> - <line - x1="178" - y1="118" - x2="182" - y2="118" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line200" /> - <line - x1="182" - y1="110" - x2="182" - y2="118" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line202" /> - <ellipse - cx="174" - cy="110" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse204" /> - <ellipse - cx="174" - cy="114" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse206" /> - <ellipse - cx="174" - cy="118" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse208" /> - <rect - x="187" - y="109" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect210" /> - <line - x1="189" - y1="114" - x2="195" - y2="114" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line212" /> - </g> - </a> - <line - x1="137" - y1="114" - x2="157" - y2="114" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line214" /> - <a - id="a4195" - title="that contains a sequence of the following nodes"> - <g - id="g351"> - <path - d="M103 104 L126 104 L132 110 L132 118 L126 124 L103 124 L97 118 L97 110 Z" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="path216" /> - <line - x1="100" - y1="114" - x2="129" - y2="114" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line218" /> - <ellipse - cx="109" - cy="114" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse220" /> - <ellipse - cx="114" - cy="114" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse222" /> - <ellipse - cx="119" - cy="114" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse224" /> - <rect - x="127" - y="109" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect226" /> - <line - x1="129" - y1="114" - x2="135" - y2="114" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line228" /> - </g> - </a> - <line - x1="77" - y1="114" - x2="97" - y2="114" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line230" /> - <a - id="a499" - href="#tests-tag" - title="Root element <tests>"> - <g - id="g342"> - <rect - x="20" - y="103" - width="52" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect232" /> - <text - x="46" - y="114" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text234">tests</text> - <rect - x="67" - y="109" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect236" /> - <line - x1="69" - y1="114" - x2="75" - y2="114" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line238" /> - </g> - </a> - <a - href="test/actions.html" - title="one of <action> elements" - target="_blank" - id="a4355"> - <g - id="g497"> - <path - d="M205 233 L299 233 L305 239 L305 249 L299 255 L205 255 L199 249 L199 239 Z" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="path240" /> - <text - x="252" - y="244" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text242">actionTypeTags</text> - <line - x1="202" - y1="252" - x2="205" - y2="249" - style="stroke:rgb(0,0,0);stroke-width:2" - id="line244" /> - <path - d="M205 249 L207 251 L208 246 L203 247 L205 249 Z" - style="fill:rgb(0,0,0)" - id="path246" /> - <rect - x="300" - y="239" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect248" /> - <line - x1="302" - y1="244" - x2="308" - y2="244" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line250" /> - <line - x1="305" - y1="241" - x2="305" - y2="247" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line252" /> - </g> - </a> - <a - id="a4350" - href="#argument-tag" - title="one <argument> element"> - <g - id="g471"> - <rect - x="373" - y="285" - width="70" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect254" /> - <text - x="408" - y="296" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text256">argument</text> - </g> - </a> - <line - x1="353" - y1="296" - x2="373" - y2="296" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line258" /> - <a - id="a4220" - title="that may contain multiple sequences of the following node"> - <g - id="g482"> - <path - d="M322 289 L345 289 L351 295 L351 303 L345 309 L322 309 L316 303 L316 295 Z" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="path260" /> - <path - d="M319 286 L342 286 L348 292 L348 300 L342 306 L319 306 L313 300 L313 292 Z" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="path262" /> - <line - x1="316" - y1="296" - x2="345" - y2="296" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line264" /> - <ellipse - cx="325" - cy="296" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse266" /> - <ellipse - cx="330" - cy="296" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse268" /> - <ellipse - cx="335" - cy="296" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse270" /> - <text - x="343" - y="316" - style="font-family:Arial;font-size:7.2pt;fill:rgb(0,0,0);text-anchor:end;dominant-baseline:central" - id="text272">0..∞</text> - <rect - x="343" - y="291" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect274" /> - <line - x1="345" - y1="296" - x2="351" - y2="296" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line276" /> - </g> - </a> - <line - x1="293" - y1="296" - x2="313" - y2="296" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line278" /> - <a - id="a4343" - href="#actiongroup-tag" - target="" - title="zero or one <actionGroup> elements"> - <g - id="g488"> - <rect - x="199" - y="285" - width="89" - height="22" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1;stroke-dasharray:4,1" - id="rect280" /> - <text - x="243.5" - y="296" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text282">actionGroup</text> - <rect - x="283" - y="291" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect284" /> - <line - x1="285" - y1="296" - x2="291" - y2="296" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line286" /> - </g> - </a> - <line - x1="189" - y1="244" - x2="199" - y2="244" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line288" /> - <line - x1="189" - y1="296" - x2="199" - y2="296" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line290" /> - <line - x1="189" - y1="244" - x2="189" - y2="296" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line292" /> - <line - x1="179" - y1="270" - x2="189" - y2="270" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line294" /> - <a - id="a4246" - title="that contains one of the following nodes"> - <g - id="g4244"> - <path - d="M145 260 L168 260 L174 266 L174 274 L168 280 L145 280 L139 274 L139 266 Z" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="path296" /> - <line - x1="144" - y1="270" - x2="148" - y2="270" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line298" /> - <line - x1="148" - y1="270" - x2="152" - y2="266" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line300" /> - <line - x1="160" - y1="266" - x2="164" - y2="266" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line302" /> - <line - x1="160" - y1="270" - x2="168" - y2="270" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line304" /> - <line - x1="160" - y1="274" - x2="164" - y2="274" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line306" /> - <line - x1="164" - y1="266" - x2="164" - y2="274" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line308" /> - <ellipse - cx="156" - cy="266" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse310" /> - <ellipse - cx="156" - cy="270" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse312" /> - <ellipse - cx="156" - cy="274" - rx="2" - ry="2" - style="rgb(0,0,0)" - id="ellipse314" /> - <rect - x="169" - y="265" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect316" /> - <line - x1="171" - y1="270" - x2="177" - y2="270" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line318" /> - </g> - </a> - <line - x1="119" - y1="270" - x2="139" - y2="270" - style="stroke:rgb(0,0,0);stroke-width:1;stroke-linecap:round" - id="line320" /> - <path - d="M26 259 L108 259 L114 265 L114 275 L108 281 L26 281 L20 275 L20 265 Z" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="path322" /> - <text - x="67" - y="270" - style="font-family:Arial;font-size:8pt;fill:rgb(0,0,0);font-weight:bold;text-anchor:middle;dominant-baseline:central" - id="text324">testTypeTags</text> - <rect - x="109" - y="265" - width="10" - height="10" - style="fill:rgb(255,255,255);stroke:rgb(0,0,0);stroke-width:1" - id="rect326" /> - <line - x1="111" - y1="270" - x2="117" - y2="270" - style="stroke:rgb(0,0,0);stroke-width:1" - id="line328" /> -</svg> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="svg330" width="601" height="322" version="1.1"><metadata id="metadata336"/><g id="g398"><path id="path2" style="fill:#fff;stroke:#000;stroke-width:1" d="M354 25 L436 25 L442 31 L442 41 L436 47 L354 47 L348 41 L348 31 Z"/><text id="text4" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" x="395" y="36">testTypeTags</text><line id="line6" style="stroke:#000;stroke-width:2" x1="351" x2="354" y1="44" y2="41"/><path id="path8" style="fill:#000" d="M354 41 L356 43 L357 38 L352 39 L354 41 Z"/><rect id="rect10" style="fill:#fff;stroke:#000;stroke-width:1" width="10" height="10" x="437" y="31"/><line id="line12" style="stroke:#000;stroke-width:1" x1="439" x2="445" y1="36" y2="36"/><line id="line14" style="stroke:#000;stroke-width:1" x1="442" x2="442" y1="33" y2="39"/></g><g id="g429"><path id="path16" style="fill:#fff;stroke:#000;stroke-width:1" d="M498 77 L580 77 L586 83 L586 93 L580 99 L498 99 L492 93 L492 83 Z"/><text id="text18" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" x="539" y="88">testTypeTags</text><line id="line20" style="stroke:#000;stroke-width:2" x1="495" x2="498" y1="96" y2="93"/><path id="path22" style="fill:#000" d="M498 93 L500 95 L501 90 L496 91 L498 93 Z"/><rect id="rect24" style="fill:#fff;stroke:#000;stroke-width:1" width="10" height="10" x="581" y="83"/><line id="line26" style="stroke:#000;stroke-width:1" x1="583" x2="589" y1="88" y2="88"/><line id="line28" style="stroke:#000;stroke-width:1" x1="586" x2="586" y1="85" y2="91"/></g><line id="line30" x1="472" x2="492" y1="88" y2="88" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a4301" title="that may contain any number of the following nodes in any order"><g id="g420"><path d="M441 81 L464 81 L470 87 L470 95 L464 101 L441 101 L435 95 L435 87 Z" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1" id="path32"/><path d="M438 78 L461 78 L467 84 L467 92 L461 98 L438 98 L432 92 L432 84 Z" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1" id="path34"/><line id="line36" x1="437" x2="441" y1="88" y2="88" style="stroke:#000;stroke-width:1"/><line id="line38" x1="441" x2="445" y1="88" y2="84" style="stroke:#000;stroke-width:1"/><line id="line40" x1="453" x2="457" y1="84" y2="84" style="stroke:#000;stroke-width:1"/><line id="line42" x1="453" x2="461" y1="88" y2="88" style="stroke:#000;stroke-width:1"/><line id="line44" x1="453" x2="457" y1="92" y2="92" style="stroke:#000;stroke-width:1"/><line id="line46" x1="457" x2="457" y1="84" y2="92" style="stroke:#000;stroke-width:1"/><ellipse id="ellipse48" cx="449" cy="84" rx="2" ry="2"/><ellipse id="ellipse50" cx="449" cy="88" rx="2" ry="2"/><ellipse id="ellipse52" cx="449" cy="92" rx="2" ry="2"/><text x="462" y="108" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" id="text54">0..∞</text><rect id="rect56" width="10" height="10" x="462" y="83" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line58" x1="464" x2="470" y1="88" y2="88" style="stroke:#000;stroke-width:1"/></g></a><line id="line60" x1="412" x2="432" y1="88" y2="88" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a4270" href="#before-tag" title="zero or one <before> element"><g id="g404"><rect id="rect62" width="59" height="22" x="348" y="77" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><text x="377.5" y="88" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text64">before</text><rect id="rect66" width="10" height="10" x="402" y="83" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line68" x1="404" x2="410" y1="88" y2="88" style="stroke:#000;stroke-width:1"/></g></a><g id="g438"><path id="path70" style="fill:#fff;stroke:#000;stroke-width:1" d="M489 129 L571 129 L577 135 L577 145 L571 151 L489 151 L483 145 L483 135 Z"/><text id="text72" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" x="530" y="140">testTypeTags</text><line id="line74" style="stroke:#000;stroke-width:2" x1="486" x2="489" y1="148" y2="145"/><path id="path76" style="fill:#000" d="M489 145 L491 147 L492 142 L487 143 L489 145 Z"/><rect id="rect78" style="fill:#fff;stroke:#000;stroke-width:1" width="10" height="10" x="572" y="135"/><line id="line80" style="stroke:#000;stroke-width:1" x1="574" x2="580" y1="140" y2="140"/><line id="line82" style="stroke:#000;stroke-width:1" x1="577" x2="577" y1="137" y2="143"/></g><line id="line84" x1="463" x2="483" y1="140" y2="140" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a4318" title="that may contain any number of the following nodes in any order"><g id="g460"><path d="M432 133 L455 133 L461 139 L461 147 L455 153 L432 153 L426 147 L426 139 Z" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1" id="path86"/><path d="M429 130 L452 130 L458 136 L458 144 L452 150 L429 150 L423 144 L423 136 Z" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1" id="path88"/><line id="line90" x1="428" x2="432" y1="140" y2="140" style="stroke:#000;stroke-width:1"/><line id="line92" x1="432" x2="436" y1="140" y2="136" style="stroke:#000;stroke-width:1"/><line id="line94" x1="444" x2="448" y1="136" y2="136" style="stroke:#000;stroke-width:1"/><line id="line96" x1="444" x2="452" y1="140" y2="140" style="stroke:#000;stroke-width:1"/><line id="line98" x1="444" x2="448" y1="144" y2="144" style="stroke:#000;stroke-width:1"/><line id="line100" x1="448" x2="448" y1="136" y2="144" style="stroke:#000;stroke-width:1"/><ellipse id="ellipse102" cx="440" cy="136" rx="2" ry="2"/><ellipse id="ellipse104" cx="440" cy="140" rx="2" ry="2"/><ellipse id="ellipse106" cx="440" cy="144" rx="2" ry="2"/><text x="453" y="160" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" id="text108">0..∞</text><rect id="rect110" width="10" height="10" x="453" y="135" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line112" x1="455" x2="461" y1="140" y2="140" style="stroke:#000;stroke-width:1"/></g></a><line id="line114" x1="403" x2="423" y1="140" y2="140" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a4277" href="#after-tag" title="zero or one <after> element"><g id="g444"><rect id="rect116" width="50" height="22" x="348" y="129" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><text x="373" y="140" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text118">after</text><rect id="rect120" width="10" height="10" x="393" y="135" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line122" x1="395" x2="401" y1="140" y2="140" style="stroke:#000;stroke-width:1"/></g></a><a id="a4335" href="#annotations-tag" title="zero or one <annotations> element"><g id="g467"><rect id="rect124" width="86" height="22" x="348" y="181" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><text x="391" y="192" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text126">annotations</text><rect id="rect128" width="10" height="10" x="429" y="187" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line130" x1="431" x2="437" y1="192" y2="192" style="stroke:#000;stroke-width:1"/><line id="line132" x1="434" x2="434" y1="189" y2="195" style="stroke:#000;stroke-width:1"/></g></a><line id="line134" x1="338" x2="348" y1="36" y2="36" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><line id="line136" x1="338" x2="348" y1="88" y2="88" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><line id="line138" x1="338" x2="348" y1="140" y2="140" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><line id="line140" x1="338" x2="348" y1="192" y2="192" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><line id="line142" x1="338" x2="338" y1="36" y2="192" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><line id="line144" x1="328" x2="338" y1="114" y2="114" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a4284" title="that may contain any number of the following nodes in any order"><g id="g389"><path d="M297 107 L320 107 L326 113 L326 121 L320 127 L297 127 L291 121 L291 113 Z" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1" id="path146"/><path d="M294 104 L317 104 L323 110 L323 118 L317 124 L294 124 L288 118 L288 110 Z" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1" id="path148"/><line id="line150" x1="293" x2="297" y1="114" y2="114" style="stroke:#000;stroke-width:1"/><line id="line152" x1="297" x2="301" y1="114" y2="110" style="stroke:#000;stroke-width:1"/><line id="line154" x1="309" x2="313" y1="110" y2="110" style="stroke:#000;stroke-width:1"/><line id="line156" x1="309" x2="317" y1="114" y2="114" style="stroke:#000;stroke-width:1"/><line id="line158" x1="309" x2="313" y1="118" y2="118" style="stroke:#000;stroke-width:1"/><line id="line160" x1="313" x2="313" y1="110" y2="118" style="stroke:#000;stroke-width:1"/><ellipse id="ellipse162" cx="305" cy="110" rx="2" ry="2"/><ellipse id="ellipse164" cx="305" cy="114" rx="2" ry="2"/><ellipse id="ellipse166" cx="305" cy="118" rx="2" ry="2"/><text x="318" y="134" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" id="text168">0..∞</text><rect id="rect170" width="10" height="10" x="318" y="109" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line172" x1="320" x2="326" y1="114" y2="114" style="stroke:#000;stroke-width:1"/></g></a><line id="line174" x1="268" x2="288" y1="114" y2="114" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a4261" href="#test-tag" title="one or more <test> elements"><g id="g373"><rect id="rect176" width="46" height="22" x="220" y="106" style="fill:#fff;stroke:#000;stroke-width:1"/><rect id="rect178" width="46" height="22" x="217" y="103" style="fill:#fff;stroke:#000;stroke-width:1"/><text x="240" y="114" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text180">test</text><text x="258" y="135" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" id="text182">1..∞</text><rect id="rect184" width="10" height="10" x="258" y="109" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line186" x1="260" x2="266" y1="114" y2="114" style="stroke:#000;stroke-width:1"/></g></a><line id="line188" x1="197" x2="217" y1="114" y2="114" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a4205" title="that contains one of the following nodes"><g id="g365"><path d="M163 104 L186 104 L192 110 L192 118 L186 124 L163 124 L157 118 L157 110 Z" style="fill:#fff;stroke:#000;stroke-width:1" id="path190"/><line id="line192" x1="162" x2="166" y1="114" y2="114" style="stroke:#000;stroke-width:1"/><line id="line194" x1="166" x2="170" y1="114" y2="110" style="stroke:#000;stroke-width:1"/><line id="line196" x1="178" x2="182" y1="110" y2="110" style="stroke:#000;stroke-width:1"/><line id="line198" x1="178" x2="186" y1="114" y2="114" style="stroke:#000;stroke-width:1"/><line id="line200" x1="178" x2="182" y1="118" y2="118" style="stroke:#000;stroke-width:1"/><line id="line202" x1="182" x2="182" y1="110" y2="118" style="stroke:#000;stroke-width:1"/><ellipse id="ellipse204" cx="174" cy="110" rx="2" ry="2"/><ellipse id="ellipse206" cx="174" cy="114" rx="2" ry="2"/><ellipse id="ellipse208" cx="174" cy="118" rx="2" ry="2"/><rect id="rect210" width="10" height="10" x="187" y="109" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line212" x1="189" x2="195" y1="114" y2="114" style="stroke:#000;stroke-width:1"/></g></a><line id="line214" x1="137" x2="157" y1="114" y2="114" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a4195" title="that contains a sequence of the following nodes"><g id="g351"><path d="M103 104 L126 104 L132 110 L132 118 L126 124 L103 124 L97 118 L97 110 Z" style="fill:#fff;stroke:#000;stroke-width:1" id="path216"/><line id="line218" x1="100" x2="129" y1="114" y2="114" style="stroke:#000;stroke-width:1"/><ellipse id="ellipse220" cx="109" cy="114" rx="2" ry="2"/><ellipse id="ellipse222" cx="114" cy="114" rx="2" ry="2"/><ellipse id="ellipse224" cx="119" cy="114" rx="2" ry="2"/><rect id="rect226" width="10" height="10" x="127" y="109" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line228" x1="129" x2="135" y1="114" y2="114" style="stroke:#000;stroke-width:1"/></g></a><line id="line230" x1="77" x2="97" y1="114" y2="114" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a499" href="#tests-tag" title="Root element <tests>"><g id="g342"><rect id="rect232" width="52" height="22" x="20" y="103" style="fill:#fff;stroke:#000;stroke-width:1"/><text x="46" y="114" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text234">tests</text><rect id="rect236" width="10" height="10" x="67" y="109" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line238" x1="69" x2="75" y1="114" y2="114" style="stroke:#000;stroke-width:1"/></g></a><a id="a4355" href="test/actions.html" target="_blank" title="one of <action> elements"><g id="g497"><path d="M205 233 L299 233 L305 239 L305 249 L299 255 L205 255 L199 249 L199 239 Z" style="fill:#fff;stroke:#000;stroke-width:1" id="path240"/><text x="252" y="244" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text242">actionTypeTags</text><line id="line244" x1="202" x2="205" y1="252" y2="249" style="stroke:#000;stroke-width:2"/><path d="M205 249 L207 251 L208 246 L203 247 L205 249 Z" style="fill:#000" id="path246"/><rect id="rect248" width="10" height="10" x="300" y="239" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line250" x1="302" x2="308" y1="244" y2="244" style="stroke:#000;stroke-width:1"/><line id="line252" x1="305" x2="305" y1="241" y2="247" style="stroke:#000;stroke-width:1"/></g></a><a id="a4350" href="#argument-tag" title="one <argument> element"><g id="g471"><rect id="rect254" width="70" height="22" x="373" y="285" style="fill:#fff;stroke:#000;stroke-width:1"/><text x="408" y="296" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text256">argument</text></g></a><line id="line258" x1="353" x2="373" y1="296" y2="296" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a4220" title="that may contain multiple sequences of the following node"><g id="g482"><path d="M322 289 L345 289 L351 295 L351 303 L345 309 L322 309 L316 303 L316 295 Z" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1" id="path260"/><path d="M319 286 L342 286 L348 292 L348 300 L342 306 L319 306 L313 300 L313 292 Z" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1" id="path262"/><line id="line264" x1="316" x2="345" y1="296" y2="296" style="stroke:#000;stroke-width:1"/><ellipse id="ellipse266" cx="325" cy="296" rx="2" ry="2"/><ellipse id="ellipse268" cx="330" cy="296" rx="2" ry="2"/><ellipse id="ellipse270" cx="335" cy="296" rx="2" ry="2"/><text x="343" y="316" style="font-family:Arial;font-size:7.2pt;fill:#000;text-anchor:end;dominant-baseline:central" id="text272">0..∞</text><rect id="rect274" width="10" height="10" x="343" y="291" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line276" x1="345" x2="351" y1="296" y2="296" style="stroke:#000;stroke-width:1"/></g></a><line id="line278" x1="293" x2="313" y1="296" y2="296" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a4343" href="#actiongroup-tag" title="zero or one <actionGroup> elements"><g id="g488"><rect id="rect280" width="89" height="22" x="199" y="285" style="fill:#fff;stroke:#000;stroke-width:1;stroke-dasharray:4,1"/><text x="243.5" y="296" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text282">actionGroup</text><rect id="rect284" width="10" height="10" x="283" y="291" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line286" x1="285" x2="291" y1="296" y2="296" style="stroke:#000;stroke-width:1"/></g></a><line id="line288" x1="189" x2="199" y1="244" y2="244" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><line id="line290" x1="189" x2="199" y1="296" y2="296" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><line id="line292" x1="189" x2="189" y1="244" y2="296" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><line id="line294" x1="179" x2="189" y1="270" y2="270" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><a id="a4246" title="that contains one of the following nodes"><g id="g4244"><path d="M145 260 L168 260 L174 266 L174 274 L168 280 L145 280 L139 274 L139 266 Z" style="fill:#fff;stroke:#000;stroke-width:1" id="path296"/><line id="line298" x1="144" x2="148" y1="270" y2="270" style="stroke:#000;stroke-width:1"/><line id="line300" x1="148" x2="152" y1="270" y2="266" style="stroke:#000;stroke-width:1"/><line id="line302" x1="160" x2="164" y1="266" y2="266" style="stroke:#000;stroke-width:1"/><line id="line304" x1="160" x2="168" y1="270" y2="270" style="stroke:#000;stroke-width:1"/><line id="line306" x1="160" x2="164" y1="274" y2="274" style="stroke:#000;stroke-width:1"/><line id="line308" x1="164" x2="164" y1="266" y2="274" style="stroke:#000;stroke-width:1"/><ellipse id="ellipse310" cx="156" cy="266" rx="2" ry="2"/><ellipse id="ellipse312" cx="156" cy="270" rx="2" ry="2"/><ellipse id="ellipse314" cx="156" cy="274" rx="2" ry="2"/><rect id="rect316" width="10" height="10" x="169" y="265" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line318" x1="171" x2="177" y1="270" y2="270" style="stroke:#000;stroke-width:1"/></g></a><line id="line320" x1="119" x2="139" y1="270" y2="270" style="stroke:#000;stroke-width:1;stroke-linecap:round"/><path d="M26 259 L108 259 L114 265 L114 275 L108 281 L26 281 L20 275 L20 265 Z" style="fill:#fff;stroke:#000;stroke-width:1" id="path322"/><text x="67" y="270" style="font-family:Arial;font-size:8pt;fill:#000;font-weight:700;text-anchor:middle;dominant-baseline:central" id="text324">testTypeTags</text><rect id="rect326" width="10" height="10" x="109" y="265" style="fill:#fff;stroke:#000;stroke-width:1"/><line id="line328" x1="111" x2="117" y1="270" y2="270" style="stroke:#000;stroke-width:1"/></svg> \ No newline at end of file