Skip to content

Commit 9bde8b0

Browse files
committed
add Actions and Extensions; refactor Capabilities
1 parent 7c619a7 commit 9bde8b0

19 files changed

+1320
-140
lines changed

lib/WebDriver/Actions.php

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
<?php
2+
3+
/**
4+
* @copyright 2025 Anthon Pang
5+
* @license Apache-2.0
6+
*
7+
* @author Anthon Pang <apang@softwaredevelopment.ca>
8+
*/
9+
10+
namespace WebDriver;
11+
12+
/**
13+
* WebDriver\Actions class
14+
*/
15+
class Actions extends AbstractWebDriver
16+
{
17+
/**
18+
* singleton
19+
*
20+
* @var \WebDriver\Actions
21+
*/
22+
private static $instance;
23+
24+
/**
25+
* @var array
26+
*/
27+
private $inputSources = [
28+
NullInput::TYPE => [],
29+
KeyInput::TYPE => [],
30+
PointerInput::TYPE => [],
31+
WheelInput::TYPE => [],
32+
];
33+
34+
/**
35+
* @var array
36+
*/
37+
private $actions;
38+
39+
/**
40+
* {@inheritdoc}
41+
*/
42+
private function __construct($url)
43+
{
44+
parent::__construct($url);
45+
46+
$this->clearAllActions();
47+
}
48+
49+
/**
50+
* Get singleton instance
51+
*
52+
* @param string $url
53+
*
54+
* @return \WebDriver\Actions
55+
*/
56+
public static function getInstance($url)
57+
{
58+
if (self::$instance === null) {
59+
self::$instance = new self($url);
60+
}
61+
62+
return self::$instance;
63+
}
64+
65+
/**
66+
* Get Null Input Source
67+
*
68+
* @return \WebDriver\NullInput
69+
*/
70+
public function getNullInput($id = 0)
71+
{
72+
if (! array_key_exists($id, $this->inputSources[NullInput::TYPE])) {
73+
$inputSource = new NullInput($id);
74+
75+
$this->inputSources[NullInput::TYPE][$id] = $inputSource;
76+
}
77+
78+
return $this->inputSources[NullInput::TYPE][$id];
79+
}
80+
81+
/**
82+
* Get Key Input Source
83+
*
84+
* @return \WebDriver\KeyInput
85+
*/
86+
public function getKeyInput($id = 0)
87+
{
88+
if (! array_key_exists($id, $this->inputSources[KeyInput::TYPE])) {
89+
$inputSource = new KeyInput($id);
90+
91+
$this->inputSources[KeyInput::TYPE][$id] = $inputSource;
92+
}
93+
94+
return $this->inputSources[KeyInput::TYPE][$id];
95+
}
96+
97+
/**
98+
* Get Pointer Input Source
99+
*
100+
* @return \WebDriver\PointerInput
101+
*/
102+
public function getPointerInput($id = 0, $subType = PointerInput::MOUSE)
103+
{
104+
if (! array_key_exists($id, $this->inputSources[PointerInput::TYPE])) {
105+
$inputSource = new PointerInput($id, $subType);
106+
107+
$this->inputSources[PointerInput::TYPE][$id] = $inputSource;
108+
}
109+
110+
return $this->inputSources[PointerInput::TYPE][$id];
111+
}
112+
113+
/**
114+
* Get Wheel Input Source
115+
*
116+
* @return \WebDriver\WheelInput
117+
*/
118+
public function getWheelInput($id = 0)
119+
{
120+
if (! array_key_exists($id, $this->inputSources[WheelInput::TYPE])) {
121+
$inputSource = new WheelInput($id);
122+
123+
$this->inputSources[WheelInput::TYPE][$id] = $inputSource;
124+
}
125+
126+
return $this->inputSources[WheelInput::TYPE][$id];
127+
}
128+
129+
/**
130+
* Perform actions: /session/:sessionId/actions (POST)
131+
*
132+
* @return mixed
133+
*/
134+
public function perform()
135+
{
136+
$actions = $this->actions;
137+
$parameters = ['actions' => $actions];
138+
139+
$this->clearAllActions();
140+
141+
$result = $this->curl('POST', '', $parameters);
142+
143+
return $result['value'];
144+
}
145+
146+
/**
147+
* Release all action state: /session/:sessionId/actions (DELETE)
148+
*
149+
* @return mixed
150+
*/
151+
public function releaseActions()
152+
{
153+
$result = $this->curl('DELETE', '');
154+
155+
return $result['value'];
156+
}
157+
158+
/**
159+
* Clear all actions from the builder
160+
*/
161+
public function clearAllActions()
162+
{
163+
$this->actions = [];
164+
}
165+
166+
/**
167+
* Add action
168+
*
169+
* @param array $action
170+
*
171+
* @return \WebDriver\Actions
172+
*/
173+
public function addAction($action)
174+
{
175+
if (($last = count($this->actions)) &&
176+
$this->actions[$last - 1]['id'] === $action['id'] &&
177+
$this->actions[$last - 1]['type'] === $action['type']
178+
) {
179+
foreach ($action['actions'] as $item) {
180+
$this->actions[$last - 1]['actions'][] = $item;
181+
}
182+
} else {
183+
$this->actions[] = $action;
184+
}
185+
186+
return $this;
187+
}
188+
}

lib/WebDriver/Browser.php

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,37 +4,25 @@
44
* @copyright 2011 Fabrizio Branca
55
* @license Apache-2.0
66
*
7-
* @package WebDriver
8-
*
97
* @author Fabrizio Branca <mail@fabrizio-branca.de>
108
*/
119

1210
namespace WebDriver;
1311

1412
/**
1513
* WebDriver\Browser class
16-
*
17-
* @package WebDriver
1814
*/
1915
final class Browser
2016
{
2117
/**
22-
* Check browser names used in static functions in the selenium source:
23-
* @see https://github.com/SeleniumHQ/selenium/blob/trunk/java/src/org/openqa/selenium/remote/BrowserType.java
18+
* @see https://github.com/SeleniumHQ/selenium/blob/trunk/java/src/org/openqa/selenium/remote/Browser.java
2419
*/
25-
const ANDROID = 'android';
26-
const CHROME = 'chrome';
27-
const EDGE = 'edge';
28-
const EDGEHTML = 'EdgeHTML';
29-
const FIREFOX = 'firefox';
30-
const HTMLUNIT = 'htmlunit';
31-
const IE = 'internet explorer';
32-
const INTERNET_EXPLORER = 'internet explorer';
33-
const IPHONE = 'iPhone';
34-
const IPAD = 'iPad';
35-
const MSEDGE = 'MicrosoftEdge';
36-
const OPERA = 'opera';
37-
const OPERA_BLINK = 'operablink';
38-
const PHANTOMJS = 'phantomjs';
39-
const SAFARI = 'safari';
20+
const CHROME = 'chrome';
21+
const EDGE = 'MicrosoftEdge';
22+
const FIREFOX = 'firefox';
23+
const HTMLUNIT = 'htmlunit';
24+
const IE = 'internet explorer';
25+
const OPERA = 'opera';
26+
const SAFARI = 'safari';
27+
const SAFARI_TECH_PREVIEW = 'Safari Technology Preview';
4028
}

lib/WebDriver/Capability.php

Lines changed: 19 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,13 @@
44
* @copyright 2011 Fabrizio Branca
55
* @license Apache-2.0
66
*
7-
* @package WebDriver
8-
*
97
* @author Fabrizio Branca <mail@fabrizio-branca.de>
108
*/
119

1210
namespace WebDriver;
1311

1412
/**
1513
* WebDriver\Capability class
16-
*
17-
* @package WebDriver
1814
*/
1915
final class Capability
2016
{
@@ -24,45 +20,34 @@ final class Capability
2420
* @see https://w3c.github.io/webdriver/webdriver-spec.html#capabilities
2521
* @see https://github.com/SeleniumHQ/selenium/blob/trunk/java/src/org/openqa/selenium/remote/CapabilityType.java
2622
*/
23+
const ACCEPT_INSECURE_CERTS = 'acceptInsecureCerts';
2724
const BROWSER_NAME = 'browserName';
2825
const BROWSER_VERSION = 'browserVersion';
29-
const PLATFORM_NAME = 'platformName';
30-
const PLATFORM_VERSION = 'platformVersion';
31-
const ACCEPT_SSL_CERTS = 'acceptSslCerts';
3226
const PAGE_LOAD_STRATEGY = 'pageLoadStrategy';
27+
const PLATFORM_NAME = 'platformName';
3328
const PROXY = 'proxy';
29+
const SET_WINDOW_RECT = 'setWindowRect';
30+
const STRICT_FILE_INTERACTABILITY = 'strictFileInteractability';
3431
const TIMEOUTS = 'timeouts';
32+
const UNHANDLED_PROMPT_BEHAVIOR = 'unhandlePromptBehavior';
33+
const USER_AGENT = 'userAgent';
3534

36-
// legacy JSON Wire Protocol
37-
const VERSION = 'version';
38-
const PLATFORM = 'platform';
39-
const JAVASCRIPT_ENABLED = 'javascriptEnabled';
40-
const TAKES_SCREENSHOT = 'takesScreenshot';
41-
const HANDLES_ALERTS = 'handlesAlerts';
42-
const DATABASE_ENABLED = 'databaseEnabled';
43-
const LOCATION_CONTEXT_ENABLED = 'locationContextEnabled';
35+
// obsolete or legacy JSON Wire Protocol
36+
const ACCEPT_SSL_CERTS = 'acceptSslCerts';
4437
const APPLICATION_CACHE_ENABLED = 'applicationCacheEnabled';
4538
const BROWSER_CONNECTION_ENABLED = 'browserConnectionEnabled';
4639
const CSS_SELECTORS_ENABLED = 'cssSelectorsEnabled';
47-
const WEB_STORAGE_ENABLED = 'webStorageEnabled';
48-
const ROTATABLE = 'rotatable';
40+
const DATABASE_ENABLED = 'databaseEnabled';
41+
const ELEMENT_SCROLL_BEHAVIOR = 'elementScrollBehavior';
42+
const HANDLES_ALERTS = 'handlesAlerts';
43+
const JAVASCRIPT_ENABLED = 'javascriptEnabled';
44+
const LOCATION_CONTEXT_ENABLED = 'locationContextEnabled';
4945
const NATIVE_EVENTS = 'nativeEvents';
46+
const PLATFORM = 'platform';
47+
const PLATFORM_VERSION = 'platformVersion';
48+
const ROTATABLE = 'rotatable';
49+
const TAKES_SCREENSHOT = 'takesScreenshot';
5050
const UNEXPECTED_ALERT_BEHAVIOUR = 'unexpectedAlertBehaviour';
51-
const ELEMENT_SCROLL_BEHAVIOR = 'elementScrollBehavior';
52-
const STRICT_FILE_INTERACTABILITY = 'strictFileInteractability';
53-
const UNHANDLED_PROMPT_BEHAVIOR = 'unhandlePromptBehavior';
54-
55-
/**
56-
* Proxy types
57-
*
58-
* @see https://w3c.github.io/webdriver/webdriver-spec.html#proxy
59-
*/
60-
const AUTODETECT = 'autodetect';
61-
const MANUAL = 'manual';
62-
const NO_PROXY = 'noproxy';
63-
const PAC = 'pac';
64-
const SYSTEM = 'system';
65-
66-
// legacy JSON Wire Protocol
67-
const DIRECT = 'direct';
51+
const VERSION = 'version';
52+
const WEB_STORAGE_ENABLED = 'webStorageEnabled';
6853
}

0 commit comments

Comments
 (0)