Ruby gtk2: button.sensitive = false - events still queue - ruby

I use a button on my ruby gtk2 app which starts a longish job processing and I want to disable the button while processing so that the user can't accidentally run it twice. I figured setting button.sensitive = false would do the job and tested it with the following code:
button.signal_connect(:clicked) do
button.sensitive = false
puts "clicked"
sleep 5
button.sensitive = true
end
Clicking on the button after the job has started still seems to put :clicked events on the stack so if I click the button twice more during the sleep, 'clicked' is displayed three times in the console window when I expected it would appear only once.
Do I misunderstand how this is meant to work? If it won't work the way I expect, is there a way to clear the event stack once the job is finished?

Thank you, Torimus - pointed me in the right direction. Apparently it helps if you read the documentation, specifically that of Gtk.events_pending?! Added the following after setting button.sensitive to force the main loop to do its thing:
while Gtk.events_pending? do
Gtk.main_iteration
end

Related

Can I detect if an element (button) is "clickable" in my rspecs?

Context: In my rspec (using Ruby and Capybara)
I click on a link to test an action in my app: adding a branch to my app.
A modal window opens, where I select the branch, and then I click a "submit" button to add the branch to my app. After clicking "submit" the modal window is closed.
The rspecs continues by clicking "Save" in the main screen, to save the state of the application (and effectively saving adding the branch).
Problem: The rspec is failing because (seemingly) it is trying to click the "Save" button on the main screen while the modal window that is used to select the branch is still present. The test doesn't complain that it can't find the "Save" button component, but that it can't be clicked.
The error in the log is:
[...]Save</button> is not clickable at point (692, 23). Other element would receive the click[...]
A gotcha: this rspec passes correctly on some environments, like when it is run against my local server, but it fails when it is executed by our automation server. Thus, this test has been tagged as "flaky".
Potential solutions: Things we have tried so far:
Play around our "clicks configuration", making sure we are on "ready state" and that the modal window is gone. We failed with this, since we kept hitting the same error.
Implement a "wait". We added a loop to sleep for a bit while the modal window seemed to exist
XYZ.add_new_branch_name(#branch_name)
while Utilities.element_visible?(:xpath, myElement)
sleep(0.5)
end
XYZ.save
The while condition checks if the "submit" button of the modal window exists. The element_visible function uses
find(method,element).visible?
but I'm not sure if find should already take into account that the button may exist and be visible but not be clickable.
Since this still fails, in spite of all our effort to make sure that the modal is gone before we attempt to click on the "save" button, I want tot ask:
Is there a proper way to detect if an element behind a modal window is clickable or not using rspecs?
find only cares about "visibility", not "clickability" (and different drivers may have slightly different interpretations of "visibility"). The reason for the flakiness you're seeing is most likely speed of the machine running the tests which affects the timing of the modal animating away. The best way to solve this issue is to disable animations in the test mode (how you do that is dependent on exactly what library and/or CSS you're using for the animations). The other way is to do as you're doing - checking that the modal has disappeared before clicking the 'Save' button, however you should just be using the Capybara provided methods (which include waiting/retrying behavior) rather than writing your own loop for that.
expect(page).not_to have_css('css selector of the modal') # RSpec version
assert_no_css('css selector of the modal') # minitest version
After looking at the mouse position from your error, one other potential issue you may be having is with screen size and scrolling. If the page requires to be scrolled to get to the 'Save' button and (692, 23) would put the button behind a fixed header (you should be able to verify that by taking a screenshot before the button click attempt) then it may not be possible for whatever driver you're using to click the button. In that case you'd need to use execute_script to scroll the page to a different location so the button is not covered on the page and/or increase the "browser" size so scrolling isn't necessary in the test.
I had a similar problem and solved it by writing my own click_on_with_wait helper function:
def click_on_with_wait(text, wait_time: Capybara.default_max_wait_time)
success = false
(wait_time * 10).round.times do
click_on text
success = true
break
rescue Selenium::WebDriver::Error::WebDriverError
sleep(0.1)
end
# Try clicking one last time, so that the error will get raised if it still doesn't work
click_on text unless success
end
This will try to click on the element. If it's still hidden by the modal, the function will wait 100ms and then try again, until the given wait_time is reached.
Using Rails, I put it in system_spec_helpers.rb so that I can simply replace click_on 'Submit Form' with click_on_with_wait 'Submit Form'.

Execute a MEL command after a window has opened

I'm writing a MEL script which involves opening the grease pencil UI toolbar. I want to remove the close button on that toolbar. I tried doing
GreasePencilTool;
window -edit -tbm 0 greasePencilFloatingWindow;
but get Error: line 2: window: Object 'greasePencilFloatingWindow' not found.
Further tests reveal that running
GreasePencilTool;
window -q -exists greasePencilFloatingWindow;
will return a result of 0.
Running GreasePencilTool; and then window -edit -tbm 0 greasePencilFloatingWindow; at separate times works as expected, as does running window -edit -tbm 0 greasePencilFloatingWindow; when the toolbar is already open.
However, I need to be able to remove the close button immediately when the toolbar opens.
The closest thing I can think of that illustrates what I want to do are Javascript callback functions, where another function can be executed once the current function is finished... but is there a way to do something like that in MEL?
I've also tried using the evalDeferred command without success.
The grease pencil tool is launched asynchronously so the window will not be present for some unknown length of time. This means the best you could do is trigger a function which would check periodically and do it the next time you find the correctly named window; you could attach this to an idle time script job.
It's ugly. But it is probably the only way since there's no event that will notify when thje window arrives. If you do that, make the script job suicide after it fires so it's not sitting there on every idle check till the end of time.

Ensure that a popup has been closed with Capybara/Selenium

I am attempting to write a capybara spec which opens a popup, and then asserts that the popup has closed itself.
visit "/my_page"
click_button "Open My Popup"
within_window("MyPopup") do
# test things on MyPopup
end
sleep 1 # long enough that window.close() has been called in the popup
# ensure that MyPopup is closed
Things I've tried so far...
Counting the window handles:
page.driver.browser.window_handles.length
This remains at 2 even after the popup is closed
As this post suggests, check for the visibility of an element on the popup. This doesn't seem to work. Even though the popup has been closed, I can run assertions against the window as if it's still there, just as before:
within_window("MyPopup") do
# test things on MyPopup
end
I'm ensured that window.close is firing from the popup (by adding some JS that modifies the popup's DOM after the window.close() and asserting on those changes).
I'm fairly stumped here; anyone out there know the secret sauce for asserting that the window actually closed?
Maybe you should wait for your page has no some specific css?
It may look like this:
def wait_for(timeout = 10)
Timeout.timeout(timeout) do
loop do
break if yield
end
end
end
wait_for { page.first(:css, 'your.specific.css').nil? }

How to get constant feedback from a slider in Xcode with ApplescriptObjC?

I'm new to ApplescriptObjC as you'll probably see if you keep reading. I was wondering how to get constant feedback from a slider so that as soon as its value is 1 it runs script A and as soon as its value is changed to 0, it runs script B.
I know you can have actions for buttons like:
on buttonClicked_(sender)
do action
end buttonClicked_
But how can I have a one that constantly checks for a change in the slider's value and does the appropriate action? Is it similar to connecting a slider to a text box with the getStringValueFrom() thing?
Any help would be appreciated. Thanks :)
Found out how!
turns out on action_(sender) will work for sliders as well. They send the signal every time the item is clicked on and released whether a change exists or not. Then its a simple matter of an if statement to run two different series of actions depending on the value the slider was set to.

When does the finish event get called in shoes?

Using Shoes, I would like to have a block executed upon window destruction. I thought I could use the finish event, but in the following piece of code, "Starting" is displayed, but "Finished" is never shown.
Shoes.app(:title => "Test") do
flow do
start do |obj|
alert("Starting")
end
finish do |obj|
alert("Finished")
end
button "Hello"
end
end
After doing some more researching...
It appears that the finish event in Shoes is currently only used for downloads.
In addition, it appears there is no onclose event currently, but it has been discussed.
http://article.gmane.org/gmane.comp.lib.shoes/2976
Apologies for answering my own question, but putting the knowledge out there for others.

Resources