Why is javascript not checking my checkbox? - ruby-on-rails-4

I am trying to test a simple header checkbox checks all checkboxes in a table.
The test is below:
scenario 'select all enrolments', js: true do
check 'all_enrolment_presentations'
expect(page).to have_css('.enrolment-presentation-listing input[type="checkbox"]:checked', count: 1)
end
This fails, however if I change the scenario a bit to
scenario 'select all enrolments', js: true do
sleep 3
check 'all_enrolment_presentations'
expect(page).to have_css('.enrolment-presentation-listing input[type="checkbox"]:checked', count: 1)
end
It works.
I have tested a couple of other selectors and they all pretty much have the same affect. I do not want to have to add sleep statements to get stuff like this to pass. I must be doing something incorrect.
When I run the test without the sleep clause, it seems to find the control (it gets highlighted), but it isn't checked. See screenshot for what I mean.
My question is why is this happening and how can I fix my issue?
Note I am using rails 4.2.4 and capybara 2.5.0

After some further investigation the bug was actually caused by upgrading selenium-webdriver from version 2.45.0 to 2.48.1. I haven't had enough time to investigate the root cause within the gem.

You have to wait until capybara to perform click operation.
So,
1. Use sleep
example sleep 5 with wait for 5 seconds
2. Change default wait time in capybara using
`Capybara.default_wait_time = some_value`

Related

Selenium Python Script, InvalidElementStateException

So I'm getting this error every so often when running the exact same test.
StaleElementReferenceException: Message: stale element reference: element is not attached to the page document
(Session info: chrome=69.0.3497.100)
(Driver info: chromedriver=2.41.578706 (5f725d1b4f0a4acbf5259df887244095596231db),platform=Mac OS X 10.12.6 x86_64)
The only problem is that it seems to happen inconsistently to different areas of the code. It's when trying to access DOM elements, like a search field, of my ReactJS page. I'm running this through ROBOT Automation Framework, using a mix of the SeleniumLibrary and a custom library.
I've read that it's simply as it sounds, the xPath as become outdated on the DOM, but that doesn't help me figure out why it's an inconsistent error happening almost anywhere at any point.
EDIT: It seems to be happening in this:
def filter_modality(self, filter):
filter_value = '//span[#title="{}"]//parent::li'.format(filter)
self.selib.click_element(filter_locator)
self.selib.wait_until_page_contains_element('//*[#class="multi-selector-options open"]')
self.selib.wait_until_element_is_visible(filter_value)
self.selib.click_element(filter_value )
self.selib.wait_until_page_contains_element('//div...[#class="option selector-item active"]',
error=("Could not select filter: {}".format(filter_value )))
#I get the stale element message from or after executing this click_element
self.selib.click_element(filter_locator)
self.selib.wait_until_page_does_not_contain_element('//*[#class="multi-selector-options open"]',
error="Filter dropdown did not disappear after selection")
The exception comes when SE has found an element, but shortly afterwards something (a JS function) has changed it - removed from/rearranged it in the DOM, or changed its attributes significantly, so it's no longer tracked as the same element.
This comes for the fact that SE builds an internal cache of the DOM, which may become desynchronized from the actual one; thus the name "stale" - the el. is cached in some state, but its actual form is now different.
The issue is that common, that there is a specific SO tag for it - https://stackoverflow.com/questions/tagged/staleelementreferenceexception (I myself was surprised from this).
The common solutions are:
sleep for some seconds before an event you know will cause the issue
re-get an element before its usage (if you store a reference to it in a WebElement object, not really the case with robotframework)
have a rertry mechanism on working with an element that you know may cause the execution
swallow the exception and move along (I've done it in a few places, where the element was just a confirmation an operation was executed - it has been shown/found by SE once, afterwards I don't care is it changed in the DOM)

Status code in microsoft dynamics navision 2009

I am triing to figure out where the status code will be changed. Because If I try to book a order. and something goes wrong.then there will be a rollback. But in present day the status code will be changed, what not has to be. Because you cant book the whole order after. Status code has to be unchanged.
Thank you
The status code will be changed after this error:
And yes, I debugged the code
and in code unit: 7301 on this line:
END ELSE
IF FromBinContent."Quantity (Base)" + "Qty. (Base)" < 0 THEN
FromBinContent.FIELDERROR(
"Quantity (Base)",STRSUBSTNO(Text000,FromBinContent."Quantity (Base)"));
END;
I will get the error
Thank you
Oke, I found the piece of code where status code will be changed.
lRecStatus.FILTERGROUP(4);
lRecStatus.SETRANGE("Change Status",lRecStatus."Change Status"::Released);
lRecStatus.FILTERGROUP(0);
IF NOT lFncNextStatus2(vRecSalesHeader,lRecStatus,FALSE,FALSE) THEN
ERROR(lCtx000,vRecSalesHeader."Document Type",vRecSalesHeader."No.",vRecSalesHeader."Status Code");
lRecStatus.SETRANGE("Change Status",lRecStatus."Change Status"::01-NEW);
vRecSalesHeader.FIND('=');
So I added this:
lRecStatus.SETRANGE("Change Status",lRecStatus."Change Status"::01-NEW);
But how to set the value New - how it was? and not that the code goes to "vrijgegeven"?
Thank you
Oke. I found in codeunit: 1107570 this:
lRecStatus.FILTERGROUP(4);
lRecStatus.SETRANGE("Change Status",lRecStatus."Change Status"::Released);
lRecStatus.FILTERGROUP(0);
IF NOT lFncNextStatus2(vRecSalesHeader,lRecStatus,FALSE,FALSE) THEN
ERROR(lCtx000,vRecSalesHeader."Document Type",vRecSalesHeader."No.",vRecSalesHeader."Status Code");
vRecSalesHeader.FIND('=');
and if I comment this:
IF NOT lFncNextStatus2(vRecSalesHeader,lRecStatus,FALSE,FALSE) THEN
ERROR(lCtx000,vRecSalesHeader."Document Type",vRecSalesHeader."No.",vRecSalesHeader."Status Code");
then the status code will not been changed. But I dont know if this is correct, because maybe somewhere else goes wrong.
Thank you
If the status code is remaining updated after an error message, then the most likely cause is that a COMMIT has been issued after the posting routing is called but before the error message.
The OMS Tab on your Sales Order is appears to be the result of ether an ISV add-on or database specific customization, so it is hard to say for sure where the suspect code would be, there are a number of ways to find it.
The most straight forward way to find the code would be to user the Debugger (Tools -> Debugger -> Active / Breakpoint on Triggers) while repeating the process and step-in / over the transactions until you encounter a COMMIT statement.
If your more familiar with C/AL code (and have a sufficient license / permissions) you can open the form for modification and manually trace the code used to post the document.
Refactoring the code to remove a COMMIT can be quite tricky and if it is being changed inside the posting routing would likely require your Dynamics Partner or ISV to make the modification due to how the development license structure works.

Capybara/Poltergeist DOM loading issues

I am writing a test suite using Capybara/Poltergeist combo for a website and I am coming across a situation where the DOM doesn't seem to be loading whatever I try to do.
I can see from the website snapshot that only the footer and the header are there, but not the main components of the page.
for example a page such as: https://www.udemy.com/courses/business/finance/all-courses/?lang=en&ordering=newest
Capybara.register_driver :poltergeist do |app|
Capybara::Poltergeist::Driver.new(app, js_errors: false, debug: false, # change this to true to troubleshoot
window_size: [1300, 1000] # this can affect dynamic layout
)
end
browser=Capybara.current_session
browser.visit "https://www.udemy.com/courses/business/finance/all-courses/?lang=en&ordering=newest"
sleep 15 ##giving it time to load
browser.save_screenshot('app/file1.png', full: true)
only the header and footer show up.
I suppose it is due to the fact that some DOM elements are loaded asynchronously, and on my current website I have the same problem.
Stuck here for 2 days now, any suggestions as to how to get the page to load properly? Thanks
You most likely need to update phantomjs to 2.0+. PhantomJS 1.9.8 which I'm guessing you're using is roughly equivalent to Safari 5 iirc and doesn't appear to work with the udemy site.

Can Amazon Simple Workflow (SWF) be made to work with jRuby?

For uninteresting reasons, I have to use jRuby on a particular project where we also want to use Amazon Simple Workflow (SWF). I don't have a choice in the jRuby department, so please don't say "use MRI".
The first problem I ran into is that jRuby doesn't support forking and SWF activity workers love to fork. After hacking through the SWF ruby libraries, I was able to figure out how to attach a logger and also figure out how to prevent forking, which was tremendously helpful:
AWS::Flow::ActivityWorker.new(
swf.client, domain,"my_tasklist", MyActivities
) do |options|
options.logger= Logger.new("logs/swf_logger.log")
options.use_forking = false
end
This prevented forking, but now I'm hitting more exceptions deep in the SWF source code having to do with Fibers and the context not existing:
Error in the poller, exception:
AWS::Flow::Core::NoContextException: AWS::Flow::Core::NoContextException stacktrace:
"aws-flow-2.4.0/lib/aws/flow/implementation.rb:38:in 'task'",
"aws-flow-2.4.0/lib/aws/decider/task_poller.rb:292:in 'respond_activity_task_failed'",
"aws-flow-2.4.0/lib/aws/decider/task_poller.rb:204:in 'respond_activity_task_failed_with_retry'",
"aws-flow-2.4.0/lib/aws/decider/task_poller.rb:335:in 'process_single_task'",
"aws-flow-2.4.0/lib/aws/decider/task_poller.rb:388:in 'poll_and_process_single_task'",
"aws-flow-2.4.0/lib/aws/decider/worker.rb:447:in 'run_once'",
"aws-flow-2.4.0/lib/aws/decider/worker.rb:419:in 'start'",
"org/jruby/RubyKernel.java:1501:in `loop'",
"aws-flow-2.4.0/lib/aws/decider/worker.rb:417:in 'start'",
"/Users/trcull/dev/etl/flow/etl_runner.rb:28:in 'start_workers'"
This is the SWF code at that line:
# #param [Future] future
# Unused; defaults to **nil**.
#
# #param block
# The block of code to be executed when the task is run.
#
# #raise [NoContextException]
# If the current fiber does not respond to `Fiber.__context__`.
#
# #return [Future]
# The tasks result, which is a {Future}.
#
def task(future = nil, &block)
fiber = ::Fiber.current
raise NoContextException unless fiber.respond_to? :__context__
context = fiber.__context__
t = Task.new(nil, &block)
task_context = TaskContext.new(:parent => context.get_closest_containing_scope, :task => t)
context << t
t.result
end
I fear this is another flavor of the same forking problem and also fear that I'm facing a long road of slogging through SWF source code and working around problems until I finally hit a wall I can't work around.
So, my question is, has anyone actually gotten jRuby and SWF to work together? If so, is there a list of steps and workarounds somewhere I can be pointed to? Googling for "SWF and jRuby" hasn't turned up anything so far and I'm already 1 1/2 days into this task.
I think the issue might be that aws-flow-ruby doesn't support Ruby 2.0. I found this PDF dated Jan 22, 2015.
1.2.1
Tested Ruby Runtimes The AWS Flow Framework for Ruby has been tested
with the official Ruby 1.9 runtime, also known as YARV. Other versions
of the Ruby runtime may work, but are unsupported.
I have a partial answer to my own question. The answer to "Can SWF be made to work on jRuby" is "Yes...ish."
I was, indeed, able to get a workflow working end-to-end (and even make calls to a database via JDBC, the original reason I had to do this). So, that's the "yes" part of the answer. Yes, SWF can be made to work on jRuby.
Here's the "ish" part of the answer.
The stack trace I posted above is the result of SWF trying to raise an ActivityTaskFailedException due to a problem in some of my activity code. That part is my fault. What's not my fault is that the superclass of ActivityTaskFailedException has this code in it:
def initialize(reason = "Something went wrong in Flow",
details = "But this indicates that it got corrupted getting out")
super(reason)
#reason = reason
#details = details
details = details.message if details.is_a? Exception
self.set_backtrace(details)
end
When your activity throws an exception, the "details" variable you see above is filled with a String. MRI is perfectly happy to take a String as an argument to set_backtrace(), but jRuby is not, and jRuby throws an exception saying that "details" must be an Array of Strings. This exception blows through all the nice error catching logic of the SWF library and into this code that's trying to do incompatible things with the Fiber library. That code then throws a follow-on exception and kills the activity worker thread entirely.
So, you can run SWF on jRuby as long as your activity and workflow code never, ever throws exceptions because otherwise those exceptions will kill your worker threads (which is not the intended behavior of SWF workers). What they are designed to do instead is communicate the exception back to SWF in a nice, trackable, recoverable fashion. But, the SWF code that does the communicating back to SWF has, itself, code that's incompatible with jRuby.
To get past this problem, I monkey-patched AWS::Flow::FlowException like so:
def initialize(reason = "Something went wrong in Flow",
details = "But this indicates that it got corrupted getting out")
super(reason)
#reason = reason
#details = details
details = details.message if details.is_a? Exception
details = [details] if details.is_a? String
self.set_backtrace(details)
end
Hope that helps someone in the same situation as me.
I'm using JFlow, it lets you start SWF flow activity workers with JRuby.

Using `afterRender` hook with nested views

Here is the jsFiddle if you like to see code first
What I want to do is simple: execute some (actually a lot) of view layer Javascript code from jQuery and jsPlumb libraries after ALL the views in the current route have finished rendering. After getting some help from this solution and finding that ember-latest has just been updated to include afterRender hook, I decided to upgrade. I now have the almighty afterRender hook.
All the views I am inserting into the dom have a block class associated with them. So the way I have been testing to see if all the views are in the dom is using $('.block').size() and seeing if it matches expected number.
However I am facing some issues when I try to use this hook in my application. I first tried to call the afterRender in the router, after the calls to connectOutlets. I always get only 1 block when I print out the number of blocks in dom while there should be 10.
If I put this code in didInsertElement of my local block view:
didInsertElement: () ->
knob = this.$("##{#get 'knobId'}")
name = this.$(".name")
main = this.$(".main") #block html content will be injected into main
knob.hide()
Ember.run.scheduleOnce('afterRender', this, ()->
console.log ">> block count: ", $(".block").size()
)
...
Then I get the following output:
>> block count: 1
>> block count: 10
>> block count: 10
>> block count: 10
>> block count: 10
>> block count: 10
>> block count: 10
>> block count: 10
>> block count: 10
>> block count: 10
For some reason the first iteration I only get 1 block in the dom and after that I get all 10. I am not sure why. But the main issue here is that if I put the hook inside didInsertElement, the code gets executed for an arbitrary number of views depending on data (in this example 10). However I only want to run this code once after all views have finished rendering.
Note that the view I am working with has nested data. I tried to reproduce this on jsFiddle, but I failed in the sense that it seems to work all find and dandy on the fiddle. Maybe because my views are big and complex it is causing some synchronization issues? In any event, I think we can use the fiddle as a way to discuss a solution and I can test it locally.
One hack I tried to do to get around the issue is to schedule my code to run after 500ms delay using Ember.run.later. That did solve the issue on my local machine. However, using a timer to do this is very sheep dung and does not work reliably since different browsers or machines may take longer to render the views.
This is a though one to reproduce and I have already spent much time trying to find a solution. I would appreciate any help in reproducing the problem here or finding a solution.
Edit (workaround): Thanks to look for helping me troubleshoot this problem, and by looking at this post about a similar problem, I came up with the following temporary workaround, which I put inside the router code:
# Keep trying until there are two or more blocks in DOM
blocksLoaded = ->
console.log "blocks number ...: ", $('.block').size()
if $('.block').size() > 1
console.log "Yay!...we have ", $('.block').size()
startTraversingBlocks()
else
Ember.run.next(this, ()->
blocksLoaded()
)
blocksLoaded()
This outputs:
blockies number ...: 0
blockies number ...: 1
blockies number ...: 1
blockies number ...: 1
...
blockies number ...: 1
blockies number ...: 10
Yay!...we have 10
As Luke pointed out, the problem here is that my nested views are being rendered over several RunLoops. when I refresh the browser I get a different number of blockies number ...: 1 output everytime, anywhere between 4 and 10 times during my tests.
In my opinion this is not a very good solution, but it seems to work for my use case. I feel that there is a need here for another hook that allows one to access DOM when it is guaranteed all the elements from views are accessible through jQuery selectors, but perhaps I am missing something here.
I ran this question past Kris Selden, and he said "afterRender is after the render queue is totally flushed for that run loop; I'm guessing this is over more than one loop"
The most likely possibility is that you have a record array loading. Perhaps it starts with one item and then 9 more load in later. If you rule out data loading, perhaps you have an Ember.run.next or Ember.run.later somewhere in your code?