The following is the third on a series of articles by @Ali Youssefi that we will be cross-posting into this Test Community Blog. These articles were first published by Ali in the Dynamics community but since the topic is very related with Testing it makes sense to publish here as well.
If you didn't get a chance to catch the first one of the series, please have a look here:
Otherwise, please read ahead!
is an open source framework built upon allowing automated UI tests to be performed on a specific Dynamics 365 organization. This article will focus on reviewing how EasyRepro works with the Document Object Model otherwise known as the DOM. This will help us understand how we can extend the EasyRepro code for use with custom objects or areas of the platform not included in the framework at this time. We will wrap with a brief look at XPath and referencing elements from the DOM.
If you haven't already, check out the first article which covers getting familiar with EasyRepro and working with the source code locally. It covers then from . and reviews setting up dependencies and test settings to run a simple test. The second article goes into common actions performed by users when interacting with Dynamics 365 and the correlating EasyRepro commands. It wraps with covering common troubleshooting and debugging scenarios.
The EasyRepro framework contains an abundance of commands that should suit most of your needs. However you'll find that at times either these commands will need to be modified per your customizations or you may need to create your own custom commands for reuse among tests.
Some example scenarios for modifying or creating custom commands may include:
Using an ADFS Redirect Login
Working with custom components and resources
Working with strongly typed entity attributes
Including navigation and functionality not present natively in the framework
These scenarios require an understanding of how EasyRepro interacts with Selenium to simulate user actions in a browser. This article will focus on a typical use case for extension: the Login process. We will describe common Selenium functionality and how to reference elements on the Document Object Model in a way to increase maintainability.
As we discussed earlier, your organization's login process may have a sign on page that a user will get redirected to once they input their username. This is where we begin our journey into extending the framework and utilizing Selenium.
Typical Single Sign On Page:
Custom method for a Single Sign On Page:
The image above shows a method designed to search through a sign in page DOM for input fields for credentials and submission. You will notice that we are working with the browser driver natively (args.Driver) and using methods not found in the sample EasyRepro unit tests. These include which is part of Selenium and WaitForPageToLoad which is part of EasyRepro's extension of Selenium. I'll touch on these at a high level now.
is part of the Selenium.WebDriver assembly and is used to find an element in the DOM. I'll cover how to search through the DOM in the next section Extending and Working with XPath but I wanted to take this time to show how we will begin extending unit tests using Selenium natively.
The method returns an IWebElement object that represents the element you want to work with. For instance if you want to work with the username textbox you can use FindElement to locate and return the username textbox. Once returned the framework can interact with it and perform actions such as input text or click.
WaitForPageToLoad is part of the EasyRepro framework as a Selenium extension. This is key to point out that we are leveraging both EasyRepro and Selenium natively to achieve our desired result to login. This method waits a specific amount of time and checks for the document ready state. The time interval used to check can be adjusted if needed.
is used to send keystrokes to an element on the page. This can be a complete string such as an email or a single keypress. This can be used to send the username and password to your sign in page. It also can be used to send the Enter or Tab keypress to move to the next field or submit.
as it sounds is used to remove any sort of input that may already exist in an element. This is useful if your sign in page attempts to automatically input credentials.
Both of these methods are part of the IWebElement shown above. Other useful properties of IWebElement include Text, Selected and GetAttribute.
Considerations need to be made when designing unit tests to help reduce the maintenance work needed if something changes. For instance when referencing custom HTML web resources or even the ADFS Redirect from above, think how a change to an element in the DOM could propagate across some of all of your unit tests. One way to control maintenance is to centralize commonly used references into proxy objects that can hide the underlying mechanics from the test designer. This is exactly how the EasyRepro framework handles references and when extending can leverage the same approach. In this section we will cover the files used by the framework to reference DOM elements and show how to extend them to include references to our custom login page.
The Microsoft.Dynamics365.UIAutomation.Api.UCI project uses the ElementReference.cs file as well as another file called AppElementReference.cs. The ElementReference file looks to have been brought over from the classic interface. What's unique about each is how they reference elements in the DOM which I'll cover in the next section. For now let's focus on reviewing the AppElementReference.cs file which is located in the DTO folder of the Microsoft.Dynamics365.UIAutomation.Api.UCI project.
Inside of the AppElementReference file are two objects used by EasyRepro to represent and locate elements: The AppReference and AppElements classes.
The AppReference class includes sub classes that represent the objects used by EasyRepro, specifically the WebClient object, to connect to DOM elements. This allows the framework to standardize how the search for a particular container or element is performed. Centralizing the reference to the DOM elements will allow the test designer to focus on writing commands against common objects and not specifying the precise location of an element in the DOM.
The AppElement class is a comma delimited key value pair consisting of the reference object property as a key and the XPath command as the value. The key represents the property name in the class object inside of AppReference while the value is the XPath location of the element in the DOM.
I highly suggest reviewing the AppElement class when extending EasyRepro as it shows recommended ways to locate and reference elements on the DOM. In the next section we will discuss the different ways you can locate elements including XPath.
References to objects generally fall into four patterns:
Resolving via Control Name
Resolving via XPath
Resolving by Element ID
Resolving by CSS Class
In this article we will focus on XPath which is what is primarily used by the EasyRepro framework for the Dynamics 365 platform. However its key to understand each of the approaches for referencing as they can be used for customizations such as web resources, custom controls, etc.
This will search the DOM for elements with a specific name which is an attribute on the element node. This is not used by EasyRepro to my knowledge. Elements can be found by their name by using By.TagName with the FindElement method.
This will attempt to find an element by its unique identifier. For instance a textbox on the login form maybe identified as 'txtUserName'. Assuming this element ID is unique we could search for this particular element by an ID and return an IWebElement representation. An example from the Microsoft.Dynamics365.UIAutomation.Api.UCI project is shown below showing usage with the timeline control.
Usage by WebClient:
This allows the ability to search by the CSS class defined on the element. Be aware that this can return multiple elements due to the nature of CSS class. There is no usage of this in EasyRepro but again this could be helpful for customizations. Elements can be found by their CSS class name by using By.Class with the FindElement method.
XPath allows us to work quickly and efficiently to search for a known element or path within the DOM. Key functions include the contains method which allow to search node attributes or values. For instance when you review the DOM of a form you'll notice attributes such as data-id or static text housed within a span element. Coupling this attribute with the html tag can result in a surprisingly accurate way to locate an element. I suggest leveraging the current element class as well as that goes into the schema of XPath.
Going back to an earlier section let's review how XPath along with the AppElementReference.cs file can help standardize element location.
Going back to our original example for the ADFS login method below you'll see an example of referencing the DOM elements using XPath directly with the Selenium objects driver and By.XPath. Consider the below two images:
Without a static representation of XPath:
Using static classes to represent XPath queries:
Both of these methods work and perform exactly the same. However the second method provides increased supportability if and when the login page goes through changes. For instance consider if the id of the textbox to input your username changes from txtUserName to txtLoginId. Also what if this txtUserName XPath query is propagated across hundreds or more unit tests?
Let's put what we have learned to use by creating a reference to our custom login page. Start by adding a class to the AppReference object and title it AdfsLogin. Inside this class declare string properties that will be used as input for your organization's login page. Typical inputs include username, password and a submit button. Here is an example:
NOTE: While this document demonstrates how to add to the AppElementReference.cs file I would suggest extending this outside of the core files as customizations will have to be merged with any updates from the framework.
Once the static class we want to use in our unit tests has been created we now need to add the XPath references to the AppElement class. Below is an image showing the key value pair discussed in the AppElement section above. The key correlates to the string value of the AdfsLogin class while the value is the XPath directive for our elements.
As shown in the image for Login_UserId we are searching the DOM for an input element with the id attribute of 'txtUserName'. XPath can be used to search for any attribute on the DOM element and can return a single value or multiple depending on what you're searching for.
PowerApps Control Framework controls and web resources are customizations that represent great options to learn and extend the EasyRepro framework. Try locating the container for the PCF controls and HTML web resources and work towards creating custom objects representing the elements for each as described above.
In this article we discussed reasons why we will may need to extend the EasyRepro framework and some techniques in doing so. We explored working with Selenium objects and creating references to help us when creating unit tests. Finally we put this in an example for working with a ADFS Redirect page on login.
Thank you again for reading! Please let me know in the comments how your journey is going!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.