Я использую PHP-скрипт с драйвером Mink + Zombie (установка как на nodejs не может найти модуль «зомби» с PHP-норкой ) отсюда: PHP Mink / Zombie – просмотр страницы возвращает код состояния 0? ; повторная публикация для полноты:
<?php $nodeModPath = "/home/USERNAME/.nvm/versions/node/v4.0.0/lib/node_modules"; # composer autoload: require_once __DIR__ . '/vendor/autoload.php'; $URL = "https://demo.centreon.com/centreon"; $USERNAME = "admin"; $PASSWORD = "centreon"; $LFID = "useralias"; $PFID = "password"; $BFID = "submitLogin"; $zsrv = new \Behat\Mink\Driver\NodeJS\Server\ZombieServer(); $zsrv->setNodeModulesPath($nodeModPath . "/"); # needs to end with a trailing '/' $driver = new \Behat\Mink\Driver\ZombieDriver( $zsrv ); $session = new \Behat\Mink\Session($driver); // start the session $session->start(); $session->setRequestHeader('User-Agent', 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36'); $statcode = 0; while ($statcode != 200) { $isleep = rand(2, 7); echo "sleeping $isleep sec...\n"; sleep($isleep); $session->visit($URL); // $session->wait(20000, '(0 === jQuery.active)'); # Uncaught exception 'RuntimeException' with message 'Could not establish connection: Connection refused (111)' $session->wait(20000, '(browser.statusCode > 0)'); ### THIS makes things work?! $statcode = $session->getStatusCode(); echo " current URL: " . $session->getCurrentUrl() ."\n"; echo " status code: " . $statcode ."\n"; } $page = $session->getPage(); $el_login = $page->findField($LFID); $el_password = $page->findField($PFID); $el_button = $page->find('xpath', '//*[@name="'.$BFID.'"]');//findById($BFID);//findField($BFID); $el_login->setValue($USERNAME); $el_password->setValue($PASSWORD); echo " pressing/clicking login button\n"; $el_button->click(); echo "Page URL after click: ". $session->getCurrentUrl() . "\n"; $page = $session->getPage(); ?>
Проблема заключается в том, что при запуске скрипта и нажатии кнопки входа в систему некоторые библиотеки JavaScript, которые использует страница, не могут быть обнаружены Mink, и возникает исключение:
$ php test_php_mink.php sleeping 4 sec... current URL: https://demo.centreon.com/centreon/ status code: 200 pressing/clicking login button PHP Fatal error: Uncaught exception 'Behat\Mink\Exception\DriverException' with message 'Error while processing event 'click': "ReferenceError: Effect is not defined\n at https://demo.centreon.com/centreon/include/common/javascript/modalbox.js:517:1\n at Object.exports.runInContext (vm.js:44:17)\n at window._evaluate (/home/USERNAME/.nvm/versions/node/v4.0.0/lib/node_modules/zombie/lib/document.js:253:75)\n at Object.DOM.languageProcessors.javascript (/home/USERNAME/.nvm/versions/node/v4.0.0/lib/node_modules/zombie/lib/dom/scripts.js:26:12)\n at define.proto._eval (/home/USERNAME/.nvm/versions/node/v4.0.0/lib/node_modules/zombie/node_modules/jsdom/lib/jsdom/level2/html.js:1477:47)\n at /home/USERNAME/.nvm/versions/node/v4.0.0/lib/node_modules/zombie/node_modules/jsdom/lib/jsdom/browser/resource-loader.js:32:22\n at Object.item.check (/home/USERNAME/.nvm/versions/node/v4.0.0/lib/node_modules/zombie/node_modules/jsdom/lib/jsdom/level2/html.js:188:11)\n at Object.item.check (/home in /path/to/test_php_mink/vendor/behat/mink-zombie-driver/src/ZombieDriver.php on line 880
Исключением является ReferenceError: Effect is not defined
, и он связан с страницей, использующей этот javascript:
<script type="text/javascript" src="./include/common/javascript/scriptaculous/scriptaculous.js?load=effects,dragdrop"></script> ... new Effect.toggle('header', 'appear', { afterFinish: function() {
Однако еще большая проблема заключается в том, что после этого сбоя, когда я запускаю скрипт во второй раз, он падает почти сразу, на этот раз с Error: listen EADDRINUSE 127.0.0.1:8124
:
$ php test_php_mink.php PHP Fatal error: Uncaught exception 'RuntimeException' with message 'Server process has been terminated: (1) [events.js:141 throw er; // Unhandled 'error' event ^ Error: listen EADDRINUSE 127.0.0.1:8124 at Object.exports._errnoException (util.js:837:11) at exports._exceptionWithHostPort (util.js:860:20) at Server._listen2 (net.js:1231:14) at listen (net.js:1267:10) at net.js:1376:9 at doNTCallback3 (node.js:440:9) at process._tickCallback (node.js:346:17) at Function.Module.runMain (module.js:473:11) at startup (node.js:117:18) at node.js:951:3 ]' in /path/to/test_php_mink/vendor/behat/mink-zombie-driver/src/NodeJS/Server.php:413 Stack trace: #0 /path/to/test_php_mink/vendor/behat/mink-zombie-driver/src/NodeJS/Server.php(306): Behat\Mink\Driver\NodeJS\Server->checkAvailability() #1 /path/to/test_php_mink/vendor/behat/mink-zombie-driver/src/ZombieDriver. in /path/to/test_php_mink/vendor/behat/mink-zombie-driver/src/NodeJS/Server.php on line 413
Похоже, что после первого крушения все еще висят mink
процессы – и действительно, есть:
$ pgrep -fl mink 7659 sh 7660 node $ ps axf | grep mink 7687 pts/0 S+ 0:00 | \_ grep --color=tty mink 7659 pts/0 S 0:00 sh -c 'node' '/path/to/test_php_mink/vendor/behat/mink-zombie-driver/bin/mink-zombie-server.js' 7660 pts/0 Sl 0:03 \_ node /path/to/test_php_mink/vendor/behat/mink-zombie-driver/bin/mink-zombie-server.js
На данный момент, если я убью эти процессы, скажем, с pkill -f mink
то они исчезнут из дерева процессов, а затем я снова смогу запустить сценарий с теми же результатами, что и первый вызов в OP (а затем я придется снова убивать процессы и т. д.).
Каким будет лучший / рекомендуемый способ справиться с этим, поэтому мне не нужно вручную убивать процессы, каждый раз, когда сценарий достигает фатального исключения? Есть ли что-то в библиотеке Mink, которая позволила бы это сделать?
Первое, что нужно сделать, чтобы избежать фатальных исключений, – это реализовать / использовать методы с правильной обработкой ошибок. Вы можете создать метод для проверки того, является ли элемент не нулевым, и если он должен выбрасывать специальное исключение.
Например, в вашем случае метод findField возвращает null, если элемент не найден, в этом случае setValue будет использоваться для не-объекта, что приведет к фатальной ошибке.
Пример обработки исключений:
public function fillWith($locator, $text){ $element = $this->getSession()->getPage()->find("xpath", $locator); if($element === null){ throw new Exception("Element $locator not found"); }else{ $element->setValue($text); } }