I need to click an okay button which might appear after completing a field - it might take 5 seconds to appear. So i need (if) Wait for existence 5 seconds. I'm using PageFactory in a pages framework, I've seen some solutions but cant figure out how to implement them in this context.
[FindsBy(How = How.Name, Using = "OK")]
private IWebElement alertOKBtn;
public void PopulateFields //method to populate the form
{
// Populate fields
dateFromField.SendKeys(DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss"));
// Click on this field
descriptionField.Click();
//OK button might appear, might take 5secs - pseudcode
if ( ***alertOKBtn exists, wait for it for 5 secs..*** )
{
alertOkBtn.Click();
}
//continue populating form
}
The PopulateFields method is called from the [Test] as:-
Pages.PTW.PopulateFields();
where Pages.PTW is a get method to PageFactory.InitElements(browser.Driver, page); return page;
Managed to resolve it - in PopulateFields i now do this:-
//wait to see if alert popup appears - give it 8 secs
string waitToSee = browser.wait(alertOKBtn, 8);
if ( waitToSee == "true" )
{
alertOKBtn.Click(); //alert popup did appear
}
Then I've added a method to my browser.class :-
public static string wait(IWebElement elem, int timeout ) //waits for existence of element up to timeout amount
{
try
{
var wait = new WebDriverWait(webDriver, TimeSpan.FromSeconds(timeout));
wait.Until(ExpectedConditions.ElementToBeClickable(elem));
return "true";
}
catch (Exception e ) //didnt appear so exception thrown return false
{
return "false";
}
So it now waits up to 8 seconds and if it doesnt appear it ignores and moves on. Thanks Bendram for the pointers.
Need to add conditional wait. That means, your code should wait till the control appears and then perform the action.
WebDriverWait class which inherits DefaultWait class serves the purpose. The below is the code snippet.
var wait = new WebDriverWait(this.driver, waitTime);
wait.Until(ExpectedConditions.ElementToBeClickable(alertOkBtn));
alertOkBtn.Click();
Related
Problem: I'm working on a calculator as my first MVVM application and have come across an interesting problem that I would like to understand better. My noob problem is that I'm trying to flash an error message for an invalid input--in this case I don't want the user to use the negate operator in an invalid location. In order to flash the message across the screen, I'm saving the display in another variable, setting the display to say "Invalid Operation", then I'd like to delay for half a second and reset the display to what it was before (from the temp variable). My problem is that the display variable gets set but the actual display doesn't update to show the error message, no matter how long the delay is.
I've tried both blocking (Thread.Sleep) and non-blocking delays (Task.Delay) within the function, writing separate functions to set and reset the display, and delaying within the Negate function instead, but none of these attempts allow the display to update. The display works as expected when adding and deleting characters in other parts of the code, so I don't think there's an issue with that.
Is this some sort of piping issue (the delay function actually starts before it can call the Display property) or something else entirely? I've checked other posts on here and those solutions don't seem to solve my issue. I'd love feedback on why this doesn't work as I'd expect it to as well as more efficient/effective ways to code this. Here are the relevant code blocks:
public void Negate()
{
if (Display.Length > 0)
{
if (Display[Display.Length - 1].Equals('-'))
{
Display = Display.Substring(0, Display.Length - 1);
}
else if (Display[Display.Length - 1].Equals(' ') || Display[Display.Length - 1].Equals('(') ||
Display[Display.Length - 1].Equals('E') || Display[Display.Length - 1].Equals('^'))
{
Display += '-';
}
else
{
InvalidOperation();
}
}
else
{
Display = "-";
}
}
public void InvalidOperation()
{
tempDisplay = Display;
Display = "Invalid Operation";
Thread.Sleep(500);
Display = tempDisplay;
}
public string Display
{
get
{
return _display;
}
set
{
_display = value;
OnPropertyChanged();
}
}
UI will be updated only after method InvalidOperation execution is complete, so because in last line of the method you set value back to original - there are no updates in UI.
Asynchronous approach should work, because await operator will "pause" InvalidOperation method and return execution to the message loop which will update UI controls.
public async Task InvalidOperation()
{
tempDisplay = Display;
Display = "Invalid Operation";
await Task.Delay(2000);
Display = tempDisplay;
}
Afternoon,
I could use a little advise. I have page object setup for example
IWebElement SiteInUse => DriverContext.Driver.FindElement(By.ClassName("site-txt"));
I have a method set up that will
1. Wait till the element is visible.
2. Check the Elements text is correct.
I am trying to above doing something like
WaitHelpers.WaitTillVisiible(By.ClassName("site-txt"));
as if the id changes I will need to edit it in two places. I am trying to create a extension method for IWebElement.
I have tried
ublic static bool WaitUntilElementIsVisible(this IWebElement element)
{
WebDriverWait wait = new WebDriverWait(DriverContext.Driver, TimeSpan.FromSeconds(30));
return wait.Until(ElementIsVisible(element));
}
public static Func<IWebDriver, bool> ElementIsVisible(IWebElement element)
{
return (driver) =>
{
try
{
return element.Displayed;
}
catch (Exception)
{
// If element is null, stale or if it cannot be located
return false;
}
This works but only if the element is visible but will not continue to look for the 30 seconds.
What am I doing wrong?
I will attempt to answer given the original problem, which was needing to test for visibility, but this required you to update a locator in two places.
The answer is insanely simple: define a instance field for the locator:
public class SomePageModel
{
By siteInUseLocator = By.ClassName("site-txt");
IWebElement SiteInUse => DriverContext.Driver.FindElement(siteInUseLocator);
...
}
Then later on you can reuse this field to test for visibility:
WaitHelpers.WaitTillVisiible(siteInUseLocator);
In some of my projects to correctly save forms user needs to perform click on "Save" or "Save changes" button. That click cause whole page to reload (changes done will be visible on page after that reload), but if something is wrong validation will stops page from reloading.
I want to create a simple assertion to check if that page was reloaded, if not my test will fail. I tried to use this code:
public bool WasPageRefreshed(float seconds)
{
DriverLocal.Manage().Timeouts().SetPageLoadTimeout(TimeSpan.MinValue);
string getReadyState = "return document.readyState;";
for (int i = 0; i < 10; i++)
{
string readyState = GetJsExecutor().ExecuteScript(getReadyState) as string;
if (readyState != "complete")
return true;
Thread.Sleep(TimeSpan.FromMilliseconds(seconds / 10));
}
DriverLocal.Manage().Timeouts().SetPageLoadTimeout(TimeSpan.FromSeconds(60));
return false;
}
I use it in Assert.True() to check if page was reloaded but it doesn't work always (I can use it 5 times on same form - 3 times its ok, 2 times test will fail).
Is there a way to upgrade it to work correctly in 100% of usage?
Or maybe there is another way to check if page was reloaded?
For Webpage load, there is unfortunately no one size fits all solution. Every situation varies. How you wait in your automation suite is very critical. Explicit waits are recommended way of waiting, instead of using Javascript options, you can just wait for a new element after the page load or wait for invisibility of certain element that tells you that the page is loaded
new WebDriverWait(driver, TimeSpan.FromSeconds(timeOut))
.Until(ExpectedConditions
.ElementExists((By.Id("new Element Id"))));
or
new WebDriverWait(driver, TimeSpan.FromSeconds(timeOut))
.Until(ExpectedConditions
.InvisibilityOfElementLocated((By.Id("old Element Id"))));
You can check ExpectedElements docs here
There may be some Ajax call works asynchronously. You can wait until ajax call finished, then do your case, see this:
public void WaitForAjax()
{
while (true) // break if ajax return false
{
var ajaxIsComplete = (bool)(driver as IJavaScriptExecutor).ExecuteScript("return jQuery.active == 0");
if (ajaxIsComplete)
break;
Thread.Sleep(100);
}
}
As my opinion, you better use SeleniumWait instead of Sleep. Try this
public bool WasPageRefreshed(double seconds)
{
WebDriverWait wait = new WebDriverWait(DriverLocal, TimeSpan.FromSeconds(seconds));
wait.PollingInterval = TimeSpan.FromSeconds(1);
string getReadyState = "return document.readyState;";
try
{
wait.Until(d =>
{
string readyState = GetJsExecutor().ExecuteScript(getReadyState) as string;
if (readyState == "complete")
return true;
});
}
catch (Exception)
{
}
return false;
}
I suggest you Wait for a specific element that marked the status of a refreshed page.
I'm suddenly getting a strange error while debugging. Up to now the variable in the watch windows has been showing correctly. Now I am always getting this error message in the watch windows:
The function evaluation requires all threads to run
I am not able to check any variable anymore. I am not explicitly working with threads. What can I do to get it working again?
I already disabled, as mentioned in some forums, the function: "Enable property Evaluation and other implicit function Calls" in the option window of the debugger. But without success, and it gives me this error:
Error Implicit Function evaluation disabled by the user
From the msdn forum:
This isn't an error in and of itself, but more of a feature of your debugger.
Some properties require code to be executed in order for the property to be read, but if this requires cross-thread interaction, then other threads may have to run as well. The debugger doesn't do this automatically, but certainly can, with your permission.
Just click the little evaluate icon and it will run your code and evaluate the property.
For further details on this behaviour check this excelent article
I ran into this issue when just trying to get items from a table called "AGENCY" using Entity Framework:
var agencies = db.AGENCY.OrderBy(e => e.FULLNAME);
Hovering over agencies in debug mode, clicking to expand the options, and clicking Results would give the dreaded "The function evaluation requires all threads to run" with a "Do Not Enter" icon at the end that, on which, clicking did nothing.
2 possible solutions:
Add .ToList() at the end:
var agencies = db.AGENCY_TABLE.OrderBy(e => e.FULLNAME).ToList();
List<AGENCY_TABLE> agencies = db.AGENCY_TABLE.OrderBy(e => e.FULLNAME).ToList();
Credit goes to Hp93 for helping me come to this solution. In the comments on MUG4N's answer where I found this solution, it also mentions trying .Any() instead of .ToList(), but this gives a Boolean instead of a <T>, like <AGENCY> is, so it probably wouldn't help.
Workaround - try a different path in the debug options. I found that I could click on the "Non-Public Members" > "_internalQuery" > ObjectQuery > Results View and get my values that way.
MUG4N has indeed provided a correct answer however if you hover over the line of code in debug, you may be looking at something like the below. If so, click the little re-evaluate icon highlighted in the image below...
NB: I obtained this image by pinning, normally the re-evaluate icone are in the middle of the window and not down the left hand column.
You should make thread safe call because accessing Windows form controls are not Thread safe in multithreading.
This is my simple code which makes Thread safe call and sets Progress bar.
public partial class Form1 : Form
{// This delegate enables asynchronous calls for setting
// the text property on a TextBox control.
delegate void StringArgReturningVoidDelegate(string text);
private Thread demoThread = null;
public int Progresscount = 0;
static EventWaitHandle waithandler = new AutoResetEvent(false);
public Form1()
{
InitializeComponent();
}
public static bool CheckForInternetConnection()
{
try
{
using (var client = new WebClient())
{
using (var stream = client.OpenRead("http://www.google.com"))
{
return true;
}
}
}
catch
{
return false;
}
}
public void Progressincrement()
{
waithandler.WaitOne();
while (CheckForInternetConnection()==true)
{
if (Progresscount==100)
{
break;
}
SetLabel("Connected");
Progresscount += 1;
SetProgress(Progresscount.ToString());
Thread.Sleep(TimeSpan.FromSeconds(1));
}
if (Progresscount <100)
{
Startthread();
}
SetLabel("Completed");
}
public void Startthread ()
{
this.demoThread= new Thread(new ThreadStart(Progressincrement));
this.demoThread.Start();
SetLabel("Waiting for connection");
while (CheckForInternetConnection() == false) ;
waithandler.Set();
}
private void SetLabel(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.label1.InvokeRequired)
{
StringArgReturningVoidDelegate d = new StringArgReturningVoidDelegate(SetLabel);
this.Invoke(d, new object[] { text });
}
else
{
this.label1.Text = text;
}
}
private void SetProgress(string Value)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.progressBar1.InvokeRequired)
{
StringArgReturningVoidDelegate d = new StringArgReturningVoidDelegate(SetProgress);
this.Invoke(d, new object[] {Value});
}
else
{
this.progressBar1.Value = Convert.ToInt32(Value);
}
}
private void Form1_Load(object sender, EventArgs e)
{
Startthread();
}
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("Responsive");
}
}
For more information MSDN
This isn't an error, but more of a feature of your debugger.
The debugger doesn't do this automatically, but certainly can, with users permission. Just click the little space icon and it will run the code and evaluate the property.
I use the next workaround to pass:
var OtherThreadField = "";
Invoke(new MethodInvoker(delegate
{
OtherThreadField = ExecuteNeededMEthod();
}));
Now i have a value for OtherThreadField.
I faced the same issue and solved .The Issue arise due to username and password ,in SQL connection there is user and password but in code there no user and password. so I enable the user and the password and the issue solved
For me, this happened when trying to break on a line that accesses a complex object instance contained by a Settings Class.
A breakpoint on the following if results in Settings.Default.FindSettings with the value being "The function evaluation requires all threads to run." If I press the force eval button, it is null. Stepping with the force eval button click or not enters the if block and initializes the object. If I remove the breakpoint and add a new breakpoint following the if block, the Settings.Default.FindSettings deserializes properly with the expected values.
if (Settings.Default.FindSettings == null)
{
Settings.Default.FindSettings = new FindSettings();
}
After trial and error, I added the following code before the above if block to access the settings prior to breaking. This seems to reliably fix the problem. I do not need it in production so I wrap in conditional compiler directive. I have a comment in the code instead of a non-descript discard:
#if DEBUG
var _ = Settings.Default.FindSettings;
#endif
I am not sure if the above line would be optimized out in production since it has side effects. As I only need it while debugging, I have not checked.
I work with webDriver in #IE9 and I find one problem. If I started tests in Run mode, then all test fail because webDriver not exists (two window ie), but if I put breakpoint in tests and start tests Debug mode I have passed all tests. Please tell me, what do, because I don't know.
This my code:
private void MyMethods(IWebdriver driver)
{
foreach (var item in driver.WindowHandles) // if I put breakpoint, I see 2 count Window Handles else this methods don't work.
{
if (driver.SwitchTo().Window(item).Title == "PortalSubMenuPopupForm")
{
driver.SwitchTo().Window(item);
break;
}
}
}
Selenium has an "issue" with IE where new windows might not appear on the WindowHandles list right away.
The solution is either
wait a fixed amount of time before calling driver.WindowHandles
or
use the WebDriverWait class to wait for the number of elements under WindowHandles to change
I think the second one is more robust. Here is a quick implementation:
public void LaunchNewWindow(IWebElement element)
{
int windowsBefore = driver.WindowHandles.Count;
element.Click();
TimeSpan timeout = new TimeSpan(0, 0, 10);
WebDriverWait wait = new WebDriverWait(driver, timeout);
wait.Until((_driver) =>
{
return _driver.WindowHandles.Count != windowsBefore;
//optionally use _driver.WindowHandles.Count > windowsBefore
});
}
Now you can use the function like so:
IWebElement clickMe = //some element that launches a new window
LaunchNewWindow(clickMe);
foreach (var item in driver.WindowHandles)
{
//etc.
}