diff --git a/behat.yml.dist b/behat.yml.dist index 0fff888b..000eaeb6 100644 --- a/behat.yml.dist +++ b/behat.yml.dist @@ -115,6 +115,7 @@ drupal8: - Drupal\DrupalExtension\Context\MarkupContext - Drupal\DrupalExtension\Context\MessageContext - Drupal\DrupalExtension\Context\MailContext + - Drupal\DrupalExtension\Context\RandomContext filters: tags: "@d8&&~@d8wip" extensions: diff --git a/doc/contexts.rst b/doc/contexts.rst index 6a722135..2fbd56d0 100644 --- a/doc/contexts.rst +++ b/doc/contexts.rst @@ -31,6 +31,11 @@ following contexts: Step-definitions that are specific to Drupal messages that get displayed (notice, warning, and error). +*RandomContext* + Contains transforms that allow for use of placeholders such as `` that will be replaced with a random string + when the scenario is run: `Given I am viewing an "Article" with the title ""` + + *DrushContext* Allows steps to directly call drush commands. diff --git a/features/random.feature b/features/random.feature new file mode 100644 index 00000000..cd700314 --- /dev/null +++ b/features/random.feature @@ -0,0 +1,20 @@ +@api @d8 @random +Feature: RandomContext functionality + In order to prove the RandomContext is functional at transforming variables + As a developer + I need to use random variables in scenarios + + # This will fail on the second scenario if random transforms are not functional. + Scenario: Create a first user + Given I am at "/user/register" + And I fill in "Email address" with "@example.com" + And I fill in "Username" with "" + When I press "Create new account" + Then an email has been sent to "@example.com" with the subject "Account details for " + + Scenario: Create the second user + Given I am at "/user/register" + And I fill in "Email address" with "@example.com" + And I fill in "Username" with "" + When I press "Create new account" + Then an email has been sent to "@example.com" with the subject "Account details for " diff --git a/spec/Drupal/DrupalExtension/Context/RandomContextSpec.php b/spec/Drupal/DrupalExtension/Context/RandomContextSpec.php new file mode 100644 index 00000000..7390b02a --- /dev/null +++ b/spec/Drupal/DrupalExtension/Context/RandomContextSpec.php @@ -0,0 +1,15 @@ +shouldHaveType(RandomContext::class); + } +} diff --git a/src/Drupal/DrupalExtension/Context/RandomContext.php b/src/Drupal/DrupalExtension/Context/RandomContext.php new file mode 100644 index 00000000..dfd9390b --- /dev/null +++ b/src/Drupal/DrupalExtension/Context/RandomContext.php @@ -0,0 +1,90 @@ +`. + */ + const VARIABLE_REGEX = '#(\<\?.*?\>)#'; + + /** + * Transform random variables. + * + * @Transform #([^<]*\<\?.*\>[^>]*)# + */ + public function transformVariables($message) + { + $patterns = []; + $replacements = []; + + preg_match_all(static::VARIABLE_REGEX, $message, $matches); + foreach ($matches[0] as $variable) { + $replacements[] = $this->values[$variable]; + $patterns[] = '#' . preg_quote($variable) . '#'; + } + $message = preg_replace($patterns, $replacements, $message); + + return $message; + } + + /** + * Set values for each random variable found in the current scenario. + * + * @BeforeScenario + */ + public function beforeScenarioSetVariables(BeforeScenarioScope $scope) + { + $steps = []; + if ($scope->getFeature()->hasBackground()) { + $steps = $scope->getFeature()->getBackground()->getSteps(); + } + $steps = array_merge($steps, $scope->getScenario()->getSteps()); + foreach ($steps as $step) { + preg_match_all(static::VARIABLE_REGEX, $step->getText(), $matches); + $variables_found = $matches[0]; + // Find variables in are TableNodes or PyStringNodes. + $step_argument = $step->getArguments(); + if (!empty($step_argument) && $step_argument[0] instanceof TableNode) { + preg_match_all(static::VARIABLE_REGEX, $step_argument[0]->getTableAsString(), $matches); + $variables_found = array_filter(array_merge($variables_found, $matches[0])); + } + foreach ($variables_found as $variable_name) { + if (!isset($this->values[$variable_name])) { + $value = $this->getDriver()->getRandom()->name(10); + // Value forced to lowercase to ensure it is machine-readable. + $this->values[$variable_name] = strtolower($value); + } + } + } + } + + /** + * Reset variables after the scenario. + * + * @AfterScenario + */ + public function afterScenarioResetVariables(AfterScenarioScope $scope) + { + $this->values = []; + } +}