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

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?

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:
Declare a script that uses the arguments array
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.)

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.

Related

Is there any benefit of defining radio buttons in a Page Object model (eg. SitePrism) rather than using Capybara directly?

I was using a cucumber/ruby/capybara/siteprism framework and implementing the test pages at present. I've reached a point where there are a lot of radio buttons (over 20) per page in several pages, and I was thinking if there's really any benefit in trying to map all those as static elements in my page object model?
Ie, thinking about it, it seems much more convenient to just use the text of the radio button in the step definition and call the capybara 'choose' method directly, something like the following, so that I don't need to do anything else for those 20+ radio buttons, it should all just work by changing the parameter we're passing in the feature:
cucumber feature:
When I select that "I am over 18"
capybara step:
When /^I select that "(.*)"$/ |option|
choose(option)
Whereas with a page object model like siteprism, I guess the implementation would need to define and maintain all those elements independently in a format similar to:
element :over_18_button, :radio_button, "I am over 18"
element :over_12_button, :radio_button, "I am over 12"
etc x50times
And for using it, one should create the page, call the element, which doesn't seem as straight forward to me?
siteprism step:
When /^I select that "(.*)"$/ |option|
case option
when 'I am over 18'
over_18_button.click
when 'I am over 12'
over_12_button.click
I guess one could create 'elements' or a 'section' with an array to all the buttons, but then, we'll have to put extra logic to parse them and click on the relevant one anyway somewhere in the code, whilst it would be all done neatly and without the need for any extra code or maintenance with the 'choose' method from capybara.
Am I right to assume that in this example using Capybara is a better option?
or if it'd be better to define 'ALL' web elements in the page object model, what would the benefit of that be? and could the page object code be done in a different way to take advantage of any possible benefit?
That complicated case statement is unnecessary.
When /^I select that I am over "(\d\d)"$/ |age|
#page_object.select_age(age)
I'm not familiar with site_prism. My watir_drops gem would let you define everything with the same pattern like this:
element(:age_button) { |age| browser.radio_button(text: "I am over #{age}")
with this method in the page object:
def select_age(age)
age_button(age).set
end
We could also get into a whole long discussion on using declarative instead of imperative steps. Also, best practice Page Object usage avoids directly calling defined elements. Call methods that accomplish the business logic and those methods do all the implementation including element definitions and actions on them.
Old question but adding important missing info
The way in which site_prism works allows you to define your selector using anything that can be queried in Capybara. So if you want to define your radio using the text, you can do that. Or any other locating strategy you want to use.
Obviously traditionally I would advise using css locators (
element :my_radio, text: 'foo'), because they're easiest to debug and re-use. Furthermore the OP advised he had 50+ of these. If they were identical, they could be abstracted out into a Helper Module or he could even meta-program them in using a loop and index (If they followed a simple index_naming_pattern)

Caching the result of all methods

I have a class which is essentially a collection of methods for some data transformations. In another words I have some data in my files and I use a few different code snippets to transform the textual data into something that I can easily query.
Now the methods often reuse each-other and as the core data is changing I'd like to simply cache the results of each method, for the speed reasons.
I don't want to change each method by adding:
^ methodsCache ifNil: [ methodsCache := "compute" ]
I want to use the power of Pharo reflection to accomplish my task without touching much of code.
One idea that I had is if I can run some code before each method, thing I can either return a cached value or continue the execution of the method and cache it's result
You could use the Reflectivity framework to add pre and post meta links to your methods. A link could check a cache before execution transparently.
link := MetaLink new
metaObject: self;
selector: #cachedExecute:;
arguments: #(selector);
control: #before.
(MyClass>>#myMethodSelector) ast link: link.
This code will install a meta link that sends #cachedExecute: to a MyClass object with the argument #myMethodSelector. The link is installed on the first AST node of the compiled method (of that same method selector, but could be on another method). The #control: message ensures that the link will be executed before the AST node is executed.
You can of course install multiple meta links that influence each other.
Note that in the above example you must not send the same message (#myMethodSelector) again inside of the #cachedExecute: method since you'd end up in a loop.
Update
There's actually an error in the code above (now fixed). The #arguments: message takes a list of symbols that define the parameters of the method specified via #selector:. Those arguments will be reified from the context. To pass the method selector you's use the #selector reification, for the method context the #context reification and for method arguments #arguments. To see which reifications are available, look at the #key on the class side of the subclasses of RFReification.
One idea that I had is to define
doesNotUnderstand: aMessage
aMessage selector beginsWith: 'cached' ifFalse: [ ^ super doesNotUnderstand: aMessage ].
^ cache at: aMessage selector ifAbsentPut: [
self perform: aMessage selector allButFirst: 6 ]
This way the only thing you have to do is to replace all message sends like self methodName with self cachedmethodName (or self cachedMethodName but then you have to do additional lowercase workaround in doesNotUnderstand:)
Another well-known option would be to replace your new and return a caching proxy, delegating to the actual object

Ruby on Rails - Where to put these helper type methods

I've been looking around for best practices on where to put some helper methods that do all this calculation / sorting for me but I haven't found a definitive answer yet and was wondering if someone had some good insight for me.
Basically I have an action method that takes a string user input, finds similar words to that string, does a bunch of string manipulation, and then ordering to return an array.
I don't know whether I should have module in /lib, make a controller helper module, ... Where I'm looking for some feedback!
But essentially I just want to:
POST a word to a controller action method
Call a helper method or execute some logic on the word outside of the controller
Have that helper method or wherever that logic will be, return to me the result
Just put that method in your application helper, wherever it is called from it will return the resulting values after processing your logic, you should not over complicate things so the good old application helper is a good place to put the common method used in views and in your controllers
I wouldn't call a helper method from your controller. Personally I would use either a module/plain old ruby object or a concern to handle calculations. The controller stores the object in an instance variable so it can be used througout your views.
Also worth noting are decorators, you should take a look at draper: https://github.com/drapergem/draper

Errors.add with object instance as message

I have a form with a custom calendar validation routine. I want to be able to display a lot of dynamic information about the this error to the user.
In this sense errors.add(:base, "this is wrong because ...") would not cut it. So I got the idea to pass in an instance of the object that performs the actual validation to the errors array. I would leave it to the view to cherrypick the bits of information it wanted by calling methods on the instance.
In my model validation routine I have:
errors.add(:date_range, [calendar] )
In the view, I do this:
<p><%= #event.errors[:date_range].first.first.parse_events.to_sentence %></p>
I had to add the array literal, otherwise the empty? method that rails calls would fail.
Even though this works, it smells bad! I thought about using render_to_string instead, but obviously that cannot be called (or should not be called) from a model.
Any suggestions on how to improve this?

Ruby: How to get method content dynamically and write it to file?

I'm working on transforming legacy code to a new one in a new project.
There are more than 100 of similar codes and I have to transform them to a slightly different new format.
Basically, get a particular method from the legacy application, rename it, modify the content of the method to fit the new format, and put that method in a class for the new project.
Since there are more than 100 of them, I want to do it programmatically, instead of manually copying and pasting and modifying.
Is there a way to get the source code of a method as a string dynamically?
It must be only for a specific method, not the entire content of the class or file.
After that is done, I think I can just do gsub, or maybe use AST (Abstract Syntax Tree) to pass to Ruby2Ruby.
So I need more than the answers for the question How can I get source code of a methods dynamically and also which file is this method locate in?.
Any help will be greatly appreciated.
After further investigation, I resorted to use live_ast gem to convert the method object to Abstract Syntax Tree and generate the code for the method from that Abstract Syntax Tree (it's using Ruby2Ruby underneath).
Actually, live_ast provides a convenient method to_ruby to do the both steps.
It's working very well.
e.g.
require 'live_ast'
require 'live_ast/to_ruby'
SomeClassWithMethod.instance_method(:method_name).to_ruby
You could use source_location to find the beginning of the method you're looking for, then parse the file from that point until the end of the method. You could examine each line of the file starting from the start of the method, incrementing a counter when you find the start of a block and decrementing it when you reach the end of a block, until the counter reaches 0.

Resources