charlietaylor
charlietaylor

Reputation: 153

Is there a way to combine page object gem and javascript calls

Im using the page object gem and selenium,

when filling in a sign up form, the form fills in correctly, but when clicking apply it errors saying the fields are required even though they are filled in.

this seems to be caused because the page object/selenium method isn't firing the javascript change method which is needed for the application to know the field has been filled in

this can be fixed by using code such as

on(SettingsPage).payment_method_account_number = number
@browser.execute_script("$('input[name=account_number]').change()")

but this is obviously not ideal and breaks the whole point of using page object in the first place by having to declare the fields name attribute again

is there a way better way to solve this problem than what i have shown?

Upvotes: 0

Views: 217

Answers (2)

Justin Ko
Justin Ko

Reputation: 46836

To avoid duplicating an element definition within the page object as well as the execute_script script, you can pass the page object element to the script.

The underlying Selenium-WebDriver (and therefore the Page-Object gem) supports an arguments array within the script being executed. This arguments array basically takes a Selenium-WebDriver elements and converts them to something usable by the script. The Page-Object execute_script method handles the conversion of elements to the right type, so you simply need to:

  1. Declare a script that uses the arguments array
  2. Pass in a PageObject::Element

For example, let us assume your page object has used the accessor:

text_field(:payment_method_account_number, :name => 'account_number')

Therefore, the page object will have a payment_method_account_number_element method that returns the PageObject::Element for this text field.

Within the script you want to execute, you can replace how you locate the element with the arguments array and pass in the PageObject::Element to the execute_script method:

execute_script("$(arguments[0]).change();", payment_method_account_number_element)

Then you can re-write the call to on as:

on(SettingsPage) do |page|
  page.payment_method_account_number = number
  page.execute_script("$(arguments[0]).change();", page.payment_method_account_number_element)
end

(Or, as Dane pointed out, put this into a method in the page object.)

Upvotes: 1

Alexis Andersen
Alexis Andersen

Reputation: 805

I have had a similar problem but the event was "onblur" instead of "onchange". I would imagine the on change would fire, but if it doesn't you could use an approach similar to mine. I ended up creating a widget that redefined the "#{name}=" method to also call the event on the spot. It's a little bit more complicated, but it centralizes all the magic to one class and keeps the code brief.

Upvotes: 0

Related Questions