Selenium Waits Logic - c#

I am building a testing framework for my website
I want to fully separate the framework away from test
the issue is when I write a test sometimes the Assert needs time until it can be true, for example if I am on Upload file page and when the file is uploaded the website should display File uploaded successfully page but it will need to much time until the browser reaches this page
How should I force the Assert to wait sometime before it returns result?
some code that might explain my current way of work:
Upload Page Class
Public class UploadPage
{
[FindsBy(How = How.Name, Using = "upload-button")]
public IWebElement BtnUpload { get; set; }
public UploadPage()
{
PageFactory.InitElements(Driver, this);
}
public void UploadFile(string path)
{
//select file
BtnUpload.Click();
}
}
Successful Upload Page:
Public class UploadSuccessfulPage
{
[FindsBy(How = How.Name, Using = "success-message")]
public IWebElement LblSuccessMessage{ get; set; }
public UploadSuccessfulPage()
{
PageFactory.InitElements(Driver, this);
}
public bool IsAt()
{
Driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(60))
return Driver.url==configurations.UploadSuccessfulPageURL;
}
}
Test Method:
public void TestUpload()
{
UploadPage uploadPage= new UploadPage ();
uploadPage.UploadFile(path);
UploadSuccessfulPage successPage= new UploadSuccessfulPage();
Assert.IsTrue(successPage.IsAt());
}
when I write my tests this way the assert do not wait despite that IsAt() contains implicit wait
P.S: I am not intending to use Thread.Sleep();

The method bool IsAt() should be implemented like:
public bool IsAt()
{
Driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(60));
try {
return driver.FindElement(By.Name("success-message").Displayed;
} catch (WebDriverException e) {
return false;
}
}
Or using explicit wait:
public bool IsAt()
{
try {
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(60));
wait.Until(ExpectedConditions.ElementIsVisible(By.Name("success-message")));
return true;
} catch (TimeoutException e){
return false;
}
}
Update:
If you want to verify by url, the bool IsAt() should look like:
public bool IsAt()
{
try {
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(60));
wait.Until(ExpectedConditions.UrlToBe(configurations.UploadSuccessfulPageURL));
return true;
} catch (TimeoutException e){
return false;
}
}
Look at the class ExpectedConditions to find a condition suitable to your require

Related

Xamarin Android ForceDarkHelper What is it?

Periodically, the application begins to update itself. There is a constant call in the logs:
[ForceDarkHelper] updateByCheckExcludeList: pkg: com.companyname.manimobile activity: crc64d14753dcc52b83b4.MainActivity#a894c70
[ForceDarkHelper] updateByCheckExcludeList: pkg: com.companyname.manimobile activity: crc64d14753dcc52b83b4.MainActivity#a894c70
[ForceDarkHelper] updateByCheckExcludeList: pkg: com.companyname.manimobile activity: crc64d14753dcc52b83b4.MainActivity#a894c70
[ForceDarkHelper] updateByCheckExcludeList: pkg: com.companyname.manimobile activity: crc64d14753dcc52b83b4.MainActivity#a894c70
When this happens, if, for example, you open the menu , it closes itself, if something is filled in, it is cleared, the page is updated. There are no timers in the code. I'm testing the app on Xiaomi Redmi. I repeat sometimes it happens sometimes it doesn't. What is it?
I do not know what the problem is, but occasionally, it happens that the application throws the fingerprint to the page. It is intermittent. Sometimes everything works fine. That is, I go through the fingerprint, the next page opens, everything is normal and a second after 5 I am again thrown to the page where you need to enter the fingerprint.
Code for the authorization page:
public authentification()
{
try
{
InitializeComponent();
bool auth = CrossSettings.Current.GetValueOrDefault("authorized", false);
if (auth == false) { CheckAuth(); }
else
{
Application.Current.MainPage = new MasterLk();
}
}
catch { }
}
async void CheckAuth()
{
try
{
var avail = await CrossFingerprint.Current.IsAvailableAsync();
if (!avail)
{
CrossSettings.Current.GetValueOrDefault("authorized", true);
Application.Current.MainPage = new MasterLk();
}
else
{
var request = new AuthenticationRequestConfiguration("NeedAuth", "-");
var result = await CrossFingerprint.Current.AuthenticateAsync(request);
if (result.Authenticated)
{
CrossSettings.Current.GetValueOrDefault("authorized", true);
Application.Current.MainPage = new MasterLk();
}
else
{
CheckAuth();
}
}
}
catch { }
}
On the page where it throws it there is a ListView with a binding:
public class OrdersViewModel : BaseViewModel
{
private Table oldLoan;
private bool isRefreshing;
private readonly string clientId;
public bool IsRefreshing
{
get
{
return isRefreshing;
}
set
{
isRefreshing = value;
OnPropertyChanged("IsRefreshing");
}
}
public ICommand RefreshCommand { get; set; }
public ObservableCollection<Table> Loans { get; set; }
public void ShowOrHideLoan(Table loan)
{
if (oldLoan == loan)
{
loan.IsExpanded = !loan.IsExpanded;
Reload(loan);
}
else
{
if (oldLoan != null)
{
oldLoan.IsExpanded = false;
Reload(oldLoan);
}
loan.IsExpanded = true;
Reload(loan);
}
oldLoan = loan;
}
private void Reload(Table loan)
{
var index = Loans.IndexOf(loan);
Loans.Remove(loan);
Loans.Insert(index, loan);
}
public async Task LoadDataAsync()
{
IsRefreshing = true;
Loans.Clear();
try
{
var loans = await ConnectAPI.GetOrdersAsync(clientId);
await Task.Delay(1000);
foreach (var item in loans)
{
Loans.Add(item);
}
}
catch (Exception exc)
{
Console.WriteLine(exc.Message);
}
finally
{
oldLoan = null;
IsRefreshing = false;
}
}
public OrdersViewModel(string clientId)
{
IsRefreshing = false;
this.clientId = clientId;
Loans = new ObservableCollection<Table>();
RefreshCommand = new Command(async () =>
{
await LoadDataAsync();
});
Task.Run(async () => await LoadDataAsync());
}
}
That is, whenever the [ForceDarkHelper] updateByCheckExcludeList: pkg: com.companyname.manimobile activity: crc64d14753dcc52b83b4 event appears.MainActivity#a894c70
Throws it to the print page...
and if you stay on this page, it is updated after a while.
MIUI 12 has made an intelligent dark theme. The system itself repaints the applications if they do not support the dark theme. Apparently this service is ForceDarkHelper. And ExcludeList is in the settings a list of applications that cannot be repainted

Testing callback with observable pattern

I want to write some Unittests with NUnit for our wpf application.
The application downloads some data with System.Net.WebClient in the background using the observer pattern.
Here is an example:
Download.cs
public class Download : IObservable<string>
{
private string url { get; }
private List<IObserver<string>> observers = new List<IObserver<string>>();
private bool closed = false;
private string data = null;
public Download(string url)
{
this.url = url;
startDownload();
}
public IDisposable Subscribe(IObserver<string> observer)
{
if (!observers.Contains(observer))
{
if (!closed)
{
observers.Add(observer);
}
else
{
sendAndComplete(observer);
}
}
return new Unsubscriber(observer, observers);
}
private void startDownload()
{
WebClient client = new WebClient();
client.DownloadStringCompleted += new DownloadStringCompletedEventHandler((object sender, DownloadStringCompletedEventArgs e) => {
if (e.Error != null)
{
data = e.Result;
}
closed = true;
sendAndComplete();
});
client.DownloadStringAsync(new Uri(url));
}
private void sendAndComplete()
{
foreach (var observer in observers)
{
sendAndComplete(observer);
}
observers.Clear();
}
private void sendAndComplete(IObserver<string> observer)
{
if (data != null)
{
observer.OnNext(data);
}
else
{
observer.OnError(new Exception("Download failed!"));
}
observer.OnCompleted();
}
private class Unsubscriber : IDisposable
{
private IObserver<string> _observer { get; }
private List<IObserver<string>> _observers { get; }
public Unsubscriber(IObserver<string> _observer, List<IObserver<string>> _observers)
{
this._observer = _observer;
this._observers = _observers;
}
public void Dispose()
{
if (_observer != null && _observers.Contains(_observer))
{
_observers.Remove(_observer);
}
}
}
}
DownloadInspector.cs
public class DownloadInspector : IObserver<string>
{
private Action<string> onSuccessAction { get; }
private Action<Exception> onErrorAction { get; }
private Action onCompleteAction { get; }
public DownloadInspector(Action<string> onSuccessAction, Action<Exception> onErrorAction, Action onCompleteAction)
{
this.onSuccessAction = onSuccessAction;
this.onErrorAction = onErrorAction;
this.onCompleteAction = onCompleteAction;
}
public void OnCompleted()
{
onCompleteAction.Invoke();
}
public void OnError(Exception error)
{
onErrorAction.Invoke(error);
}
public void OnNext(string value)
{
onSuccessAction.Invoke(value);
}
}
example (usage)
Download download = new Download("http://stackoverflow.com");
DownloadInspector inspector = new DownloadInspector(
(string data) =>
{
Debug.WriteLine("HANDLE DATA");
},
(Exception error) =>
{
Debug.WriteLine("HANDLE ERROR");
},
() =>
{
Debug.WriteLine("HANDLE COMPLETE");
}
);
I'm still new in c# and not very familiar with asynchronous programming in that language. I know the await and async keywords and know that they work with NUnit, but the current construct don't use this keywords.
Can you help me creating a unit test for this case? Its okay to change/remove the observer pattern.
The constructor for the Download class starts the download, which means that I can't subscribe an observer until after the download has started. That's a race condition. It's possible (although unlikely) that observers will be notified before they can be subscribed.
public Download(string url)
{
this.url = url;
startDownload();
}
But I can go ahead and test because I'm subscribing an observer before that can happen. If you can I'd recommend not doing that. Allow the caller to construct the class in one step and then start the download with a method call.
I also had to change this method. I figured that testing for an error would be the easiest first step, but it needs to do data = e.Result if there is no error, not if there is an error.
private void StartDownload()
{
WebClient client = new WebClient();
client.DownloadStringCompleted += new DownloadStringCompletedEventHandler((object sender, DownloadStringCompletedEventArgs e) =>
{
if (e.Error == null) // <== because of this
{
data = e.Result;
}
closed = true;
sendAndComplete();
});
client.DownloadStringAsync(new Uri(url));
}
What I didn't see coming is that WebClient.DownloadStringAsync isn't actually async. It doesn't return a Task. It just takes a callback. What that means is that there's no sure way to know whether it's done except to wait for it to notify the observer that the download is complete.
My NUnit test runner wasn't running, so I used MsTest. It's the same thing.
The basic approach is that I'm creating some flags, and the inspector responds to notifications by setting the flags. That way I can see which notifications were raised.
The last problem is that because DownloadStringComplete is a callback, the test exits before the Assert. That means it will always pass. So in order to fix it I had to do something I've never seen before, which I found here:
[TestMethod]
public void download_raises_error_notification()
{
var success = false;
bool error = false;
bool complete = false;
var pause = new ManualResetEvent(false);
var download = new Download("http://NoSuchUrlAnywhere.com");
var inspector = new DownloadInspector(
onSuccessAction: s => success = true,
onCompleteAction: () =>
{
complete = true;
pause.Set();
},
onErrorAction: s => error = true
);
download.Subscribe(inspector);
// allow 500ms for the download to fail. This is a race condition.
pause.WaitOne(500);
Assert.IsTrue(error,"onErrorAction was not called.");
}
This is technically an integration test since it must actually attempt a download in order to run. That could be remedied by mocking WebClient.

Xamarin.Forms TextToSpeech

I'm trying to develop a mobile app with a SpeechToText feature, I found an example here Original Post and i tried to follow its steps, but when i run the application and i tap on the button to record, i get a message saying "Unhandled Exception occurr, No body on method..".
I tried to debug and what I get is that its something related to the DependecyService running the SpeechToTextAsync method from the ISpeecehToText interface.
Now I dont use interfaces too much so i'm a bit stuck understanding what is causing this error and how to solve it.
namespace LiveScoring {
public partial class MainPage : ContentPage {
public MainPage() {
InitializeComponent();
}
public void RecordBtn_Clicked(object sender, EventArgs e) {
WaitForSpeechToText();
}
private async void WaitForSpeechToText() {
Output_lbl.Text = await DependencyService.Get<ISpeechToText>().SpeechToTextAsync();
>> here I get the error
}
}
}
using System.Threading.Tasks;
namespace LiveScoring {
public interface ISpeechToText {
Task<string> SpeechToTextAsync();
}
}
namespace LiveScoring.Droid {
public class SpeechToText : ISpeechToText {
private const int VOICE = 10;
public static string SpeechText;
public static AutoResetEvent autoEvent = new AutoResetEvent(false);
public SpeechToText() { }
public async Task<string> SpeechToTextAsync() {
var tcs = new TaskCompletionSource<string>();
try {
var voiceIntent = new Intent(RecognizerIntent.ActionRecognizeSpeech);
voiceIntent.PutExtra(RecognizerIntent.ExtraLanguageModel, RecognizerIntent.LanguageModelFreeForm);
voiceIntent.PutExtra(RecognizerIntent.ExtraPrompt, "Talk now");
voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputCompleteSilenceLengthMillis, 1500);
voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputPossiblyCompleteSilenceLengthMillis, 1500);
voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputMinimumLengthMillis, 15000);
voiceIntent.PutExtra(RecognizerIntent.ExtraMaxResults, 1);
voiceIntent.PutExtra(RecognizerIntent.ExtraLanguage, Java.Util.Locale.Default);
SpeechText = "";
autoEvent.Reset();
try {
((Activity)Forms.Context).StartActivityForResult(voiceIntent, VOICE);
} catch (ActivityNotFoundException a) {
tcs.SetResult("Device doesn't support speech to text");
}
await Task.Run(() => { autoEvent.WaitOne(new TimeSpan(0, 2, 0)); });
return SpeechText;
} catch (Exception ex) {
tcs.SetException(ex);
}
return "";
}
}
}
Try to add this above your namespace LiveScoring.Droid { line, ie:
[assembly: Dependency(typeof(SpeechToText))]
namespace LiveScoring.Droid {
...
}
This way it will register the dependency service, so it will be called when you use the DependencyService.Get<>() method.

Creating a Loading view in .NET Core / Change view without returning c#

I am working on a website created in .NET Core (using the full .NET Framework) that uses background tasks to get a devices list.
I want to display a loading "view" like this while the task is getting data from another PC (using GET requests) and then, when the task is completed I want to display the table with the devices. How can I do that?
Here is a little piece of my code:
public class DeviceController : Controller {
public IActionResult Index() {
if (DataSyncronizer.getDeviceListTask.Status == TaskStatus.Running) {
// TODO Show the loading screen here.
// return this.View("Loading");
}
if (DataSyncronizer.getDeviceListTask.Status == TaskStatus.Faulted) {
ViewData["ErrorTitle"] = "Errore di sincronizzazione";
ViewData["ErrorText"] = "Cannot get devices";
return this.View("Error");
}
if (DataSyncronizer.getDeviceListTask.Status == TaskStatus.Canceled) {
ViewData["ErrorTitle"] = "Errore di sincronizzazione";
ViewData["ErrorText"] = "";
return this.View("Error");
}
return this.View(DataSyncronizer.Devices);
}
And this is the function that gets the device list:
public static class DataSyncronizer {
public static Task<List<Device>> getDeviceListTask { get; private set; }
public static List<Device> Devices = new List<Device>();
public static Task UpdateDevices() {
getDeviceListTask = new Task<List<Device>>(() =>
Device.GetMyDevicesList(meUser));
getDeviceListTask.ContinueWith((result) => {
DataSyncronizer.Devices = result.Result;
}, TaskScheduler.Current);
getDeviceListTask.Start();
return getDeviceListTask;
}
}
You could display the loader right before you call UpdateDevices().
add this to the end of your TASK
.ContinueWith(t => "Function to hide loader");
Example
var webTask = Task.Run(() =>
{
try
{
wcf.UploadMotionDynamicRaw(bytes); //my web service
}
catch (Exception ex)
{
//deal with error
}
}).ContinueWith(t => "Function to hide loader");

WebDriver: explicitly wait doesn`t work by click to element

My code with implicitly wait works well. But I read information about waits and understood, that I need using explicitly wait in my projects. That`s why I am trying implement my test project with it.
When step of my alhorithm equel click to button, I have error : http://joxi.ru/BA0GMyDhnY0n2y
Please, help me with it.
Base class:
using NUnit.Framework;
using System;
using LinkedinAddContacts.Pages;
using LinkedinAddContacts.TestData;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;
namespace LinkedinAddContacts
{
[TestFixture]
public class TestClass
{
private IWebDriver webDriver;
private WebDriverWait waitDriver;
[SetUp]
public void InitializeBrowser()
{
webDriver = new ChromeDriver();
waitDriver = new WebDriverWait(webDriver, TimeSpan.FromSeconds(10));
webDriver.Manage().Window.Maximize();
webDriver.Manage().Timeouts().PageLoad = TimeSpan.FromSeconds(30);
webDriver.Navigate().GoToUrl("https://www.linkedin.com/");
}
[Test]
public void TestMethod()
{
Authorization authorizationData = new Authorization();
StartPage objStartPage = new StartPage(waitDriver);
NetworkPage objNetworkPage = new NetworkPage(waitDriver);
objStartPage.EntrySystem(authorizationData);
objNetworkPage.ConnectPeople();
}
[TearDown]
public void CloseBrowser()
{
webDriver.Quit();
}
}
}
Secondary class:
using NUnit.Framework;
using LinkedinAddContacts.TestData;
using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;
namespace LinkedinAddContacts.Pages
{
public class StartPage
{
// private IWebDriver webDriver;
private WebDriverWait waitDriver;
#region Objects
public StartPage(WebDriverWait waitDriver)
{
this.waitDriver = waitDriver;
}
private IWebElement EmailInput
{
get
{
return waitDriver.Until(ExpectedConditions.ElementToBeClickable(By.Name("session_key")));
//return webDriver.FindElement(By.Name("session_key"));
}
}
private IWebElement PasswordInput
{
get
{
return waitDriver.Until(ExpectedConditions.ElementToBeClickable(By.Name("session_password")));
// return webDriver.FindElement(By.Name("session_password"));
}
}
private IWebElement LoginButton
{
get
{
return waitDriver.Until(ExpectedConditions.ElementToBeClickable(By.Name("login-submit")));
//return webDriver.FindElement(By.Id("login-submit"));
}
}
private IWebElement RegistrationForm
{
get
{
return waitDriver.Until(ExpectedConditions.ElementToBeClickable(By.Id("regForm")));
// return webDriver.FindElement(By.Id("regForm"));
}
}
#endregion
#region Methods
public void CloseRegistrationForm()
{
IJavaScriptExecutor js = waitDriver as IJavaScriptExecutor;
js.ExecuteScript("document.getElementById('regForm').style.display = 'none';");
// ((IJavascriptExecutor)driver).executeScript("scroll(0,400)");
}
public void EntrySystem(Authorization authorizationData)
{
// CloseRegistrationForm();
EmailInput.SendKeys(authorizationData.Email);
PasswordInput.SendKeys(authorizationData.Password);
LoginButton.Click();
}
#endregion
}
}
Error there:
public void EntrySystem(Authorization authorizationData)
{
// CloseRegistrationForm();
EmailInput.SendKeys(authorizationData.Email);
PasswordInput.SendKeys(authorizationData.Password);
LoginButton.Click();
}
When I understand it properly your code crashes at this line:
return waitDriver.Until(ExpectedConditions.ElementToBeClickable(By.Name("login-submit")));
Now, taking a look at the startpage of linkedIn reveals that the login-submit button doesn't have a name attribute defined, but you can use it's id instead.
<input tabindex="1" id="login-submit" class="login submit-button" type="submit" value="Einloggen">
So you should be using By.id() instead of By.name().
It is important to notice which web driver you use.
First of all, As #Robert says, its better to find by Id whenever it is available to you.
Second, I think LoginButton.Click() does not work. I had such a problem with chrome driver. When page scale(zooming) is changed, the Click method does not work properly, or clicks elsewhere on the page.
I recommend you to use SendKeys for any click action.
Just like this:
LoginButton.SendKeys(Keys.Enter);// or Keys.Return
Never ever use Click method

Categories