Skip to content

Commit 0ac8147

Browse files
Merge pull request #271 from uuf6429/feature/improve-outline-example-titles
Improve title handling, especially for example scenarios
2 parents 3384970 + 225d28d commit 0ac8147

File tree

6 files changed

+110
-32
lines changed

6 files changed

+110
-32
lines changed

src/Behat/Gherkin/Node/ExampleNode.php

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
*
1616
* @author Konstantin Kudryashov <ever.zet@gmail.com>
1717
*/
18-
class ExampleNode implements ScenarioInterface
18+
class ExampleNode implements ScenarioInterface, NamedScenarioInterface
1919
{
2020
/**
2121
* @var string
2222
*/
23-
private $title;
23+
private $text;
2424
/**
2525
* @var string[]
2626
*/
@@ -45,25 +45,31 @@ class ExampleNode implements ScenarioInterface
4545
* @var string
4646
*/
4747
private $outlineTitle;
48+
/**
49+
* @var null|int
50+
*/
51+
private $index;
4852

4953
/**
5054
* Initializes outline.
5155
*
52-
* @param string $title
56+
* @param string $text The entire row as a string, e.g. "| 1 | 2 | 3 |"
5357
* @param string[] $tags
5458
* @param StepNode[] $outlineSteps
5559
* @param string[] $tokens
56-
* @param integer $line
57-
* @param string|null $outlineTitle
60+
* @param integer $line Line number within the feature file.
61+
* @param string|null $outlineTitle Original title of the scenario outline.
62+
* @param null|int $index The 1-based index of the row/example within the scenario outline.
5863
*/
59-
public function __construct($title, array $tags, $outlineSteps, array $tokens, $line, $outlineTitle = null)
64+
public function __construct($text, array $tags, $outlineSteps, array $tokens, $line, $outlineTitle = null, $index = null)
6065
{
61-
$this->title = $title;
66+
$this->text = $text;
6267
$this->tags = $tags;
6368
$this->outlineSteps = $outlineSteps;
6469
$this->tokens = $tokens;
6570
$this->line = $line;
6671
$this->outlineTitle = $outlineTitle;
72+
$this->index = $index;
6773
}
6874

6975
/**
@@ -87,13 +93,16 @@ public function getKeyword()
8793
}
8894

8995
/**
90-
* Returns example title.
96+
* Returns the example row as a single string.
9197
*
9298
* @return string
99+
*
100+
* @deprecated You should normally not depend on the original row text, but if you really do, please switch
101+
* to {@see self::getExampleText()} as this method will be removed in the next major version.
93102
*/
94103
public function getTitle()
95104
{
96-
return $this->title;
105+
return $this->text;
97106
}
98107

99108
/**
@@ -178,6 +187,23 @@ public function getOutlineTitle()
178187
return $this->outlineTitle;
179188
}
180189

190+
public function getName(): ?string
191+
{
192+
return "{$this->replaceTextTokens($this->outlineTitle)} #{$this->index}";
193+
}
194+
195+
/**
196+
* Returns the example row as a single string.
197+
*
198+
* You should normally not need this, since it is an implementation detail.
199+
* If you need the individual example values, use {@see self::getTokens()}.
200+
* To get the fully-normalised/expanded title, use {@see self::getName()}.
201+
*/
202+
public function getExampleText(): string
203+
{
204+
return $this->text;
205+
}
206+
181207
/**
182208
* Creates steps for this example from abstract outline steps.
183209
*
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace Behat\Gherkin\Node;
4+
5+
interface NamedScenarioInterface
6+
{
7+
/**
8+
* Returns the human-readable name of the scenario.
9+
*/
10+
public function getName(): ?string;
11+
}

src/Behat/Gherkin/Node/OutlineNode.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,8 @@ protected function createExamples()
236236
$this->getSteps(),
237237
$row,
238238
$exampleTable->getRowLine($rowNum + 1),
239-
$this->getTitle()
239+
$this->getTitle(),
240+
$rowNum + 1
240241
);
241242
}
242243
}

src/Behat/Gherkin/Node/ScenarioNode.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*
1616
* @author Konstantin Kudryashov <ever.zet@gmail.com>
1717
*/
18-
class ScenarioNode implements ScenarioInterface
18+
class ScenarioNode implements ScenarioInterface, NamedScenarioInterface
1919
{
2020
/**
2121
* @var string
@@ -70,12 +70,20 @@ public function getNodeType()
7070
* Returns scenario title.
7171
*
7272
* @return null|string
73+
*
74+
* @deprecated You should use {@see self::getName()} instead as this method will be removed in the next
75+
* major version.
7376
*/
7477
public function getTitle()
7578
{
7679
return $this->title;
7780
}
7881

82+
public function getName(): ?string
83+
{
84+
return $this->title;
85+
}
86+
7987
/**
8088
* Checks if scenario is tagged with tag.
8189
*

tests/Behat/Gherkin/Cache/FileCacheTest.php

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,23 @@
33
namespace Tests\Behat\Gherkin\Cache;
44

55
use Behat\Gherkin\Cache\FileCache;
6+
use Behat\Gherkin\Exception\CacheException;
7+
use Behat\Gherkin\Gherkin;
68
use Behat\Gherkin\Node\FeatureNode;
79
use Behat\Gherkin\Node\ScenarioNode;
8-
use Behat\Gherkin\Gherkin;
910
use PHPUnit\Framework\TestCase;
1011

1112
class FileCacheTest extends TestCase
1213
{
1314
private $path;
1415
private $cache;
1516

16-
public function testIsFreshWhenThereIsNoFile()
17+
public function testIsFreshWhenThereIsNoFile(): void
1718
{
1819
$this->assertFalse($this->cache->isFresh('unexisting', time() + 100));
1920
}
2021

21-
public function testIsFreshOnFreshFile()
22+
public function testIsFreshOnFreshFile(): void
2223
{
2324
$feature = new FeatureNode(null, null, array(), null, array(), null, null, null, null);
2425

@@ -27,7 +28,7 @@ public function testIsFreshOnFreshFile()
2728
$this->assertFalse($this->cache->isFresh('some_path', time() + 100));
2829
}
2930

30-
public function testIsFreshOnOutdated()
31+
public function testIsFreshOnOutdated(): void
3132
{
3233
$feature = new FeatureNode(null, null, array(), null, array(), null, null, null, null);
3334

@@ -36,7 +37,7 @@ public function testIsFreshOnOutdated()
3637
$this->assertTrue($this->cache->isFresh('some_path', time() - 100));
3738
}
3839

39-
public function testCacheAndRead()
40+
public function testCacheAndRead(): void
4041
{
4142
$scenarios = array(new ScenarioNode('Some scenario', array(), array(), null, null));
4243
$feature = new FeatureNode('Some feature', 'some description', array(), null, $scenarios, null, null, null, null);
@@ -47,19 +48,23 @@ public function testCacheAndRead()
4748
$this->assertEquals($feature, $featureRead);
4849
}
4950

50-
public function testBrokenCacheRead()
51+
public function testBrokenCacheRead(): void
5152
{
52-
$this->expectException('Behat\Gherkin\Exception\CacheException');
53+
$this->expectException(CacheException::class);
5354

5455
touch($this->path . '/v' . Gherkin::VERSION . '/' . md5('broken_feature') . '.feature.cache');
5556
$this->cache->read('broken_feature');
5657
}
5758

58-
public function testUnwriteableCacheDir()
59+
public function testUnwriteableCacheDir(): void
5960
{
60-
$this->expectException('Behat\Gherkin\Exception\CacheException');
61+
$this->expectException(CacheException::class);
6162

62-
new FileCache('/dev/null/gherkin-test');
63+
if (PHP_OS_FAMILY === 'Windows') {
64+
new FileCache('C:\\Windows\\System32\\drivers\\etc');
65+
} else {
66+
new FileCache('/dev/null/gherkin-test');
67+
}
6368
}
6469

6570
protected function setUp(): void

tests/Behat/Gherkin/Node/OutlineNodeTest.php

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22

33
namespace Tests\Behat\Gherkin\Node;
44

5+
use Behat\Gherkin\Node\ExampleNode;
56
use Behat\Gherkin\Node\ExampleTableNode;
67
use Behat\Gherkin\Node\OutlineNode;
78
use Behat\Gherkin\Node\StepNode;
89
use PHPUnit\Framework\TestCase;
910

1011
class OutlineNodeTest extends TestCase
1112
{
12-
public function testCreatesExamplesForExampleTable()
13+
public function testCreatesExamplesForExampleTable(): void
1314
{
1415
$steps = array(
1516
new StepNode('Gangway!', 'I am <name>', array(), null, 'Given'),
@@ -33,7 +34,7 @@ public function testCreatesExamplesForExampleTable()
3334
$this->assertEquals(array('name' => 'example', 'email' => 'example@example.com'), $examples[1]->getTokens());
3435
}
3536

36-
public function testCreatesExamplesForExampleTableWithSeveralExamplesAndTags()
37+
public function testCreatesExamplesForExampleTableWithSeveralExamplesAndTags(): void
3738
{
3839
$steps = array(
3940
new StepNode('Gangway!', 'I am <name>', array(), null, 'Given'),
@@ -79,7 +80,7 @@ public function testCreatesExamplesForExampleTableWithSeveralExamplesAndTags()
7980
}
8081
}
8182

82-
public function testCreatesEmptyExamplesForEmptyExampleTable()
83+
public function testCreatesEmptyExamplesForEmptyExampleTable(): void
8384
{
8485
$steps = array(
8586
new StepNode('Gangway!', 'I am <name>', array(), null, 'Given'),
@@ -94,10 +95,10 @@ public function testCreatesEmptyExamplesForEmptyExampleTable()
9495

9596
$outline = new OutlineNode(null, array(), $steps, $table, null, null);
9697

97-
$this->assertCount(0, $examples = $outline->getExamples());
98+
$this->assertCount(0, $outline->getExamples());
9899
}
99100

100-
public function testCreatesEmptyExamplesForNoExampleTable()
101+
public function testCreatesEmptyExamplesForNoExampleTable(): void
101102
{
102103
$steps = array(
103104
new StepNode('Gangway!', 'I am <name>', array(), null, 'Given'),
@@ -110,10 +111,10 @@ public function testCreatesEmptyExamplesForNoExampleTable()
110111

111112
$outline = new OutlineNode(null, array(), $steps, array($table), null, null);
112113

113-
$this->assertCount(0, $examples = $outline->getExamples());
114+
$this->assertCount(0, $outline->getExamples());
114115
}
115116

116-
public function testPopulatesExampleWithOutlineTitle()
117+
public function testPopulatesExampleWithOutlineTitle(): void
117118
{
118119
$steps = array(
119120
new StepNode('', 'I am <name>', array(), null, 'Given'),
@@ -122,11 +123,37 @@ public function testPopulatesExampleWithOutlineTitle()
122123
$table = new ExampleTableNode(array(
123124
10 => array('name', 'email'),
124125
11 => array('Ciaran', 'ciaran@example.com'),
126+
12 => array('John', 'john@example.com'),
125127
), 'Examples');
126128

127-
$outline = new OutlineNode('An outline title', array(), $steps, $table, null, null);
128-
129-
$this->assertCount(1, $examples = $outline->getExamples());
130-
$this->assertEquals('An outline title', current($examples)->getOutlineTitle());
129+
$outline = new OutlineNode('An outline title for <name>', array(), $steps, $table, null, null);
130+
131+
$this->assertSame(
132+
[
133+
[
134+
'getName' => 'An outline title for Ciaran #1',
135+
'getTitle' => '| Ciaran | ciaran@example.com |',
136+
'getOutlineTitle' => 'An outline title for <name>',
137+
'getExampleText' => '| Ciaran | ciaran@example.com |',
138+
],
139+
[
140+
'getName' => 'An outline title for John #2',
141+
'getTitle' => '| John | john@example.com |',
142+
'getOutlineTitle' => 'An outline title for <name>',
143+
'getExampleText' => '| John | john@example.com |',
144+
],
145+
],
146+
array_map(
147+
static function (ExampleNode $node) {
148+
return [
149+
'getName' => $node->getName(),
150+
'getTitle' => $node->getTitle(),
151+
'getOutlineTitle' => $node->getOutlineTitle(),
152+
'getExampleText' => $node->getExampleText(),
153+
];
154+
},
155+
$outline->getExamples()
156+
)
157+
);
131158
}
132159
}

0 commit comments

Comments
 (0)