Sunday, July 6, 2014

Custom locators

In this article we'll talk about custom locators implementation. Well, I guess some of you would probably ask - why do we need to reinvent the wheel, if it already exists in a form of FindBy annotation + WebElement bunch or just By class?

Let's start with some basics. I prefer using By class, as it's more flexible. But readability and bulkiness of the following construction:


- cries 'refactor me', unlike FindBy + WebElement bunch, which is pretty laconic and straightforward. So the first reason of such customization was aspiration of decoration to increase readability and code understanding.

Let's assume we've decorated our locator. What other advantages could this technique give us? Well, now we can solve a problem of creating locators on fly (dynamic locators). Actually, there's no problem, but for me it's quite strange to create locators dynamically within PageObjects' methods. Such 'no name' elements are dropped from a real page model. Yes, someone can say that in such case we need to use PageElement pattern, but it doesn't make sense, when we use only common page controls.

Saving space. Let's assume that we have lots of identical elements without unique attributes, which require quick access for any kind of interaction, e.g. getText or click. We can create dozen of locators, which differ only by index or text or just use 'no name' dynamic locator within PageObject's method. In first case our PageObject will swell and become hard to read. And of course it's a moveton to use indexes or text inside locators, as it wouldn't be possible to support them. Second case's disadvantage was described earlier.

Passing custom parameters. Custom locators gives us an opportunity to pass custom parameters to any decorated element. As you may know, we can't do this via pure Selenium annotations or By class.

Now let's look at implementation. We would annotate all the elements with HTML annotation:


Let's decorate By class:


This wrapper implements updateElement method, which allows us to create locators on fly. We'll see how it looks like in further PageObject's implementation.

Now we need to provide some way of custom locators' initialization. We can achieve this via java reflection within abstract page class:


And we shouldn't care which page has triggered elements' initialization. This mechanism supports chain inheritance, when we need to move through all child pages to their parent one.

Sample PageObject may look like the following:


As you can see, this example contains both static and dynamic locators, which are marked with special ? symbol within path. This symbol will be replaced with missing member (which is needed for elements' unique identification on a page) in runtime.

You can pull a full example from GitHub.

Tuesday, July 1, 2014

FirePath upgrade: saving locators in a java properties format

Nowadays there are lots of useful tools, that could help QA automation engineers in their routing. When we talk about web automation, one of the most important part is related to elements' locators preparation to create reliable page objects. I guess the most popular tool for elements' inspecting is FireBug with its FirePath addon. I like FirePath features, but it looks incomplete for me. It's really annoying to copy/paste every single element and always switch between IDE and browser. So it would be useful to have some feature to save locators with custom names in e.g. java properties format, without leaving browser's focus.

In this article I'll show you, how to upgrade FirePath by adding such feature.

To start developing Firefox extensions, first read XUL guide. It will help you to understand common structure of Firefox addons.

Let's checkout FirePath project from SVN repository. You can do it via any SVN client or directly from IDE. Next we need to create a new project from existing sources. Actually, Mozilla developers recommend to use Kommodo Edit tool, that supports XUL syntax. But for such small feature, it would be enough to use any IDE, that supports XML / JS syntax.

Mostly we would only need content/bindings.xml file. It contains FirePath UI components implementation. You know that generally we can find any locator by activating special inspecting button and clicking needed element on UI. Depending on selected menu item (XPath / CSS), FirePath will automatically populate text field with full / optimized locator. Let's assume that we want to set some name to found locator, and save it to file. So besides existing components we would also need 2 inputs (locator name / file path) and 1 button (save). Let's add labels first for our new components. All labels' entities are located in locale/en-US/FirePath.dtd.


Now let's create appropriate inputs / button in content/bindings.xml after menu (XPath / CSS) toolbaritem section.



As you see, syntax is pretty straightforward. I'll just pay attention to newly created Save button. It contains a special oncommand handler. It means that when we click this button, saveLocator method will be executed. Let's look at its implementation.


It's a simple JS code that reads a file by a given path and adds new / replaces existing locator by name. By default it uses java properties (key/value) format, but you can easily add your own one. Ideally, this part should be splitted into read / write methods, but as it's only example, it's up to you how to decorate it. locatorName, selector and filePath are simple properties to provide an easy access to textbox values.


To avoid custom fields validation, I've also added a new CSS class into skin/classic/FirePath.css to ignore default one for textbox items.



To build modified FirePath extension, just run ant command inside root folder. After that, you can install it from Firefox addons section. You can look at how it works by downloading and installing already modified extension. Or alternatively you can pull sources from GitHub.

Final FirePath panel view would be the following: