By adding a while(ele == null) loop, I got the code to run and work most of the time out of the debugger. Pretty ugly. This leads me to think that I need to over ride the FindElements() function using a wrapper but have no idea how to do this to add some delay. There is an example at Explicit Wait for findElements in Selenium Webdriver but it's written in JavaScript. I put that example in the code below. Can some one guide me on this?
public void WriteAPost()
{
ele = driver.FindElements(By.CssSelector(".a8c37x1j.ni8dbmo4.stjgntxs.l9j0dhe7.ltmttdrg.g0qnabr5.ojkyduve")).FirstOrDefault(x => x.Text == "Create Post");
while(ele == null)
{
ele = driver.FindElements(By.CssSelector(".a8c37x1j.ni8dbmo4.stjgntxs.l9j0dhe7.ltmttdrg.g0qnabr5.ojkyduve")).FirstOrDefault(x => x.Text == "Create Post");
}
ele.Click();
Thread.Sleep(3000);
ele = driver.SwitchTo().ActiveElement();
PClipboard.SetText("Post text to use for Text Area");
ele.SendKeys(OpenQA.Selenium.Keys.Control + 'v');
Thread.Sleep(3000);
ele = driver.FindElements(By.XPath("//div[#role = 'button']")).FirstOrDefault(x => x.Text == "Post");
while (ele == null)
{
ele = driver.FindElements(By.XPath("//div[#role = 'button']")).FirstOrDefault(x => x.Text == "Post");
}
ele.Click();
Thread.Sleep(3000);
driver.Quit();
}
static class PClipboard
{
public static void SetText(string p_Text)
{
Thread STAThread = new Thread(
delegate ()
{
// Use a fully qualified name for Clipboard otherwise it
// will end up calling itself.
System.Windows.Forms.Clipboard.SetText(p_Text);
});
STAThread.SetApartmentState(ApartmentState.STA);
STAThread.Start();
STAThread.Join();
}
}
}
// Javascript FindElements() wrapper
/// <summary>
/// Allows you to execute the FindElements call but specify your own timeout explicitly for this single lookup
/// </summary>
/// <remarks>
/// If you want no timeout, you can pass in TimeSpan.FromSeconds(0) to return an empty list if no elements match immediately. But then you may as well use the original method
/// </remarks>
/// <param name="driver">The IWebDriver instance to do the lookup with</param>
/// <param name="findBy">The By expression to use to find matching elements</param>
/// <param name="timeout">A timespan specifying how long to wait for the element to be available</param>
public static ReadOnlyCollection<IWebElement> FindElements(this IWebDriver driver, By findBy, TimeSpan timeout)
{
var wait = new WebDriverWait(driver, timeout);
return wait.Until((d) =>
{
var elements = d.FindElements(findBy);
return (elements.Count > 0)
? elements
: null;
});
}
You can wait for a condition to be met:
new WebDriverWait(driver, timeout).Until(ExpectedConditions.ElementExists((By.Id(id))));
or you can wait implicitly:
driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(timeInSeconds);
I just don't know where in the code to wait.
Personally, my Selenium code is full of "test failure reporting" tests and try-catch blocks which report where the failure happened. If you model your code this way, it should narrow down the problem and clue you to where waits are needed.
Related
Per my code below. I'm testing UI to ensure correct permissions for a application are applied to certain user accounts.
When I run the below, the test passes at "Assert.Pass(); //marks as a pass here ok".
Following this, code drops into the catch block.
The exception message is literally blank, the stack trace is:
at NUnit.Framework.Assert.Pass(String message, Object[] args) at
NUnit.Framework.Assert.Pass() at
SigangeCoreUiTests.Tests.PermissionTests.BslUserPermissionTest() in
C:...\PermissionTests.cs:line 90
The test then obviously fails because of the assert fail, however there is no reason for the exception to be raised and it already passed. The screen shot capture is not raising an issue, it seems to be the Assert.Pass.
Why might my code do this?
public void BslUserPermissionTest()
{
var _testUsername = _configuration.GetValue<string>("PermissionsTestUserList:BSLUser:Username");
var _testPassword = _configuration.GetValue<string>("PermissionsTestUserList:BSLUser:Password");
var wait = new WebDriverWait(_driver, new TimeSpan(0, 0, 60));
try
{
if (!LoginHandler(_testUsername, _testPassword))
{
Assert.Fail();
}
System.Threading.Thread.Sleep(2000);
var menuItem = wait.Until(ExpectedConditions.ElementIsVisible(By.LinkText("BSL Interpreter")));
menuItem.Click();
var result = wait.Until(ExpectedConditions.ElementIsVisible(By.TagName("app-bsl-interpreter")));
if (result.Text.Contains("Message for Interpretation"))
{
//test no other menu items are present - only expecting the one menu item
if (ValidateSingleMenuItemPresent())
{
new SupportClasses.ScreenShot().Take(_driver, false);
Assert.Fail();
}
new SupportClasses.ScreenShot().Take(_driver, true);
Assert.Pass(); //marks as a pass here ok
}
else
{
new SupportClasses.ScreenShot().Take(_driver, false);
Assert.Fail();
}
}
catch (Exception ex) //raises exception for unknown reason
{
new SupportClasses.ScreenShot().Take(_driver, false);
Assert.Fail();
}
finally
{
_driver = new SupportClasses.SsdAuthentiation(_driver).Logout();
}
}
Assert.Pass throws exception, you should use Assert to check values as per your test case.
See the below code from GitHub.
/// <summary>
/// Throws a <see cref="SuccessException"/> with the message and arguments
/// that are passed in. This allows a test to be cut short, with a result
/// of success returned to NUnit.
/// </summary>
[DoesNotReturn]
static public void Pass()
{
Assert.Pass(string.Empty, null);
}
I have code which finds element with delay, but sometimes element is already but not clickable and not available in DOM, so what i should to add to my code to check those arguments
public IWebElement FindElement(IWebDriver driver, By howBy, int timeoutInSeconds = 10)
{
TimeSpan elementTimeOut = TimeSpan.FromSeconds(20);
IWebElement elementfound = null;
try
{
WebDriverWait wait = new WebDriverWait(driver, elementTimeOut);
elementfound = wait.Until<IWebElement>(d =>
{
try
{
elementfound = driver.FindElement(howBy);
}
catch (NoSuchElementException e)
{
Debug.WriteLine("Please fail NoSuchElementException");
throw;
}
return elementfound;
});
}
catch (WebDriverTimeoutException e)
{
Debug.WriteLine("Please fail WebDriverTimeoutException");
throw;
}
return elementfound;
}
Firstly, It'll check if it's 'visible' by using the standard ExpectedConditions.visibilityOfElementLocated, it'll then simply check if the element.isEnabled() is true or not.
This can be condensed slightly, this basically means (simplified, in C#):
Wait until the element is returned from the DOM
Wait until the element's .Displayed property is true (which is essentially what visibilityOfElementLocated is checking for).
Wait until the element's .Enabled property is true (which is essentially what the elementToBeClickable is checking for).
I would implement this like so (adding onto the current set of ExpectedConditions, but there are multiple ways of doing it:
// <param name="locator">The locator used to find the element.</param>
// <returns>The <see cref="IWebElement"/> once it is located, visible and clickable.</returns>
public static Func<IWebDriver, IWebElement> ElementIsClickable(By locator)
{
return driver =>
{
var element = driver.FindElement(locator);
return (element != null && element.Displayed && element.Enabled) ? element : null;
};
}
Above method can be used something like:
var wait = new WebDriverWait(driver, TimeSpan.FromMinutes(1));
var clickableElement = wait.Until(ExpectedConditions.ElementIsClickable(By.Id("id")));
However, you can pass howBy as the param of ElementIsClickable() method.
elementToBeClickable is used to wait for an element to be clickable .
Please use the following code inside your method.
elementfound = wait.until(ExpectedConditions.elementToBeClickable(howBy);
I'm using the swagger-codegen to generate c# client, however noticing that the sortParamsByRequiredFlag is not applied to model generation.
For example, here is a sample config file:
{
"packageVersion" : "1.0.0",
"sortParamsByRequiredFlag": true,
"optionalProjectFile" : false
}
Here is the generated truncated code for model's constructor:
/// <summary>
/// Initializes a new instance of the <see cref="V2alpha1CronJobSpec" /> class.
/// </summary>
/// <param name="ConcurrencyPolicy">Specifies how to treat concurrent executions of a Job. Defaults to Allow..</param>
/// <param name="FailedJobsHistoryLimit">The number of failed finished jobs to retain. This is a pointer to distinguish between explicit zero and not specified..</param>
/// <param name="JobTemplate">Specifies the job that will be created when executing a CronJob. (required).</param>
/// <param name="Schedule">The schedule in Cron format, see https://en.wikipedia.org/wiki/Cron. (required).</param>
/// <param name="StartingDeadlineSeconds">Optional deadline in seconds for starting the job if it misses scheduled time for any reason. Missed jobs executions will be counted as failed ones..</param>
/// <param name="SuccessfulJobsHistoryLimit">The number of successful finished jobs to retain. This is a pointer to distinguish between explicit zero and not specified..</param>
/// <param name="Suspend">This flag tells the controller to suspend subsequent executions, it does not apply to already started executions. Defaults to false..</param>
public V2alpha1CronJobSpec(string ConcurrencyPolicy = default(string), int? FailedJobsHistoryLimit = default(int?), V2alpha1JobTemplateSpec JobTemplate = default(V2alpha1JobTemplateSpec), string Schedule = default(string), long? StartingDeadlineSeconds = default(long?), int? SuccessfulJobsHistoryLimit = default(int?), bool? Suspend = default(bool?))
{
// to ensure "JobTemplate" is required (not null)
if (JobTemplate == null)
{
throw new InvalidDataException("JobTemplate is a required property for V2alpha1CronJobSpec and cannot be null");
}
else
{
this.JobTemplate = JobTemplate;
}
// to ensure "Schedule" is required (not null)
if (Schedule == null)
{
throw new InvalidDataException("Schedule is a required property for V2alpha1CronJobSpec and cannot be null");
}
else
{
this.Schedule = Schedule;
}
this.ConcurrencyPolicy = ConcurrencyPolicy;
this.FailedJobsHistoryLimit = FailedJobsHistoryLimit;
this.StartingDeadlineSeconds = StartingDeadlineSeconds;
this.SuccessfulJobsHistoryLimit = SuccessfulJobsHistoryLimit;
this.Suspend = Suspend;
}
As you can see from the swagger spec, JobTemplate, Schedule are required parameters. However, the params in the constructor are sorted alphabetically.
I've been sorting through the swagger-codegen code base and I think the sortParamsByRequiredFlag only applies to API generated methods.
Is this by design? I'm not sure if I'm missing some config that I should be setting?
Here is the GitHub issue I opened but haven't heard anything on it.
This is not an answer to why Swagger is not generating the correct code, but an answer to your problem on GitHub.
There is absolutely no need for you to use this:
var jobSpec = new V2alpha1CronJobSpec(null, null, new V2alpha1JobTemplateSpec(), "stringValue", null, ...);
You can just use this (called named parameters):
var jobSpec = new V2alpha1CronJobSpec(JobTemplate: new V2alpha1JobTemplateSpec(), Schedule: "stringValue");
For c# client this flag is ignored in the main codebase.
You can create your own extension and override fromModel method to sort the properties.
Have a look at below code on how to do it.
#Override
public CodegenModel fromModel(String name, Model model, Map<String, Model> allDefinitions) {
CodegenModel codegenModel = super.fromModel(name, model, allDefinitions);
if (sortParamsByRequiredFlag)
{
Collections.sort(codegenModel.readWriteVars, new Comparator<CodegenProperty>() {
#Override
public int compare(CodegenProperty one, CodegenProperty another) {
if (one.required == another.required) return 0;
else if (one.required) return -1;
else return 1;
}
});
System.out.println("***Sorting based on required params in model....***");
}
return codegenModel;
}
I'm writing a Portable Class Library that is going to be used by WPF, Windows Phone and possibly WinRT apps and I'm doing some work on background threads that occasionally need to call back to the UI. I instantiate the classes doing this in the UI thread, so I can easily save the SynchronizationContext and use it to call back to the UI.
However, in PCL, SynchronizationContext.Send() is obsolete, because it's not supported by WinRT and SynchronizationContext.Post() (which runs asynchronously) is not always appropriate.
I figured I'd just wait until the delegate passed to Post() is run, but all my attempts ended with a deadlock if Post() was invoked from the same thread the saved SynchronizationContext referred to.
Now I've managed to fix this by checking if it's the same thread and just simply calling my delegate if it is, but the checks are incredibly ugly involving reflecting out the value of private fields of the API, so I thought someone could help me find a more proper way.
Here is my current code if you'd like to see some gore:
/// <summary>
/// Invokes the passed callback on this SynchronizationContext and waits for its execution. Can be used even if
/// SynchronizationContext.Send is not available. Throws the exceptions thrown in the delegate.
/// </summary>
/// <param name="context">the context to run the method</param>
/// <param name="d">the method to run</param>
/// <param name="state">the parameter of the method to run</param>
public static void InvokeSynchronized( this SynchronizationContext context, SendOrPostCallback d, object state )
{
if ( !context.Match( SynchronizationContext.Current ) )
{
ManualResetEvent waitHandle = new ManualResetEvent( false );
Exception error = null;
// replicate SynchronizationContext.Send with .Post as Send is obsolete in the Portable Class Library
context.Post( ( o ) =>
{
try
{
d( o );
}
catch ( Exception exc )
{
error = exc;
}
finally
{
waitHandle.Set();
}
},
state );
waitHandle.WaitOne();
if ( error != null )
{
throw error;
}
}
else
{
d( state );
}
}
/// <summary>
/// Checks if the two SynchronizationContexts refer to the same thread
/// </summary>
/// <param name="sc1"></param>
/// <param name="sc2"></param>
/// <returns></returns>
public static bool Match(this SynchronizationContext sc1, SynchronizationContext sc2)
{
if ( sc2 == null )
{
return false;
}
else if ( sc1 == sc2 || sc1.Equals(sc2) )
{
return true;
}
// check if the two contexts run on the same thread
// proper equality comparison is generally not supported, so some hacking is required
return sc1.FindManagedThreadId() == sc2.FindManagedThreadId();
}
/// <summary>
/// Finds the ManagedThreadId of the thread associated with the passed SynchronizationContext
/// </summary>
/// <param name="sc"></param>
/// <returns></returns>
public static int FindManagedThreadId(this SynchronizationContext sc)
{
// here be dragons
try
{
BindingFlags bindFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
switch ( sc.GetType().FullName )
{
case "System.Windows.Threading.DispatcherSynchronizationContext":
// sc._dispatcher.Thread.ManagedThreadId
var _dispatcher_field = sc.GetType().GetField( "_dispatcher", bindFlags );
var _dispatcher_value = _dispatcher_field.GetValue( sc );
var Thread_property = _dispatcher_value.GetType().GetProperty( "Thread", bindFlags );
var Thread_value = Thread_property.GetValue( _dispatcher_value, null ) as Thread;
return Thread_value.ManagedThreadId;
}
}
catch ( Exception e )
{
throw new InvalidOperationException( "ManagedThreadId could not be obtained for SynchronizationContext of type " + sc.GetType().FullName, e );
}
throw new InvalidOperationException( "ManagedThreadId not found for SynchronizationContext of type " + sc.GetType().FullName );
}
Thanks!
I think that SynchronizationContext.Send is being deprecated by Microsoft for a good reason. They really want the new Windows Store and WP8 apps to fully embrace asynchronous programming model and make the blocking code a thing of the past.
So, something that was:
void SendDataToUI()
{
_synchronizationContext.Send(_callback, data);
}
Should now become:
async Task SendDataToUIAsync()
{
var tcs = new TaskCompletionSource<object>();
_synchronizationContext.Post(a =>
{
try
{
_callback(a);
tcs.SetResult(Type.Missing);
}
catch (Exception ex)
{
tcs.SetException(ex);
}
}, data);
await tcs.Task;
}
That said, I suppose you have your own good reasons to use SynchronizationContext.Send in your PCL library.
The first part of your logic looks good, and you could cut off the reflection part of it by simply memorizing the Thread.CurrentThread.ManagedThreadId of the UI thread, at the same place where you memorize the SynchronizationContext.Current of the UI thread. Then in your implementation of InvokeSynchronized you just compare it to the Thread.CurrentThread.ManagedThreadId of the current thread, and use waitHandle.WaitOne() if your are on non-UI thread.
I recently came across this code:
public static class ClientBaseExtender
{
/// <summary>
/// Tries to execute async service call. If <see cref="TimeoutException"/> occured retries again.
/// </summary>
/// <typeparam name="TChannel">ServiceClient class.</typeparam>
/// <typeparam name="TArgs">Type of service client method return argument.</typeparam>
/// <param name="client">ServiceClient instance.</param>
/// <param name="tryExecute">Delegate that execute starting of service call.</param>
/// <param name="onCompletedSubcribe">Delegate that subcribes an event handler to the OnCompleted event of the service client method.</param>
/// <param name="onCompleted">Delegate that executes when service call is succeeded.</param>
/// <param name="onError">Delegate that executes when service call fails.</param>
/// <param name="maxAttempts">Maximum attempts to execute service call before error if <see cref="TimeoutException"/> occured (by default 5).</param>
public static void ExecuteAsyncRepeatedly<TChannel, TArgs>(this ClientBase<TChannel> client, Action tryExecute,
Action<EventHandler<TArgs>> onCompletedSubcribe, EventHandler<TArgs> onCompleted,
EventHandler<TArgs> onError, int maxAttempts)
where TChannel : class
where TArgs : AsyncCompletedEventArgs
{
int attempts = 0;
var serviceName = client.GetType().Name;
onCompletedSubcribe((s, e) =>
{
if (e.Error == null) // Everything is OK
{
if (onCompleted != null)
onCompleted(s, e);
((ICommunicationObject)client).Close();
Debug.WriteLine("[{1}] Service '{0}' closed.", serviceName, DateTime.Now);
}
else if (e.Error is TimeoutException)
{
attempts++;
if (attempts >= maxAttempts) // Final timeout after n attempts
{
Debug.WriteLine("[{2}], Final Timeout occured in '{0}' service after {1} attempts.", serviceName, attempts, DateTime.Now);
if (onError != null)
onError(s, e);
client.Abort();
Debug.WriteLine("[{1}] Service '{0}' aborted.", serviceName, DateTime.Now);
return;
}
// Local timeout
Debug.WriteLine("[{2}] Timeout occured in '{0}' service (attempt #{1}).", serviceName, attempts, DateTime.Now);
Debug.WriteLine("[{2}] Attempt #{0} to execute call to '{1}' service.", attempts + 1, serviceName, DateTime.Now);
tryExecute(); // Try again.
}
else
{
if (onError != null)
onError(s, e);
client.Abort();
Debug.WriteLine("[{1}] Service '{0}' aborted.", serviceName, DateTime.Now);
}
});
Debug.WriteLine("[{2}] Attempt #{0} to execute call to '{1}' service.", attempts + 1, serviceName, DateTime.Now);
tryExecute(); // First attempt to execute
}
}
public void GetData()
{
var client = new MyServiceClient();
client.ExecuteAsyncRepeatedly(() => client.MyOperationAsync(...),
(EventHandler<MyOperationCompletedEventArgs> handler) =>client.MyOperationCompleted += handler,
(s, e) => // OnCompleted
{
Do(e.Result);
},
(s, e) => // OnError
{
HandleError(e.Error);
}
);
}
The problem is, I have a button that fires this code off. When the button is pushed more than once the handler gets added again and again. This is a problem because the code will fire as many times as the user has pushed the button. How can I remove the handler created with the lambda expression in this code so it will only run once?
Thanks!
EDIT:
I'm calling the code like this from my button click command:
_dataService.GetData(GetDataCompleted);
private void GetDataComplete(Data data)
{
//do something with data }
I think that you can solve it by implementing a push-pull strategy in your code-behind. I propose something similar to this:
bool _requestPending;
readonly object _lock = new object();
void OnClick (...)
{
lock(_lock)
{
if (_requestPending == false)
{
_dataService.GetData(GetDataCompleted);
_requestPending = true;
}
}
}
private void GetDataComplete(Data data)
{
lock(_lock)
{
try
{
//do something with data
}
finally
{
_requestPending = false;
}
}
}
Even better, disable the UI button when you have a pending request. You wouldn't have any concurrency issues with accessing and modifying the _requestPending from different threads, but still you could suffer a race condition if the service response is fast enough, so still better to synchronize the two blocks of code.
Anyway, personally I don't like this implementation for what you're trying to achieve. The code is quite confusing, and makes it hard to foresee problems that may arise. Make sure that:
you provide a way to abort a request
and reenable the button again
the code that updates the screen is
executed by the UI thread