I want to check that a piece of text either does not even exist in the DOM or that if it exists, it is invisible.
cy.contains(text).should("not.visible) handles the second case, cy.contains(text).should("not.exist") the first, but either of them fails in the case of the other.
Before trying a conditional solution, have a read through this paragraph
https://docs.cypress.io/guides/core-concepts/conditional-testing#Error-Recovery
This is a feature that they intentionally made not available
Enabling this would mean that for every single command, it would recover from errors, but only after each applicable command timeout was reached. Since timeouts start at 4 seconds (and exceed from there), this means that it would only fail after a long, long time.
every cy...should has a built-in timeout, so if you have multiple your wait time would stack.
TL;DR;
If you can get around having to use a conditional, try that approach first
Alternatively, you can use this trick (at your peril 😉).
cy.get("body").then(($body) => {
if ($body.find(":contains(texta)").length > 0) {
cy.contains("texta").should("not.be.visible");
} else {
cy.contains("texta").should("not.exist");
}
});
cy.get("body").then(($body) => { will get the copy of body(DOM) in the current state and make it available for synchronous querying using jQuery. With jQuery we can determine synchronously whether an element contains the text string with $body.find(":contains(text)")
using the result's length you can make a condition that will then fire off cypress' asynchronous assertions.
Related
I have a very different problem here.
I have this code
xpath = "//div[#class='z-listheader-content'][normalize-space()='Name']/ancestor::table/../following-sibling::div/table"
array = #browser.table(xpath: xpath, visible: true).rows.map { |row| [row.cells[0], row.cells[0].text] }
col = array.filter_map { |x| x if x[1].eql?(result) }
When I am executing the aforementioned code, it throws the following error
timed out after 10 seconds, waiting for #<Watir::Row: located: false; {:xpath=>\"//div[#class='z-listheader-content'][normalize-space()='Name']/ancestor::table/../following-sibling::div/table\", :visible=>true, :tag_name=>\"table\"} --> {:index=>10}> to be located\""
10 is actually the last index of the table.
But it works fine if I put sleep 5 before my code segment. However, I was expecting WATIR to be automatically waited, but this is not the case, May I know why?
Here is more clear explanation
I am printing this line
p #browser.table(xpath: xpath, visible: true).rows.count
With sleep this is printing 10
without sleep, this is throwing the following error ends with {:index=>11}> to be located\, you could see the full error below
"timed out after 10 seconds, waiting for #<Watir::Row: located: false; {:xpath=>\"//div[#class='z-listheader-content'][normalize-space()='Name']/ancestor::table/../following-sibling::div/table\", :visible=>true, :tag_name=>\"table\"} --> {:index=>11}> to be located\""
Per the Documentation on waiting there are a few key points that should be noted:
The idea behind implicit waits is good, but there are two main issues with this form of implementation, so Watir does not recommend and does not provide direct access for setting them.
The wait happens during the locate instead of when trying to act on the element. This makes it impossible to immediately query the state of an element before it is there.
Implicit waits by themselves will not be sufficient to handle all of the synchronization issues in your code. The combination of delegating waiting responsibilities to the driver and leveraging polling in the code (explicit waits) can cause weirdness that is difficult to debug...
...The second and recommended approach to waiting in Selenium is to use explicit waits...
...Note that Watir does its automatic waiting when taking actions, not when attempting to locate...
In your case the wait is needed for location and thus the "automatic" wait you were expecting is not actually how watir works.
The Watir library does however provide mechanisms for explicit waits:
wait_until which waits until a specific condition is true
wait Waits until readyState of document is complete.
It appears that based on your posted issue that a waiting timeout has expired for your location before the element could be found.
It is possible that wait_until would resolve this e.g.
table = #browser.table(xpath: xpath).wait_until(&:visible?)
puts table.rows.count
I have some async form validation code that I'd like to put under test using Cypress. The code is pretty simple -
on user input, enter async validation UI state (or stay in that state if there are previous validation requests that haven't been responded to)
send a request to the server
receive a response
if there are no pending requests, leave async validation UI state
Step 1 is the part I want to test. Right now, this means checking if some element has been assigned some class -- but the state changes can happen very fast, and most of the time (not always!) Cypress times out waiting for something that has ALREADY happened (in other words, step 4 has already occurred by the time we get around to seeing if step 1 happened).
So the failing test looks like:
cy.get("#some-input").type("...");
cy.get("#some-target-element").should("have.class", "class-to-check-for");
Usually, by the time Cypress gets to the second line, step 4 has already ran and the test fails. Is there a common pattern I should know about to solve this? I would naturally prefer not to have change the code under test.
Edit 1:
I'm not certain that I've 100% solved the "race" condition here, but if I use the underlying native elements (discarding the jQuery abstraction), I haven't had a failure yet.
So, changing:
cy.get("#some-input").type("...")
to:
cy.get("#some-input").then(jQueryObj => {
let nativeElement = jQueryObj[0];
nativeElement.value = "...";
nativeElement.dispatchEvent(new Event("input")); // make sure the app knows this element changed
});
And then running Cypress' checks for what classes have / haven't been added has been effective.
You can stub the server request that happens during form validation - and slow it down, see delay parameter https://docs.cypress.io/api/commands/route.html#Use-delays-for-responses
While the request is delayed, your app's validation UI is showing, you can validate it and then once the request finishes, check if the UI goes away.
I m developping a Winjs/HTML windows Store application .
I have to do some tests every period of time so let's me explain my need.
when i navigate to my specific page , I have to test (without a specific time in advance=loop)
So when my condition is verified it Will render a Flyout(Popup) and then exit from the Promise. (Set time out need a specific time but i need to verify periodically )
I read the msdn but i can't fullfill this goal .
If someone has an idea how to do it , i will be thankful.
Every help will be appreciated.
setInterval can be used.
var timerId = setInternal(function ()
{
// do you work.
}, 2000); // timer event every 2s
// invoke this when timer needs to be stopped or you move out of the page; that is unload() method
clearInternal(timerId);
Instead of polling at specific intervals, you should check if you can't adapt your code to use events or databinding instead.
In WinJS you can use databinding to bind input values to a view model and then check in its setter functions if your condition has been fulfilled.
Generally speaking, setInterval et al should be avoided for anything that's not really time-related domain logic (clocks, countdowns, timeouts or such). Of course there are situations when there's no other way (like polling remote services), so this may not apply to your situation at hand.
I need to perform data analysis on files in a directory as they come in.
I'd like to know, if it is better,
to implement an event listener on the directory, and start the analysis process when activated. Then having the program go into sleep forever: while(true), sleep(1e10), end
or to have a loop polling for changes and reacting.
I personally prefer the listeners way, as one is able to start the analysis twice on two new files coming in NEARLY the same time but resulting in two events. While the other solution might just handle the first one and after that finds the second new data.
Additional idea for option 1: Hiding the matlab GUI by calling frames=java.awt.Frame.getFrames and setting frames(index).setVisible(0) on the index matching the com.mathworks.mde.desk.MLMainFrame-frame. (This idea is taken from Yair Altman)
Are there other ways to realize such things?
In this case, (if you are using Windows), the best way is to use the power of .NET.
fileObj = System.IO.FileSystemWatcher('c:\work\temp');
fileObj.Filter = '*.txt';
fileObj.EnableRaisingEvents = true;
addlistener(fileObj,'Changed',#eventhandlerChanged);
There are different event types, you can use the same callback for them, or different ones:
addlistener(fileObj, 'Changed', #eventhandlerChanged );
addlistener(fileObj, 'Deleted', #eventhandlerChanged );
addlistener(fileObj, 'Created', #eventhandlerChanged );
addlistener(fileObj, 'Renamed', #eventhandlerChanged );
Where eventhandlerChanged is your callback function.
function eventhandlerChanged(source,arg)
disp('TXT file changed')
end
There is no need to use sleep or polling. If your program is UI based, then there is nothing else to do, when the user closes the figure, the program has ended. The event callbacks are executed exactly like button clicks. If your program is script-like, you can use an infinite loop.
More info in here: http://www.mathworks.com/help/matlab/matlab_external/working-with-net-events-in-matlab.html
Our team has been testing our application with Selenium as it's heavily JavaScript driven we've always had issues with tests occasionally failing. As the number of tests has increased the probability of at least one two tests failing in a complete run has become a certainty.
What we recently figured out is that we probably have a race condition where selenium will click links before the initialization JavaScript has had a chance to attach event handlers to the element that is being clicked. Of course at this point the effects we're looking for don't happen and we get a failing test.
For the time being we've added a slight delay before clicks to give the initialization JavaScript code time to finish, this is obviously a bit hackish, adds time to overall test execution, and doesn't guarantee tests won't still fail so we're looking for a better solution.
The best idea we've come up with so far is to inject a hidden element into the DOM that Selenium can wait for, before firing the click event to know that it's ready. This will be a lot of extra overhead in terms of developer time when we're working our asynchronous events, removing and adding the element. Also it adds extra stuff to our pages that really isn't necessary for the application.
Does anyone have any better strategies? What have you done to effectively solve this problem?
We moved to Selenium 2 (WebDriver) and are using Page Objects pattern with PageFactory/AjaxElementLocatorFactory - an example of this is here
I did exactly like you : add some delay and wait for some elements to be present on the page. And I'm perfectly fine with it. Maybe switching to Webdriver / selenium 2.0 would help though. Test execution can be trimmed down if you work with an in-memory database or sharing the same selenium/selenium server between tests, or even with parallelization (easy with TestNG for instance).
Have you tried the waitForElementPresent command, and then make it click ?
To eliminate race conditions use Selenium's runScript(String initCondition) combined with waitForCondition(String jsConditional, String timeout) methods.
For example, if the AJAX functionality you want to test causes a new element to be added to the dom you can use something like the following.
String jsPoll = "";
jsPoll += "selenium.browserbot.getCurrentWindow()";
jsPoll += ".document.getElementById('DOMID')";
selenium.waitForCondition(jsPoll, "30000");
The condition will evaluate true when the element is added and the method will continue. If your AJAX function swaps elements (ie: one div for another similarly identified div), you can initialize your conditional with something like the following.
String jsInit = "";
jsInit += "!selenium.browserbot.getCurrentWindow()";
jsInit += ".document.getElementById('DOMID').setAttribute('SELENIUMTEST','1')";
String jsPoll = "";
selenium.runScript(jsInit);
jsPoll += "selenium.browserbot.getCurrentWindow()";
jsPoll += ".document.getElementById('DOMID').getAttribute('SELENIUMTEST') != 1";
selenium.waitForCondition(jsPoll, "30000");
The condition evaluates true when the element is swapped out by the AJAX function.