Skip to content

Commit

Permalink
fix could not find node with given id
Browse files Browse the repository at this point in the history
  • Loading branch information
Seriyyy95 committed Apr 23, 2024
1 parent dc463f0 commit df56311
Show file tree
Hide file tree
Showing 12 changed files with 168 additions and 16 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ composer.lock
phpstan.neon
phpunit.xml
vendor
.idea

4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
],
"require": {
"php": "^7.4.15 || ^8.0.2",
"chrome-php/wrench": "^1.6",
"chrome-php/wrench": "^1.7",
"evenement/evenement": "^3.0.1",
"monolog/monolog": "^1.27.1 || ^2.8 || ^3.2",
"psr/log": "^1.1 || ^2.0 || ^3.0",
Expand Down Expand Up @@ -46,6 +46,8 @@
},
"preferred-install": "dist"
},
"minimum-stability": "dev",
"prefer-stable": true,
"extra": {
"bamarni-bin": {
"bin-links": true,
Expand Down
9 changes: 9 additions & 0 deletions src/Communication/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,15 @@ public function readLine()
return false;
}

public function processAllEvents(): void
{
$hasData = $this->wsClient->waitForData(0);

if ($hasData) {
$this->receiveData();
}
}

/**
* Dispatches the message and either stores the response or emits an event.
*
Expand Down
7 changes: 7 additions & 0 deletions src/Communication/Socket/MockSocket.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,11 @@ public function disconnect($reason = 1000)

return true;
}

public function waitForData(float $maxSeconds): bool
{
// TODO: Implement wait if needed.

return !empty($this->receivedData);
}
}
2 changes: 2 additions & 0 deletions src/Communication/Socket/SocketInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,6 @@ public function isConnected();
* @return bool
*/
public function disconnect($reason = 1000);

public function waitForData(float $maxSeconds): bool;
}
5 changes: 5 additions & 0 deletions src/Communication/Socket/Wrench.php
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,9 @@ public function disconnect($reason = 1000)

return $disconnected;
}

public function waitForData(float $maxSeconds): bool
{
return $this->client->waitForData($maxSeconds);
}
}
26 changes: 22 additions & 4 deletions src/Dom/Dom.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@ class Dom extends Node
{
public function __construct(Page $page)
{
$message = new Message('DOM.getDocument');
$response = $page->getSession()->sendMessageSync($message);

$rootNodeId = $response->getResultData('root')['nodeId'];
$rootNodeId = $this->getRootNodeId($page);

parent::__construct($page, $rootNodeId);
}
Expand All @@ -24,6 +21,8 @@ public function __construct(Page $page)
*/
public function search(string $selector): array
{
$this->prepareForRequest();

$message = new Message('DOM.performSearch', [
'query' => $selector,
]);
Expand Down Expand Up @@ -55,4 +54,23 @@ public function search(string $selector): array

return $nodes;
}

public function prepareForRequest(bool $throw = true)
{
$this->page->assertNotClosed();

$this->page->getSession()->getConnection()->processAllEvents();

if ($this->isStale) {
$this->nodeId = $this->getRootNodeId($this->page);
}
}

public function getRootNodeId(Page $page)
{
$message = new Message('DOM.getDocument');
$response = $page->getSession()->sendMessageSync($message);

return $response->getResultData('root')['nodeId'];
}
}
53 changes: 43 additions & 10 deletions src/Dom/Node.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use HeadlessChromium\Communication\Message;
use HeadlessChromium\Communication\Response;
use HeadlessChromium\Exception\DomException;
use HeadlessChromium\Exception\StaleElementException;
use HeadlessChromium\Page;

class Node
Expand All @@ -21,16 +22,37 @@ class Node
*/
protected $nodeId;

/**
* @var bool
*/
protected bool $isStale = false;

public function __construct(Page $page, int $nodeId)
{
$this->page = $page;
$this->nodeId = $nodeId;

$page->getSession()->on('method:DOM.documentUpdated', function (...$event) {
$this->isStale = true;
});
}

public function getNodeId(): int
{
return $this->nodeId;
}

public function getNodeIdForRequest(): int
{
$this->prepareForRequest();

return $this->getNodeId();
}

public function getAttributes(): NodeAttributes
{
$message = new Message('DOM.getAttributes', [
'nodeId' => $this->nodeId,
'nodeId' => $this->getNodeIdForRequest(),
]);
$response = $this->page->getSession()->sendMessageSync($message);

Expand All @@ -44,7 +66,7 @@ public function getAttributes(): NodeAttributes
public function setAttributeValue(string $name, string $value): void
{
$message = new Message('DOM.setAttributeValue', [
'nodeId' => $this->nodeId,
'nodeId' => $this->getNodeIdForRequest(),
'name' => $name,
'value' => $value,
]);
Expand All @@ -56,7 +78,7 @@ public function setAttributeValue(string $name, string $value): void
public function querySelector(string $selector): ?self
{
$message = new Message('DOM.querySelector', [
'nodeId' => $this->nodeId,
'nodeId' => $this->getNodeIdForRequest(),
'selector' => $selector,
]);
$response = $this->page->getSession()->sendMessageSync($message);
Expand All @@ -74,7 +96,7 @@ public function querySelector(string $selector): ?self
public function querySelectorAll(string $selector): array
{
$message = new Message('DOM.querySelectorAll', [
'nodeId' => $this->nodeId,
'nodeId' => $this->getNodeIdForRequest(),
'selector' => $selector,
]);
$response = $this->page->getSession()->sendMessageSync($message);
Expand All @@ -93,7 +115,7 @@ public function querySelectorAll(string $selector): array
public function focus(): void
{
$message = new Message('DOM.focus', [
'nodeId' => $this->nodeId,
'nodeId' => $this->getNodeIdForRequest(),
]);
$response = $this->page->getSession()->sendMessageSync($message);

Expand All @@ -108,7 +130,7 @@ public function getAttribute(string $name): ?string
public function getPosition(): ?NodePosition
{
$message = new Message('DOM.getBoxModel', [
'nodeId' => $this->nodeId,
'nodeId' => $this->getNodeIdForRequest(),
]);
$response = $this->page->getSession()->sendMessageSync($message);

Expand All @@ -131,7 +153,7 @@ public function hasPosition(): bool
public function getHTML(): string
{
$message = new Message('DOM.getOuterHTML', [
'nodeId' => $this->nodeId,
'nodeId' => $this->getNodeIdForRequest(),
]);
$response = $this->page->getSession()->sendMessageSync($message);

Expand All @@ -143,7 +165,7 @@ public function getHTML(): string
public function setHTML(string $outerHTML): void
{
$message = new Message('DOM.setOuterHTML', [
'nodeId' => $this->nodeId,
'nodeId' => $this->getNodeIdForRequest(),
'outerHTML' => $outerHTML,
]);
$response = $this->page->getSession()->sendMessageSync($message);
Expand All @@ -159,7 +181,7 @@ public function getText(): string
public function scrollIntoView(): void
{
$message = new Message('DOM.scrollIntoViewIfNeeded', [
'nodeId' => $this->nodeId,
'nodeId' => $this->getNodeIdForRequest(),
]);
$response = $this->page->getSession()->sendMessageSync($message);

Expand Down Expand Up @@ -198,7 +220,7 @@ public function sendFiles(array $filePaths): void
{
$message = new Message('DOM.setFileInputFiles', [
'files' => $filePaths,
'nodeId' => $this->nodeId,
'nodeId' => $this->getNodeIdForRequest(),
]);
$response = $this->page->getSession()->sendMessageSync($message);

Expand All @@ -214,4 +236,15 @@ public function assertNotError(Response $response): void
throw new DOMException($response->getErrorMessage());
}
}

protected function prepareForRequest()
{
$this->page->assertNotClosed();

$this->page->getSession()->getConnection()->processAllEvents();

if ($this->isStale) {
throw new StaleElementException();
}
}
}
8 changes: 8 additions & 0 deletions src/Exception/StaleElementException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace HeadlessChromium\Exception;

class StaleElementException extends DomException
{

}
13 changes: 12 additions & 1 deletion src/Page.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ class Page
*/
protected $keyboard;

/**
* @var Dom|null
*/
protected $dom = null;

/**
* Page constructor.
*
Expand Down Expand Up @@ -807,7 +812,13 @@ public function keyboard()

public function dom(): Dom
{
return new Dom($this);
$this->assertNotClosed();

if ($this->dom === null) {
$this->dom = new Dom($this);
}

return $this->dom;
}

/**
Expand Down
53 changes: 53 additions & 0 deletions tests/DomTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use HeadlessChromium\Browser;
use HeadlessChromium\BrowserFactory;
use HeadlessChromium\Exception\StaleElementException;

/**
* @covers \HeadlessChromium\Dom\Dom
Expand Down Expand Up @@ -187,4 +188,56 @@ public function testSetHTML(): void

self::assertEquals('<span id="span">hello</span>', $value);
}

public function testDomDoesReturnsTheSameObject(): void
{
$page = $this->openSitePage('domForm.html');

$firstDom = $page->dom();

$element = $firstDom->querySelector('#myinput');

$secondDom = $page->dom();

$element->focus();

$this->assertEquals($firstDom, $secondDom);
}

public function testRootNodeIdIsUpdatedAfterReload(): void
{
$page = $this->openSitePage('domForm.html');

$dom = $page->dom();

$nodeId = $dom->getNodeId();

$reloadBtn = $dom->querySelector('#reload-btn');
$reloadBtn->click();

$page->waitForReload();

$reloadBtn = $dom->querySelector('#reload-btn');
$this->assertNotNull($reloadBtn);

$this->assertNotEquals($nodeId, $page->dom()->getNodeId());
}

public function testRegularNodeIsMarkedAsStaleAfterReload(): void
{
$page = $this->openSitePage('domForm.html');

$dom = $page->dom();

$inputNode = $dom->querySelector('#myinput');

$reloadBtn = $dom->querySelector('#reload-btn');
$reloadBtn->click();

$page->waitForReload();

$this->expectException(StaleElementException::class);

$inputNode->sendKeys('test');
}
}
2 changes: 2 additions & 0 deletions tests/resources/static-web/domForm.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@ <h1>Form</h1>
<div id="div1" type="foo">bar</div>
<div id="div2"></div>

<button id="reload-btn" onclick="location.reload()">Reload</button>

</body>
</html>

0 comments on commit df56311

Please sign in to comment.