Do/While infinitely loops issue c# - c#

I am automating interaction with a website where the user will have to refresh the pages n times manually (sometimes 3 or 5 or even longer) so that the buttons appear on the web page. To overcome this issue, I created a do / while loop that should refresh the page until the button is visible so it can be clicked. The problem is it goes out of sync and infinitely loops. I tried the script below, but it still doesn't stop refreshing. Any idea how to make it stop refreshing as soon as the element is visible? by default, the element will not be visible, so the user will have to refresh the page first. The refresh works, but it is very quick, and it doesn't give enough time to check the state of visibility of the button, and maybe that's why it goes into an infinite loop
int retries = 0;
bool isElementVisible = false;
do {
await Page.ReloadAsync(new PageReloadOptions() { Timeout = 5000 });
isElementVisible = await Page.IsVisibleAsync("input[name='elementname']");
retries ++;
while (!isElementVisible)

The problem with your code is that IsVisibleAsync will resolve to false immediately.
You could wait for visible with some timeout using WaitForSelectorAsync. For instance, 5 seconds:
int retries = 0;
bool isElementVisible = false;
do {
await Page.ReloadAsync(new PageReloadOptions() { Timeout = 5000 });
try {
// The default State is Visible
await Page.WaitForSelectorAsync("input[name='elementname']", new(){ Timeout = 5000});
isElementVisible = true;
} catch(Exception ex) {
retries ++;
}
} while (!isElementVisible)

Related

How to wait until selenium completes its navigation?

Ok here my code and but it immediately executes
private static ChromeDriver mainDriver;
mainDriver.Navigate().GoToUrl(srFetchUrl);
string srPageSource = mainDriver.PageSource;
I have to get the source code after the page is actually navigated to new page and page is loaded
You can try this method, this will wait until page loads completely and you can add your expected time to page load.
public void E_WaitForPageLoad() throws Exception
{
JavascriptExecutor js = (JavascriptExecutor)driver;
//This loop will rotate for 100 times to check If page Is ready after every 1 second.
//You can replace your if you wants to Increase or decrease wait time.
int waittime;
waittime = 60;
for (int i=0; i<waittime; i++)
{
try
{
Thread.sleep(1000);
}catch (InterruptedException e) {}
//To check page ready state.
if (js.executeScript("return document.readyState").toString().equals("complete"))
{
//System.out.println("Wait for Page Load : "+js.executeScript("return document.readyState").toString());
break;
}
}
System.out.println("\nWeb-Page Loaded.");
}
Thank You,
Ed D, India.
Specify , implicit or explicit wait till the element in the page is loaded.
refer this link for C# wait syntax

How to scroll a web page in Coded UI Test with VS 2012?

I'm recording Coded UI Tests with VS 2012, which shall test the functions of a web application.
After I loaded the web page, I click on a button to start p.e. a job application.
After the next page has loaded on the same site, my problem begins.
The entry controls are at the end of the web site.
To take a look and input data into the entry controls, I must scroll down.
The recording produced the following method in the UIMap.
Designer.cs:
public void Scrollen()
{
#region Variable Declarations
Playback.PlaybackSettings.WaitForReadyLevel = WaitForReadyLevel.AllThreads;
this.UIGoogleMozillaFirefoxWindow.UIItemPropertyPage.UIBewerbungDemoFirmaDocument.WaitForControlExist();
this.UIGoogleMozillaFirefoxWindow.UIItemPropertyPage.UIBewerbungDemoFirmaDocument.WaitForControlReady();
Playback.PlaybackSettings.WaitForReadyLevel = WaitForReadyLevel.UIThreadOnly;
WinControl uIBewerbungDemoFirmaDocument = this.UIGoogleMozillaFirefoxWindow.UIItemPropertyPage.UIBewerbungDemoFirmaDocument;
#endregion
// Click "Job application" document
Point pt = new Point(1390, 553);
int count = 0;
while (!uIBewerbungDemoFirmaDocument.TryGetClickablePoint(out pt) && count < 20)
{
count++;
System.Threading.Thread.Sleep(10);
if (count == 20)
Console.WriteLine("ClickablePoint not found");
}
Mouse.Click(uIBewerbungDemoFirmaDocument, new Point(1390, 553));
Mouse.MoveScrollWheel(10);
}
As You can see, I tried WaitForControlExist, WaitForControlReady, TryGetClickablePoint and the method MoveScrollWheel.
But neither Mouse.Click nor Mouse.MoveScrollWheel are working.
And in the next method, where I click into the first of the entry fields, I get a message at execution time, that the click event produces an error, because the control is hidden (because it's down below on the website, out of visible range).
After several tests this is making me crazy.
Any idea what has gone wrong and how can I scroll down the web site, so my entry controls are in visible range?
You can try Control.EnsureClickable(). Or you can use below mentioned function to scroll the page until the control is not clickable.
public static void ScrollAndClick(HtmlControl Control)
{
bool isClickable = false;
if (Control.TryFind())
{
while (!isClickable)
{
try
{
Control.EnsureClickable();
Mouse.Click(Control);
isClickable = true;
}
catch (FailedToPerformActionOnHiddenControlException)
{
Mouse.MoveScrollWheel(-1);
throw;
}
}
}
else
{
throw new AssertInconclusiveException("Control Not Found");
}
}
You can also add condition related to timeout to make sure it don't go to infinite loop.
Let me know if you are having issue with this at your end.

CancellationTokenSource cancelling more then expected

Basically i am running a programm that executes a method that is repeated several times (for example 7 times), but i need an option to cancel the CURRENTLY run one of it, but still allow new ones to start.
My issue is that the programm ends as soon as i hit the cancel button. So i seem to be missing something.
Main:
for(int i = 0; i < 7; i++)
{
cts = new CancellationTokenSource();
taskUbung = Task.Factory.StartNew(async() =>
{
await doSomething();
}, cts.Token);
}
Button:
private void buttonSkipUbung_Click(object sender, RoutedEventArgs e)
{
cts.Cancel();
}
So if i am hitting the button on the 3rd round of doSomething(), the remaining 4 will never execute.
What do i have to change for my desired behavior? I could just use some booleans and return in doSomething(), but i figured this would be cleaner and more responsive, if it works that is.
You need to keep track of the tokens you are creating in some kind of list. Otherwise you only remember the last one and call cancel only on that one

Continue the `while` loop when ExecuteScript(setInterval) is finished

I have a code that scrolls a growing page to the bottom (until it's not possible to scroll to the bottom).
When it's not possible, it scrolls to the top and the javascript code is finished.
For example: imagine a timeline on facebook.
It's a growing page, so I can scroll it again and again until it's not possible to scroll (then I will be in: "BORN").
So this is my code:
while (i < elements.Count)
{
js.ExecuteScript("var timeId = setInterval( function() {
if(window.scrollY<(document.body.scrollHeight-window.screen.availHeight))
window.scrollTo(0,document.body.scrollHeight); else { clearInterval(timeId);
window.scrollTo(0,0); } },5000);");
i++;
}
I want to add 1 to i only when the setInterval is finished.
I tried the next thing:
while (i < elements.Count)
{
object a = js.ExecuteScript("setInterval( function() {
if(window.scrollY<(document.body.scrollHeight-window.screen.availHeight)) {
window.scrollTo(0,document.body.scrollHeight); return '1'}; else {
clearInterval(timeId); window.scrollTo(0,0); return '2'} },5000);");
while (a != '2') {
// do nothing, this while will be ended when we arrived the bottom and
// go back to the top
}
// all the page is loaded
i++;
}
but it doesn't work.. maybe there is a way to scroll to the bottom more and more and then to the top without using set interval? (but remember: it's a growing page that grows when you scroll it down and down..
How can I do it?
The setInterval function is asynchronous, meaning that it happens after the ExecuteScript function gets a return value, this is why what you tried didn't work. The best solution I can think of is to change a little bit the structure of your code and use C# Threading.
Using C# Threading
This way, what we are going to do is to each time stop the code for 5 seconds and then execute a JavaScript code that checks if you can scroll further down, if yes scroll down and if not scroll back up. This JavaScript code will also return whether we should continue running this loop or not.
Basically, this is the JavaScript code we will execute:
if (window.scrollY < (document.body.scrollHeight - window.screen.availHeight)) {
window.scrollTo(0, document.body.scrollHeight);
return true;
} else {
window.scrollTo(0, 0);
return false;
}
And this is how the overall C# code should look:
while (i < elements.Count)
{
bool run = true;
while (run)
{
System.Threading.Thread.Sleep(5000);
run = (bool)js.ExecuteScript("if(window.scrollY<(document.body.scrollHeight-window.screen.availHeight)){window.scrollTo(0,document.body.scrollHeight);return true;}else{window.scrollTo(0,0);return false;}");
}
i++;
}
find something to use as a variable for when you hit the bottom and then use an if statement in the While loop to increment i when that has happened

C# BackgroundWorker

I have a button that on click event I get some information from the network.
When I get information I parse it and add items to ListBox. All is fine, but when I do a fast double-click on button, it seems that two background workers are running and after finishing all work, items in the list are dublicated.
I want to do so that if you click button and the proccess of getting information is in work, this thread is stopping and only after first work is completed the second one is beginning.
Yes, I know about AutoResetEvent, but when I used it it helped me only one time and never more. I can't implement this situation and hope that you will help me!
Now I even try to make easier but no success :( : I added a flag field(RefreshDialogs)(default false), when the user clicks on button, if flag is true(it means that work is doing), nothing is doing, but when flag field is set to false, all is fine and we start a new proccess.
When Backgroundwork completes, I change field flag to false(it means that user can run a new proccess).
private void Message_Refresh_Click(object sender, EventArgs e)
{
if (!RefreshDialogs)
{
RefreshDialogs = true;
if (threadBackgroundDialogs.WorkerSupportsCancellation)
{
threadBackgroundDialogs.CancelAsync();
}
if (!threadBackgroundDialogs.IsBusy)
{
downloadedDialogs = 0;
threadBackgroundDialogs = new BackgroundWorker();
threadBackgroundDialogs.WorkerSupportsCancellation = true;
threadBackgroundDialogs.DoWork += LoadDialogs;
threadBackgroundDialogs.RunWorkerCompleted += ProcessCompleted;
threadBackgroundDialogs.RunWorkerAsync();
}
}
}
void ProcessCompleted(object sender, RunWorkerCompletedEventArgs e)
{
RefreshDialogs = false;
}
So you want to keep the second process running while the first works, but they shouldn't disturb each other? And after the first one finishes the second one continues?
Crude way: While loop:
if (!RefreshDialogs)
{
RefreshDialogs = true;
this becomes:
while(RefreshDialogs)
{
}
RefreshDialogs = true;
After you set it false the second process wwill jump out of the while. (Note this is extremly inefficent since both processes will be running all the time, i'm pretty sure the second one will block the first one, but with multitasking now it shouldn't, if it block use a Dispatcher.Thread)
Elegant way: Use A Semaphore
http://msdn.microsoft.com/de-de/library/system.threading.semaphore%28v=vs.80%29.aspx
If you find it impossible to have both processes running at the same time, or want another way:
Add an Array/List/int and when the second process notices there is the first process running, like with your bool, increase your Added variable, and at the end of the process, restart the new process and decrese the variable:
int number;
if (!RefreshDialogs)
{
RefreshDialogs = true;
your code;
if(number > 0)
{
number--;
restart process
}
}
else
{
number++;
}
I have to admit, i like my last proposal the most, since its highly efficent.
Make your thread blocking. That is easy;
lock(someSharedGlobalObject)
{
Do Work, Exit early if cancelled
}
This way other threads will wait until the first thread releases the lock. They will never execute simultaneously and silently wait until they can continue.
As for other options; why not disable the button when clicked and re-enable it when the backgroundworker completes. Only problem is this does not allow for cancelling the current thread. The user has to wait for it to finish. It does make any concurrency go away very easily.
How about this approach?
Create a request queue or counter which will be incremented on every button click. Every time that count is > 0. Start the background worker. When the information comes, decrement the count and check for 0. If its still > 0 restart the worker. In that your request handler becomes sequential.
In this approach you may face the problem of continuous reference of the count by two threads, for that you may use a lock unlock condition.
I hav followed this approach for my app and it works well, hope it does the same for you.
I'm not an Windows Phone expert, but as I see it has support for TPL, so following code would read nicely:
private object syncRoot =new object();
private Task latestTask;
public void EnqueueAction(System.Action action)
{
lock (syncRoot)
{
if (latestTask == null)
latestTask = Task.Factory.StartNew(action);
else
latestTask = latestTask.ContinueWith(tsk => action());
}
}
Use can use semaphores
class TheClass
{
static SemaphoreSlim _sem = new SemaphoreSlim (3);
static void Main()
{
for (int i = 1; i <= 5; i++)
new Thread (Enter).Start (i);
}
static void Enter (object name)
{
Console.WriteLine (name + " wants to enter");
_sem.Wait();
Console.WriteLine (name + " has entered!");
Thread.Sleep (1000 * (int) name );
Console.WriteLine (name + " is leaving");
_sem.Release(); }
}
}
I found the solution and thanks to #Giedrius. Flag RefreshingDialogs is set to true only when proccess is at the end, when I added items to Listbox. The reason why I'am using this flag is that state of process changes to complete when the asynchronous operation of getting content from network(HttpWebRequest, method BeginGetRequestStream) begins, but after network operaion is complete I need to make UI operations and not only them(parse content and add it to Listbox)My solution is:
private object syncRoot = new object();
private Task latestTask;
public void EnqueueAction(System.Action action)
{
lock (syncRoot)
{
if (latestTask == null)
{
downloadedDialogs = 0;
latestTask = Task.Factory.StartNew(action);
}
else if(latestTask.IsCompleted && !RefreshingDialogs)
{
RefreshingDialogs = true;
downloadedDialogs = 0;
latestTask = Task.Factory.StartNew(action);
}
}
}
private void Message_Refresh_Click(object sender, EventArgs e)
{
Action ac = new Action(LoadDialogs2);
EnqueueAction(ac);
}

Categories