最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Can't click a web button with webdriverio - Stack Overflow

programmeradmin0浏览0评论

I'm trying to learn automation with webdriverio in nodejs right now, with admittedly not the most knowledge of jquery in HTML. here's where I am:

I've wrote a script that, so far successfully logs me in to an account and navigates to the page I want. My goal is to make a reservation- but when I click a reservation item, a pop up window appears with some pre-loaded data and the "make reservation" button, which on click runs a javascript function. However, I haven't been able to successfully recreate an actual click..

The HTML of the button looks like this:

<div class="inside">
            <ul class="toolBtns">

                <li id="ctl00_ctrl_MakeBookingTime_liCancelChanges" class="cancelChanges">
                    <a id="ctl00_ctrl_MakeBookingTime_lbCancelChanges" href="javascript:__doPostBack('ctl00$ctrl_MakeBookingTime$lbCancelChanges','')">Discard Changes</a></li>
                <li id="ctl00_ctrl_MakeBookingTime_liBook" class="bookRes">
                    <a id="ctl00_ctrl_MakeBookingTime_lbBook" href="javascript:__doPostBack('ctl00$ctrl_MakeBookingTime$lbBook','')">Make Reservation</a></li>
            </ul>               
        </div>

Thus far, I've tried to click it using this (this is the code after my "client" declaration)

  .execute(executeFunction).then(function(resp){
  console.log('execute function status:',resp.state) // should log true if element is there
})
.waitForExist('#ctl00_ctrl_MakeBookingTime_lbBook').then(function(exists){
  console.log('button exists status:',exists.state) // should log true if element is there
})
.elements('#ctl00_ctrl_MakeBookingTime_lbBook').then(function(resp){
    console.log('element found status: ',resp);
  return; //wait for the popup to load before executing the click
}).click('=Make Reservation') //this is the line that doesn't seem to work

that last line is the one that doesn't work. As you see I'm using a regex as the query element, but i've also tried just the item ID directly as suggested here. I've also tried to manually execute the javascript function in the HREF link, but that just dismissess the window without actually making the reservation:

.execute("javascript:__doPostBack('ctl00$ctrl_MakeBookingTime$lbBook")

I am guessing there are some params in _doPostBack function which I'm not understanding..

Any suggestions or links to other articles would be very helpful. I've be scouring for hours and can't quite figure it out. Thanks!

Update

: ChristianB requested for logs, here they are:

2:32:16.747 INFO - Done: [execute script: javascript:LaunchLockedReserver(this,event,'54','200','12/19/2015','9:15 AM','2');, []]
12:32:16.752 INFO - Executing: [find elements: By.xpath: //*[contains(@id, "ctl00_ctrl_MakeBookingTime_lbBook") and contains(., "Make Reservation")]])
12:32:16.766 INFO - Done: [find elements: By.xpath: //*[contains(@id, "ctl00_ctrl_MakeBookingTime_lbBook") and contains(., "Make Reservation")]]
12:32:17.023 INFO - Executing: [find elements: By.xpath: //*[contains(@id, "ctl00_ctrl_MakeBookingTime_lbBook") and contains(., "Make Reservation")]])
12:32:17.038 INFO - Done: [find elements: By.xpath: //*[contains(@id, "ctl00_ctrl_MakeBookingTime_lbBook") and contains(., "Make Reservation")]]
12:32:17.303 INFO - Executing: [find elements: By.xpath: //*[contains(@id, "ctl00_ctrl_MakeBookingTime_lbBook") and contains(., "Make Reservation")]])
12:32:17.303 INFO - Executing: [find element: By.xpath: //*[contains(@id, "ctl00_ctrl_MakeBookingTime_lbBook") and contains(., "Make Reservation")]])
12:32:17.311 INFO - Done: [find elements: By.xpath: //*[contains(@id, "ctl00_ctrl_MakeBookingTime_lbBook") and contains(., "Make Reservation")]]
12:32:17.568 WARN - Exception thrown
org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"xpath","selector":"//*[contains(@id, "ctl00_ctrl_MakeBookingTime_lbBook") and contains(., "Make Reservation")]"}

It seems the last piece isn't working. Thanks for pointing me to the logs. What's odd is that when I change the regex to just the ID directly, it still gives that error:

12:38:33.483 WARN - Exception thrown
org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"id","selector":"ctl00_ctrl_MakeBookingTime_lbBook"}

I'll keep trying and checking the logs

Update #2

I put in logging into the .then functions for each of functions I run (see the updated code above) and the .waitForExists function never seems to even be run. My console output after running the function looks like this:

execute function status: success
Error: element (#ctl00_ctrl_MakeBookingTime_lbBook) still not existing after 500ms
at elements("#ctl00_ctrl_MakeBookingTime_lbBook") - isExisting.js:43:17
at isExisting("#ctl00_ctrl_MakeBookingTime_lbBook") - waitForExist.js:31:21

Basically it seems to go from the .execute straight to the .elements function...

I'm trying to learn automation with webdriverio in nodejs right now, with admittedly not the most knowledge of jquery in HTML. here's where I am:

I've wrote a script that, so far successfully logs me in to an account and navigates to the page I want. My goal is to make a reservation- but when I click a reservation item, a pop up window appears with some pre-loaded data and the "make reservation" button, which on click runs a javascript function. However, I haven't been able to successfully recreate an actual click..

The HTML of the button looks like this:

<div class="inside">
            <ul class="toolBtns">

                <li id="ctl00_ctrl_MakeBookingTime_liCancelChanges" class="cancelChanges">
                    <a id="ctl00_ctrl_MakeBookingTime_lbCancelChanges" href="javascript:__doPostBack('ctl00$ctrl_MakeBookingTime$lbCancelChanges','')">Discard Changes</a></li>
                <li id="ctl00_ctrl_MakeBookingTime_liBook" class="bookRes">
                    <a id="ctl00_ctrl_MakeBookingTime_lbBook" href="javascript:__doPostBack('ctl00$ctrl_MakeBookingTime$lbBook','')">Make Reservation</a></li>
            </ul>               
        </div>

Thus far, I've tried to click it using this (this is the code after my "client" declaration)

  .execute(executeFunction).then(function(resp){
  console.log('execute function status:',resp.state) // should log true if element is there
})
.waitForExist('#ctl00_ctrl_MakeBookingTime_lbBook').then(function(exists){
  console.log('button exists status:',exists.state) // should log true if element is there
})
.elements('#ctl00_ctrl_MakeBookingTime_lbBook').then(function(resp){
    console.log('element found status: ',resp);
  return; //wait for the popup to load before executing the click
}).click('=Make Reservation') //this is the line that doesn't seem to work

that last line is the one that doesn't work. As you see I'm using a regex as the query element, but i've also tried just the item ID directly as suggested here. I've also tried to manually execute the javascript function in the HREF link, but that just dismissess the window without actually making the reservation:

.execute("javascript:__doPostBack('ctl00$ctrl_MakeBookingTime$lbBook")

I am guessing there are some params in _doPostBack function which I'm not understanding..

Any suggestions or links to other articles would be very helpful. I've be scouring for hours and can't quite figure it out. Thanks!

Update

: ChristianB requested for logs, here they are:

2:32:16.747 INFO - Done: [execute script: javascript:LaunchLockedReserver(this,event,'54','200','12/19/2015','9:15 AM','2');, []]
12:32:16.752 INFO - Executing: [find elements: By.xpath: //*[contains(@id, "ctl00_ctrl_MakeBookingTime_lbBook") and contains(., "Make Reservation")]])
12:32:16.766 INFO - Done: [find elements: By.xpath: //*[contains(@id, "ctl00_ctrl_MakeBookingTime_lbBook") and contains(., "Make Reservation")]]
12:32:17.023 INFO - Executing: [find elements: By.xpath: //*[contains(@id, "ctl00_ctrl_MakeBookingTime_lbBook") and contains(., "Make Reservation")]])
12:32:17.038 INFO - Done: [find elements: By.xpath: //*[contains(@id, "ctl00_ctrl_MakeBookingTime_lbBook") and contains(., "Make Reservation")]]
12:32:17.303 INFO - Executing: [find elements: By.xpath: //*[contains(@id, "ctl00_ctrl_MakeBookingTime_lbBook") and contains(., "Make Reservation")]])
12:32:17.303 INFO - Executing: [find element: By.xpath: //*[contains(@id, "ctl00_ctrl_MakeBookingTime_lbBook") and contains(., "Make Reservation")]])
12:32:17.311 INFO - Done: [find elements: By.xpath: //*[contains(@id, "ctl00_ctrl_MakeBookingTime_lbBook") and contains(., "Make Reservation")]]
12:32:17.568 WARN - Exception thrown
org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"xpath","selector":"//*[contains(@id, "ctl00_ctrl_MakeBookingTime_lbBook") and contains(., "Make Reservation")]"}

It seems the last piece isn't working. Thanks for pointing me to the logs. What's odd is that when I change the regex to just the ID directly, it still gives that error:

12:38:33.483 WARN - Exception thrown
org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"id","selector":"ctl00_ctrl_MakeBookingTime_lbBook"}

I'll keep trying and checking the logs

Update #2

I put in logging into the .then functions for each of functions I run (see the updated code above) and the .waitForExists function never seems to even be run. My console output after running the function looks like this:

execute function status: success
Error: element (#ctl00_ctrl_MakeBookingTime_lbBook) still not existing after 500ms
at elements("#ctl00_ctrl_MakeBookingTime_lbBook") - isExisting.js:43:17
at isExisting("#ctl00_ctrl_MakeBookingTime_lbBook") - waitForExist.js:31:21

Basically it seems to go from the .execute straight to the .elements function...

Share Improve this question edited May 23, 2017 at 12:07 CommunityBot 11 silver badge asked Dec 12, 2015 at 17:10 RodneyStangerRodneyStanger 411 gold badge1 silver badge5 bronze badges 13
  • Can you provide any Selenium logs? Would like to see if the click was successful and if the element even exists – ChristianB Commented Dec 12, 2015 at 17:18
  • @ChristianB just added them to the original post. Thanks for pointing me to the logs. It doesn't seem to find the element. I'll see if I can fix the element selector. – RodneyStanger Commented Dec 12, 2015 at 17:44
  • What I don't understand is that the .waitForExist functions and the .click functions use the same selector param but the .click function doesn't find the element. – RodneyStanger Commented Dec 12, 2015 at 17:50
  • Try just do this: ".click('#ctl00_ctrl_MakeBookingTime_lbBook')" there should be only one element with that id. – ChristianB Commented Dec 12, 2015 at 17:54
  • Yea I tried that, still not finding the element. See the last log in my original post for the selenium log to that attempt. Is it possible that my waitForExist function isn't working long enough to let the popup load? – RodneyStanger Commented Dec 12, 2015 at 18:01
 |  Show 8 more ments

1 Answer 1

Reset to default 2

You may be using .waitForExist wrong.

From http://webdriver.io/api/utility/waitForExist.html . Its Future returns a Boolean depending on whether it finds the selector or not, once ms has run out.

.waitForExist(selector[,ms][,reverse]).then(callback);

ms and reverse are optional. You want the default, which for ms is set in your wdio config file.

To verify that the element is found you can do this,

waitForExist('#ctl00_ctrl_MakeBookingTime_lbBook').then(function(exists){ console.log(exists) // should log true if element is there })

You shouldn't need to try to partially match 'Make Reservation' as the id selector should be unique.

Update:

Futures are chained, and it can be hard to tell where a Future has broken up the chain. Sometimes, when I can't make heads or tails where something is breaking, I put in calls in between each chained member with something I know will return something, like

.getTitle().then(function(title){
    console.log(title);
});

The property, exists.state, is not available. Though it's not in the documentation, I've verified that waitForExists resolves to true or false. If you're not sure about the parameter being passed in, you can use console.log(arguments) to get arguments as an array. DO NOT USE THIS FOR PRODUCTION. Try doing this in your waitForExist.then() callback to see what you have.

You shouldn't need elements (even though that may not be the root of the problem). If you're only wanting to click one button .click(#ctl00_ctrl_MakeBookingTime_lbBook) is what's supposed to be done.

Can you describe more about the following code? It could affect the rest of the Future chain also. Can you output console.log(arguments) and post it?

.execute(executeFunction).then(function(resp){
  console.log('execute function status:',resp.state) // should log true if element is there
  console.log(arguments);
})
发布评论

评论列表(0)

  1. 暂无评论