Winium example with word automation

I have been exploring the new tools for windows based apps automation, having worked on white API and its lack of documentation and complexity in writing the code, i was searching for good alternative.

Winium seems to be one of the options suggested by selenium group of people, as the syntax is similar to selenium.

Winium uses the winium.desktop.driver to start off the listening of the commands sent by the driver and redirect them to the application under test. There are several dependencies that are required just as selenium web driver for the desktop driver.

The basics need to work on WInium is

  1. Winium.desktop.driver.exe (winium.driver.exe)
  2. Eclipse with maven plugin
  3. Inspect tool  / .Net framework with windows tool kit
  4. Selenium background

Eclips with maven plugin : This is required since there are dependencies that are required to work with Winium, with maven plugin and with the POM file we can download all the plugins.  the POM file is given below for the dependencies.

<project xmls="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>
<groupId>WiniumTests</groupId>
<artifactId>WiniumTests</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>com.github.2gis.winium</groupId>
<artifactId>winium-webdriver</artifactId>
<version>0.1.0-1</version>
</dependency>
</dependencies>
</project>

Once you have created the project and updated the project with dependencies. You can create a test case and will be able to use the sample code below.

Just like chrome driver options we can initiate the desktop driver with options.

DesktopOptions option = new DesktopOptions();
option.setApplicationPath("C:\\Program Files\\Microsoft Office\\root\\Office16\\WINWORD.EXE");

First line is to create the options object for the desktop driver.

After creation of the object, set the application under test executable path. In the above case it is windows word.

Let us look at how do we identify the windows objects. In case of web elements we can use firebug, firepath or developer mode in browsers to get required css or xpaths.

In the windows based apps, there is tool called Inspect.exe which will be located in below path.

C:\Program Files (x86)\Windows Kits\8.1\bin\x86\Inspect.exe

Or you can search for it in entire computer, just in case of you don’t find it.

2. Inspect tool : This tool is similar to developer tools of browser. It can tell us the windows object properties. We can make use of some of the properties like classname, name, automation id etc to identify and perform operations on those objects.

InspectScreenshot

In the current context we are trying to do word automation, so to go to insert tab, we can use find element by name of it, as you see the properties description it says name is ‘Insert’

Similarly we can identify the object based on their names. Following is the code for the identification of some of the basic word GUI objects.

//Selects the blank document
driver.findElement(By.name("Blank document")).click();
//Goes to insert tab
driver.findElement(By.name("Insert")).click();
//Clicks on shapes
driver.findElement(By.name("Shapes")).click();
//Selects the rectangle
driver.findElement(By.name("Rectangle")).click();
//Clicks on rectangle to get it on the word.
driver.findElement(By.name("Page 1")).click();

The entire code is below.

package com.tests;

import java.net.MalformedURLException;
import java.net.URL;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.winium.DesktopOptions;
import org.openqa.selenium.winium.WiniumDriver;

public class Tests 
{

@Test
public void CalcTest() throws MalformedURLException, InterruptedException
{

DesktopOptions option = new DesktopOptions();
option.setApplicationPath("C:\\Program Files\\Microsoft Office\\root\\Office16\\WINWORD.EXE");

WiniumDriver driver = new WiniumDriver(new URL("http://localhost:9999"), option);
//SLeep is to wait until the word becomes visible
Thread.sleep(5000);
driver.findElement(By.name("Blank document")).click();
driver.findElement(By.name("Insert")).click();
driver.findElement(By.name("Shapes")).click();
driver.findElement(By.name("Rectangle")).click();
driver.findElement(By.name("Page 1")).click();
driver.quit();
}

}

Entire code is given in the below git repo.

Winium_Example

Before we execute any of the test cases, we need to start the winium driver exe as it is the listener to the events provided by the driver. Also, check the port on which it is running , use the same port while creating the driver.

Following is the demo.

 

Thank you. Please write in comments in case you need more information on winium automation.

TestNG Annotations list and execution order

TestNG is testing framework enhancing the Junit framework.

Lets look at different annotations it provides for the test execution stand point.

Following is the list of all annotations that one may require to control after or before facts of test execution. These methods will execute before or after the event is called. These annotations does not depend on the test execution status.

@BeforeSuite
@AfterSuite
@BeforeTest
@AfterTest
@BeforeGroups
@AfterGroups
@BeforeClass
@AfterClass
@BeforeMethod
@AfterMethod

the sample test class with annotations produces following output. All the other annotations does not need any parameters except that before and after group annotation, following is how we can mention the group name.

@BeforeGroups("Sanity")
	public void beforeGroups() {
		System.out.println("Calling before groups");
	}

Output from java console :

Consoleoutput

While doing console logs, I have struggled to get rid off other console messages produced by the chrome driver. Following piece of code is used to suppress the console logs produced by chrome driver, added this just thought might be relevant to share.

System.setProperty("webdriver.chrome.driver", ChromeDriverPath);
System.setProperty("webdriver.chrome.silentOutput", "true");

 

 

 

 

J soup example for editing html

In static web pages some times we might need parse and edit the pages.

Simple example would be generating static html report we might want to make use of html parser or html editing libs.

Jsoup is one of the good create/editing libs that is available.

Below is simple example of editing the html file with Jsoup.

There are three simple steps in the process for the editing of htmls with Jsoup.

Step 1 : Parsing the html code.

Following is the example for parsing the html file with Jsoup. The document is type of html document.

Document reportDoc = Jsoup.parse(new File(filePath), "UTF-8");

Now that we have reportDoc as html document that we need to update, lets just say if html is containing below structure, problem statement is to add data to the following table in the existing html doc.

Step 2 : Update/Append or change the text in the doc

JSoup1

In general all html objects (I.E the elements that are inside the tags) are called as elements in Jsoup.

Steps to insert data would be to find the “Element” with table tag and append the element with a row i.e “tr” tag and then add the data to the table in td tags. We can insert all data at once or we can edit data by index of the tr and td as shown below.

Element ele = reportDoc.getElementsByTag("tbody").last();
ele.append("<tr class='styleincss'>
     <td style='text-align: center;'>1</td>
     <td style='text-align: left;'>desc</td>
     <td style='text-align: left;'>col3</td>
     <td style='text-align: left;'>col4</td>
     <td style='text-align: left;'>col5</td>
     <td style='text-align: center;'>col6</td>
     <td style='text-align: center;'>Complete</td>
    </tr>")
//This will generte the html
reportDoc.html()

//If we want to change the values of existing rows we can write
reportDoc.getElementsByTag("tr").last().getElementsByTag("td").get(4).text(data);

//If you want to change or add attribute
reportDoc.getElementsByTag("a").last().attr("style", "text-align: center;Color: " + colorCode);

 

In the above code we have seen ways to add inline html, editing dynamically with rows and columns, we can loop through as well and write some intelligent code to go to particular column and particular row and edit data.

We can also set attributes for example as color, or href for links shown in above example.

But we just appended the document, how do we save ?

Step 3 : Save and flush to disk

We can use Buffered-reader to read the html that J soup has just appended to the original document.

Lets just say you have file name that you want to create and also appended document, below is the code to save to disk.

public static void writeToFileAndFlushToDisk(Document doc, String outputFile) throws IOException {
BufferedWriter htmlWriter = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream(outputFile), "UTF-8"));
htmlWriter.write(doc.html());
//Optional new line
htmlWriter.newLine();
htmlWriter.flush();
htmlWriter.close();
}

 

This is general idea on how to use J Soup for editing html files. I have used this and created simple html reporting for LeanFT tests. We can create files and dynamically update link references so that test results can be systematically generated.

Please write to me if you need more information.

Conditional testing with ITestAnnotation interface

In TestNG there is provision that we can run tests conditionally, like we can have test case that needed to be executed with flags yes or no and we want to conditionally run these tests.

For this purpose we can make use of ITestAnnotation interface. This provides the interface to override the test annotations during runtime.

TestNG_ItestAnnotation

The above example is listener class that can override the transform method, which dictates the test annotation. We can control the enabled annotation attribute to make test available to pickup by the TestNG framework.

Make sure that you have enabled annotation available for the test. I.E explicitly add this annotation for the test so that, TestNG overrides the Annotation. If this attribute is not there TestNG cannot  override the same.

TestNG_ITestAnnotation_Enabled

And finally add this listener to TestNG XML to make things work.

TestNG_XML

LeanFT quick setup for ECLIPS IDE

Hello, recent days I have been working with LeanFT and faced some hiccups in installing configuring and setting up for ECLIPS IDE.

LeanFT is plugin for integrated development environments. It supports ECLIPS and MS Visual Studio and ItelliJ.

In this blog, I will quickly discuss about setup for ECLIPS IDE and issues I have faced with step by step instructions.

  1. First of all we have to down load ECLIPS IDE. As per LeanFT documentation ECLIPS Oxygen 32 bit version is most supported. you can view from the same.                Eclips download link
  2. ECLIPS
  3. Now got to micro focus site and download the LeanFT installable.
  4. In the installation follow the instructions carefully to avoid the issues later.
  5. The most important instruction is, you have to select the path of the ECLIPS exe folder.
  6. You might have several ECLIPS installations, but which one you want to use it, carefully keep the same path and use the same ECLIPS exe to see the LeanFT plugin.
  7. After installation, restart the machine.
  8. Boom!! now if you open LeanFT menu will appear in ECLIPS. But, unfortuantely we have few more steps to see the LeanFT plugin.
  9. Download and copy (gson-2.8.1.jar) file to plugins directory in ECLIPS folder, it is mentioned as known sssue in the leanFT instructions manual a, see below.    LeanFT KnownIssues

KnownIssues

9. Once everything is done, lets open the ECLIPS exe. There is another .exe file gets generated in the ECLIPS directory, see below.

ECLIPSFolder10.  Use eclipsec.exe to launch the IDE.  You should see below menu in the ECLIPS.

LeanFTMeny

11. You should see leanFT related projects when you click File->New->Project from ECLIPS. See below

newProject

12. LeanFT is UFTPro, if you are worked with UFT its like cake walk for automating anytype of project, if you are UFT guy better to start project as Application Model project.

13. In LeanFT, there is run time engine called LFTRuntime, when you start project LFTRuntime will start on port 5095. This is responsible for detection of objects and running the created tests. Lets see how to kick start project as Application Model project and resolving starting hiccups in next section.

 

 

Extent report logging while parallel testing

Hi As we discussed in the last post Parallel testing and Thread Safe driver for testNG, lets discuss about extent report log synchronization.

We can achieve this by invoking parallel threads for each of the test.  Lets consider we have one html extent report and we want to add several tests together.

We can do extent report as static and we can create tests in different threads,  and at the end we can flush each thread to report. Lets see below code for extReport and extTest classes which does the same.

public class ExtReport {
public static Calendar cal = Calendar.getInstance(TimeZone .getTimeZone("GMT")); 
public static long time = cal.getTimeInMillis();   
    public synchronized static ExtentReports getReport() 
    {          
      ExtentReports Report = ( new ExtentReports(System.getProperty("user.dir")    + "/test-output/ExtentReport_" + time + ".html", true));    
      Report.addSystemInfo("Host Name", "TestMachine") 
         .addSystemInfo("Environment", "Automation Testing")
         .addSystemInfo("User Name", "Tester");
      Report.loadConfig(new File(System.getProperty("user.dir")    + "\\extent-config.xml"));     
      return Report;   
    }                
 }

In the above class we are generating static report and have one method to get the report.

This method, will return the static report object. Lets look at creating test and adding it to the same report.

public class ExtTest 
{
public class ExtTest
{
   private static ExtentReports extent = ExtReport.getReport(); 
   public static ThreadLocal<ExtentTest>  extentTestThreadSafe = new ThreadLocal<ExtentTest>(); 
   public static synchronized ExtentTest getTest() 
{ 
  return extentTestThreadSafe.get(); 
}
public static void setTest(ExtentTest tst) 
{ 
   extentTestThreadSafe.set(tst); 
}

In the above class we are creating methods to set and get thread safe version of ExtentTest and use the same test in logging all the actions. Lets look at below code how we can make use of above two classes and do the reporting.

We initiate the logger (extent test) from test method and use setTest and getTest methods to set and access the started ExtentTest.

//this is to get the extent report created and declared in test class
public ExtentReports extent = ExtReport.getReport();
@Test 
public void login_Test_Case_01() 
{ 
try 
{ 
 ExtentTest test = extent.startTest(SheetName); 
 st = new start(); 
 ExtTest.setTest(test); 
//your testing code here you can pass the test to other page classes etc.
 } catch (Exception e) 
{ 
  ExtTest.getTest().log(LogStatus.FAIL, "unexpected error " + e.getStackTrace().toString()); e.printStackTrace(); 
} finally
{ 
 extent.flush(); 
} 
}

This way tests that are running parallel can write in parallel to the Extent-report.

Here also, there is one challenge that these tests can flush to report when ever they are done/complete/fail. so the final report might not contain tests in any particular order., but all the steps in each test will not jumble up and you see report steps for each test will be listed in the same test. Below is the example report running tests in parallel.

Report

Parallel testing and Thread Safe driver for testNG

In the recent times cicd is being the buzz word. Keeping this in mind the automation testing has been evolved to support this very need. Since after the build automation test suite need to be executed, the tests run time being the critical for whole build time. Most often because the tests run longer only prioritized tests will run in build generation cycle.

In this context its useful to know about parallel testing to reduce the turn around time. Let’s first look at parallel testing in testNg and selenium.

TestNg gives option to run parallel tests in threads. We can define how many threads we want to kick off simultaneously.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Suite" parallel="methods" thread-count="2">
 <test name="Test" thread-count="3">
 <classes>
 <class name="com.tests.testcases"/>
 </classes>
 </test> <!-- Test -->
</suite> <!-- Suite -->

<suite name=”Suite” parallel=”methods” thread-count=”2″>

At Suite level the attribute parallel=”methods” added to run tests simultaneously.

The highlighted thread-count attribute determines how many threads testNG framework wants to kick off, these are parallel process running with different thread ids.

<test name=”Test” thread-count=”3″>

At test level also we have thread-count attribute and it is set to 3 in above example.

This means, three tests can run in parallel provided if we have enough threads.

Although you give thread-count is 2 at suite level and 3 at test level only two tests will run simultaneously, the third test will run only when first thread is freed up.

So batches of 2 tests will run until all tests completes.

The most common issue here being creating driver object which is thread-safe

And the other issue is being managing logging, as several threads trying to write to the same report. At the end we want single report for all tests.

Let us look at above mentioned two concepts. In java programming we can create driver which is thread safe with given command.

protected ThreadLocal<WebDriver> wbdriver = new ThreadLocal<WebDriver>();

ThreadLocal class in java is helpful in creating objects which are thread safe. It has get and set methods.  Following is its implementation

//chrome driver (options describe the desired capabilities for chrome driver.)
//you can just use string url instead of getting from properties file
String url = "https://google.com";
wbdriver.set(new ChromeDriver(options));
wbdriver.get().manage().window().maximize(); 
wbdriver.get().get(url);

in the above example, wbdriver holds the driver created, it is protected by ThreadLocal class for thread safety.

This way if you create driver, each test will run by its own thread. The only challenge being, the results will be hard to interpret when lot of concurrent driver processes are doing job simultaneously.

Lets discuss about synchronizing the logs with ExtentReports in next posts.

Extent report logging while parallel testing

 

 

 

Intro to ShiftLeft and BDD in Automation Testing Context

In recent times the shift left is happening trend in the software DevOps.

DevOps is basically a ladder between development and testing which enables continues integration and continues development.

In the context of DevOps shift left testing is getting more focus as the strategy of shift left is to test early and deploy early. (shifting testing left side of the “requirements to development to production roll out” pipe line).

That means the automation testing should happen as and when build is getting generated. The cycle times of test execution must be low so that build can be generated quickly. To do this seamlessly with conventional automated testing tools is a challenge as these tools typically have different UI and not integrated with development environment.

So the ideal solution is to have IDE(Integrated Development Environment) or a plugin for development environments. Be it Microsoft Visual Studio, be it Java Eclipse or be it any other development environment, Test Automation can be performed right from IDE right from the same development environment integrating with favorite unit testing frameworks.

This will be one shop stop for both development and testing.

Selenium is already being great tool for Test Automation right from integrated build environments for C# and Java for Web Applications.

So where will BDD fit, BDD is approach for faster testing and provides transparency in testing “what you write as requirement (feature) is what you test”. Requirements are written as features and features are implemented and tested.

It starts with Features, which all features we want to include. And each features contain multiple scenarios and each scenario can have flavors with different data sets.

Application -> Features – > Secenarios -> DataSets

Let us try to write the feature and scenarios for Calculator application in general to get to better understand, and after that we can see how these features can implemented.

Lets first create feature file as calc.feature  and write following.

 

bdd1

Then lets choose how many types of scenarios we want to cover for this feature and tag them separately.

@Basicoperations

@Advancedoperations

Let us take in each of these operations lets write basic scenarios with keywords Given, When and Then.

Given describes or sets the context of the scenario under stated environment. The best practice is to check the system state. Its like prerequisite for the given scenario.

When describes the state change parameters. Like user actions to move the system from one state to another state.

Then describes the consequence or result caused by the state change. Its like if when is the cause Then is the effect.

And is key word will be used to add multiple whens or multiple Thens.

But is used in the same context as then and mostly used for negative testing.

Here is how a scenario looks like.scenario example

The tag @Basicoperations is like category of the test.

Scenario Outline can contain multiple examples, It is always better to write as Scenario Outline instead of just scenario so that we can specifically mention the parameters and looping of the test data is also possible.

We have several ways of writing the same scenario. Its better to write the scenario as re-usable blocks so that the steps can be re-used.

Let us take another example to see how we can re-use the same steps.

In the below scenarios same steps are used as above scenario and just the operation is being changed.

bdd2

Let us look at @Advancedoperation description and figure out how we can write the detailed re-usable steps for more advanced operations.

advanced

In the above we can see multiple and statements and some of the “And” statements are similar. The above scenario enters data in below form. the multiple And statements enter the values in the respective text boxes.

form

This is very small example of how we can write BDD tests, I will try to explain how this can be implemented in next blog.

Page Object Model – Framework

Most of the times, many project demands start of best fit automation framework from scratch. Page Object Model (POM) is most popular design pattern for the Selenium automation.

In this post, lets try to figure out the details. Before diving in its better to look at this post to get insight of what we are talking here.

Page Object Model – Approach

Lets us look at the following different packages for the purpose of the understanding.

pages contains the test pages for the site, where as each page contains the objects corresponding to that page.

In any UI testing we typically do two things with objects, either we retrieve properties for it or we perform actions on it.

eclipsstructure

In the start section we write necessary code to start the browser. Driver session creation, extent test creation, logger creation etc.

The tests section contains the test classes we are intended to write.

The utilities section contains the common actions class and the reusable action classes.

expandedpackages

Also, its better use config properties for the entire test setup along with the test data sheets. Also maintain drivers in different folder for better readability.

projectStructure

As shown above utilities package contains the excel manipulations such as get and set data operations.

Lets deep dive into start class and what it is doing.

Start class has all declarations and webdriver creation depending the config settings.

Create config file with browser type and other details so that we can use them in the code.

config

Start class will have the entire code for reading the config file and depending on the browser type mentioned in the config it creates the web driver session.

If we look at the declarations, the entire project is using extent reports as it will generate beautiful reports for the test execution.

Also, all other variables are declared as static where as driver is non static. The report logger is also static, since once we create start instance driver will be recreated but not the report logger. This will help to run the same test in multiple iterations keeping the same report.

If we look at the declarations, we are declaring the xldriver, extent report and logger properties as static as they dont need to be re initialized for loop execution. (Static variables are created once, they are not recreated for each instance of class)

start2

the launch_browser method returns the pagefactory object with created driver. This will flow to subsequent pages.

return.PNG

Will see why it is returning the page factory object.

If we look at the pagefactory class, it has definitions of all pages.

We are using pagefactory constructor to send the driver to all the sub subsequent classes.

And, the home and other pages will inherit this class so that they can get the latest driver created by the start class.

pagefactory

Each page class is contains the deification of elements and initialization of elements.

We will use PageFactory class (Selenium specific class) along with ajaxelemetlocator since it has advantage of creating element only when it is being used, we can also define the time duration for the locating element. We are also using reference class object for the common functions.

The reference, and the home class gets the driver created in the start class.

home1.PNG

Also the each class in the page returns the same page for better creation of tests.

home2

And finally coming to writing test cases.

Starting with method name, we are using the data sheet name as test method name.

So to avoid hard coding of the methodname passing to excel setExcelSheet method , we are programatically getting method name and assigning it.

Since xldriver and set_logger method is static, we dont have create start class object to use them.

And looking at the loop, we are getting rows in the excel sheet and running the required actions for each row. That means creating driver doing all actions and logging out.

We can restrict this for certain actions if we dont want to quit the browser, by keeping the creating of start object outside the for loop.

And by keeping (.) at the launch_browser(), we get access to the methods in pagefactory class, and since all other classes are extending pagefactory class, all of them gets access to pagefactory class methods. Thats the reason for writing page navigation methods in the pagefactory class.

This way we can write single line test cases, this will ease the reading of test case and writing and debugging them.

TestCase

the output for the test looks like below.

reports

This is gist of implement page object model with one sample testcase.

In this post we have not included the excel data manulations, hash maps and extent report creation.

We will try to address them in subseqnet posts.

Thank you.

 

 

 

Synchronization in Automation Testing with selenium.

When you ask selenium tester what is the most common issues he is facing during his automation testing experience, the first thing he would say is Sync problem.

Let’s take a bird eye view on this and will take deep dive on the synchronization issues and how to address them.

Selenium framework has several methods to address the synchronization issues. Mainly they are segregated into two different varieties.

  • Implicit waits
  • Explicit waits

Implicit wait:

This is the most common wait type we use; it is also called as default wait. The page load time out, and the timeouts.implicitwait is the two types of implicit wait. The implicit wait meaning that the driver has to wait until the web element is existed on the dom. It will come out of the waiting loop if element exists beforehand. Example you have given 10 seconds on element x, and it has loaded in 2 seconds web driver knows it and goes to next step without waiting for 10 seconds. It is called as implicit wait.

driver.manage().timeouts().pageLoadTimeout(10, TimeUnit.SECONDS);
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

Explicit wait:

Explicit waits are defined on the particular web element to wait until the property value becomes true.

It will pole every 500 milliseconds to get the property value and verifies it with defined value.

Examples:

//webdriver wait class
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(ExpectedConditions.elementToBeClickable(driver.findElement(By.xpath(menu))));

//for multiple elements
WebDriverWait wait = new WebDriverWait(driver, 30);
List options = driver.findElements(By.xpath(option_to_select));
wait.until(ExpectedConditions.visibilityOfAllElements(options));

//Another example
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(ExpectedConditions.invisibilityOfElementWithText(By.className("jqx-fill-state-normal"), "Loading..."));

Fluent wait:

Fluent waits also called as explicit waits, but only difference being we can define interval to pole and can tell to ignore any exceptions. It will be useful to save resources not to check every 500 milliseconds if element load takes long time.

Wait<WebDriver> fluentwait = new FluentWait<WebDriver>(driver)
                        .withTimeout(20, TimeUnit.SECONDS)
                        .pollingEvery(1, TimeUnit.SECONDS)
                        .ignoring(java.util.NoSuchElementException.class);
fluentwait.until(ExpectedConditions.invisibilityOfElementWithText(By.className("jqx-fill-state-normal"), "Loading..."));

The another type of wait is normally not recommended is static wait or pause the program.

Thread.sleep(500);

So, the gist is the know when to use what. Fluent wait is used when application slower and running in a slow paced machine where we don’t want driver to hit every 500 milliseconds, and you know it will not come till 2 sec or 3 seconds, we can define the polling interval. I am guessing this as it is synonymous to implicit wait where the default polling is 500 ms.

We can use web driver wait almost in all cases where we know element loading is taking place, but the properties are not loaded until some other action is completed, example, state dropdown is enabled only when country drop down is selected, in that case we can use expected conditions on the enabled of the state dropdown after country select.

Default waits or implicit waits are used when we know dom loading is taking some time and not to give wait on existence of each element. Normally this would serve the purpose, but angular applications waits plays key role in test execution failures.

If we use waits wisely and where ever we need depending the application behavior with limited use of static waits will improve the script quality drastically.

Thank you.