Coding Flood Element TypeScript which (like Selenium) emulates manual actions in Google Chrome browsers
Overview
This is a hands-on step-by-step deep-dive introduction to automating manual actions into flood.io Element TypeScript using Google Chrome Developer Tools. After validation, the scripts are used on flood.io in the cloud to performance test public websites.
NOTE: Content here are my personal opinions, and not intended to represent any employer (past or present). “PROTIP:” here highlight information I haven’t seen elsewhere on the internet because it is hard-won, little-know but significant facts based on my personal research and experience.
This is a component illustrated as the upper-right corner of the video and flowchart at https://wilsonmar.github.io/flood-the-internet, reiterated here:
PROTIPs here provide additional commentary based on experience and foresight not available elsewhere.
-
If you don’t have a Google Chrome Browser app installed, please install it now so that we can make use of the Google Chrome browser’s Developer Tools to analyze web pages interacting with the server.
-
Since you’ll be using it a lot, drag the app icon to whatever edge of the screen your Mac’s Launchbar or Windows dock bar uses. This is usually the bottom edge.
-
Open Google Chrome.
-
If you are not using Chrome to view this page, triple-click the URL below to copy the URL, then switch to the Chrome browser and paste this page’s address in the address field:
URLs to sample apps
Below are my articles about sample apps available:
- the-internet badly coded UI that challenge test automation
- sap-fiori
- JPetstore Java
- Microtrader async http/2 app
-
Click the link to the app to be automated.
Alternately, go directly to an app we want to automate, such as:https://sapui5.hana.ondemand.com/#/demoapps
View Source
In order for a script to manipulate a control such as a checkbox, the script needs to have a handle which the browser uses internally. One way to do that we need to view Source. There are several ways to do that.
-
Cursor anywhere on a background area of the web page where the cursor is an arrow, then right-click to select “View Source” in the context menu.
The HTML shown may be minified stripped of white space such as line breaks and indents that only people need for readability. This is a best-practice for production sites to reduce what is downloaded, which reduces load time for end-users.
To get a formatted view of HTML:
Chrome Developer Tools
There are several ways to bring up Developer Tools.
-
Click Google Chrome’s menu button (the three line icon) at the upper-right corner to reach More Tools, Developer Tools.
This we can also be reached from clicking the top View menu.
But remember there is a keyboard shortcut of option+command+I on the Mac, which is what I usually do to avoid spending time reaching for my mouse.
-
Click the Developer Tool’s menu icon (with the three vertical dots) to select which way the screen is docked.
-
Drag the top divider to see more lines.
-
Drag the separator between the two panes to see more code.
Notice that within the head section are requests for additional files.
In HTML are links for the client to download CSS and JavaScript code for download from a server or CDN.
When JavaScript runs, it can manipulate that DOM (Document Object Model) that browsers build as the basis for what it shows to end-users.
-
To see the control handle, click the “Element” tab.
-
Mouse over the icon with the arrow into the box to “Select an element in the page to inspect it”.
But I prefer toggling using the keyboard shortcut command+shift+C.
-
Press that key if you don’t see different colors when you mouse over the control you want to automate.
-
When highlighted, press the return key on your keyboard to highlight the HTML responsible for displaying that element.
-
If the line’s arrow points to the right, click on it to expand its sub-levels.
CSS id
The ideal way to obtain a reliable handle is to use a CSS id, which are supposed to be unique on each page. An example of HTML code providing an id is:*
<input id="username" type="text" name="username"/>
Selenium code to reference the id is this:
WebElement txtUsername = driver.findElement(By.id("username")); txtUsername.sendKeys(username);
Typescript code for Flood is:
WebElement txtUsername = driver.findElement(By.id("username")); ??? txtUsername.sendKeys(username); ???
Alas, some developers do not code in that convenience. If the developer cannot be reached or doesn’t have time to add id’s, then we need to use alternative methods.
Sequence number for multiple elements
-
View HTML which does not provide an id.
???
To specify a handle for multiple possibles, specify an nth-child instance value such as this Typescript:
let linkHref = await browser.findElement(By.css('#content > ul > li:nth-child(6) > a'))
This can be a rather brittle specification because the nth-child number may change over time if another element is inserted.
XPath search
A more reliable (and elegant) object identification string is using xpath:
let selIssueType = await browser.findElement(By.xpath("//input[contains(@id, 'issuetype-field')]"))
The usage of the
contains
method cuts down on the use of long and complex strings while targeting the specific nested object we want to interact with. We simply use the object property (in this case theid
property) along with the property value.
Title Lookup
One of the features of the SAP Fiori main page (and other screens) is that the order (positioning) of tiles can be changed by the use. And additional tiles can be added. For this reason, a method is needed to ensure that changes to a particular tile targeted for testing will continue to be recognized even after repositioning. This example code makes use of an XPath command to search within “<dev” tags containing a particular text string titled:
let tileEmployeeLookup = By.xpath("//div[contains(@title, 'Employee Lookup')]")
In the above code, the variable tileEmployeeLookup would contains the title Employee Lookup since very tile has a title property this should make our script resistant to changes made on this screen.
This would not work if the text “Employee lookup” is in several locations (is not unique).
This also would not work if the text is changed in the code by developers.
partialVisibleText
-
We can also take advantage of the partialVisibleText method when identifying SAP objects - as follows:
let tileEmployeeLookup = By.partialVisibleText('Employee Lookup')
Walk down nested properties
The last-resort approach is to define multiple levels of <DIV> or <TABLE> tags such as:
let linkNewAccount = await browser.findElement(By.xpath('//*[@id="brandBand_1"]/div/div[1]/div[2]/div/div/div[1]/div[1]/div[2]/ul/li[1]/a'))
This usually causes the object identification string to be very long and virtually unreadable.
This can be brittle because any changes to the hierarchy of tags in the script will likely make the test script fail when run again.
SAP Fiori
Based on Jason’s https://docs.google.com/document/d/1w0UPPSBYLck4BDqtiBm1yGWYOS4DvIldng96ub-MWZg/edit