WebDriver ExecuteScript and Promises

Hi all,

I am creating a monitor on Synthetics. I need to execute some front end javascript using webdriver.executeScript. The code I need to run is asynchronous so I need to wait for the result of a asynchronous task and send it back to the webdriver context. I am using the Promise interface to achieve this. but in all the cases when I grab the result in the webdriver context I get an empty object.

This is pretty much what I need to do:

$browser.executeScript(function(){
     var execute = new Promise(function(resolve, reject) {
    
	      // Set interval every n seconds during m seconds and on every 
           var timer = 0;
           var maxTime = 5;
      
          // Run the interval
         var interval = window.setInterval(function(){
         // Async code ... and then when I get the end result I fulfil the promise
         if (timer == maxTime) {
            resolve({test:true});
            window.clearInterval(interval);
         }
         timer++;
       },1000);
    });

    return execute.then(function(val){
      return val;
    }).catch(function(reason){
      return reason;
    });

}).then(function(val){
    
   // Assert val, etc
   console.log(val);
   // it logs {} even if I resolve a string, etc.
    
});

If I do not use promise and I just return any other type such as plain object or string, it works. The thing is I do need to use Promise because I need to execute async code and then return the final result.

Does anybody know why it is not working?

Thanks.

UPDATE

I was able so solve the by problem calling executeAsyncScript in liue of executeScript.

Hi @carlos_landman - you are not actually returning your promise anywhere in your function as I think you are expecting. For a clear example of how to use promises using q take a look at my API Synthetic maintenance workaround.

1 Like

Hey @stefan_garnham thanks for the reply, looking at your example I see you are using nodejs and Q.
which is a bit different. If you have a look at the Promise api (front end) you will see that you don’t need to explicitly return a promise, just by calling resolve|reject make it theneable. The developers mozilla page provides some information about the Promise global object and I following the same implementation: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

Your promise resolved is being handled in your executeScript function. Changing it to this should work.

$browser.executeScript(function(){
     var execute = new Promise(function(resolve, reject) {
    
	      // Set interval every n seconds during m seconds and on every 
           var timer = 0;
           var maxTime = 5;
      
          // Run the interval
         var interval = window.setInterval(function(){
         // Async code ... and then when I get the end result I fulfil the promise
         if (timer == maxTime) {
            resolve({test:true});
            window.clearInterval(interval);
         }
         timer++;
       },1000);
    });

    return val;

}).then(function(val){
    
   // Assert val, etc
   console.log(val);
   // it logs {} even if I resolve a string, etc.
    
}).catch(function(reason){
      return reason;
});

thanks again, I ran it but I’ve got some errors, val needs to be defined somewhere. I found maybe a clue, there is the method driver.executeAsyncScript.

Of course val hasn’t been defined!

I haven’t used this form of Promise so I am uncertain how it actually resolves; I just took a look at the documentation you provided. I have now realised that the sample documentation and your function are essentially doing the same thing as in the promise runs and fulfils in your function. You will have to return your promise to chain onto it.

$browser.executeScript(function(){
     var execute = new Promise(function(resolve, reject) {
    
	      // Set interval every n seconds during m seconds and on every 
           var timer = 0;
           var maxTime = 5;
      
          // Run the interval
         var interval = window.setInterval(function(){
         // Async code ... and then when I get the end result I fulfil the promise
         if (timer == maxTime) {
            resolve({test:true});
            window.clearInterval(interval);
         }
         timer++;
       },1000);
    });

    return execute;

}).then(function(val){
    
   // Assert val, etc
   console.log(val);
   // it logs {} even if I resolve a string, etc.
    
}).catch(function(reason){
      return reason;
});

Yes, well I was doing something similar:

return execute.then(function(val){return val;});

So I wanted to return the value instead the promise. I returned the execute var as you stated but still doesn’t work :open_mouth:. I’ll rewrite the example using executeAsyncScript first it makes more sense.

To chain promises from functions, you have to return the promise variable. The function containing the promise will then execute in the promise chain with one of 2 outcomes.

Resolve - where the value of the result of the function logic is returned.
Reject - usually because a certain condition fails. In my example, because the API is within the maintenance window.

BTW, are you using this in a Browser synthetic? If you are then I do not understand why you need the executeScript method at all.

Yeah I got these concepts very clear. As explained above, I need to execute some client javascript in my scripted monitor. Thanks anyway.

Hey @carlos_landman - I want to jump in here. @stefan_garnham has been helping you out and explaining a lot - thank you @stefan_garnham!

But I am also slightly confused - as it happens. Do you still need help getting something working? If so - where are you stuck, as it were? I want to be clear on where you’re at before jumping into the deep end. :slight_smile:

Thank you!

1 Like