From 8c789639be1c0029a4e2139ad81d78683eace430 Mon Sep 17 00:00:00 2001 From: Dipak Acharya Date: Wed, 15 Jan 2020 09:06:32 +0545 Subject: [PATCH] Add support for Outline on background --- src/Behat/Gherkin/Loader/ArrayLoader.php | 18 ++++++++- src/Behat/Gherkin/Loader/YamlFileLoader.php | 7 ++++ src/Behat/Gherkin/Node/BackgroundNode.php | 28 ++++++++++++- src/Behat/Gherkin/Node/OutlineNode.php | 28 +++++++++---- src/Behat/Gherkin/Parser.php | 39 +++++++++++++------ .../etalons/background_with_outline.yml | 31 +++++++++++++++ .../features/background_with_outline.feature | 13 +++++++ .../Behat/Gherkin/Loader/ArrayLoaderTest.php | 6 ++- 8 files changed, 147 insertions(+), 23 deletions(-) create mode 100644 tests/Behat/Gherkin/Fixtures/etalons/background_with_outline.yml create mode 100644 tests/Behat/Gherkin/Fixtures/features/background_with_outline.feature diff --git a/src/Behat/Gherkin/Loader/ArrayLoader.php b/src/Behat/Gherkin/Loader/ArrayLoader.php index 3492d6e6..3f7d9876 100644 --- a/src/Behat/Gherkin/Loader/ArrayLoader.php +++ b/src/Behat/Gherkin/Loader/ArrayLoader.php @@ -119,7 +119,23 @@ protected function loadBackgroundHash(array $hash) $steps = $this->loadStepsHash($hash['steps']); - return new BackgroundNode($hash['title'], $steps, $hash['keyword'], $hash['line']); + if (isset($hash['examples']['keyword'])) { + $examplesKeyword = $hash['examples']['keyword']; + unset($hash['examples']['keyword']); + } else { + $examplesKeyword = 'Examples'; + } + if (isset($hash['examples'])) { + $examplesTable = $hash['examples']; + } else { + $examplesTable = array(); + } + if (\count($examplesTable) === 0) { + $examples = null; + } else { + $examples = new ExampleTableNode($examplesTable, $examplesKeyword); + } + return new BackgroundNode($hash['title'], $steps, $hash['keyword'], $hash['line'], $examples); } /** diff --git a/src/Behat/Gherkin/Loader/YamlFileLoader.php b/src/Behat/Gherkin/Loader/YamlFileLoader.php index 0c268fd3..728c90b8 100644 --- a/src/Behat/Gherkin/Loader/YamlFileLoader.php +++ b/src/Behat/Gherkin/Loader/YamlFileLoader.php @@ -57,6 +57,13 @@ public function load($path) $filename = $this->findRelativePath($path); return array_map(function (FeatureNode $feature) use ($filename) { + if ($feature->getBackground() !== null && $feature->getBackground()->hasExamples()) {; + foreach ($feature->getScenarios() as $scenario) { + if (!$scenario->hasExamples()) { + $scenario->setExampleTable($feature->getBackground()->getExamples()); + } + } + } return new FeatureNode( $feature->getTitle(), $feature->getDescription(), diff --git a/src/Behat/Gherkin/Node/BackgroundNode.php b/src/Behat/Gherkin/Node/BackgroundNode.php index fb1edb4b..a6b1aa8a 100644 --- a/src/Behat/Gherkin/Node/BackgroundNode.php +++ b/src/Behat/Gherkin/Node/BackgroundNode.php @@ -33,6 +33,10 @@ class BackgroundNode implements ScenarioLikeInterface * @var integer */ private $line; + /** + * @var ExampleTableNode + */ + private $exampleTable; /** * Initializes background. @@ -41,13 +45,15 @@ class BackgroundNode implements ScenarioLikeInterface * @param StepNode[] $steps * @param string $keyword * @param integer $line + * @param null|ExampleTableNode $exampleTable */ - public function __construct($title, array $steps, $keyword, $line) + public function __construct($title, array $steps, $keyword, $line, $exampleTable=null) { $this->title = $title; $this->steps = $steps; $this->keyword = $keyword; $this->line = $line; + $this->exampleTable = $exampleTable; } /** @@ -109,4 +115,24 @@ public function getLine() { return $this->line; } + + /** + * Returns if background has ExampleTable + * + * @return boolean + */ + public function hasExamples() + { + return $this->exampleTable !== null; + } + + /** + * Returns if background has ExampleTable + * + * @return null|ExampleTableNode + */ + public function getExamples() + { + return $this->exampleTable; + } } diff --git a/src/Behat/Gherkin/Node/OutlineNode.php b/src/Behat/Gherkin/Node/OutlineNode.php index 62f55181..11edcb22 100644 --- a/src/Behat/Gherkin/Node/OutlineNode.php +++ b/src/Behat/Gherkin/Node/OutlineNode.php @@ -49,18 +49,18 @@ class OutlineNode implements ScenarioInterface /** * Initializes outline. * - * @param null|string $title - * @param string[] $tags - * @param StepNode[] $steps - * @param ExampleTableNode $table - * @param string $keyword - * @param integer $line + * @param null|string $title + * @param string[] $tags + * @param StepNode[] $steps + * @param null|ExampleTableNode $table + * @param string $keyword + * @param integer $line */ public function __construct( $title, array $tags, array $steps, - ExampleTableNode $table, + $table, $keyword, $line ) { @@ -151,7 +151,19 @@ public function getSteps() */ public function hasExamples() { - return 0 < count($this->table->getColumnsHash()); + return $this->table !== null && 0 < count($this->table->getRows()); + } + + /** + * Add Example to the outline. + * + * @param ExampleTableNode + * + * @return void + */ + public function setExampleTable($table) + { + $this->table = $table; } /** diff --git a/src/Behat/Gherkin/Parser.php b/src/Behat/Gherkin/Parser.php index 5cc85424..632b400c 100644 --- a/src/Behat/Gherkin/Parser.php +++ b/src/Behat/Gherkin/Parser.php @@ -275,6 +275,26 @@ protected function parseFeature() } } + if ($background === null || !$background->hasExamples()) { + foreach ($scenarios as $scenario) { + if ($scenario instanceof OutlineNode && !$scenario->hasExamples()) { + throw new ParserException(sprintf( + 'Outline should have examples table, but got none for outline "%s" on line: %d%s', + rtrim($scenario->getTitle()), + $scenario->getLine(), + $this->file ? ' in file: ' . $this->file : '' + )); + } + } + } + if ($background !== null && $background->hasExamples()) {; + foreach ($scenarios as $scenario) { + if ($scenario instanceof OutlineNode && !$scenario->hasExamples()) { + $scenario->setExampleTable($background->getExamples()); + } + } + } + return new FeatureNode( rtrim($title) ?: null, rtrim($description) ?: null, @@ -302,6 +322,7 @@ protected function parseBackground() $title = trim($token['value']); $keyword = $token['keyword']; $line = $token['line']; + $example = null; if (count($this->popTags())) { throw new ParserException(sprintf( @@ -313,10 +334,15 @@ protected function parseBackground() // Parse description and steps $steps = array(); - $allowedTokenTypes = array('Step', 'Newline', 'Text', 'Comment'); + $allowedTokenTypes = array('Step', 'Newline', 'Text', 'Comment', 'Examples'); while (in_array($this->predictTokenType(), $allowedTokenTypes)) { $node = $this->parseExpression(); + if ($node instanceof ExampleTableNode) { + $example = $node; + continue; + } + if ($node instanceof StepNode) { $steps[] = $this->normalizeStepNodeKeywordType($node, $steps); continue; @@ -350,7 +376,7 @@ protected function parseBackground() } } - return new BackgroundNode(rtrim($title) ?: null, $steps, $keyword, $line); + return new BackgroundNode(rtrim($title) ?: null, $steps, $keyword, $line, $example); } /** @@ -470,15 +496,6 @@ protected function parseOutline() } } - if (null === $examples) { - throw new ParserException(sprintf( - 'Outline should have examples table, but got none for outline "%s" on line: %d%s', - rtrim($title), - $line, - $this->file ? ' in file: ' . $this->file : '' - )); - } - return new OutlineNode(rtrim($title) ?: null, $tags, $steps, $examples, $keyword, $line); } diff --git a/tests/Behat/Gherkin/Fixtures/etalons/background_with_outline.yml b/tests/Behat/Gherkin/Fixtures/etalons/background_with_outline.yml new file mode 100644 index 00000000..5fe2f0b1 --- /dev/null +++ b/tests/Behat/Gherkin/Fixtures/etalons/background_with_outline.yml @@ -0,0 +1,31 @@ +feature: + title: Feature with background and example + language: en + line: 1 + description: ~ + + background: + line: 3 + steps: + - { keyword_type: Given, type: Given, text: a passing step, line: 4 } + examples: + 6: [login, password] + 7: ['', ''] + 8: [unknown_user, ''] + + scenarios: + - + type: outline + title: ~ + line: 10 + steps: + - { keyword_type: 'Given', type: 'Given', text: 'a failing step', line: 11 } + - { keyword_type: 'When', type: 'When', text: 'I fill in "login" with ""', line: 12 } + - { keyword_type: 'When', type: 'And', text: 'I fill in "password" with ""', line: 13 } + arguments: + - + type: table + rows: + 6: [ login, password ] + 7: [ '' , '' ] + 8: [ unknown_user , '' ] \ No newline at end of file diff --git a/tests/Behat/Gherkin/Fixtures/features/background_with_outline.feature b/tests/Behat/Gherkin/Fixtures/features/background_with_outline.feature new file mode 100644 index 00000000..eebd708f --- /dev/null +++ b/tests/Behat/Gherkin/Fixtures/features/background_with_outline.feature @@ -0,0 +1,13 @@ +Feature: Feature with background and example + + Background: + Given a passing step + Examples: + | login | password | + | | | + | unknown_user | | + + Scenario Outline: + Given a failing step + When I fill in "login" with "" + And I fill in "password" with "" diff --git a/tests/Behat/Gherkin/Loader/ArrayLoaderTest.php b/tests/Behat/Gherkin/Loader/ArrayLoaderTest.php index 697d1d3d..bbdc0eca 100644 --- a/tests/Behat/Gherkin/Loader/ArrayLoaderTest.php +++ b/tests/Behat/Gherkin/Loader/ArrayLoaderTest.php @@ -217,7 +217,8 @@ public function testLoadSteps() 'steps' => array( array('type' => 'Gangway!', 'keyword_type' => 'Given', 'text' => 'bg step 1', 'line' => 3), array('type' => 'Blimey!', 'keyword_type' => 'When', 'text' => 'bg step 2') - ) + ), + 'examples' => null ), 'scenarios' => array( array( @@ -326,7 +327,8 @@ public function testLoadStepArguments() ) ) ) - ) + ), + 'examples' => null ) ) )