This post could have been “Reliable Selenium locators” since this is always a point of interrest, but the topic is covered regularly and a google search will get you a good result easily. However some specific cases are not that widely discussed, as I discovered in my latest assignment.
The assignment is pretty straightforward, the system under test is migrating to a new front-end and the company grabs this opportunity to introduce an automated test strategy. I’m hired to do the actual set up of the automation framework. The new front-end is ExtJs based and for me it’s the first time automating an ExtJs application with Selenium.
After some research and getting to know the application I discovered that ExtJs re-generates unique id’s for all elements, so a simple WebDriverBy(id) will not suffice. Looking at the structure xpath’s will result in long, cluttered and leaning towards brittle. So I started some google adventures and what I found was not promising.
The top three results (skipping Sencha results) are motivators to not use Selenium as the automation tool for ExtJs applications, which is not going to fly with me since I believe in Selenium for browser applications.
I went to the root of the “problem” and ended up in the docs of ExtJs and found a little gem in there “Ext.ComponentQuery“. It is the internal component locator for ExtJs, it’s capable of finding components on the page and retrieving information, like the current id. Selenium is capable of running javascript, so I did a 1+1=2 and settled for the following locator strategy:
// Note, not production code, but shows the main idea. // Initialize a new object of type Button // Give it the unique ExtJs locator // Can be anything from name, value, structure $myButton = new Button("nextItemButton"); // Use click function of Button $myButton->click(); class Button { // Will hold the changable id to use by Selenium protected $seleniumLocator; public function __construct($extJsLocator) { $this->seleniumLocator = getLocator($extJsLocator); } // Execute the ComponentQuery to get the current id private function getLocator($loc) { return $driver->executeScript( "return Ext.ComponentQuery.query('button[$loc]')" ); } // Use the current id as selector in Selenium public function click() { $driver->findElement(WebDriverBy::id($this->seleniumLocator))->click(); } }