Currently I am using ProtractorJS to access a page that has an unspecified number of popup dialog boxes that are not crucial to the operation of the webpage, but block further interaction with it.
For example, when I open the login screen several (but of unknown quantity) pop-ups appear, and one after another (they are not present at the same time). I am currently handling this in a sloppy way (I see if the object is present and click the existing button to terminate it) and I believe their has to be a better way of handling this... Essentially, I would like to "loop" through these actions till they are finished, in a promise like manner if possible.
Also, as a caveat, I would like to be able to handle messages that randomly should appear, without disrupting the flow of my tests. I understand the latter maybe a little to good to be true, but I figured I would ask.
This is one way.
boolean popupFound=true;
while (popupFound) {
try {
// You should temporarily lower implicit wait to avoid slowing things down
driver.setImplicitWait(6);
driver.switchTo().alert().accept(); // select ok or cancel
} catch (NoAlertPresentException ex) {
// Not needed so exit; assumes no delay between popups
popupFound = false;
} finally {
driver.setImplicitWait(60); // Or whatever you had it set at originally
}
}
Better make sure that implicit wait is only as large as it needs to be.
Related
I'm writing E2E tests in Cypress (version 12.3.0). I have a page with a table in a multi-step creation process that requires some data from back-end application. In some cases (rarely, but it occurs) the request gets stuck and the loader never disappears. The solution is simple: go back to the previous step and return to the "stuck" table. The request is sent anew and most likely receives a response - the process and the tests can proceed further. If the loader is not present, then going back and forth should be skipped (most of the times).
I managed to work around that with the code below, but I'm wondering if it could be done with some built-in Cypress functions and without explicit waiting. Unfortunately, I didn't find anything in the Cypress docs and on StackOverflow. I thought that maybe I could use the then function to work on a "conditionally present" element, but it fails on get, that's why I've used find on the jQuery ancestor element.
waitForTableData() {
return cy.get('.data-table')
.should('exist')
.then(table => {
if (this.loaderNotPresent(table)) {
return;
}
cy.wait(200)
.then(() => {
if (this.loaderNotPresent(table)) {
return;
}
cy.get('button')
.contains('Back')
.click()
.get('button')
.contains('Next')
.click()
.then(() => this.waitForTableData());
});
});
}
loaderNotPresent(table: JQuery) {
return !table.find('.loader')?.length;
}
Your code looks to me to be the best you could do at present.
The cy.wait(200) is about the right size, maybe a bit smaller would be better - 50 - 100 ms. The recursive call is going to give you similar behaviour to Cypress retry (which also waits internally, in order not to hammer the test runner).
Another approach would be to cy.intercept() and mock the backend, presuming it's the backend that gets stuck.
Also worth trying a simple test retry, if the loading only fails on a small percentage of times.
I'm using the latest Appium and webdriverion versions to test a native app, and what I need to do in my script is Click on a Button if it exists, but continue if it doesn't.
So, if the Accept and Close button is present it will be clicked, and then the subsequent Allow button will be clicked.
But, if the Accept and Close button isn't present, then it will go straight to the next command and click the Allow button straight away.
My code currently looks like this;
if (await expect(await closeCMP).isExisting()) {
await closeCMP.click()
} else {
var allow = await $('~Allow');
await allow.click();
}
});
});
However, if the Accept and Close button isn't present then the test fails (with a timeout error, as the Accept and Close element cannot be found) rather than perform the next command (which is to click on the Allow button).
Is there an obvious reason for this?
Also, do I need the else part of the loop, or will just the if part of the loop suffice?
I appreciate that some may perceive this as bad practice, but I'm not able to alter anything on the DOM, or do anything with Cookies so I'm not sure what else I can do to get this to work.
Any help would be greatly appreciated.
There's more than one way to do this, but I generally use try/catch blocks to prevent tests from failing when evaluating conditionals.
Here's an example of how it could look using this approach.
try {
await expect(await closeCMP).isExisting();
await closeCMP.click();
} catch {
console.warn('one of the previous lines threw an error');
}
const allow = await $('~Allow');
await allow.click();
Hi i am using selenium webdriver to automate my script and i have used wait.until condition in my script to click on the delivery bttn in below html page. The problem is selenium is finding my element but since the java script reloads the certain element. And the delivery bttn only becomes clickable after reloading. And my selenium script throws "stale element reference: element is not attached to the page document". What should i do to overcome this error.
WebElement delibttn=wait.until(ExpectedConditions.elementToBeClickable(By.xpath("(//button[#class='btn-to-cart nopricetohide btn btn-primary your-catalog-deliver btn-block btn-unpadded tocart-rounded'])[1]")));
delibttn.click();
WebElement contshopping=wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//a[#class='btn btn-link full-width mb-10']")));
Screenshot:
there are two ways to solve your problem.
1) Run the code with Async, that way you can 'await' a line of code, for example..
function async(test1){
await driver.findElement(By.id("");
driver.click();
});
or you can also do the following
2)
function (test1) {
let element = driver.findElement(By.id(elementId));
driver.wait(until.elementIsVisible(element), 10000).then(async () =>{
element.click();
});
This wait in number 2, is the one that i use in my code and it always works.
A very barbaric way of doing it would be to add a ridiculous wait time to check that it isn't something else showing an error similar to a wait problem
driver.sleep(10000);
or
thread.sleep(10000);
(the measurement is in milliseconds unless defined otherwise)
Please let me know if these solutions do not solve the problem.
as Jack suggested you could use async, but I always used an infinte while loop
Code i have given below is in python, but you can use the logic in java too
def wait_for_element():
val = True
while val:
web_elem = driver.find_element_by_id('id')
try:
web_elem.is_displayed()
except Exception as ex:
val = True
else:
val = False
i know infinite loop is not a better way than async, but if there are cases where you can't use async you can use this. Also keep in mind to put timeout for loop, otherwise you would looping infinitely when the page was unresponsive or has not loaded.
the reason it is still throwing this issue is because you are not handling your exceptions properly, this is a response to it still throwing stale element errors.
Add something like this to your project, if you look at the bottom of my code you will see that i have added exceptions to catch errors so it does not affect the code the way it is doing.
driver.findElement(By.id(buttonID)).then(pageElement => {
driver.wait(until.elementIsVisible(pageElement), 10000).then( () => {
pageElement.click();
next();
})
.catch(ex => {
console.log(ex.message, ex.stack)
});
}).catch(ex => {console.log(ex.message, ex.stack)});
This is the example of how i am using catches, however many promises you have in your function the more catches you will need, if you hover over an element in Visual Code / Studio you will be able to see if it throws a promise or not.
This question already has answers here:
Stop page execution like the alert() function
(8 answers)
JavaScript: Overriding alert()
(12 answers)
Closed 4 years ago.
I'm looking at trying to recreate the behavior of a basic prompt box in JavaScript so that I can style it. Essentially, I want to be able to call a function (window.vars.prompt) and have it prompt the user, then return the value the user inputted. I want everything to happen synchronously, so that I can call it via a function and have it returned to the caller.
What I have so far freezes the program, then crashes it. I know why, but i have no Idea how to fix it. Anybody fix it?
Thanks!
(function () {
window.vars.userHasResponded = false
window.vars.userResponse = ""
window.vars.prompt = function(displayMsg) {
$(".input").html(`<div class='prompt'><h2>${displayMsg}</h2><div class="input"><input id="promptValue"/></div><div class="promptContros"><button>ok</button><button>cancel</button></div></div>`)
while (!window.vars.userHasResponded) {
if (window.vars.userResponse)
return window.vars.userResponse;
}
}
window.vars.confirmPrompt = function() {
$(".prompt").html("")
window.vars.userResponse = $("#promptValue").val()
window.vars.userHasResponded = window.vars.userResponse != "";
}
})()
The HTML for the box is stored in a div with a class of input
I'm looking at trying to recreate the behaviour of a basic prompt box in javascript...I want everything to happen synchronously, so that I can call it via a function and have it returned to the caller.
You cannot do so. prompt, alert, confirm, and beforeunload handlers are the only synchronous UI in the browser-based JavaScript world, and you cannot style them. It's impossible to replicate that behavior in your own UI widget.
Your own widget will have to be asynchronous.
In a comment on the question you've asked:
how come that while loop doesn't work?
Because the loop ties up the main UI thread by busy-waiting. User events in browser-based JavaScript queue up waiting for the thread to yield back to the browser (if the user even sees the updated DOM elements in the first place). Your busy-wait is keeping the current task active, meaning the events that follow it in the queue wait on your task to complete.
Instead, have your prompt and such return a Promise. Then, using it looks like this in a normal function:
prompt(/*...*/)
.then(result => {
// ...use the result
});
...or like this in an async function:
const result = await prompt(/*...*/);
(Error handling omitted for brevity.)
I want everything to happen synchronously
Unfortunately, this is impossible - script-writers can't write their own APIs that basically block until they're resolved without freezing the browser completely, they can only invoke a few special built-in methods that have that peculiar property. As is, your while loop's thread will run forever, preventing confirmPrompt from ever running. The thread never ends and so never gives confirmPrompt a chance to run.
Try using Promises instead. await, while not synchronous, can look more synchronous than using .then.
I am porting an old game from C to Javascript. I have run into an issue with display code where I would like to have the main game code call display methods without having to worry about how those status messages are displayed.
In the original code, if the message is too long, the program just waits for the player to toggle through the messages with the spacebar and then continues. This doesn't work in javascript, because while I wait for an event, all of the other program code continues. I had thought to use a callback so that further code can execute when the player hits the designated key, but I can't see how that will be viable with a lot of calls to display.update(msg) scattered throughout the code.
Can I architect things differently so the event-based, asynchronous model works, or is there some other solution that would allow me to implement a more traditional event loop?
Am I making sense?
Example:
// this is what the original code does, but obviously doesn't work in Javascript
display = {
update : function(msg) {
// if msg is too long
// wait for user input
// ok, we've got input, continue
}
};
// this is more javascript-y...
display = {
update : function(msg, when_finished) {
// show part of the message
$(document).addEvent('keydown', function(e) {
// display the rest of the message
when_finished();
});
}
};
// but makes for amazingly nasty game code
do_something(param, function() {
// in case do_something calls display I have to
// provide a callback for everything afterwards
// this happens next, but what if do_the_next_thing needs to call display?
// I have to wait again
do_the_next_thing(param, function() {
// now I have to do this again, ad infinitum
}
}
The short answer is "no."
The longer answer is that, with "web workers" (part of HTML5), you may be able to do it, because it allows you to put the game logic on a separate thread, and use messaging to push keys from the user input into the game thread. However, you'd then need to use messaging the other way, too, to be able to actually display the output, which probably won't perform all that well.
Have a flag that you are waiting for user input.
var isWaiting = false;
and then check the value of that flag in do_something (obviously set it where necessary as well :) ).
if (isWaiting) return;
You might want to implement this higher up the call stack (what calls do_something()?), but this is the approach you need.