I am trying to understand the page events in jQueryMobile navigation, but I found some very weird behaviour, as some event handlers get called several times:
I have two pages: home.html and disclaimer.html. Both contain the same header:
<head>
<script src="js/jquery-1.8.2.min.js"></script>
<script src="js/events.js"></script>
<script src="js/jquery.mobile-1.2.0.min.js"></script>
</head>
On the page home.html is a link:
<section data-role="page" id="home">
Test
</section>
And in the file events.js is the following code:
var i = 0;
$(document).on('pageinit', 'section#home', function(event) {
console.log(i++, 'pageinit');
$('a#test').on('click', function() {
console.log(i++, 'click pageinit');
});
});
$(document).on('pagebeforeshow', 'section#home', function(event) {
console.log(i++, 'pagebeforeshow');
$('a#test').on('click', function() {
console.log(i++, 'click pagebeforeshow');
});
});
Then I do the following steps:
Navigate to home.html (http)
Click the link
Go to disclaimer.html (ajax)
Go to home.html (ajax)
Click the link
With the following console output:
0 "pageinit" // step 1
1 "pagebeforeshow"
2 "click pageinit" // step 2
3 "click pagebeforeshow"
4 "pagebeforeshow" // step 4
5 "click pageinit" // step 5
6 "click pagebeforeshow"
7 "click pagebeforeshow"
Makes sense, right? But now the weird part. When I change the order in which I visit the pages: the behaviour changes.
Navigate to disclaimer.html (http)
Go to home.html (ajax)
Click the link
Go to disclaimer.html (ajax)
Go to home.html (ajax)
Click the link
Console output:
0 "pageinit" // step 2
1 "pagebeforeshow"
2 "click pageinit" // step 3
3 "click pagebeforeshow"
4 "pageinit" // step 5
5 "pagebeforeshow"
6 "click pageinit" // step 6
7 "click pagebeforeshow"
Which is weird, because I would expect the 6th and 7th result to have been duplicated.
Sorry for the very long question. I hope someone can explain to me exactly what is happening and if this is expected behaviour?
tldr; Where do you listen for (click) events in jQueryMobile?
In short: in jQueryMobile you should listen (bind) your events inside pageinit; this is equivalent (more of less) to jQuery's ready event. And it is what the jQueryMobile's guys recommend.
pageinit is triggered once the page has been loaded and initialized (via AJAX or HTTP), but pagebeforeshow may be triggered more than once if the page is already in the DOM, for example after closing a jQueryMobile dialog. Whatever you bind on pagebeforeshow is going to be rebind again every time the page is showed again. That is why you have two click pagebeforeshow.
EDIT: Explanation of your tests
I replicated your 2 html pages and js file and repeated all the steps in both tests.
In your first test you have:
Navigate to home.html (http): It binds (by delegating on document) and triggers pageinit and pagebeforeshow (logs 0 and 1) because your page was initialized and was going to be shown. this also binds the oter two functions to the link (important: in this case is not delegation, but a direct bind!). This is the only time in this test in which "events.js" is going to be loaded and executed.
Click the link: this executes both click pageinit and click pagebeforeshow as expected (logs 2 and 3) because step 1.
Go to disclaimer.html (ajax): this doesn't show any log.
Go to home.html (ajax): since "home.html" is still in the DOM this triggers pagebeforeshow, as you can see in log (4). This executes too the binding in the link. NOTE: I suspect that at this step "disclaimer.html" was remove from DOM (more on this in second test).
Click the link: shows tree logs, the first 2 because step 1, and the last (duplicated) because step 4.
In your second test you have:
Navigate to disclaimer.html (http): It binds pageinit and pagebeforeshow, but doesn't show a log since none of the event is being triggered; both events are being bind to document (by delegation), so it doesn't matters if the specific page isn't yet in the DOM. This is the only time in this test in which "events.js" is going to be loaded and executed.
Go to home.html (ajax): It triggers pageinit and pagebeforeshow and you can see logs 0 and 1. When both events are triggered, the corresponding click events are being bind to the link (a direct bind!)
Click the link: This step shows logs 2 and 3, as expected.
Go to disclaimer.html (ajax): Nothing is shown in the log... but: jQueryMobile decided that "home.html" should be removed from DOM! that is because JQM removes every page once you navigate to another one. Note that "disclaimer.html" is not going to be removed from the DOM ever, since he is the "owner" of it.
Go to home.html (ajax): this step triggers pageinit and pagebeforeshow (since both events are still bind to the document object) as you can see in logs 4 and 5. This binds the two functions to the link, just as in step 2, but... (see next step)
Click the link: Here is where you said "I would expect the 6th and 7th result to have been duplicated"; well they weren't duplicated because the whole page (the div containing the link) and all its content where removed from the DOM, and the first click events you bind directly to the link (in step 2) are gone! so you see only the logs caused by the bind in step 5.
If I (finally) understood how JQM events work, the first page loaded (via full HTTP request) is kept in the DOM until the user navigate to an external page or reload the page (via F5 or CTRL+R). Any other page (loaded via AJAX) is added to the "main" DOM and then unloaded/deleted from it when you navigate to another one. So: if you do all your binds in pageinit (direct binds or at most delegating to its parent div[data-role:page]) you won't need to worry about duplicated event binds.
PD: If you note something weird in how I write, is probably because I'm not used to speak/write in English in passive voice, and sometimes I mix up prepositions :P
Related
I need to test this login form on iOS Emulator, but when I try to insert text on element '//input[#name="email"]' the text is putted however when I select the element '//input[#name="password"]' the text from the first element disappear, the same happens when I press the '//div[#id="react-component-login-header']//button/div/span[1]" element.
I think the problem is related how the Text is inputted in form, since that using Selenium2Library (for Desktop) don't have this problem.
Any other way how I can insert text on the field? I don't have any problem in using other Libraries or creating Keywords on Python to auxiliary the tests (already did on other tests).
I already tried with:
Input Text
Input Value
Input Password (I know, but i needed to try something else)
*** Settings ***
Library Dialogs
Library AppiumLibrary
*** Variables ***
${defaultTimeout} 15s
*** Test Cases ***
TC001
[Setup] Configuration
Start Test
Wait Until Page Contains Element //*[#id='age-gate-yes'] ${defaultTimeout}
Click Element //a[#id='age-gate-yes']
Wait Until Page Contains Element //a[#href="/profile"] ${defaultTimeout}
Click Element //a[#href="/profile"]
Wait Until Page Contains Element //input[#name="email"] ${defaultTimeout}
Click Element //input[#name="email"]
Input Text //input[#name="email"] johndoe#john.doe
Click Element //input[#name="password"]
Input Text //input[#name="password"] JohnDoe123
Click Element //div[#id='react-component-login-header']//button/div/span[1]
Wait Until Page Does Not Contain Element //div[#id='react-component-login-header']//button/div/span[1] ${defaultTimeout}
[Teardown] End Test
I can see the text being written on field, but when the context of that element is lost, the text is too.
For Android I resolve the problem using the keyword "AppiumLibrary.Press Keycode"
Example, sending a "AppiumLibrary.Press Keycode 67" I managed to send a backspace
https://developer.android.com/reference/android/view/KeyEvent.html
Here is the bot for the auto liker:
TAB T=1
TAG POS={{!LOOP}} TYPE=BUTTON ATTR=CLASS:ProfileTweet-actionButton<SP>js-actionButton<SP>js-actionFavoriteā€¯
WAIT SECONDS=1
And here is the error:
RuntimeError: element BUTTON specified by
CLASS:ProfileTweet-actionButtonjs-actionButtonjs-actionFavoriteā€¯
was not found, line: 2
How to fix it?
You need to specify more details about the button, the below code seems to work fine.
VERSION BUILD=9030808 RECORDER=FX
TAB T=1
TAG POS={{!LOOP}} TYPE=BUTTON ATTR=TYPE:button&&DATA-MODAL:ProfileTweet-retweet&&CLASS:ProfileTweet-actionButton<SP><SP>js-actionButton<SP>js-actionRetweet
WAIT SECONDS=3
TAG POS=24 TYPE=BUTTON ATTR=TXT:Close
WAIT SECONDS=2
The selector is from this forum link.
I test following assumption And I click on the text "2018/2019" within ".year" with capybara/headless_chrome and constantly get the error
element not visible
(Session info: headless chrome=67.0.3396.87)
(Driver info: chromedriver=2.40.565386 (45a059dc425e08165f9a10324bd1380cc13ca363),platform=Mac OS X 10.13.5 x86_64) (Selenium::WebDriver::Error::ElementNotVisibleError)
I've already tried to adjust the window size, as suggested here. But it didn't work.
My step definition:
When(/^(?:|I )click on the text "([^"]*)"(?: within "([^"]*)")?$/) do |link, selector|
begin
page.find(:css, selector).click
end
end
The element is actually visible and found by Capybara
[1] pry(#<Cucumber::Rails::World>)> page.find(:css, ".year")
=> #<Capybara::Node::Element tag="a" path="/html/body/div[2]/div[2]/section/div[2]/div/div[1]/div[1]/div[2]/div/div[2]/ul/li/a">
But click fails
[2] pry(#<Cucumber::Rails::World>)> page.find(:css, ".year").click
Selenium::WebDriver::Error::ElementNotVisibleError: element not visible
Why doesn't click work here?
EDIT:
The HAML of the link is
%ul.facet_values
- unselected.each do |facet_value|
%li.filtered{data: {hayf: {text: facet_value.name.downcase}}}
= link_to facet_value.path, title: facet_value.name, class: 'year' do
=truncate("#{facet_value.name}", length: 24)
- if facet.has_counts?
%span.small="(#{facet_value.count})"
I tried headless testing with Poltergeist and got Poltergeist detected another element with CSS selector 'html body header div.container-fluid' at this position which was solved with .trigger('click') and the test passed.
Since this doesn't work in non-headless Chrome or Poltergeist, then the simplest answer is that the element isn't actually visible. Firstly remove the Capybara.ignore_hidden_elements = false setting since that makes no sense when testing an app, and will screw up all sorts of waiting behaviors. Secondly use save_and_open_screenshot to get a picture of what the page actually looks like before you are trying to click the link.
I'm guessing you'll see that the link isn't actually visible at that point and your test is missing a step a user would have to do to make the link visible, is it in a menu where you have to hover over a different element first? is it in a popup where you have to click on something else first?, does it need to be scrolled to? etc.
Finally, you'll generally have less issues if you stick with Chrome via Selenium. Poltergeist uses PhantomJS which hasn't been updated in quite some time and doesn't support modern JS or CSS which can lead to all sorts of strangeness.
When a user logs in or out I add a faces context message. e.g.
facesContext.addMessage(null, new FacesMessage("Loged out"));
However, the messages appears twice. No matter wheather for logout or login.
<rich:notifyStack id="loginInfoStack" position="bottomRight"
direction="vertical" method="first">
<rich:notifyMessages stayTime="5000" nonblocking="false"
showCloseButton="false" showShadow="false" />
</rich:notifyStack>
For a few seconds I thought I would invoke the login twice, but that is not the case. (I debugged.)
I'm using RF 4.3.3.
Any hints?
https://gist.github.com/773349
RTE field validation is not happening if I traverse from RTE to RTE. Please find the attached git.
Steps to reproduce
Case 1
Focus into RTE1, type Hello
Tab out to text input (Node Selector)
Validation works
Case 2
Focus into RTE1, type Hello
Tab out to RTE2
Validation doesn't work
I tried with nightly build and was able to reproduce the above error and case 1 is failing too. An other difference that I noticed is "xxforms-value-change-with-focus-change" event is not fired when moved from RTE to RTE.
This is fixed as of 2011-01-24, and this fix will be included in the Orbeon Forms 3.9 release. Also see: [ #315639 ] RTE: values are not sent to the server when the RTE looses the focus.