From 51fef3bc57a3e4308b14a9109e1c2fac1741ad0d Mon Sep 17 00:00:00 2001 From: divinity76 Date: Fri, 23 May 2025 21:36:04 +0200 Subject: [PATCH 1/8] fix missing encoding in CssSelector.php CSS Selector expressions are not properly encoded, for example input[type="password"] is a perfectly valid CSS selector, and $page->mouse()->find('input[type="password"]') should have worked, but it generate a javascript syntax error at runtime: ``` document.querySelectorAll("input[name="email"]").length ``` resulting in PHP Fatal error: Uncaught HeadlessChromium\Exception\ElementNotFoundException: The search for "document.querySelectorAll("input[name="email"]").length" returned no result. in /home/hans/projects/tryparrotai-unofficial-api/vendor/chrome-php/chrome/src/Input/Mouse.php:302 Stack trace: #0 /home/hans/projects/tryparrotai-unofficial-api/vendor/chrome-php/chrome/src/Input/Mouse.php(269): HeadlessChromium\Input\Mouse->findElement() Exactly the same issue as https://github.com/chrome-php/chrome/pull/576 --- src/Dom/Selector/CssSelector.php | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/Dom/Selector/CssSelector.php b/src/Dom/Selector/CssSelector.php index 26b518f5..a5723a64 100644 --- a/src/Dom/Selector/CssSelector.php +++ b/src/Dom/Selector/CssSelector.php @@ -19,11 +19,32 @@ public function __construct(string $expression) public function expressionCount(): string { - return \sprintf('document.querySelectorAll("%s").length', $this->expression); + $encodedExpr = \json_encode( + $this->expression, + \JSON_UNESCAPED_SLASHES + | \JSON_UNESCAPED_UNICODE + | \JSON_THROW_ON_ERROR + ); + + return \sprintf( + 'document.querySelectorAll(%s).length', + $encodedExpr + ); } public function expressionFindOne(int $position): string { - return \sprintf('document.querySelectorAll("%s")[%d]', $this->expression, $position - 1); + $encodedExpr = \json_encode( + $this->expression, + \JSON_UNESCAPED_SLASHES + | \JSON_UNESCAPED_UNICODE + | \JSON_THROW_ON_ERROR + ); + + return \sprintf( + 'document.querySelectorAll(%s)[%d]', + $encodedExpr, + $position - 1 + ); } } From 2c7a59c258b25cbbcc69aebee37433128b583dad Mon Sep 17 00:00:00 2001 From: divinity76 Date: Fri, 23 May 2025 22:16:18 +0200 Subject: [PATCH 2/8] update testcase.. --- tests/PageTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/PageTest.php b/tests/PageTest.php index 68953ed5..a83db8d5 100644 --- a/tests/PageTest.php +++ b/tests/PageTest.php @@ -21,7 +21,7 @@ */ class PageTest extends BaseTestCase { - private const WAIT_FOR_ELEMENT_HTML = '
content
'; + private const WAIT_FOR_ELEMENT_HTML = '
content
'; private const WAIT_FOR_ELEMENT_RESOURCE_FILE = 'elementLoad.html'; public function testSetViewport(): void @@ -441,7 +441,9 @@ public function testWaitUntilContainsElement(): void self::assertStringNotContainsString(self::WAIT_FOR_ELEMENT_HTML, $page->getHtml()); - $page->waitUntilContainsElement('div[data-name=\"el\"]'); + $page->waitUntilContainsElement('div[data-name="el"]'); // search for
+ $page->waitUntilContainsElement('div[data-name=el]'); // search for
+ $page->waitUntilContainsElement('div[data-name=\"el\"]'); // search for
content
'; + private const WAIT_FOR_ELEMENT_HTML = '
content1
content2
'; private const WAIT_FOR_ELEMENT_RESOURCE_FILE = 'elementLoad.html'; public function testSetViewport(): void @@ -445,7 +445,9 @@ public function testWaitUntilContainsElement(): void $page->waitUntilContainsElement('div[data-name=el]'); // search for
$page->waitUntilContainsElement('div[data-name=\"el\"]'); // search for
page a el.innerHTML = 'content'; document.body.appendChild(el) + + let el2 = document.createElement('div'); + + el2.dataset.name = '"el"'; + el2.innerHTML = 'content'; + document.body.appendChild(el2) }, 500) From cdc0df77148e41c1e44533bf87412b7e484d6d8d Mon Sep 17 00:00:00 2001 From: divinity76 Date: Fri, 23 May 2025 22:32:13 +0200 Subject: [PATCH 4/8] StyleCI --- tests/PageTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/PageTest.php b/tests/PageTest.php index 50dd5aa0..67419f13 100644 --- a/tests/PageTest.php +++ b/tests/PageTest.php @@ -445,9 +445,9 @@ public function testWaitUntilContainsElement(): void $page->waitUntilContainsElement('div[data-name=el]'); // search for
$page->waitUntilContainsElement('div[data-name=\"el\"]'); // search for
getHtml(), [ + '"' => '"', + ])); } public function testWaitUntilContainsElementByXPath(): void From ddbec799cff303f07b7c7526b6fbec52765b8449 Mon Sep 17 00:00:00 2001 From: divinity76 Date: Fri, 23 May 2025 22:32:56 +0200 Subject: [PATCH 5/8] StyleCI --- tests/PageTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/PageTest.php b/tests/PageTest.php index 67419f13..88d4dfab 100644 --- a/tests/PageTest.php +++ b/tests/PageTest.php @@ -446,8 +446,8 @@ public function testWaitUntilContainsElement(): void $page->waitUntilContainsElement('div[data-name=\"el\"]'); // search for
'"', + ])); } public function testWaitUntilContainsElementByXPath(): void From aa654a5cce96d6faaa45be754ad938d372c09058 Mon Sep 17 00:00:00 2001 From: divinity76 Date: Fri, 23 May 2025 22:36:51 +0200 Subject: [PATCH 6/8] testacse --- tests/PageTest.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/PageTest.php b/tests/PageTest.php index 88d4dfab..57769b0c 100644 --- a/tests/PageTest.php +++ b/tests/PageTest.php @@ -445,9 +445,7 @@ public function testWaitUntilContainsElement(): void $page->waitUntilContainsElement('div[data-name=el]'); // search for
$page->waitUntilContainsElement('div[data-name=\"el\"]'); // search for
getHtml()); } public function testWaitUntilContainsElementByXPath(): void From 58c967a43be556372818a2d3ceb6bd0ffcb125d4 Mon Sep 17 00:00:00 2001 From: divinity76 Date: Fri, 23 May 2025 22:40:30 +0200 Subject: [PATCH 7/8] testcase --- tests/resources/static-web/elementLoad.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/resources/static-web/elementLoad.html b/tests/resources/static-web/elementLoad.html index f236547b..5a080daa 100644 --- a/tests/resources/static-web/elementLoad.html +++ b/tests/resources/static-web/elementLoad.html @@ -11,14 +11,14 @@

page a

let el = document.createElement('div'); el.dataset.name = 'el'; - el.innerHTML = 'content'; + el.innerHTML = 'content1'; document.body.appendChild(el) let el2 = document.createElement('div'); el2.dataset.name = '"el"'; - el2.innerHTML = 'content'; + el2.innerHTML = 'content2'; document.body.appendChild(el2) }, 500) From a9cee6ef218f76c5025c8df0a3e73237dceeefbf Mon Sep 17 00:00:00 2001 From: divinity76 Date: Mon, 26 May 2025 17:04:39 +0200 Subject: [PATCH 8/8] nit --- src/Dom/Selector/CssSelector.php | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/src/Dom/Selector/CssSelector.php b/src/Dom/Selector/CssSelector.php index a5723a64..0fcf7ed6 100644 --- a/src/Dom/Selector/CssSelector.php +++ b/src/Dom/Selector/CssSelector.php @@ -10,40 +10,31 @@ final class CssSelector implements Selector { /** @var string */ - private $expression; + private $expressionEncoded; public function __construct(string $expression) { - $this->expression = $expression; - } - - public function expressionCount(): string - { - $encodedExpr = \json_encode( - $this->expression, + $this->expressionEncoded = \json_encode( + $expression, \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE | \JSON_THROW_ON_ERROR ); + } + public function expressionCount(): string + { return \sprintf( 'document.querySelectorAll(%s).length', - $encodedExpr + $this->expressionEncoded ); } public function expressionFindOne(int $position): string { - $encodedExpr = \json_encode( - $this->expression, - \JSON_UNESCAPED_SLASHES - | \JSON_UNESCAPED_UNICODE - | \JSON_THROW_ON_ERROR - ); - return \sprintf( 'document.querySelectorAll(%s)[%d]', - $encodedExpr, + $this->expressionEncoded, $position - 1 ); }