Skip to content

Commit aab8ded

Browse files
committed
Merge pull request #641 from stof/escape_named_selector
Moved the escaping of the xpath locator to the NamedSelector
2 parents 1125c2f + e238faa commit aab8ded

File tree

12 files changed

+67
-39
lines changed

12 files changed

+67
-39
lines changed

driver-testsuite/tests/Form/SelectTest.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,7 @@ public function testElementSelectedStateCheck($selectName, $optionValue, $option
6666
$session->visit($this->pathTo('/multiselect_form.html'));
6767
$select = $webAssert->fieldExists($selectName);
6868

69-
$optionValueEscaped = $session->getSelectorsHandler()->xpathLiteral($optionValue);
70-
$option = $webAssert->elementExists('named', array('option', $optionValueEscaped));
69+
$option = $webAssert->elementExists('named', array('option', $optionValue));
7170

7271
$this->assertFalse($option->isSelected());
7372
$select->selectOption($optionText);

driver-testsuite/tests/TestCase.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,6 @@ protected function getAssertSession()
102102
*/
103103
protected function findById($id)
104104
{
105-
$id = $this->getSession()->getSelectorsHandler()->xpathLiteral($id);
106-
107105
return $this->getAssertSession()->elementExists('named', array('id', $id));
108106
}
109107

src/Element/DocumentElement.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@ public function getContent()
4646
*/
4747
public function hasContent($content)
4848
{
49-
return $this->has('named', array(
50-
'content', $this->getSelectorsHandler()->xpathLiteral($content),
51-
));
49+
return $this->has('named', array('content', $content));
5250
}
5351
}

src/Element/Element.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ protected function getDriver()
8585
* Returns selectors handler.
8686
*
8787
* @return SelectorsHandler
88+
*
89+
* @deprecated Accessing the selectors handler in the element is deprecated as of 1.7 and will be impossible in 2.0.
8890
*/
8991
protected function getSelectorsHandler()
9092
{
@@ -156,7 +158,7 @@ public function findAll($selector, $locator)
156158
return $items;
157159
}
158160

159-
$xpath = $this->getSelectorsHandler()->selectorToXpath($selector, $locator);
161+
$xpath = $this->selectorsHandler->selectorToXpath($selector, $locator);
160162
$xpath = $this->xpathManipulator->prepend($xpath, $this->getXpath());
161163

162164
return $this->getDriver()->find($xpath);

src/Element/NodeElement.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -228,9 +228,7 @@ public function selectOption($option, $multiple = false)
228228
return;
229229
}
230230

231-
$opt = $this->find('named', array(
232-
'option', $this->getSelectorsHandler()->xpathLiteral($option),
233-
));
231+
$opt = $this->find('named', array('option', $option));
234232

235233
if (null === $opt) {
236234
throw $this->elementNotFound('select option', 'value|text', $option);

src/Element/TraversableElement.php

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@ abstract class TraversableElement extends Element
2828
*/
2929
public function findById($id)
3030
{
31-
$id = $this->getSelectorsHandler()->xpathLiteral($id);
32-
3331
return $this->find('named', array('id', $id));
3432
}
3533

@@ -54,9 +52,7 @@ public function hasLink($locator)
5452
*/
5553
public function findLink($locator)
5654
{
57-
return $this->find('named', array(
58-
'link', $this->getSelectorsHandler()->xpathLiteral($locator),
59-
));
55+
return $this->find('named', array('link', $locator));
6056
}
6157

6258
/**
@@ -98,9 +94,7 @@ public function hasButton($locator)
9894
*/
9995
public function findButton($locator)
10096
{
101-
return $this->find('named', array(
102-
'button', $this->getSelectorsHandler()->xpathLiteral($locator),
103-
));
97+
return $this->find('named', array('button', $locator));
10498
}
10599

106100
/**
@@ -142,9 +136,7 @@ public function hasField($locator)
142136
*/
143137
public function findField($locator)
144138
{
145-
return $this->find('named', array(
146-
'field', $this->getSelectorsHandler()->xpathLiteral($locator),
147-
));
139+
return $this->find('named', array('field', $locator));
148140
}
149141

150142
/**
@@ -245,9 +237,7 @@ public function uncheckField($locator)
245237
*/
246238
public function hasSelect($locator)
247239
{
248-
return $this->has('named', array(
249-
'select', $this->getSelectorsHandler()->xpathLiteral($locator),
250-
));
240+
return $this->has('named', array('select', $locator));
251241
}
252242

253243
/**
@@ -281,9 +271,7 @@ public function selectFieldOption($locator, $value, $multiple = false)
281271
*/
282272
public function hasTable($locator)
283273
{
284-
return $this->has('named', array(
285-
'table', $this->getSelectorsHandler()->xpathLiteral($locator),
286-
));
274+
return $this->has('named', array('table', $locator));
287275
}
288276

289277
/**

src/Selector/NamedSelector.php

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
namespace Behat\Mink\Selector;
1212

13+
use Behat\Mink\Selector\Xpath\Escaper;
14+
1315
/**
1416
* Named selectors engine. Uses registered XPath selectors to create new expressions.
1517
*
@@ -157,12 +159,15 @@ class NamedSelector implements SelectorInterface
157159
.//*[%idOrNameMatch%]
158160
XPATH
159161
);
162+
private $xpathEscaper;
160163

161164
/**
162165
* Creates selector instance.
163166
*/
164167
public function __construct()
165168
{
169+
$this->xpathEscaper = new Escaper();
170+
166171
foreach ($this->replacements as $from => $to) {
167172
$this->replacements[$from] = strtr($to, $this->replacements);
168173
}
@@ -217,7 +222,7 @@ public function translateToXPath($locator)
217222
$xpath = $this->selectors[$selector];
218223

219224
if (null !== $locator) {
220-
$xpath = strtr($xpath, array('%locator%' => $locator));
225+
$xpath = strtr($xpath, array('%locator%' => $this->escapeLocator($locator)));
221226
}
222227

223228
return $xpath;
@@ -235,4 +240,24 @@ protected function registerReplacement($from, $to)
235240
{
236241
$this->replacements[$from] = $to;
237242
}
243+
244+
private function escapeLocator($locator)
245+
{
246+
// If the locator looks like an escaped one, don't escape it again for BC reasons.
247+
if (
248+
preg_match('/^\'[^\']*+\'$/', $locator)
249+
|| (false !== strpos($locator, '\'') && preg_match('/^"[^"]*+"$/', $locator))
250+
|| ((8 < $length = strlen($locator)) && 'concat(' === substr($locator, 0, 7) && ')' === $locator[$length - 1])
251+
) {
252+
trigger_error(
253+
'Passing an excaped locator to the named selector is deprecated as of 1.7 and will be removed in 2.0.'
254+
.' Pass the raw value instead.',
255+
E_USER_DEPRECATED
256+
);
257+
258+
return $locator;
259+
}
260+
261+
return $this->xpathEscaper->escapeLiteral($locator);
262+
}
238263
}

src/Selector/SelectorsHandler.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,22 @@ public function selectorToXpath($selector, $locator)
114114
/**
115115
* Translates string to XPath literal.
116116
*
117+
* @deprecated since Mink 1.7. Use \Behat\Mink\Selector\Xpath\Escaper::escapeLiteral when building Xpath
118+
* or pass the unescaped value when using the named selector.
119+
*
117120
* @param string $s
118121
*
119122
* @return string
120123
*/
121124
public function xpathLiteral($s)
122125
{
126+
trigger_error(
127+
'The '.__METHOD__.' method is deprecated as of 1.7 and will be removed in 2.0.'
128+
.' Use \Behat\Mink\Selector\Xpath\Escaper::escapeLiteral instead when building Xpath'
129+
.' or pass the unescaped value when using the named selector.',
130+
E_USER_DEPRECATED
131+
);
132+
123133
return $this->escaper->escapeLiteral($s);
124134
}
125135
}

tests/Element/ElementTest.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,6 @@ protected function setUp()
3636

3737
$this->selectors = $this->getMockBuilder('Behat\Mink\Selector\SelectorsHandler')->getMock();
3838
$this->session = new Session($this->driver, $this->selectors);
39-
40-
$this->selectors
41-
->expects($this->any())
42-
->method('xpathLiteral')
43-
->will($this->returnArgument(0));
4439
}
4540

4641
protected function mockNamedFinder($xpath, array $results, $locator, $times = 2)

tests/Selector/NamedSelectorTest.php

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
namespace Behat\Mink\Tests\Selector;
44

55
use Behat\Mink\Selector\NamedSelector;
6-
use Behat\Mink\Selector\SelectorsHandler;
6+
use Behat\Mink\Selector\Xpath\Escaper;
77

88
abstract class NamedSelectorTest extends \PHPUnit_Framework_TestCase
99
{
@@ -42,10 +42,6 @@ public function testSelectors($fixtureFile, $selector, $locator, $expectedExactC
4242
$dom = new \DOMDocument('1.0', 'UTF-8');
4343
$dom->loadHTML(file_get_contents(__DIR__.'/fixtures/'.$fixtureFile));
4444

45-
// Escape the locator as Mink 1.x expects the caller of the NamedSelector to handle it
46-
$selectorsHandler = new SelectorsHandler();
47-
$locator = $selectorsHandler->xpathLiteral($locator);
48-
4945
$namedSelector = $this->getSelector();
5046

5147
$xpath = $namedSelector->translateToXPath(array($selector, $locator));
@@ -56,6 +52,20 @@ public function testSelectors($fixtureFile, $selector, $locator, $expectedExactC
5652
$this->assertEquals($expectedCount, $nodeList->length);
5753
}
5854

55+
/**
56+
* @dataProvider getSelectorTests
57+
*/
58+
public function testEscapedSelectors($fixtureFile, $selector, $locator, $expectedExactCount, $expectedPartialCount = null)
59+
{
60+
// Escape the locator as Mink 1.x expects the caller of the NamedSelector to handle it
61+
$escaper = new Escaper();
62+
$locator = $escaper->escapeLiteral($locator);
63+
64+
$this->iniSet('error_reporting', -1 & ~E_USER_DEPRECATED);
65+
66+
$this->testSelectors($fixtureFile, $selector, $locator, $expectedExactCount, $expectedPartialCount);
67+
}
68+
5969
public function getSelectorTests()
6070
{
6171
$fieldCount = 8; // fields without `type` attribute
@@ -122,6 +132,7 @@ public function getSelectorTests()
122132

123133
// 3 matches, because matches every HTML node in path: html > body > div
124134
'content' => array('test.html', 'content', 'content-text', 1, 4),
135+
'content with quotes' => array('test.html', 'content', 'some "quoted" content', 1, 3),
125136

126137
'select (name/label)' => array('test.html', 'select', 'the-field', 3),
127138
'select (with-id)' => array('test.html', 'select', 'the-field-select', 1),

0 commit comments

Comments
 (0)