Commands.pm 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. package Selenium::Remote::Commands;
  2. use strict;
  3. use warnings;
  4. use Carp qw{croak};
  5. # ABSTRACT: Implement commands for Selenium::Remote::Driver for use with webdriver 2
  6. =head1 DESCRIPTION
  7. Defines all the HTTP endpoints available to execute on a selenium v2 server.
  8. If you have either a customized Selenium Server, or want new features
  9. you should update the _cmds hash.
  10. =for Pod::Coverage *EVERYTHING*
  11. =cut
  12. use Moo;
  13. has '_cmds' => (
  14. is => 'lazy',
  15. reader => 'get_cmds',
  16. builder => sub {
  17. return {
  18. 'status' => {
  19. 'method' => 'GET',
  20. 'url' => 'status',
  21. 'no_content_success' => 0
  22. },
  23. 'newSession' => {
  24. 'method' => 'POST',
  25. 'url' => 'session',
  26. 'no_content_success' => 0
  27. },
  28. 'getSessions' => {
  29. 'method' => 'GET',
  30. 'url' => 'sessions',
  31. 'no_content_success' => 0
  32. },
  33. 'getCapabilities' => {
  34. 'method' => 'GET',
  35. 'url' => 'session/:sessionId',
  36. 'no_content_success' => 0
  37. },
  38. 'setTimeout' => {
  39. 'method' => 'POST',
  40. 'url' => 'session/:sessionId/timeouts',
  41. 'no_content_success' => 1
  42. },
  43. 'setAsyncScriptTimeout' => {
  44. 'method' => 'POST',
  45. 'url' => 'session/:sessionId/timeouts/async_script',
  46. 'no_content_success' => 1
  47. },
  48. 'setImplicitWaitTimeout' => {
  49. 'method' => 'POST',
  50. 'url' => 'session/:sessionId/timeouts/implicit_wait',
  51. 'no_content_success' => 1
  52. },
  53. 'quit' => {
  54. 'method' => 'DELETE',
  55. 'url' => 'session/:sessionId',
  56. 'no_content_success' => 1
  57. },
  58. 'getCurrentWindowHandle' => {
  59. 'method' => 'GET',
  60. 'url' => 'session/:sessionId/window_handle',
  61. 'no_content_success' => 0
  62. },
  63. 'getWindowHandles' => {
  64. 'method' => 'GET',
  65. 'url' => 'session/:sessionId/window_handles',
  66. 'no_content_success' => 0
  67. },
  68. 'getWindowSize' => {
  69. 'method' => 'GET',
  70. 'url' => 'session/:sessionId/window/:windowHandle/size',
  71. 'no_content_success' => 0
  72. },
  73. 'getWindowPosition' => {
  74. 'method' => 'GET',
  75. 'url' => 'session/:sessionId/window/:windowHandle/position',
  76. 'no_content_success' => 0
  77. },
  78. 'maximizeWindow' => {
  79. 'method' => 'POST',
  80. 'url' => 'session/:sessionId/window/:windowHandle/maximize',
  81. 'no_content_success' => 1
  82. },
  83. 'setWindowSize' => {
  84. 'method' => 'POST',
  85. 'url' => 'session/:sessionId/window/:windowHandle/size',
  86. 'no_content_success' => 1
  87. },
  88. 'setWindowPosition' => {
  89. 'method' => 'POST',
  90. 'url' => 'session/:sessionId/window/:windowHandle/position',
  91. 'no_content_success' => 1
  92. },
  93. 'getCurrentUrl' => {
  94. 'method' => 'GET',
  95. 'url' => 'session/:sessionId/url',
  96. 'no_content_success' => 0
  97. },
  98. 'get' => {
  99. 'method' => 'POST',
  100. 'url' => 'session/:sessionId/url',
  101. 'no_content_success' => 1
  102. },
  103. 'goForward' => {
  104. 'method' => 'POST',
  105. 'url' => 'session/:sessionId/forward',
  106. 'no_content_success' => 1
  107. },
  108. 'goBack' => {
  109. 'method' => 'POST',
  110. 'url' => 'session/:sessionId/back',
  111. 'no_content_success' => 1
  112. },
  113. 'refresh' => {
  114. 'method' => 'POST',
  115. 'url' => 'session/:sessionId/refresh',
  116. 'no_content_success' => 1
  117. },
  118. 'executeScript' => {
  119. 'method' => 'POST',
  120. 'url' => 'session/:sessionId/execute',
  121. 'no_content_success' => 0
  122. },
  123. 'executeAsyncScript' => {
  124. 'method' => 'POST',
  125. 'url' => 'session/:sessionId/execute_async',
  126. 'no_content_success' => 0
  127. },
  128. 'screenshot' => {
  129. 'method' => 'GET',
  130. 'url' => 'session/:sessionId/screenshot',
  131. 'no_content_success' => 0
  132. },
  133. 'availableEngines' => {
  134. 'method' => 'GET',
  135. 'url' => 'session/:sessionId/ime/available_engines',
  136. 'no_content_success' => 0
  137. },
  138. 'switchToFrame' => {
  139. 'method' => 'POST',
  140. 'url' => 'session/:sessionId/frame',
  141. 'no_content_success' => 1
  142. },
  143. 'switchToWindow' => {
  144. 'method' => 'POST',
  145. 'url' => 'session/:sessionId/window',
  146. 'no_content_success' => 1
  147. },
  148. 'getAllCookies' => {
  149. 'method' => 'GET',
  150. 'url' => 'session/:sessionId/cookie',
  151. 'no_content_success' => 0
  152. },
  153. 'addCookie' => {
  154. 'method' => 'POST',
  155. 'url' => 'session/:sessionId/cookie',
  156. 'no_content_success' => 1
  157. },
  158. 'deleteAllCookies' => {
  159. 'method' => 'DELETE',
  160. 'url' => 'session/:sessionId/cookie',
  161. 'no_content_success' => 1
  162. },
  163. 'deleteCookieNamed' => {
  164. 'method' => 'DELETE',
  165. 'url' => 'session/:sessionId/cookie/:name',
  166. 'no_content_success' => 1
  167. },
  168. 'getPageSource' => {
  169. 'method' => 'GET',
  170. 'url' => 'session/:sessionId/source',
  171. 'no_content_success' => 0
  172. },
  173. 'getTitle' => {
  174. 'method' => 'GET',
  175. 'url' => 'session/:sessionId/title',
  176. 'no_content_success' => 0
  177. },
  178. 'findElement' => {
  179. 'method' => 'POST',
  180. 'url' => 'session/:sessionId/element',
  181. 'no_content_success' => 0
  182. },
  183. 'findElements' => {
  184. 'method' => 'POST',
  185. 'url' => 'session/:sessionId/elements',
  186. 'no_content_success' => 0
  187. },
  188. 'getActiveElement' => {
  189. 'method' => 'POST',
  190. 'url' => 'session/:sessionId/element/active',
  191. 'no_content_success' => 0
  192. },
  193. 'describeElement' => {
  194. 'method' => 'GET',
  195. 'url' => 'session/:sessionId/element/:id',
  196. 'no_content_success' => 0
  197. },
  198. 'findChildElement' => {
  199. 'method' => 'POST',
  200. 'url' => 'session/:sessionId/element/:id/element',
  201. 'no_content_success' => 0
  202. },
  203. 'findChildElements' => {
  204. 'method' => 'POST',
  205. 'url' => 'session/:sessionId/element/:id/elements',
  206. 'no_content_success' => 0
  207. },
  208. 'clickElement' => {
  209. 'method' => 'POST',
  210. 'url' => 'session/:sessionId/element/:id/click',
  211. 'no_content_success' => 1
  212. },
  213. 'submitElement' => {
  214. 'method' => 'POST',
  215. 'url' => 'session/:sessionId/element/:id/submit',
  216. 'no_content_success' => 1
  217. },
  218. 'sendKeysToElement' => {
  219. 'method' => 'POST',
  220. 'url' => 'session/:sessionId/element/:id/value',
  221. 'no_content_success' => 1
  222. },
  223. 'sendKeysToActiveElement' => {
  224. 'method' => 'POST',
  225. 'url' => 'session/:sessionId/keys',
  226. 'no_content_success' => 1
  227. },
  228. 'sendModifier' => {
  229. 'method' => 'POST',
  230. 'url' => 'session/:sessionId/modifier',
  231. 'no_content_success' => 1
  232. },
  233. 'isElementSelected' => {
  234. 'method' => 'GET',
  235. 'url' => 'session/:sessionId/element/:id/selected',
  236. 'no_content_success' => 0
  237. },
  238. 'setElementSelected' => {
  239. 'method' => 'POST',
  240. 'url' => 'session/:sessionId/element/:id/selected',
  241. 'no_content_success' => 0
  242. },
  243. 'toggleElement' => {
  244. 'method' => 'POST',
  245. 'url' => 'session/:sessionId/element/:id/toggle',
  246. 'no_content_success' => 0
  247. },
  248. 'isElementEnabled' => {
  249. 'method' => 'GET',
  250. 'url' => 'session/:sessionId/element/:id/enabled',
  251. 'no_content_success' => 0
  252. },
  253. 'getElementLocation' => {
  254. 'method' => 'GET',
  255. 'url' => 'session/:sessionId/element/:id/location',
  256. 'no_content_success' => 0
  257. },
  258. 'getElementLocationInView' => {
  259. 'method' => 'GET',
  260. 'url' => 'session/:sessionId/element/:id/location_in_view',
  261. 'no_content_success' => 0
  262. },
  263. 'getElementTagName' => {
  264. 'method' => 'GET',
  265. 'url' => 'session/:sessionId/element/:id/name',
  266. 'no_content_success' => 0
  267. },
  268. 'clearElement' => {
  269. 'method' => 'POST',
  270. 'url' => 'session/:sessionId/element/:id/clear',
  271. 'no_content_success' => 1
  272. },
  273. 'getElementAttribute' => {
  274. 'method' => 'GET',
  275. 'url' => 'session/:sessionId/element/:id/attribute/:name',
  276. 'no_content_success' => 0
  277. },
  278. 'elementEquals' => {
  279. 'method' => 'GET',
  280. 'url' => 'session/:sessionId/element/:id/equals/:other',
  281. 'no_content_success' => 0
  282. },
  283. 'isElementDisplayed' => {
  284. 'method' => 'GET',
  285. 'url' => 'session/:sessionId/element/:id/displayed',
  286. 'no_content_success' => 0
  287. },
  288. 'close' => {
  289. 'method' => 'DELETE',
  290. 'url' => 'session/:sessionId/window',
  291. 'no_content_success' => 1
  292. },
  293. 'getElementSize' => {
  294. 'method' => 'GET',
  295. 'url' => 'session/:sessionId/element/:id/size',
  296. 'no_content_success' => 0
  297. },
  298. 'getElementText' => {
  299. 'method' => 'GET',
  300. 'url' => 'session/:sessionId/element/:id/text',
  301. 'no_content_success' => 0
  302. },
  303. 'getElementValueOfCssProperty' => {
  304. 'method' => 'GET',
  305. 'url' => 'session/:sessionId/element/:id/css/:propertyName',
  306. 'no_content_success' => 0
  307. },
  308. 'mouseMoveToLocation' => {
  309. 'method' => 'POST',
  310. 'url' => 'session/:sessionId/moveto',
  311. 'no_content_success' => 1
  312. },
  313. 'getAlertText' => {
  314. 'method' => 'GET',
  315. 'url' => 'session/:sessionId/alert_text',
  316. 'no_content_success' => 0
  317. },
  318. 'sendKeysToPrompt' => {
  319. 'method' => 'POST',
  320. 'url' => 'session/:sessionId/alert_text',
  321. 'no_content_success' => 1
  322. },
  323. 'acceptAlert' => {
  324. 'method' => 'POST',
  325. 'url' => 'session/:sessionId/accept_alert',
  326. 'no_content_success' => 1
  327. },
  328. 'dismissAlert' => {
  329. 'method' => 'POST',
  330. 'url' => 'session/:sessionId/dismiss_alert',
  331. 'no_content_success' => 1
  332. },
  333. 'click' => {
  334. 'method' => 'POST',
  335. 'url' => 'session/:sessionId/click',
  336. 'no_content_success' => 1
  337. },
  338. 'doubleClick' => {
  339. 'method' => 'POST',
  340. 'url' => 'session/:sessionId/doubleclick',
  341. 'no_content_success' => 1
  342. },
  343. 'buttonDown' => {
  344. 'method' => 'POST',
  345. 'url' => 'session/:sessionId/buttondown',
  346. 'no_content_success' => 1
  347. },
  348. 'buttonUp' => {
  349. 'method' => 'POST',
  350. 'url' => 'session/:sessionId/buttonup',
  351. 'no_content_success' => 1
  352. },
  353. 'uploadFile' => {
  354. 'method' => 'POST',
  355. 'url' => 'session/:sessionId/file',
  356. 'no_content_success' => 0
  357. },
  358. 'getLocalStorageItem' => {
  359. 'method' => 'GET',
  360. 'url' => '/session/:sessionId/local_storage/key/:key',
  361. 'no_content_success' => 0
  362. },
  363. 'deleteLocalStorageItem' => {
  364. 'method' => 'DELETE',
  365. 'url' => '/session/:sessionId/local_storage/key/:key',
  366. 'no_content_success' => 1
  367. },
  368. 'cacheStatus' => {
  369. 'method' => 'GET',
  370. 'url' => 'session/:sessionId/application_cache/status',
  371. 'no_content_success' => 0
  372. },
  373. 'setGeolocation' => {
  374. 'method' => 'POST',
  375. 'url' => 'session/:sessionId/location',
  376. 'no_content_success' => 1
  377. },
  378. 'getGeolocation' => {
  379. 'method' => 'GET',
  380. 'url' => 'session/:sessionId/location',
  381. 'no_content_success' => 0
  382. },
  383. 'getLog' => {
  384. 'method' => 'POST',
  385. 'url' => 'session/:sessionId/log',
  386. 'no_content_success' => 0
  387. },
  388. 'getLogTypes' => {
  389. 'method' => 'GET',
  390. 'url' => 'session/:sessionId/log/types',
  391. 'no_content_success' => 0
  392. },
  393. 'setOrientation' => {
  394. 'method' => 'POST',
  395. 'url' => 'session/:sessionId/orientation',
  396. 'no_content_success' => 1
  397. },
  398. 'getOrientation' => {
  399. 'method' => 'GET',
  400. 'url' => 'session/:sessionId/orientation',
  401. 'no_content_success' => 0
  402. },
  403. # firefox extension
  404. 'setContext' => {
  405. 'method' => 'POST',
  406. 'url' => 'session/:sessionId/moz/context',
  407. 'no_content_success' => 1
  408. },
  409. 'getContext' => {
  410. 'method' => 'GET',
  411. 'url' => 'session/:sessionId/moz/context',
  412. 'no_content_success' => 0
  413. },
  414. # geckodriver workarounds
  415. 'executeScriptGecko' => {
  416. 'method' => 'POST',
  417. 'url' => 'session/:sessionId/execute/sync',
  418. 'no_content_success' => 0
  419. },
  420. 'executeAsyncScriptGecko' => {
  421. 'method' => 'POST',
  422. 'url' => 'session/:sessionId/execute/async',
  423. 'no_content_success' => 0
  424. },
  425. # /session/:sessionId/local_storage
  426. # /session/:sessionId/local_storage/key/:key
  427. # /session/:sessionId/local_storage/size
  428. # /session/:sessionId/session_storage
  429. # /session/:sessionId/session_storage/key/:key
  430. # /session/:sessionId/session_storage/size
  431. };
  432. }
  433. );
  434. # helper methods to manipulate the _cmds hash
  435. sub get_url {
  436. my ( $self, $command ) = @_;
  437. return $self->get_cmds->{$command}->{url};
  438. }
  439. sub get_method {
  440. my ( $self, $command ) = @_;
  441. return $self->get_cmds->{$command}->{method};
  442. }
  443. sub get_no_content_success {
  444. my ( $self, $command ) = @_;
  445. return $self->get_cmds->{$command}->{no_content_success};
  446. }
  447. # This method will replace the template & return
  448. sub get_params {
  449. my ( $self, $args ) = @_;
  450. if ( !( defined $args->{'session_id'} ) ) {
  451. return;
  452. }
  453. my $data = {};
  454. my $command = $args->{'command'};
  455. #Allow fall-back in the event the command passed doesn't exist
  456. return unless $self->get_cmds()->{$command};
  457. my $url = $self->get_url($command);
  458. # Do the var substitutions.
  459. $url =~ s/:sessionId/$args->{'session_id'}/;
  460. $url =~ s/:id/$args->{'id'}/;
  461. $url =~ s/:name/$args->{'name'}/;
  462. $url =~ s/:propertyName/$args->{'property_name'}/;
  463. $url =~ s/:other/$args->{'other'}/;
  464. $url =~ s/:windowHandle/$args->{'window_handle'}/;
  465. $data->{'method'} = $self->get_method($command);
  466. $data->{'no_content_success'} = $self->get_no_content_success($command);
  467. $data->{'url'} = $url;
  468. return $data;
  469. }
  470. sub parse_response {
  471. my ( $self, $res, $resp ) = @_;
  472. if ( ref($resp) eq 'HASH' ) {
  473. if ( $resp->{cmd_status} && $resp->{cmd_status} eq 'OK' ) {
  474. return $resp->{cmd_return};
  475. }
  476. my $msg = "Error while executing command";
  477. $msg .= ": $resp->{cmd_error}" if $resp->{cmd_error};
  478. if ( $resp->{cmd_return} ) {
  479. if ( ref( $resp->{cmd_return} ) eq 'HASH' ) {
  480. $msg .= ": $res->{command}"
  481. if $res->{command};
  482. $msg .= ": $resp->{cmd_return}->{error}->{msg}"
  483. if $resp->{cmd_return}->{error}->{msg};
  484. $msg .= ": $resp->{cmd_return}->{message}"
  485. if $resp->{cmd_return}->{message};
  486. }
  487. else {
  488. $msg .= ": $resp->{cmd_return}";
  489. }
  490. }
  491. croak $msg;
  492. }
  493. return $resp;
  494. }
  495. 1;
  496. __END__