PageFactory seems to be slow when used in Appium iOS automation - appium-ios

We are automating a react-native iOS app using Appium. We are using PageFactory design pattern. For clicking a element, this is the code am using:
Waiting for element to be visible.
Clicking on the element
public Boolean waitUntilVisible(WebElement element)
{
try {
wait.until(ExpectedConditions.visibilityOf(element));
return true;
}catch (Exception e)
{}
return false;
}
public boolean click(WebElement element)
{
//Click on the element and return true if successful and false if unsuccessful.
try
{
waitUntilVisible(element);
element.click();
} catch (Exception e) {}
return false;
}
The overall execution seems to be taking too much time. As per my understanding, waitUntilVisible waits until the element's isDisplayed() became true.
As we are using PageFactory, I assume that element identification occurs twice.
1. The element will be identified first before checking for visibility.
2. The same element will be identified again before click.
Since we are using xpath in many areas, the element identification usually takes longer time. For a simple click, the same element is identified twice which further increases the time.
I want to know any solution to store the identified element so that it won't spend time in identifying it again.
So I modified my code like below:
public WebElement waitUntilVisible(WebElement element)
{
try {
return wait.until(ExpectedConditions.visibilityOf(element));
}catch (Exception e)
{}
return null;
}
public boolean click(WebElement element)
{
//Click on the element and return true if successful and false if unsuccessful.
try
{
WebElement remoteElement = waitUntilVisible(element);
remoteElement.click();
} catch (Exception e) {}
return false;
}
This method doesn't seem to save time.
Is there any other way for me to reduce the execution time.
Note: We are using WebElement instead of IOSElement so that the same code which was used in Desktop automation can be used in IOS Automation as well.

use
mobileElement = driver.findElement(MobileBy.locator("locator"));
appiumDriverActions.moveToElement(mobileElement).click().perform();
appiumWait.until(ExpectedConditions.condition(Element/locator));
instead of
mobileElement = driver.findElement(MobileBy.locator("locator"));
mobileElement.click();
in some cases with the new default VC from iOS13, it is better to moveToElement then use action click instead of element.click();
for more details, https://medium.com/#ayman.ibrahim.mansour/appiums-best-way-to-deal-with-the-new-view-controller-presentation-in-ios-13-6d801fcc3cb

Related

Why ActivityIndicator changes state after entire method is completed?

I would like to show ActivityIndicator object after user tap the login button on page. Unfortunately there is small problem to do that because it seems like ActivityIndicator change state after entire method is completed. This is code I wrote so far:
private void Login(object sender, EventArgs ev)
{
BusyIndicator.IsVisible = true; //<- here I want to show indicator
try
{
//some input validation, connection opening etc
ConnectionHandler.OpenConnection(ServerIP, "dmg", false);
}
catch (Exception e)
{
Logging.Error(e.Message, "Connection", e);
}
}
When I set breakpoint after BusyIndicator.IsVisible = true; there is absolutely no change in app. However I noticed that when method is completed then indicator is shown. Is this a correct behavior of this control?
Why I need this? Because field validation and connecting with server takes some time and I need to show to user that something happens in background. Login function takes ~1 sec so indicator show and hide quickly I can't even see any change.
How can I show indicator immediately after user tap a button?
Your problem is that Login() method is being executed in the UI thread. So, despite setting BusyIndicator.IsVisible = true;, the thread continues tio execute the method to get data, so the UI does not respond.
Solution, run the OpenConnection in a different thread:
private async void Login(object sender, EventArgs ev)
{
BusyIndicator.IsVisible = true; //<- here I want to show indicator
try
{
//some input validation, connection opening etc
await Task.Run(() => { ConnectionHandler.OpenConnection(ServerIP, "dmg", false);});
}
catch (Exception e)
{
Logging.Error(e.Message, "Connection", e);
}
}

Best place to load data when navigating XamarinForms Prism 6?

One of the cool features in Prism 6 is the deep linking and passing parameters. In a lot of cases, you'd want to use this parameter to look up data from a web service. Ideally this would be using async/await to get the data. Where is the best place to do this? The OnNavigatedTo method for example is a void.
Although I don't have a case for Deep Linking yet, I am doing many loads on many pages inside OnNavigatedTo and it is working great!
Here is a sample:
public void OnNavigatedTo(NavigationParameters parameters)
{
if (parameters != null &&
parameters.ContainsKey("MyKey"))
{
SomePrivateFieldInViewModel = (YourVariable)parameters["MyKey"];
//SomeWork
}
GetItems();
}
private async void GetItems()
{
try
{
SomeListInViewModel = await WebServices.GetEntity(SomePrivateFieldInViewModel);
//SomeWork
}
catch (Exception ex)
{
//SomeWork
}
}

Checking if a Part inside of a PartStack was closed by pressing the close icon on the corresponding tab

Platform: Windows 8.1 Pro, E4 with e(fx)clipse
I'm currently working on caching opened Parts to reopen then when reloading the PartStack. This reloading method uses EPartService.hidePart() to close all Parts in the PartStack. Since I also need to remove Parts from the cache, I need to differentiate between reloading and actually closing a tab/Part.
I already tried to add the part to the cache a second time before removing it again by sending an event from the preDestroy() method of the Part. But this is less than ideal.
Is there a special event I can catch when clicking on the close icon or another way I could check for this?
Thanks for your help.
Turns out, the easiest way to do what I wanted to do was to use tags.
Since I could only access the code for when the Part was closed by the program, I needed to set a tag on the part.
if (part.isDirty()) {
if(!partService.savePart(part, true)) {
return;
}
part.getTags().add(Tag.PART_CLOSED_BY_PROGRAM);
partService.hidePart(part);
} else if (part.isCloseable()) {
part.getTags().add(Tag.PART_CLOSED_BY_PROGRAM);
partService.hidePart(part);
}
}
Now I can just check in the preDestroy() method if the Part is being closed by the program or by the user.
#PreDestroy
protected void preDestroy() {
if (part.getTags().contains(Tag.PART_CLOSED_BY_PROGRAM)) {
part.getTags().remove(Tag.PART_CLOSED_BY_PROGRAM);
} else {
try {
//remove "Part" from cache
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
} catch (NoSuchMethodException e) {
}
}
}

Windows Form TopMost don't work with BackgroundWorker?

I'm trying to show window when user need to be notify about some work to do. Every think work fine, but i want to show form absolute topmost. I set form property TopMost = true but it does not work, window still show behind other forms.
I figure out that TopMost = true don't work only with BackgroundWorker, when i use Timer class it work fine. I'm wonder why? Anybody can explain me this?
Here is simple example what i want to do.
static void Main(string[] args)
{
try
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerAsync();
Application.Run(new Form());
}
catch (Exception exp)
{
Console.WriteLine(exp);
}
}
static void worker_DoWork(object sender, DoWorkEventArgs e)
{
while (true)
{
System.Threading.Thread.Sleep(1000);
if (NeedNotify())
{
NotifyForm myNotifyForm = new NotifyForm();
myNotifyForm.TopMost = true;
myNotifyForm.ShowDialog(); // NotifyForm still show behind others windows
}
}
}
private static bool NeedNotify()
{
return true;
}
}
Creating the form within the background worker causes the form to be created on a different thread. Instead, create and show the form in your main thread before calling RunWorkerAsync.
Another problem may arise from the fact that you're creating the "notification" before the application's main loop is even started. You may consider reorganizing your code so that the background worker is started from the main form's OnLoad event.

How do i improve the legacy code implementation, Response.Redirect?

Some scenarios to ponder. There is a legacy code which has following implementation Example1 and Example2. If we try to implement MSDN recommendation then the legacy code fails.
Here is a Legacy code example:
Example 1:
void Page_Load() {
.... some code
if(condition) {
/// some condition
} else {
RedirectPage(url);
}
// another code block
// some other conditions.
}
Example 2:
a. File1.ascx
void Page_Load() {
try {
.. some code
base.CheckPreference();
RedirectPage(defaultPage);
}
catch(Exception ex) {
ExceptionHandling.GetErrorMessage(ex);
}
}
b. BaseClass.cs // this is the base class
void CheckPreference() {
try {
if(condition) {
RedirectPage(url1);
} else if(condition2) {
RedirectPage(url2);
} else {
// update session
}
}
catch(Exception ex) {
ExceptionHandling.GetErrorMessage(ex);
throw;
}
}
void RedirectPage(string url) {
Response.Redirect(url);
}
One possible way is to add a boolean field in the class e.g endExecution, set the field to true whenever RedirectPage is called.
We have to update RedirectPage code see code snippet below:
// Updated code - MSDN recommendation.
void RedirectPage(url) {
Response.Redirect(url, false);
this.Context.ApplicationInstance.CompleteRequest();
endExecution = true;
}
Please suggest some other better ways to improve the legacy code implementation.
Probably the most unintuitive thing for folks issuing a redirect is that in our minds we've already returned from the method what we call Respond.Redirect (or whatever the equivilent is in your language/platform of the day. All we've done is call a method.
Bottom line is that you have to stop processing the request to avoid trying to commit to responses for the same request. That would throw an exception on just about any platform I've worked with.
ASP.NET MVC improved this with the ActionResponse so that you are returning from the method (and terminating the remainder of request processing) with code that looks like this:
return Redirect(url);
Bottom line is that you need to get in the habit of returning from your event right after you perform your redirect. Any deviation from that habit needs to be documented in the code why. This will help make the application perform the way you expect.
The approach that you've taken is perfectly reasonable.

Resources