SlideShare a Scribd company logo
Selenide Alternative in Practice
Implementation & Lessons Learned
Preface…
Implementation & Lessons Learned
Selenide Alternative in Practice
Selenide
Selenide = ?
Selenide = Effective
web test automation tool
=
tool to automate
web UI tests logic
not browser
(it should be already
automated;)
Selenide = Effective
web test automation tool
=
tool to automate
web UI tests logic
not browser
concise API
…
…
…
Selenide = Effective
web test automation tool
=
tool to automate
web UI tests logic
not browser
concise API
waiting search
…
…
Selenide = Effective
web test automation tool
=
tool to automate
web UI tests logic
not browser
concise API
waiting search
waiting asserts
…
Selenide = Effective
web test automation tool
=
tool to automate
web UI tests logic
not browser
concise API
waiting search
waiting asserts
dynamic elements
Selenide = Effective
web test automation tool
=
tool to automate
web UI tests logic
not browser
concise API
waiting search
waiting asserts
dynamic elements
Selenide Alternative?
concise API
waiting search
waiting asserts
dynamic elements
Selenide Alternative?
concise API
waiting search
waiting asserts
dynamic elements
How should it work?
Selenide Alternative?
concise API
waiting search
waiting asserts
dynamic elements
How should it work? How to build?
With examples in
Proviso
Partial sacrificing
DRY, privatisation, etc.
for simplification of examples
Selenide Alternative in Practice - Implementation & Lessons learned [SeleniumCamp 2016]
Concise API
driver.find_element(By.XPATH, "//*[contains(text(),'task')]")

# vs


s(by_xpath("//*[contains(text(),'task')]"))

# vs


s(with_text('task'))
driver.find_element(By.XPATH, "//*[contains(text(),'task')]")

# vs


s(by_xpath("//*[contains(text(),'task')]"))

# vs


s(with_text('task'))
DRY locator helpers
driver.find_element(By.XPATH, "//*[contains(text(),'task')]")

# vs


s(by_xpath("//*[contains(text(),'task')]"))

# vs


s(with_text('task'))
driver.find_element(By.XPATH, "//*[contains(text(),'task')]")

# vs


s(by_xpath("//*[contains(text(),'task')]"))

# vs


s(with_text('task'))
OOP
driver.find_element(By.XPATH, "//*[contains(text(),'task')]")

# vs


s(by_xpath("//*[contains(text(),'task')]"))

# vs


s(with_text('task'))
from selenium import webdriver
driver = webdriver.Firefox()
# ... OOP
driver.find_element(By.XPATH, "//*[contains(text(),'task')]")

# vs


s(by_xpath("//*[contains(text(),'task')]"))

# vs


s(with_text('task'))
Modular
from selenium import webdriver
driver = webdriver.Firefox()
# ... OOP
driver.find_element(By.XPATH, "//*[contains(text(),'task')]")

# vs


s(by_xpath("//*[contains(text(),'task')]"))

# vs


s(with_text('task'))
Modular
from selenium import webdriver
driver = webdriver.Firefox()
# ...
from selene.tools import set_driver, s
set_driver(webdriver.Firefox())
# ...
OOP
driver.find_element(By.XPATH, "//*[contains(text(),'task')]")
# vs


s(by_xpath("//*[contains(text(),'task')]")).

# vs


s(with_text('task'))
Modular
OOP
from selenium import webdriver
driver = webdriver.Firefox()
driver.get(‘http://todomvc4tasj.herokuapp.com’)
from selene.tools import set_driver, s
set_driver(webdriver.Firefox())
visit(‘http://todomvc4tasj.herokuapp.com’)
driver.find_element(By.XPATH, "//*[contains(text(),'task')]")
# vs


s(by_xpath("//*[contains(text(),'task')]")).

# vs


s(with_text('task'))
Functions over Methods
for main actions
from selenium import webdriver
driver = webdriver.Firefox()
driver.get(‘http://todomvc4tasj.herokuapp.com’)
from selene.tools import set_driver, s
set_driver(webdriver.Firefox())
visit(‘http://todomvc4tasj.herokuapp.com’)
s(by_css(‘#new-todo’))
# vs/or

s('#new-todo')
Convenient defaults


driver.find_element_by_css_selector('#new-todo').clear()

driver.find_element_by_css_selector(‘#new-todo’)
.send_keys(‘task')


# vs


s(‘#new-todo’).clear().send_keys(‘task’)


driver.find_element_by_css_selector('#new-todo').clear()

driver.find_element_by_css_selector(‘#new-todo’)
.send_keys(‘task')


# vs


s(‘#new-todo’).clear().send_keys(‘task’)
Chainable methods


driver.find_element_by_css_selector('#new-todo')

.send_keys('task', Keys.ENTER)

# vs


s('#new-todo').send_keys('task').press_enter()


driver.find_element_by_css_selector('#new-todo')

.send_keys('task', Keys.ENTER)

# vs


s('#new-todo').send_keys('task').press_enter()
“Short-cut” methods
s(‘#new-todo’).clear().send_keys(‘task’)


# vs


s(‘#new-todo’).set(‘task’)
“Short-cut” methods
Built in Explicit Waits aka Waiting
Asserts
WebDriverWait(driver, 4).until(
element_to_be_clickable(by_css('#new-todo')))



# vs



s('#new-todo').should_be(clickable)


new_todo = by_css('#new-todo')



visit('http://todomvc4tasj.herokuapp.com')



s(new_todo).set('task 1').press_enter()

# ...

s(new_todo).set('task 2').press_enter()



# vs



new_todo = s('#new-todo')



visit('http://todomvc4tasj.herokuapp.com')



new_todo.set('task 1').press_enter()

# ...

new_todo.set('task 2').press_enter()


new_todo = by_css('#new-todo')



visit('http://todomvc4tasj.herokuapp.com')



s(new_todo).set('task 1').press_enter()

# ...

s(new_todo).set('task 2').press_enter()



# vs



new_todo = s('#new-todo')



visit('http://todomvc4tasj.herokuapp.com')



new_todo.set('task 1').press_enter()

# ...

new_todo.set('task 2').press_enter()


new_todo = by_css('#new-todo')



visit('http://todomvc4tasj.herokuapp.com')



s(new_todo).set('task 1').press_enter()

# ...

s(new_todo).set('task 2').press_enter()



# vs



new_todo = s('#new-todo')



visit('http://todomvc4tasj.herokuapp.com')



new_todo.set('task 1').press_enter()

# ...

new_todo.set('task 2').press_enter()
?
Dynamic Elements
Dynamic Elements
aka Lazy Proxy Elements
new_todo = s('#new-todo')
def s(css_selector_or_locator):

return SElement(css_selector_or_locator)
Element Factory
class SElement(...):

def __init__(self, css_selector_or_locator, context=...):

self.locator = parse(css_selector_or_locator)
# ...



def finder(self):

return self.context.find_element(*self.locator)
def assure(self, condition):

wait_for(self, condition, timeout)

return self
def do(self, command):

self.assure(visible)

command(self.finder())
return self


def click(self):

return self.do(lambda element: element.click())
class SElement(...):

def __init__(self, css_selector_or_locator, context=...):

self.locator = parse(css_selector_or_locator)
# ...



def finder(self):

return self.context.find_element(*self.locator)
def assure(self, condition):

wait_for(self, condition, timeout)

return self
def do(self, command):

self.assure(visible)

command(self.finder())
return self


def click(self):

return self.do(lambda element: element.click())
class SElement(...):

def __init__(self, css_selector_or_locator, context=...):

self.locator = parse(css_selector_or_locator)
# ...



def finder(self):

return self.context.find_element(*self.locator)
def assure(self, condition):

wait_for(self, condition, timeout)

return self
def do(self, command):

self.assure(visible)

command(self.finder())
return self


def click(self):

return self.do(lambda element: element.click())
class SElement(...):

def __init__(self, css_selector_or_locator, context=...):

self.locator = parse(css_selector_or_locator)
# ...



def finder(self):

return self.context.find_element(*self.locator)
def assure(self, condition):

wait_for(self, condition, timeout)

return self
def do(self, command):

self.assure(visible)

command(self.finder())
return self


def click(self):

return self.do(lambda element: element.click())
class SElement(...):

def __init__(self, css_selector_or_locator, context=...):

self.locator = parse(css_selector_or_locator)
# ...



def finder(self):

return self.context.find_element(*self.locator)
def assure(self, condition):

wait_for(self, condition, config.timeout)

return self
def do(self, command):

self.assure(visible)

command(self.finder())
return self


def click(self):

return self.do(lambda element: element.click())
class SElement(...):

def __init__(self, css_selector_or_locator, context=...):

self.locator = parse(css_selector_or_locator)
# ...



def finder(self):

return self.context.find_element(*self.locator)
def assure(self, condition):

wait_for(self, condition, config.timeout)

return self
def do(self, command):

self.assure(visible)

command(self.finder())
return self


def click(self):

return self.do(lambda element: element.click())
“waiting search”
class SElement(...):

def __init__(self, css_selector_or_locator, context=...):

self.locator = parse(css_selector_or_locator)
# ...



def finder(self):

return self.context.find_element(*self.locator)
def assure(self, condition):

wait_for(self, condition, config.timeout)

return self
def do(self, command):

self.assure(visible)

command(self.finder())
return self


def click(self):

return self.do(lambda element: element.click())
“waiting assert”


def wait_for(entity, condition, timeout):

# ...



end_time = time.time() + timeout

while True:

try:

value = condition(entity)

if value is not None:

return value

except (WebDriverException,) as exc:

# ...

time.sleep(config.poll_during_waits)

if time.time() > end_time:

break

raise TimeoutException(

"""

failed while waiting %s seconds

to assert %s%s

""" % (timeout, condition.__class__.__name__,
str(condition), ...)


def wait_for(entity, condition, timeout):

# ...



end_time = time.time() + timeout

while True:

try:

value = condition(entity)

if value is not None:

return value

except (WebDriverException,) as exc:

# ...

time.sleep(config.poll_during_waits)

if time.time() > end_time:

break

raise TimeoutException(

"""

failed while waiting %s seconds

to assert %s%s

""" % (timeout, condition.__class__.__name__,
str(condition), ...)


def wait_for(entity, condition, timeout):

# ...



end_time = time.time() + timeout

while True:

try:

value = condition(entity)

if value is not None:

return value

except (WebDriverException,) as exc:

# ...

time.sleep(config.poll_during_waits)

if time.time() > end_time:

break

raise TimeoutException(

"""

failed while waiting %s seconds

to assert %s%s

""" % (timeout, method.__class__.__name__,
str(condition), ...)


def wait_for(entity, condition, timeout):

# ...



end_time = time.time() + timeout

while True:

try:

value = condition(entity)

if value is not None:

return value

except (WebDriverException,) as exc:

# ...

time.sleep(config.poll_during_waits)

if time.time() > end_time:

break

raise TimeoutException(

"""

failed while waiting %s seconds

to assert %s%s

""" % (timeout, method.__class__.__name__,
str(condition), ...)
class Visible(object):



def __call__(self, selement):
self.selement = selement

found = selement.finder()

return found if found.is_displayed() else None



def __str__(self):

return """

for element found by: %s...

""" % (self.selement.locator, …)


visible = Visible()
class Visible(object):



def __call__(self, selement):
self.selement = selement

found = selement.finder()

return found if found.is_displayed() else None



def __str__(self):

return """

for element found by: %s...

""" % (self.selement.locator, …)


visible = Visible()
class Visible(object):



def __call__(self, webelement):
self.selement = selement

found = selement.finder()

return webelement.is_displayed()



def __str__(self):

return """

for element found by: %s...

""" % (self.selement.locator, …)


visible = Visible()
Original jSelenide style
with selement.finder() being moved to wait_for
class Visible(object):



def __call__(self, webelement):
self.selement = selement

found = selement.finder()

return webelement.is_displayed()



def __str__(self):

return """

for element found by: %s...

""" % (self.selement.locator, …)


visible = Visible()
Original jSelenide style
with selement.finder() being moved to wait_for
more simple

and secure

but 

less powerful
class SElement(...):

def __init__(self, css_selector_or_locator, context=...):

self.locator = parse(css_selector_or_locator)
# ...



def finder(self):

return self.context.find_element(*self.locator)
def assure(self, condition):

wait_for(self, condition, config.timeout)

return self
def do(self, command):

self.assure(visible)

command(self.finder())
return self


def click(self):

return self.do(lambda element: element.click())
class SElement(...):

def __init__(self, css_selector_or_locator, context=...):

self.locator = parse(css_selector_or_locator)
# ...



def finder(self):

return self.context.find_element(*self.locator)
def assure(self, condition):

wait_for(self, condition, config.timeout)

return self


insist = assure

should = assure

should_be = assure

should_have = assure

def click(self):

return self.do(lambda element: element.click())
Speed?
class SElement(...):

def __init__(self, css_selector_or_locator, context=...):

self.locator = parse(css_selector_or_locator)
# ...



def finder(self):

return self.context.find_element(*self.locator)
def assure(self, condition):

wait_for(self, condition, config.timeout)

return self
def do(self, command):

self.assure(visible)

command(self.finder())
return self


def click(self):

return self.do(lambda element: element.click())
redundant finder call


def finder(self):

return self.context.find_element(*self.locator)
def refind(self):

self.found = self.finder()

return self.found
def assure(self, condition):

self.found = wait_for(self, condition, config.timeout)

return self
def do(self, command):

self.assure(visible)

command()

return self


def click(self):

return self.do(lambda: self.found.click())
reusing self.found


def finder(self):

return self.context.find_element(*self.locator)
def refind(self):

self.found = self.finder()

return self.found
def assure(self, condition):

self.found = wait_for(self, condition, config.timeout)

return self
def do(self, command):

self.assure(visible)

command()

return self


def click(self):

return self.do(lambda: self.found.click())
even when not needed
wait always
def refind(self):

self.found = self.finder()

return self.found
def assure(self, condition):

self.found = wait_for(self, condition, config.timeout)

return self
def do(self, command):

try:

self.refind()

command()

except (WebDriverException):

self.assure(visible)

command()

return self


def click(self):

return self.do(lambda: self.found.click())
smarter:)
def refind(self):

self.found = self.finder()

return self.found
def assure(self, condition):

self.found = wait_for(self, condition, config.timeout)

return self
def do(self, command):

try:

self.refind()

command()

except (WebDriverException):

self.assure(visible)

command()

return self


def click(self):

return self.do(lambda: self.found.click())
smarter:)
Makes Selene as fast
as Selenium “with research” :)
def refind(self):

self.found = self.finder()

return self.found
def assure(self, condition):

self.found = wait_for(self, condition, config.timeout)

return self
def do(self, command):

try:

self.refind()

command()

except (WebDriverException):

self.assure(visible)

command()

return self


def click(self):

return self.do(lambda: self.found.click())
def refind(self):

self.found = self.finder()

return self.found
def assure(self, condition):

self.found = wait_for(self, condition, config.timeout)

return self
def do(self, command):

try:

self.refind()

command()

except (WebDriverException):

self.assure(visible)

command()

return self


def click(self):

return self.do(lambda: self.found.click())
What if I sometimes…

I want “raw selenium” speed?


def cash(self):

self.is_cached = True

self.finder = lambda: self.found

return self
f
def do(self, command):

try:
if not self.is_cached:

self.refind()

command()

# ...

self.assure(visible)

command()

return self


def click(self):

return self.do(lambda: self.found.click())
Introducing simple cashing


def cash(self):

self.is_cached = True

self.finder = lambda: self.found

return self
f
def do(self, command):

try:
if not self.is_cached:

self.refind()

command()

# ...

self.assure(visible)

command()

return self


def click(self):

return self.do(lambda: self.found.click())
Introducing simple cashing
Making Selene almost as fast
as raw Selenium :)
Proof Demo
Total Laziness
todo_list = s('#todo-list')


active_tasks = todo_list.find_all(‘.active’)


first_completed_task = todo_list.find(‘.completed')



visit('http://todomvc4tasj.herokuapp.com')

# ...
Usage
tasks = ss(‘#todo-list>li')


first_task = tasks.get(1)


task_a = tasks.find(exact_text(“a"))


visible_tasks = tasks.filter(visible)



visit('http://todomvc4tasj.herokuapp.com')

# ...
Usage
visible_tasks = ss(‘#todo-list>li').filter(visible)



visit('http://todomvc4tasj.herokuapp.com')

# ...
def ss(css_selector_or_locator):

return SElementsCollection(css_selector_or_locator)
class SElementsCollection(...):

def __init__(self, css_selector_or_locator, ..., ...,):

self.locator = parse(css_selector_or_locator)

...



def finder(self):

return ...



def filter(self, condition):

return ...
...
class SElementsCollection(...):

def __init__(self, css_selector_or_locator, ..., ...,):

self.locator = parse(css_selector_or_locator)

...



def finder(self):

return ...



def filter(self, condition):

return ...
...
locator = lambda index: '%s[%s]' % (self.locator, index)

webelements = self.context.find_elements(*self.locator)

return [SElement(locator(index)).cash_with(element)

for index, element in enumerate(webelements)]
SElementsCollection#finder
locator = lambda index: '%s[%s]' % (self.locator, index)

webelements = self.context.find_elements(*self.locator)

return [SElement(locator(index)).cash_with(element)

for index, element in enumerate(webelements)]
SElementsCollection#finder
locator = lambda index: '%s[%s]' % (self.locator, index)

webelements = self.context.find_elements(*self.locator)

return [SElement(locator(index)).cash_with(element)

for index, element in enumerate(webelements)]
SElementsCollection#finder
class SElementsCollection(...):

def __init__(self, css_selector_or_locator, ..., ...,):

self.locator = parse(css_selector_or_locator)

...



def finder(self):

return ...



def filter(self, condition):

return FilteredSElementsCollection(self, condition)
...
class FilteredSElementsCollection(SElementsCollection):

def __init__(self, selements_collection, condition):

self.coll = selements_collection

self.condition = condition

# ...



def finder(self):

filtered_elements = ...

return filtered_elements
class FilteredSElementsCollection(SElementsCollection):

def __init__(self, selements_collection, condition):

self.coll = selements_collection

self.condition = condition

# ...



def finder(self):

filtered_elements = ...

return filtered_elements
class FilteredSElementsCollection(SElementsCollection):

def __init__(self, selements_collection, condition):

self.coll = selements_collection

self.condition = condition

# ...



def finder(self):

filtered_elements = ...

return filtered_elements
self.coll = selements_collection

self.condition = condition

locator = "(%s).filter(%s)" % (

self.coll.locator,

self.condition.__class__.__name__)

SElementsCollection.__init__(self, ('selene', locator))

# ...
FilteredSElementsCollection#__init__
self.coll = selements_collection

self.condition = condition

locator = "(%s).filter(%s)" % (

self.coll.locator,

self.condition.__class__.__name__)

SElementsCollection.__init__(self, ('selene', locator))

# ...
FilteredSElementsCollection#__init__
filtered_elements = [selement for selement in self.coll

if self.condition(selement)]


return filtered_elements
FilteredSElementsCollection#finder
Meta-programming?
class SElement(...):

def __init__(self, ..., context=...):
# …
def finder(self):

return self.context.find_element(*self.locator)
# ...



class SElementsCollection(...):

def __init__(self, ..., context=..., selement_class=…):
# ...

# ...
def __init__(self, ..., context=RootSElement()):
class RootSElement(object):

def __getattr__(self, item):

return getattr(selene.tools.get_driver(), item)
The most innocent example :)
def __getattr__(self, item):

return self.do(lambda: getattr(self.found, item))
# VS
def click(self):

return self.do(lambda: self.found.click())



def submit(self):

return self.do(lambda: self.found.submit())



def clear(self):

return self.do(lambda: self.found.clear())
...
Proxying vs Overriding
def __getattr__(self, item):

return self.do(lambda: getattr(self.found, item))
# VS
def click(self):

return self.do(lambda: self.found.click())



def submit(self):

return self.do(lambda: self.found.submit())



def clear(self):

return self.do(lambda: self.found.clear())
...
Proxying vs Overriding
Widgets
class Task(SElement):

def delete(self):

self.hover()

self.s(".destroy").click()





def test_custom_selement():

given_active("a", "b")

Task("#todo-list>li:nth-child(1)").delete()
Just works :)
class Task(SElement):

def delete(self):

self.hover()

self.s(".destroy").click()





def test_custom_selement():

given_active("a", "b")

Task("#todo-list>li:nth-child(1)").delete()
Just works :)
Because…
class SElement(...):

def __init__(self, ..., context=RootSElement()):

#...

def finder(self):

return self.context.find_element(*self.locator)



def s(self, css_selector_or_locator):

return SElement(css_selector_or_locator, context=self)
#...
Because…
class SElement(...):

def __init__(self, ..., context=RootSElement()):

#...

def finder(self):

return self.context.find_element(*self.locator)



def s(self, css_selector_or_locator):

return SElement(css_selector_or_locator, context=self)
#...
Collection of widgets
class Task(SElement):

def delete(self):

self.hover()

self.s(".destroy").click()



def test_selements_collection_of_custom_selements():

given_active("a", "b", "c")

for task in ss("#todo-list>li", of=Task):
task.delete()
ss("#todo-list>li", of=Task).should_be(empty)
Collection of widgets
class Task(SElement):

def delete(self):

self.hover()

self.s(".destroy").click()



def test_selements_collection_of_custom_selements():

given_active("a", "b", "c")

for task in ss("#todo-list>li", of=Task):
task.delete()
ss("#todo-list>li", of=Task).should_be(empty)
class SElementsCollection(...):


def __init__(self, ..., ...):

...

...

...



def finder(self):
...

return [
SElement(locator(index)).cash_with(element)

for index, element in enumerate(webelements)]

...
recalling basic implementation…
class SElementsCollection(...):


def __init__(self, ..., ..., of=SElement):

...

self.wrapper_class = of

...



def finder(self):
...

return [
self.wrapper_class(locator(index)).cash_with(element)

for index, element in enumerate(webelements)]

...
needs more…
and sometimes even much more…
including meta-programming…
Collection of widgets:
selection of one of them
visible_tasks = ss("#todo-list>li", of=Task).filter(visible)
...
...

task = visible_tasks.find(exact_text("a")):
task.delete()
...
class SElementsCollectionElementByCondition(SElement):

def __init__(self, selements_collection, condition):

self.coll = selements_collection

self.condition = condition

locator = "(%s).found_by(%s)" % (

self.coll.locator,

self.condition.__class__.__name__)

...



def finder(self):

for selement in self.coll:

if self.condition(selement):

return selement.found
find(exact_text("a")) =>
self.coll = selements_collection

self.condition = condition

locator = "(%s).found_by(%s)" % (

self.coll.locator,

self.condition.__class__.__name__)

SElementsCollectionElementByCondition.__init__(self,
(“selene”, locator))

...
SElementsCollectionElementByCondition#__init__
self.coll = selements_collection

self.condition = condition

locator = "(%s).found_by(%s)" % (

self.coll.locator,

self.condition.__class__.__name__)

SElementsCollectionElementByCondition.__init__(self,
(“selene”, locator))

extend(self, self.coll.wrapper_class, ("selene", locator))
SElementsCollectionElementByCondition#__init__
def extend(obj, cls, *init_args, **init_kwargs):

obj.__class__ = type(obj.__class__.__name__,
(obj.__class__, cls),
{})

cls.__init__(obj, *init_args, **init_kwargs)
Dynamic class extension
def extend(obj, cls, *init_args, **init_kwargs):

obj.__class__ = type(obj.__class__.__name__,
(obj.__class__, cls),
{})

cls.__init__(obj, *init_args, **init_kwargs)
Dynamic class extension
def extend(obj, cls, *init_args, **init_kwargs):

obj.__class__ = type(obj.__class__.__name__,
(obj.__class__, cls),
{})

cls.__init__(obj, *init_args, **init_kwargs)
Dynamic class extension
e.g. to initialise probable widget’s subelements
class Task(SElement):

def init(self):

self.destroy_button = self.s(".destroy")

...



...

task = ss("#todo-list>li", of=Task).find(text("a")):
task.hover()
task.destroy_button.click()
...
like in this example ;)
__init__ vs init ? o_O
class SElement(...):

def __init__(self):
...

if hasattr(self, 'init'):

self.init()
__init__ vs init ? o_O
Proxying vs dynamic extension
SElement(...)
def __getattr__(self, item):

return self.do(lambda: getattr(self.found, item))
SElementsCollectionElementByCondition(SElement)
__init__
extend(self, self.coll.wrapper_class, ('selene', locator))
# VS
SElement(...)
def __getattr__(self, item):

return self.do(lambda: getattr(self.found, item))
SElementsCollectionElementByCondition(SElement)
__init__
extend(self, self.coll.wrapper_class, ('selene', locator))
Install & Docs
$ pip install selene
https://github.com/yashaka/selene
visit(‘/questions_and_answers')


s('#question').set('<YOUR QUESTION>’).press_enter()


ss('.answer').should_not_be(empty)
github.com/yashaka
github.com/yashaka/selene
yashaka@gmail.com
@yashaka
Thank You

More Related Content

What's hot (20)

PDF
Webdriver cheatsheets summary
Alan Richardson
 
PDF
Test automation & Seleniun by oren rubin
Oren Rubin
 
PDF
KISS Automation.py
Iakiv Kramarenko
 
PDF
Nightwatch at Tilt
Dave King
 
PDF
ForwardJS 2017 - Fullstack end-to-end Test Automation with node.js
Mek Srunyu Stittri
 
PDF
20160905 - BrisJS - nightwatch testing
Vladimir Roudakov
 
PDF
Hands on Exploration of Page Objects and Abstraction Layers with Selenium Web...
Alan Richardson
 
PDF
Introduction to Selenium and Ruby
Ynon Perek
 
PPT
Testing in AngularJS
Peter Drinnan
 
PDF
Join the darkside: Selenium testing with Nightwatch.js
Seth McLaughlin
 
PDF
Carmen Popoviciu - Protractor styleguide | Codemotion Milan 2015
Codemotion
 
PDF
Night Watch with QA
Carsten Sandtner
 
PPTX
Selenium withnet
Vlad Maniak
 
PPTX
Protractor Training in Pune by QuickITDotnet
QuickITDotNet Training and Services
 
PDF
Introduction to Protractor
Jie-Wei Wu
 
PDF
Automation Abstraction Layers: Page Objects and Beyond
Alan Richardson
 
PDF
Automation Abstractions: Page Objects and Beyond
TechWell
 
PDF
Lets make a better react form
Yao Nien Chung
 
PDF
Automated Testing with Ruby
Keith Pitty
 
PDF
Enhance react app with patterns - part 1: higher order component
Yao Nien Chung
 
Webdriver cheatsheets summary
Alan Richardson
 
Test automation & Seleniun by oren rubin
Oren Rubin
 
KISS Automation.py
Iakiv Kramarenko
 
Nightwatch at Tilt
Dave King
 
ForwardJS 2017 - Fullstack end-to-end Test Automation with node.js
Mek Srunyu Stittri
 
20160905 - BrisJS - nightwatch testing
Vladimir Roudakov
 
Hands on Exploration of Page Objects and Abstraction Layers with Selenium Web...
Alan Richardson
 
Introduction to Selenium and Ruby
Ynon Perek
 
Testing in AngularJS
Peter Drinnan
 
Join the darkside: Selenium testing with Nightwatch.js
Seth McLaughlin
 
Carmen Popoviciu - Protractor styleguide | Codemotion Milan 2015
Codemotion
 
Night Watch with QA
Carsten Sandtner
 
Selenium withnet
Vlad Maniak
 
Protractor Training in Pune by QuickITDotnet
QuickITDotNet Training and Services
 
Introduction to Protractor
Jie-Wei Wu
 
Automation Abstraction Layers: Page Objects and Beyond
Alan Richardson
 
Automation Abstractions: Page Objects and Beyond
TechWell
 
Lets make a better react form
Yao Nien Chung
 
Automated Testing with Ruby
Keith Pitty
 
Enhance react app with patterns - part 1: higher order component
Yao Nien Chung
 

Viewers also liked (11)

PPT
Page object with selenide
COMAQA.BY
 
PDF
You do not need automation engineer - Sqa Days - 2015 - EN
Iakiv Kramarenko
 
PPTX
Automation is Easy! (python version)
Iakiv Kramarenko
 
PDF
How To Use Selenium Successfully (Java Edition)
Dave Haeffner
 
PDF
Selenium Tips & Tricks
Dave Haeffner
 
PDF
Selenium documentation,
t7t7uyt
 
PPTX
Selenium web driver
Roman Savitskiy
 
PPT
Selenium
Kalyan ch
 
PDF
Allure Framework
Artem Eroshenko
 
PDF
Better Page Object Handling with Loadable Component Pattern
Sargis Sargsyan
 
PPTX
Teaching Automation. How big companies do it.
Vitali Shulha
 
Page object with selenide
COMAQA.BY
 
You do not need automation engineer - Sqa Days - 2015 - EN
Iakiv Kramarenko
 
Automation is Easy! (python version)
Iakiv Kramarenko
 
How To Use Selenium Successfully (Java Edition)
Dave Haeffner
 
Selenium Tips & Tricks
Dave Haeffner
 
Selenium documentation,
t7t7uyt
 
Selenium web driver
Roman Savitskiy
 
Selenium
Kalyan ch
 
Allure Framework
Artem Eroshenko
 
Better Page Object Handling with Loadable Component Pattern
Sargis Sargsyan
 
Teaching Automation. How big companies do it.
Vitali Shulha
 
Ad

Similar to Selenide Alternative in Practice - Implementation & Lessons learned [SeleniumCamp 2016] (20)

PPT
Selenium Concepts
Swati Bansal
 
PDF
Tellurium At Rich Web Experience2009
John.Jian.Fang
 
PPTX
Web UI Tests: Introduce UI tests using Selenium
Peyman Fakharian
 
PDF
Selenium RC: Automated Testing of Modern Web Applications
qooxdoo
 
PPTX
Test automation with selenide
Isuru Madanayaka
 
PPTX
Selenium training
Suresh Arora
 
ODP
Integrating Selenium testing infrastructure into Scala Project
Knoldus Inc.
 
PDF
Basics of Selenium IDE,Core, Remote Control
usha kannappan
 
PPTX
تست وب اپ ها با سلنیوم - علیرضا عظیم زاده میلانی
irpycon
 
PPT
Intro Of Selenium
Kai Feng Zhang
 
PDF
2010 za con_jurgens_van_der_merwe
Johan Klerk
 
PPT
Selenium Primer
gueste1e4db
 
PDF
QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"
GeeksLab Odessa
 
PPT
Selenium
Ruturaj Doshi
 
PPTX
Presentation on Introduction to Selenium
hafizrizwanumar10
 
KEY
Graceful Failure with Selenium and Continuous Integration
Chris B. France
 
PDF
Selenium
g2ix
 
PPTX
Escape from the automation hell
Nikita Simonovets
 
PPTX
Selenium
Jahan Murugassan
 
PPTX
Introduction to selenium
Archana Krushnan
 
Selenium Concepts
Swati Bansal
 
Tellurium At Rich Web Experience2009
John.Jian.Fang
 
Web UI Tests: Introduce UI tests using Selenium
Peyman Fakharian
 
Selenium RC: Automated Testing of Modern Web Applications
qooxdoo
 
Test automation with selenide
Isuru Madanayaka
 
Selenium training
Suresh Arora
 
Integrating Selenium testing infrastructure into Scala Project
Knoldus Inc.
 
Basics of Selenium IDE,Core, Remote Control
usha kannappan
 
تست وب اپ ها با سلنیوم - علیرضا عظیم زاده میلانی
irpycon
 
Intro Of Selenium
Kai Feng Zhang
 
2010 za con_jurgens_van_der_merwe
Johan Klerk
 
Selenium Primer
gueste1e4db
 
QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"
GeeksLab Odessa
 
Selenium
Ruturaj Doshi
 
Presentation on Introduction to Selenium
hafizrizwanumar10
 
Graceful Failure with Selenium and Continuous Integration
Chris B. France
 
Selenium
g2ix
 
Escape from the automation hell
Nikita Simonovets
 
Introduction to selenium
Archana Krushnan
 
Ad

Recently uploaded (20)

PDF
NLJUG Speaker academy 2025 - first session
Bert Jan Schrijver
 
PDF
“Computer Vision at Sea: Automated Fish Tracking for Sustainable Fishing,” a ...
Edge AI and Vision Alliance
 
PDF
Future-Proof or Fall Behind? 10 Tech Trends You Can’t Afford to Ignore in 2025
DIGITALCONFEX
 
PPTX
Agentforce World Tour Toronto '25 - Supercharge MuleSoft Development with Mod...
Alexandra N. Martinez
 
PDF
Bitcoin for Millennials podcast with Bram, Power Laws of Bitcoin
Stephen Perrenod
 
PPT
Ericsson LTE presentation SEMINAR 2010.ppt
npat3
 
PDF
POV_ Why Enterprises Need to Find Value in ZERO.pdf
darshakparmar
 
PDF
“NPU IP Hardware Shaped Through Software and Use-case Analysis,” a Presentati...
Edge AI and Vision Alliance
 
PDF
Kit-Works Team Study_20250627_한달만에만든사내서비스키링(양다윗).pdf
Wonjun Hwang
 
PDF
UPDF - AI PDF Editor & Converter Key Features
DealFuel
 
PDF
Reverse Engineering of Security Products: Developing an Advanced Microsoft De...
nwbxhhcyjv
 
PDF
Transforming Utility Networks: Large-scale Data Migrations with FME
Safe Software
 
PDF
Go Concurrency Real-World Patterns, Pitfalls, and Playground Battles.pdf
Emily Achieng
 
PDF
What’s my job again? Slides from Mark Simos talk at 2025 Tampa BSides
Mark Simos
 
PPTX
Mastering ODC + Okta Configuration - Chennai OSUG
HathiMaryA
 
PPTX
New ThousandEyes Product Innovations: Cisco Live June 2025
ThousandEyes
 
PPTX
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
PPTX
Designing_the_Future_AI_Driven_Product_Experiences_Across_Devices.pptx
presentifyai
 
PDF
AI Agents in the Cloud: The Rise of Agentic Cloud Architecture
Lilly Gracia
 
PDF
SIZING YOUR AIR CONDITIONER---A PRACTICAL GUIDE.pdf
Muhammad Rizwan Akram
 
NLJUG Speaker academy 2025 - first session
Bert Jan Schrijver
 
“Computer Vision at Sea: Automated Fish Tracking for Sustainable Fishing,” a ...
Edge AI and Vision Alliance
 
Future-Proof or Fall Behind? 10 Tech Trends You Can’t Afford to Ignore in 2025
DIGITALCONFEX
 
Agentforce World Tour Toronto '25 - Supercharge MuleSoft Development with Mod...
Alexandra N. Martinez
 
Bitcoin for Millennials podcast with Bram, Power Laws of Bitcoin
Stephen Perrenod
 
Ericsson LTE presentation SEMINAR 2010.ppt
npat3
 
POV_ Why Enterprises Need to Find Value in ZERO.pdf
darshakparmar
 
“NPU IP Hardware Shaped Through Software and Use-case Analysis,” a Presentati...
Edge AI and Vision Alliance
 
Kit-Works Team Study_20250627_한달만에만든사내서비스키링(양다윗).pdf
Wonjun Hwang
 
UPDF - AI PDF Editor & Converter Key Features
DealFuel
 
Reverse Engineering of Security Products: Developing an Advanced Microsoft De...
nwbxhhcyjv
 
Transforming Utility Networks: Large-scale Data Migrations with FME
Safe Software
 
Go Concurrency Real-World Patterns, Pitfalls, and Playground Battles.pdf
Emily Achieng
 
What’s my job again? Slides from Mark Simos talk at 2025 Tampa BSides
Mark Simos
 
Mastering ODC + Okta Configuration - Chennai OSUG
HathiMaryA
 
New ThousandEyes Product Innovations: Cisco Live June 2025
ThousandEyes
 
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
Designing_the_Future_AI_Driven_Product_Experiences_Across_Devices.pptx
presentifyai
 
AI Agents in the Cloud: The Rise of Agentic Cloud Architecture
Lilly Gracia
 
SIZING YOUR AIR CONDITIONER---A PRACTICAL GUIDE.pdf
Muhammad Rizwan Akram
 

Selenide Alternative in Practice - Implementation & Lessons learned [SeleniumCamp 2016]