Extensible Selenium Framework
Extensible Selenium Framework
Extensible Selenium Framework
E t
Extensible
ibl F
Framework k
Around Selenium
Apple Chow
Santiago Etchebehere
Outline
• Our Challenges
g
• Our Design Decisions
• Framework Architecture
• Framework Features
• Our Experience
• Q&A
Our Challenges
• Frequent
q Requirement
q Changes
g
• Complex Web UI
• Multiple
p Projects
j to Test
• Limited Resources
• Browsers, Platforms
Design Decisions
• Simplicity
– Isolating application actions
– Utilities for filling forms
– Utilities for interacting with tables
– AJAX handling utilities
– Uniform way to access UI elements
• Flexibility
– Grouping
p g of test cases
– Custom place holders (configuration & data)
– Ability to support non-standard UI elements
Design Decisions
• Maintainability/Configurability
y g y
– Externalized configuration
– Reduce data duplication
• Data driven tests
– Execute same test against multiple datasets
– Randomly
R d l generate
t structured
t t dd data
t
Selected Tools
• Selenium RC (http://www.openqa.org/selenium/)
( p p q g )
– Locators
– WaitForCondition xpath://img[@alt=“Google”]
Name: q
– getEval DOM: document.f.q
• TestNG ((http://testng.org/doc/index.html)
p g g )
• Firebug
@Test(dataProvider =
"customerDataProvider")
public void test(String id,
id String name) {
...
}
Framework Architecture
Application
GUI Map Data Map
Configuration
Application-Specific Application-Specific
Uses
Client Test Class
Application Config
<appconfig>
<parameters>
<
<protocol>http</protocol>
t l>htt </ t l>
<host>www.google.com</host>
<port></port>
<pagesXml>googlesearch/uimap.xml</pagesXml>
<projectXml>googlesearch/datamap.xml</projectXml>
j tX l l h/d t l / j tX l
<browserType>FIREFOX</browserType>
<browserVersion>2.0</browserVersion>
<timeout>300000</timeout>
</parameters>
/
</appconfig>
UI Object
• UI Element Abstraction
• read/write interface
<page name="searchForm">
< i l
<uielements>
t >
<uiobject name="search.query" type="text">
<locator>q</locator>
</uiobject>
<uiobject name="search.button“ type="button">
<locator>btnG</locator>
</uiobject>
</uielements>
</page>
Common vs. Test-case Data
<category name="search">
<data name="defaultSearch">
<properties>
<prop name="search.query">United States</prop>
<prop name="search.button"/>
</properties>
</data>
</category> references and o
overrides
errides
<testcase id="googleSearch001">
<dataset name="searchSet001">
<dataref name="search001Query" ref="search.defaultSearch">
<prop name="search.query">Argentina</prop>
name="search query">Argentina</prop>
</dataref>
</dataset>
</testcase>
UI Object and Data Mapping
<page name="searchForm">
name= searchForm >
<uielements> <data name=“searchData">
<uiobject name="search.query" <properties>
type="text"> <prop name="search.query">
<locator>q</locator> United States</prop>
</uiobject> <prop
p p name="search.button"/>/
</properties>
<uiobject name="search.button" </data>
type="button”>
<locator>btnG</locator>
</ i bj t>
</uiobject>
</uielements>
</page>
…
seleniumHelper.fillForm(“searchForm”, “searchData”);
…
Application Client
• Clients (GoogleSearchClient)
• Tests: hierarchy (e.g. GoogleSearchTest)
BaseClient BaseTest
G
GoogleSearchClient
l S hCli t Uses G
GoogleSearchTest
l S hT t
... ...
public TableObject basicSearch(data); public void basicSearchTest(DataSet dataset){
assertNotEmpty(client.basicSearch(
public TableObject advancedSearch(data); dataSet.getDataObject("searchData"));
... ...
Advanced Features
<page name="iGoogle">
<page name="search">
<loaded-condition>
selenium.isElementPresent("q") &&
selenium.isElementPresent("btnG")
</loaded-condition>
…
100
…
seleniumHelper.waitForPageToLoad(“iGoogle.search”);
…
AJAX Handling (Reload Trigger)
<page name="searchResults">
<loaded-condition> ... </loaded-condition>
<uiobject name="nextLink" type="anchor" reloadTrigger="searchResults">
ocato //a[te t() e t ] / ocato
<locator>//a[text()='Next']</locator>
...
Custom UI Object
<uiobject name="elapsedTime"
type="SuggestTextBox">
gg
<locator>q</locator>
...
public
bli class
l BlurDecorator extends
t d UIObj
UIObjectDecorator
tD t {
...
public void write(String value) {
decoratedObject.write(value);
selenium.fireEvent(decoratedObject.getLocator(),"blur");
}
Table Object
...
TableObject questions = new TableObject("questionsTable");
Map<String, String> firstRow = questions.getRow(1);
String subject = questions.readCell(1,3);
questions writeCell(1 "subject");
questions.writeCell(1, subject );
...
Placeholders
• Configuration <appconfig>
...
<host>${sys.testHost}</host>
• UI Object <user>${env.USER_NAME}<user>
...
• Data </appconfig>
...
<locator>//div[@id='results']/span[${paginationResultNum}]</locator>
...
<data name=“userProfile">
<properties>
<
<prop name=“username“>user_${timestamp}</prop>
“ “> ${ti t }</ >
<prop name="name">${dataGenerator.string(10)}</prop>
<prop name="email">${dataGenerator.email}</prop>
<prop name="age">${dataGenerator.regex([1..9][0..9])}</prop>
</properties>
</data>
/
Automation Process
• UI Changes
Before After
L
Location:
ti Location:
• Custom UI Object
...
super.write(selectedOptions.toString());
}
...
Our Experience
@Test(dataProvider="searchDataProvider")
@Testcase(id="test_001")
void testSearch(DataSet set) {
TableObject resutls =
getClient().search(set.getDataObject("criteria"));
Our Team