Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Background outline #2

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion src/Behat/Gherkin/Loader/ArrayLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

/**
Expand Down
28 changes: 27 additions & 1 deletion src/Behat/Gherkin/Node/BackgroundNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ class BackgroundNode implements ScenarioLikeInterface
* @var integer
*/
private $line;
/**
* @var ExampleTableNode
*/
private $exampleTable;

/**
* Initializes background.
Expand All @@ -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;
}

/**
Expand Down Expand Up @@ -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;
}
}
28 changes: 20 additions & 8 deletions src/Behat/Gherkin/Node/OutlineNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
) {
Expand Down Expand Up @@ -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;
}

/**
Expand Down
38 changes: 27 additions & 11 deletions src/Behat/Gherkin/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,25 @@ 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 : ''
));
}
}
} else {
foreach ($scenarios as $scenario) {
if ($scenario instanceof OutlineNode && !$scenario->hasExamples()) {
$scenario->setExampleTable($background->getExamples());
}
}
}

return new FeatureNode(
rtrim($title) ?: null,
rtrim($description) ?: null,
Expand Down Expand Up @@ -302,6 +321,7 @@ protected function parseBackground()
$title = trim($token['value']);
$keyword = $token['keyword'];
$line = $token['line'];
$example = null;

if (count($this->popTags())) {
throw new ParserException(sprintf(
Expand All @@ -313,10 +333,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;
Expand Down Expand Up @@ -350,7 +375,7 @@ protected function parseBackground()
}
}

return new BackgroundNode(rtrim($title) ?: null, $steps, $keyword, $line);
return new BackgroundNode(rtrim($title) ?: null, $steps, $keyword, $line, $example);
}

/**
Expand Down Expand Up @@ -470,15 +495,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);
}

Expand Down
28 changes: 28 additions & 0 deletions tests/Behat/Gherkin/Fixtures/etalons/background_with_outline.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
feature:
title: Feature with example in the background
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, 'known_pass']

scenarios:
-
type: outline
title: Scenario outline without example table
line: 10
steps:
- { keyword_type: 'Given', type: 'Given', text: 'I browse to the login page', line: 11 }
- { keyword_type: 'When', type: 'When', text: 'I fill in "login" with "<login>"', line: 12 }
- { keyword_type: 'When', type: 'And', text: 'I fill in "password" with "<password>"', line: 13 }
examples:
6: [login, password]
7: ['', '']
8: [unknown_user, 'known_pass']
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
feature:
title: Feature with example in background and multiple scenarios
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, known_pass]

scenarios:
-
type: outline
title: Scenario outline without example
line: 10
steps:
- { keyword_type: 'Given', type: 'Given', text: 'I have browsed to login page', line: 11 }
- { keyword_type: 'When', type: 'When', text: 'I fill in "login" with "<login>"', line: 12 }
- { keyword_type: 'When', type: 'And', text: 'I fill in "password" with "<password>"', line: 13 }
examples:
6: [ login, password ]
7: [ '' , '' ]
8: [ unknown_user , known_pass ]

- type: scenario
title: A regular scenario
line: 15
steps:
- { keyword_type: 'Given', type: 'Given', text: 'I have browsed to login page', line: 16 }
- { keyword_type: 'When', type: 'When', text: 'I fill in "login" with "user"', line: 17 }
- { keyword_type: 'When', type: 'And', text: 'I fill in "password" with "password"', line: 18 }

- type: outline
title: Scenario outline with it's own example table
line: 20
steps:
- { keyword_type: 'Given', type: 'Given', text: 'I have browsed to login page', line: 21 }
- { keyword_type: 'When', type: 'When', text: 'I fill in "login" with "<login>"', line: 22 }
- { keyword_type: 'When', type: 'And', text: 'I fill in "password" with "<password>"', line: 23 }
examples:
25: [ login, password ]
26: [ hello, world ]
27: [ user , pass ]
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Feature: Feature with example in the background

Background:
Given a passing step
Examples:
| login | password |
| | |
| unknown_user | known_pass |

Scenario Outline: Scenario outline without example table
Given I browse to the login page
When I fill in "login" with "<login>"
And I fill in "password" with "<password>"
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
Feature: Feature with example in background and multiple scenarios

Background:
Given a passing step
Examples:
| login | password |
| | |
| unknown_user | known_pass |

Scenario Outline: Scenario outline without example
Given I have browsed to login page
When I fill in "login" with "<login>"
And I fill in "password" with "<password>"

Scenario: A regular scenario
Given I have browsed to login page
When I fill in "login" with "user"
And I fill in "password" with "password"

Scenario Outline: Scenario outline with it's own example table
Given I have browsed to login page
When I fill in "login" with "<login>"
And I fill in "password" with "<password>"
Examples:
| login | password |
| hello | world |
| user | pass |
6 changes: 4 additions & 2 deletions tests/Behat/Gherkin/Loader/ArrayLoaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -326,7 +327,8 @@ public function testLoadStepArguments()
)
)
)
)
),
'examples' => null
)
)
)
Expand Down