I'm using PHPUnit with the Selenium2 extension.
I'm opening a popup window, entering data and hit the submit button - after that the popup window closes.
Later then I'm switching back to the main window - all that works flawlessly. But after switching back no other steps of my tests are executed and the test fails with the following error message:
PHPUnit_Extensions_Selenium2TestCase_NoSeleniumException: Error connection[28] to http://localhost:4444/wd/hub/session/d6977d2b-76ac-4754-9a08-5119413b0965/element/4/submit: Operation timed out after 60004 milliseconds with 0 bytes received
For the sake of completeness the code:
$windowHandles = $this->windowHandles();
$this->window($windowHandles[1]);
$this->byCssSelector('input[id=email]')->value($fbUsername);
$this->byCssSelector('input[id=pass]')->value($fbPassword);
$this->byCssSelector('input[id=u_0_1]')->submit();
$this->window($windowHandles[0]);
Did I miss some required step? Do I have to wait for something? Any pointers would help.
#akluth, a bug was discovery and will be fix. You can see more information here. I'm waiting for a new release.
I am not a PHP guy but I hope the following code will give you some ideas how to handle this. Note: the following is C# code
//You probably missing this the concept of handling current and original handle
string currentHandle = driver.CurrentWindowHandle;
ReadOnlyCollection<string> originalHandles = driver.WindowHandles;
// Cause the pop-up to appear
driver.FindElement(By.XPath("//*[#id='webtraffic_popup_start_button']")).Click();
// WebDriverWait.Until<T> waits until the delegate returns
// a non-null value for object types. We can leverage this
// behaviour to return the pop-up window handle.
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(5));
string popupWindowHandle = wait.Until<string>((d) =>
{
string foundHandle = null;
// Subtract out the list of known handles. In the case of a single
// pop-up, the newHandles list will only have one value.
List<string> newHandles = driver.CurrentWindowHandles.Except(originalHandles).ToList();
if (newHandles.Count > 0)
{
foundHandle = newHandles[0];
}
return foundHandle;
});
driver.SwitchTo().Window(popupWindowHandle);
// Do whatever you need to on the pop-up browser, then...
driver.Close();
driver.SwitchToWindow(currentHandle);
As, you said all that works flawlessly. But after switching back no other steps of my tests are executed and the test fails
because the you have not correctly switch back to the original window handle.
This code is copy pasted from here
Thanks #JimEvans for explaning this process.
Looks like your browser is upgraded. You need to update your selenium libraries accordingly.
Related
I'm getting this error when trying to resume a Speech to Text operation.
Google\Protobuf\Internal\GPBDecodeException: Error occurred during parsing: Class google.cloud.speech.v1.LongRunningRecognizeMetadata hasn't been added to descriptor pool in Google\Protobuf\Internal\Message->parseFromJsonStream()
What I'm doing is starting the longrunning operation and storing the name. Later I'm creating a separate page with the status of the operation based on the name I stored previously.
This is what I'm using to try and get the operation status
$speechClient = new SpeechClient();
$operationResponse = $speechClient->resumeOperation($record->operation_name, 'longRunningRecognize');
Is it possible to do something like this?
This took me way too long to figure out for such a simple fix, but here you go.
Put this line before calling resumeOperation:
\GPBMetadata\Google\Cloud\Speech\V1\CloudSpeech::initOnce();.
I think this is a bug within the SDK, but considering their docs say the client libraries are in Alpha, it makes sense.
A longer explanation (since it took me so darn long, and I know I'll find my SO answer in the future if I run into this problem again):
The DocBlocks above the SpeechGapicClient::longRunningRecognize() method show an alternative to blocking polling with $operation->pollUntilComplete()
// start the operation, keep the operation name, and resume later
$operationResponse = $speechClient->longRunningRecognize($config, $audio);
$operationName = $operationResponse->getName();
// ... do other work
$newOperationResponse = $speechClient->resumeOperation($operationName, 'longRunningRecognize');
while (!$newOperationResponse->isDone()) {
// ... do other work
$newOperationResponse->reload();
}
if ($newOperationResponse->operationSucceeded()) {
$result = $newOperationResponse->getResult();
// doSomethingWith($result)
} else {
$error = $newOperationResponse->getError();
// handleError($error)
}
Everything works great if you call resumeOperation() on the same operation returned by the longRunningRecognize() method. If you try to resume in a separate request, as you and I did, we get the error you mentioned above.
The difference is, the longRunningRecognize() method creates a request (LongRunningRecognizeRequest) which is executed whereas resumeOperation() is pretty straight forward and doesn't need to combine request parameters for sending to Google.
The difference here is, the constructor of the LongRunningRecognizeRequest calls \GPBMetadata\Google\Cloud\Speech\V1\CloudSpeech::initOnce(); which sets up the needed speech descriptors.
I hope this helps!
I had a very similar issue, trying to get information about an operation (getOperation):
Google\Protobuf\Internal\GPBDecodeException
Error occurred during parsing: Class google.cloud.speech.v1p1beta1.LongRunningRecognizeMetadata hasn't been added to descriptor pool
As #stevenwadejr already answered correctly, this can be solved by calling initOnce() before the call.
<?php
use Google\Cloud\Speech\V1p1beta1\SpeechClient;
use GPBMetadata\Google\Cloud\Speech\V1P1Beta1\CloudSpeech;
$client = new SpeechClient();
// This line is required. It adds LongRunningRecognizeMetadata and others to the pool of recognized classes
CloudSpeech::initOnce();
// Now, I can get the operation without raising an exception
$operation = $client->getOperationsClient()->getOperation('1234567890123456789');
You can check file \vendor\google\protobuf\src\Google\Protobuf\Internal\AnyBase.php function unpack(). Without the initOnce command the pool variable did not have the fully_qualifed_name (google.cloud.speech.v1p1beta1.LongRunningRecognizeMetadata) in the $proto->proto_to_class array.
I need to accept an IE javascript alert using using the php webdriver for selenium
This works for FF and Chrome, but IE fails
Here's the code I'm using:
$web_driver = new WebDriver();
// opens Internet explorer browser
$session = $web_driver->session('internet explorer');
// Navigates to page that has JS alert on close.
$session->open('http://mypage.com/');
// Closes Offer window
$session->deleteWindow();
// Accepts alert to leave page
$session->accept_alert(); // Except accept_alert isn't working correctly in IE
// Closes last window
$session->close();
// Kill session for garbage collection
unset($session);
I know there's this answer for Java and this answer for C#, but am looking for a PHP specific solution since the java methods aren't the same
This one took me forever to figure out. What I have done before is after the deleteWindow() call, grab the newest window handle and set the focus to it. Once you have the alert in focus you can call accept_alert() on it and the window will close as expected. Here's the idea.
$web_driver = new WebDriver();
$session = $web_driver->session('internet explorer');
$session->open('http://mypage.com/');
$session->deleteWindow();
// Here's the new part
$handles = $this->_session->window_handles(); // stores array of window handles
$new_handle = end($handles); // grabs the newest handle, in this case our alert
$this->_session->focusWindow($new_handle); // gives the alert window focus
// Should now work as expected
$session->accept_alert();
$session->close();
unset($session);
This will also work for the firefox and chrome drivers, so you can use the same code for all drivers if you wanted to. Good luck!
I have a JavaScript functions which calls a PHP function through AJAX.
The PHP function has a set_time_limit(0) for its purposes.
Is there any way to stop that function when I want, for example with an HTML button event?
I want to explain better the situation:
I have a php file which uses a stream_copy_to_stream($src, $dest) php function to retrieve a stream in my local network. The function has to work until I want: I can stop it at the end of the stream or when I want. So I can use a button to start and a button to stop. The problem is the new instance created by the ajax call, in fact I can't work on it because it is not the function that is recording but it is another instance. I tried MireSVK's suggest but it doesn't worked!
Depending on the function. If it is a while loop checking for certain condition every time, then you could add a condition that is modifiable from outside the script (e.g. make it check for a file, and create / delete that file as required)
It looks like a bad idea, however. Why you want to do it?
var running = true;
function doSomething(){
//do something........
}
setInterval(function(){if(running){doSomething()}},2000); ///this runs do something every 2 seconds
on button click simply set running = false;
Your code looks like:
set_time_limit(0);
while(true==true){//infinite loop
doSomething(); //your code
}
Let's upgrade it
set_time_limit(0);
session_start();
$_SESSION['do_a_loop'] = true;
function should_i_stop_loop(){
#session_start();
if( $_SESSION['do_a_loop'] == false ) {
//let's stop a loop
exit();
}
session_write_close();
}
while(true==true){
doSomething();
should_i_stop_loop(); //your new function
}
Create new file stopit.php
session_start();
$_SESSION['do_a_loop'] = false;
All you have to do now is create a request on stopit.php file (with ajax or something)
Edit code according to your needs, this is point. One of many solutions.
Sorry for my English
Sadly this isn't possible (sort of).
Each time you make an AJAX call to a PHP script the script spawns a new instance of itself. Thus anything you send to it will be sent to a new operation, not the operation you had previously started.
There are a number of workarounds.
Use readystate 3 in AJAX to create a non closing connection to the PHP script, however that isn't supported cross browser and probably won't work in IE (not sure about IE 10).
Look into socket programming in PHP, which allows you to create a script with one instance that you can connect to multiple times.
Have PHP check a third party. I.E have one script running in a loop checking a file or a database, then connect to another script to modify that file or database. The original script can be remotely controlled by what you write to the file/database.
Try another programming language (this is a silly option, but I'm a fan of node). Node.js does this sort of thing very very easily.
I have a PHP script (let's call it execute.php) that draws the whole page (HTML tags and body tags etc.) at the beginning and, afer that, executes some commands (C++ programs) in the background. It then waits for these programs to terminate (some depend on the results of others, so they may be executed sequentially) and then has a JavaScript that auto-submits a form to another PHP script (which we will call results.php) because results.php needs the POST-information from the previous script.
execute.php:
<?php
print"
<html>
<body>
Some HTML code here
</body>
</html>
";
// Here come some C++-program calls
$pid_program1 = run_in_background($program1)
$pid_program2 = run_in_background($program2)
while (is_running($pid_program1) or is_running($pid_program2) )
{
//echo(".");
sleep(1);
}
// Here come some later C++-program calls that execute quickly
$pid_program3 = run_in_background($program3)
$pid_program4 = run_in_background($program4)
while (is_running($pid_program3) or is_running($pid_program4) )
{
sleep(1);
}
...
// We are now finished
print "
<form action=\"results.php\" id=\"go_to_results\" method=\"POST\">
<input type='hidden' name=\"session_id\" value=\"XYZ\">
</form>
<script type=\"text/javascript\">
AutoSubmitForm( 'go_to_results' );
</script>
";
This works nicely if the C++ programs 1 and 2 execute quickly. However, when they take their time (around 25 minutes in total), the PHP script seems to fail to continue. Interestingly the C++ programs 3 and 4 are nevertheless executed and produce the expected outputs etc.
However, when I put a echo("."); in the first while-loop before the sleep(), it works and continues until the JavaScript autosubmit.
So it seems to me that the remaining PHP code (including the autosubmit) is, for whatever reason, not send when there is no output in the first while loop.
I have also tried using set_time_limit(0) and ignore_user_abort(true) and different other things like writing to an outputbuffer (don't want to clutter the already finally displayed webpage) instead of the echo, but none of these work.
When I run the same scripts on a machine with multiple cores, so that program1 and 2 can be executed in parallel, it also works, without the echo(".").
So I am currently very confused and can't find any error messages in the apache log or PHP log and thus would really appreciate your thoughts on this one.
EDIT
Thanks again for your suggestions so far.
I have now adopted a solution involving (really simple) AJAX and it's definitely nicer this way.
However, if the C++-programs executions take "longer" it is not autosubmitting to the results-page, which is actually created this time (failed to do so before).
Basically what I have done is:
process.php:
<?php
$params = "someparam=1";
?>
<html>
<body>
<script type="text/javascript">
function run_analyses(params){
// Use AJAX to execute the programs independenantly in the background
// Allows for the user to close the process-page and come back at a later point to the results-link, w/o need to wait.
if (window.XMLHttpRequest)
{
http_request = new XMLHttpRequest();
}
else
{
//Fallback for IE5 and IE6, as these don't support the above writing/code
http_request = new ActiveXObject("Microsoft.XMLHTTP");
}
//Is http_request still false
if (!http_request)
{
alert('Ende :( Kann keine XMLHTTP-Instanz erzeugen');
}
http_request.onreadystatechange=function(){
if (http_request.readyState==4 && http_request.status==200){
// Maybe used to display the progress of the execution
//document.getElementById("output").innerHTML=http_request.responseText;
// Call of programs is finished -> Go to the results-page
document.getElementById( "go_to_results" ).submit();
}
};
http_request.open("POST","execute.php",true);
//Send the proper header information along with the request
http_request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http_request.setRequestHeader("Content-length", params.length);
http_request.setRequestHeader("Connection", "close");
http_request.send(params);
};
</script>
<?php
// Do some HTML-markup
...
// Start the programs!
print "
<script type=\"text/javascript\">
run_analyses('".$params."');
</script>
<form action=\"results.html" id=\"go_to_results\" method=\"POST\">
<input type='hidden' name=\"session_id\" value=\"XYZ\">
</form>
?>
</html>
</body>
and execute.php contains the C++-program calls, waiting-routines and finally, via "include("results.php")" the creation of the results-page.
Again, for "not so long" program executions, the autosubmission works as expected, but not if it takes "longer". By "longer" I mean around 25 minutes.
I have absolutely no idea what could cause this as again, there are no error-messages to be found.
Am I missing a crucial configuration option there (apache, php, etc.)?
EDIT
As it turned out, letting the requested PHP-script "echo" something repeatedly prevents the timeout. So it is basically the same as for the PHP-solution without AJAX, but this time, since the responseText of the AJAX-request is not necessarily needed, the progress-page is not cluttered and it may be used as a workaround. Specifically, I would not necessarily recommend it a as a general solution or good-practice.
It occurs to me that a better approach would be to:
Output the complete HTML page
Show a loading message to the user
Send an AJAX request to start the external program
Wait for callback (waiting for external program to finish)
Repeat steps 3 and 4 until all program have been executed
Update the page to tell the user what is going on
Submit the form
This way, you get the HTML to the user as quickly as possible, then you execute the programs sequentially in an orderly and controlled fashion without worrying about hitting the max_execution_time threshold. This also enables you to keep your user informed - after each AJAX callback, you can tell the user that "program ABC has completed, starting DEF..." and so on.
EDIT
Per request, I'll add an outline of how this could be implemented. A caveat, too: If you are going to be adding more javascript-derived functionality to your page, you'll want to consider using a library like jQuery or mootools (my personal favorite). This is a decision you should make right away - if you aren't going to be doing a lot of javascript except this, then a library will only bloat your project, but if you are going to be adding a lot of javascript, you don't want to have to come back later and re-write your code because you add a library 3/4 of the way through the project.
I've used mootools to create this demonstration, but it isn't necessary or even advisable to add mootools if this is the only thing you're going to use it for. It is simply easier for me to write an example really quick without having to stop and think :)
First, the main page. We'll call this page view.php. This should contain your initial HTML as well as the javascript that will fire off the AJAX requests. Basically, this entire jsFiddle would be view.php: http://jsfiddle.net/WPnEy/1/
Now, execute.php looks like this:
$program_name = isset($_POST['program_name']) ? $_POST['program_name'] : false;
switch ($program_name) {
case 'program1':
$program_path = '/path/to/executable/';
$friendly_name = 'Some program 1';
break;
case 'program2':
$program_path = '/path/to/executable/';
$friendly_name = 'Some program 2';
break;
case 'program3':
$program_path = '/path/to/executable/';
$friendly_name = 'Some program 3';
break;
case 'program4':
$program_path = '/path/to/executable/';
$friendly_name = 'Some program 4';
break;
default:
die(json_encode(array(
'program_name'=>'Invalid',
'status'=>'FAILED',
'error'->true,
'error_msg'=>'Invalid program'
)));
break;
}
$pid = run_in_background($program_path)
while (is_running(pid)) {
sleep(1);
}
// check here for errors, get any error messages you might have
$error = false;
$error_msg = '';
// use this for failures that are not necessarily errors...
$status = 'OK';
die(json_encode(array(
'program_name'=>$friendly_name,
'status'=>$status,
'error'->$error,
'error_msg'=>$error_msg
)));
execute.php would then be called once for each program. The $friendly_program variable gives you a way to send back something for the user to see. The switch statement there makes sure that the script isn't being asked to execute anything you aren't expecting. The program is executed, and when it is done you send along a little package of information with the status, the friendly name, any errors, etc. This comes into the javascript on view.php, which then decides if there are more programs to run. If so, it will call execute.php again... if not, it will submit the form.
This seems rather convoluted... And very risky. Any network glitches, the user's browser closing for whatever reason, and even a firewall timing out, and this script is aborted.
Why not run the whole thing in the background?
<?php
session_start();
$_SESSION['background_run_is_done'] = false;
session_write_close(); // release session file lock
set_time_limit(0);
ignore_user_abort(true); // allow job to keep running even if client disconnects.
.... your external stuff here ...
if ($successfully_completed) {
session_start(); // re-open session file to update value
$_SESSION['background_run_is_done'] = TRUE;
}
... use curl to submit job completion post here ...
?>
This disconnects the state of the user's browser from the processing of the jobs. You then just have your client-side code ping the server occasionally to monitor the job's progress.
Launching and managing multiple and long-running processes from a webserver PHP process is fraught with complications and complexity. It's also very different on different platforms (you didn't say which you are using).
Handling the invocation of these processes synchronously from the execution of your PHP is not the way to address this. You really need to run the programs in a seperate session group - and use (e.g.) Ajax or Comet to poll the status of them.
I am trying to get Selenium RC up and running for doing some automated testing on my website. I am finding that I constantly want to verify that I haven't broken any features, and manual testing is starting to become tiresome.
However, I can't seem to get Selenium RC to work with WaitForPageToLoad.
I tried copying the basic example that they give in the selenium documentation, but the test always gets stuck at: $this->waitForPageToLoad("30000"); I can see that it gets that far in the window that it brings up and that the page appears to have loaded correctly (we are at a google search result page). But the test fails with a timeout.
require_once 'PHPUnit/Extensions/SeleniumTestCase.php';
/**
* Description of Test
*
* #author brian
*/
class Test extends PHPUnit_Extensions_SeleniumTestCase {
function setUp() {
$this->setBrowser("*safari");
$this->setBrowserUrl("http://www.google.com/");
}
function testMyTestCase() {
$this->open("/");
$this->type("q", "selenium rc");
$this->click("btnG");
$this->waitForPageToLoad("30000");
$this->assertTrue($this->isTextPresent("Results * for selenium rc"));
}
}
What is even more interesting is that if I refresh the page when it is waiting, everything continues on as expected. So it would appear as though the waitForPageToLoad isn't realizing that the page has already loaded.
The example in the Selenium RC documentation is obsolete. Google changed the way their home page worked quite a while ago, and it is no longer a simple HTML page. Pressing the search button is now an AJAX-type operation that sends the search request and gets back a JSON response that is processed by the JavaScript code in the page. So the page never is re-loaded, and WaitForPageToLoad() eventually times out.
There is also another possible cause of this situation that I ran into just now. According to the documentation, if you call ANY SELENIUM COMMANDS in between loading a page and calling waitForPageToLoad, then it is possible that waitForPageToLoad will hang. (If I understand it correctly, it is technically a race condition between the test script and selenium server, so it happens sometimes, not necessarily all the time).
In most cases, the page load is caused by a click event. When you have a test script like:
$this->click("/some/path");
// <<- NO SELENIUM COMMANDS HERE
$this->waitForPageToLoad("30000");
Make extra sure that no selenium commands ever accidentally get inserted into the marked area.
While this is not technically the same problem that the OP posted about, it has the same error message, and I couldn't find this information without digging around quite a bit. Hopefully this is easier to find for other people in the future.
I have observed same problem many times. Hence I did not use this command when user is not navigating away from current page. It hangs at times and using IsElementPresent in while loop and exit after it return true.
An alernative to "WaitForPageToLoad()" Is to wait for an element to be present.
$SECONDS = 360;
for ($second = 0; ; $second++) {
if ($second >= $SECONDS) $this->fail("TIMEOUT");
try {
if ($this->isElementPresent("edit-submit")) break;
} catch (Exception $e) {}
sleep(1);
}
This code will loop for 360 seconds, checking if the value (edit-submit) is present each second. ("sleep(1)"). It essentially will achieve the same result as WaitForPageToLoad, but you can specify an absolute target.