Skip to content

Commit

Permalink
Merge pull request #180 from ElSnoMan/negative-test-select-dropdown
Browse files Browse the repository at this point in the history
add .select_by_() methods and deprecate .select()
  • Loading branch information
ElSnoMan authored Apr 14, 2021
2 parents 80d5c60 + 10963e2 commit ba2fafc
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 112 deletions.
94 changes: 70 additions & 24 deletions pylenium/element.py
Original file line number Diff line number Diff line change
Expand Up @@ -972,31 +972,25 @@ def click(self, force=False):
return self.py

def deselect(self, value):
""" Deselects an `<option>` within a multi `<select>` element.
""" Deselects all `<option>` within a multi `<select>` element that match the given value.
Args:
value: The value or text content of the `<option>` to be deselected.
value: The value or text content of the `<option>` elements to be deselected.
Raises:
`ValueError` if this element is not a `<select>`
* `UnexpectedTagNameException` if this element is not a `<select>`
* `NoSuchElementException` if a matching `<option>` element is not found.
Returns:
The current instance of Pylenium so you can chain another command.
This dropdown element so you can chain another command.
"""
self.py.log.info(' [STEP] .deselect() - Deselect this element')
if self.webelement.tag_name != 'select':
raise ValueError(f'Can only perform Deselect on <select> elements. Tag name: {self.webelement.tag_name}')

self.py.log.info(' [STEP] .deselect() - Deselect options from a dropdown element')
select = Select(self.webelement)
if not select.is_multiple:
raise NotImplementedError('Deselect can only be performed on multi-select elements.')

try:
select.deselect_by_visible_text(value)
except NoSuchElementException:
select.deselect_by_value(value)
finally:
return self.py
return self

def double_click(self):
""" Double clicks the element.
Expand Down Expand Up @@ -1063,7 +1057,7 @@ def right_click(self):
return self.py

def select(self, value) -> 'Element':
""" Selects an `<option>` within a `<select>` element.
""" DEPRECATED: Selects an `<option>` within a `<select>` element.
Args:
value: The value, text content or index of the `<option>` to be selected.
Expand All @@ -1074,6 +1068,8 @@ def select(self, value) -> 'Element':
Returns:
This element so you can chain another command if needed.
"""
self.py.log.warning(
'DEPRECATED: This method will be removed in a future release. Please use .select_by_*() instead.')
self.py.log.info(' [STEP] .select() - Select an option in this element')
if self.webelement.tag_name != 'select':
raise ValueError(
Expand All @@ -1087,8 +1083,64 @@ def select(self, value) -> 'Element':
finally:
return self

def select_by_index(self, index: int) -> 'Element':
""" Select an `<option>` element within a `<select>` dropdown given its index.
This is not done by counting the options, but by examining their index attributes.
Args:
index: The index position of the `<option>` to be selected.
Raises:
* `UnexpectedTagNameException` if the dropdown is not a `<select>` element.
* `NoSuchElementException` if the `<option>` with the given index doesn't exist.
Returns:
The dropdown element so you can chain another command if needed.
"""
self.py.log.info(' [STEP] .select_by_index() - Select an <option> element in this dropdown')
dropdown = Select(self.webelement)
dropdown.select_by_index(index)
return self

def select_by_text(self, text: str) -> 'Element':
""" Selects all `<option>` elements within a `<select>` dropdown given the option's text.
Args:
text: The text within the `<option>` to be selected.
Raises:
* `UnexpectedTagNameException` if the dropdown is not a `<select>` element.
* `NoSuchElementException` if the `<option>` with the given text doesn't exist.
Returns:
The dropdown element so you can chain another command if needed.
"""
self.py.log.info(' [STEP] .select_by_text() - Select all <option> elements in this dropdown')
dropdown = Select(self.webelement)
dropdown.select_by_visible_text(text)
return self

def select_by_value(self, value) -> 'Element':
""" Selects all `<option>` elements within a `<select>` dropdown given the option's value.
Args:
value: The value within the `<option>` to be selected.
Raises:
* `UnexpectedTagNameException` if the dropdown is not a `<select>` element.
* `NoSuchElementException` if the `<option>` with the given value doesn't exist.
Returns:
The dropdown element so you can chain another command if needed.
"""
self.py.log.info(' [STEP] .select_by_value() - Select all <option> elements in this dropdown')
dropdown = Select(self.webelement)
dropdown.select_by_value(value)
return self

def select_many(self, values: list):
""" Selects multiple `<options>` within a `<select>` element.
""" DEPRECATED: Selects multiple `<options>` within a `<select>` element.
Args:
values: The list of values or text contents of the `<option>` to be selected.
Expand All @@ -1099,23 +1151,17 @@ def select_many(self, values: list):
Returns:
The current instance of Pylenium so you can chain another command.
"""
self.py.log.warning(
'DEPRECATED: This method will be removed in a future release. Please use .select_by_*() instead.')
self.py.log.info(' [STEP] .select_many() - Select many options in this element')
if self.webelement.tag_name != 'select':
raise ValueError(
f'Can only perform Select on <select> elements. Current tag name: {self.webelement.tag_name}')

select = Select(self.webelement)
if not select.is_multiple:
raise NotImplementedError('This <select> only allows a single option. Use .select() instead.')

try:
for val in values:
select.select_by_visible_text(val)
except NoSuchElementException:
for val in values:
select.select_by_value(val)
finally:
return self.py
return self.py

def submit(self):
""" Submits the form.
Expand Down
117 changes: 58 additions & 59 deletions tests/ui/test_element.py
Original file line number Diff line number Diff line change
@@ -1,190 +1,189 @@
import pytest
from pylenium.driver import Pylenium
from selenium.common.exceptions import ElementNotInteractableException


def test_element_with_no_siblings(py):
py.visit('https://deckshop.pro')
elements = py.get("a[href='/spy/']").siblings()
THE_INTERNET = 'https://the-internet.herokuapp.com'
DEMO_QA = 'https://demoqa.com'


def test_element_with_no_siblings(py: Pylenium):
py.visit(f'{THE_INTERNET}/dropdown')
elements = py.get('#page-footer > div').siblings()
assert elements.should().be_empty()


def test_element_parent_and_siblings(py):
py.visit('https://demoqa.com/menu')
def test_element_parent_and_siblings(py: Pylenium):
py.visit(f'{DEMO_QA}/menu')
parent = py.contains('Main Item 1').parent()
assert parent.tag_name() == 'li'
assert parent.siblings().should().have_length(2)


def test_element_text(py):
py.visit('https://demoqa.com/text-box')
def test_element_text(py: Pylenium):
py.visit(f'{DEMO_QA}/text-box')
assert py.get('#userName-label').should().have_text('Full Name')


def test_find_in_element_context(py):
py.visit('https://demoqa.com/menu')
def test_find_in_element_context(py: Pylenium):
py.visit(f'{DEMO_QA}/menu')
menu_2 = py.contains('Main Item 2')
items = menu_2.parent().find('li')
assert items.should().have_length(5)


def test_input_type_and_get_value(py):
def test_input_type_and_get_value(py: Pylenium):
py.visit('https://deckshop.pro')
search_field = py.get('#smartSearch')
assert search_field.type('golem').should().have_value('golem')
assert search_field.clear().should().have_value('')


def test_children(py):
py.visit('https://deckshop.pro')
first_row_of_cards_in_deck = py.get("[href*='/deck/detail/'] > span").children()
assert first_row_of_cards_in_deck.should().have_length(4)
def test_children(py: Pylenium):
py.visit(f'{THE_INTERNET}/dropdown')
options = py.get('#dropdown').children()
assert options.should().have_length(3)


def test_forced_click(py):
py.visit('https://demoqa.com/checkbox')
def test_forced_click(py: Pylenium):
py.visit(f'{DEMO_QA}/checkbox')
# without forcing, this raises ElementNotInteractableException
py.get("[type='checkbox']").click(force=True)
assert py.get('#result').should().contain_text('You have selected')


def test_not_forcing_click_raises_error(py):
py.visit('https://demoqa.com/checkbox')
with pytest.raises(ElementNotInteractableException):
py.get("[type='checkbox']").click()


def test_element_should_be_clickable(py):
py.visit('https://demoqa.com/buttons')
def test_element_should_be_clickable(py: Pylenium):
py.visit(f'{DEMO_QA}/buttons')
assert py.contains("Click Me").should().be_clickable()


def test_element_should_not_be_clickable(py):
py.visit('https://demoqa.com/checkbox')
def test_element_should_not_be_clickable(py: Pylenium):
py.visit(f'{DEMO_QA}/checkbox')
with pytest.raises(AssertionError):
py.get('[type="checkbox"]').should(timeout=3).be_clickable()


def test_element_should_be_visible(py):
def test_element_should_be_visible(py: Pylenium):
py.visit('http://book.theautomatedtester.co.uk/chapter1')
py.get('#loadajax').click()
assert py.get('#ajaxdiv').should().be_visible()


def test_element_should_be_hidden(py):
def test_element_should_be_hidden(py: Pylenium):
py.visit('https://deckshop.pro')
assert py.get('#smartHelp').should().be_hidden()


def test_element_should_be_focused(py):
def test_element_should_be_focused(py: Pylenium):
py.visit('https://deckshop.pro')
py.get('#smartSearch').click()
assert py.get('#smartSearch').should().be_focused()


def test_element_should_not_be_focused(py):
def test_element_should_not_be_focused(py: Pylenium):
py.visit('https://deckshop.pro')
assert py.get('#smartSearch').should().not_be_focused()


def test_elements_should_be_empty(py):
def test_elements_should_be_empty(py: Pylenium):
py.visit('https://google.com')
assert py.find('select', timeout=3).should().be_empty()
assert py.findx('//select', timeout=0).should().be_empty()


def test_elements_should_not_be_empty(py):
py.visit('https://the-internet.herokuapp.com/add_remove_elements/')
def test_elements_should_not_be_empty(py: Pylenium):
py.visit(f'{THE_INTERNET}/add_remove_elements/')
py.contains('Add Element').click()
py.contains('Add Element').click()
assert py.find('.added-manually').should().not_be_empty()


def test_elements_should_have_length(py):
py.visit('https://the-internet.herokuapp.com/add_remove_elements/')
def test_elements_should_have_length(py: Pylenium):
py.visit(f'{THE_INTERNET}/add_remove_elements/')
py.contains('Add Element').click()
py.contains('Add Element').click()
assert py.find('.added-manually').should().have_length(2)


def test_elements_should_be_greater_than(py):
py.visit('https://the-internet.herokuapp.com/add_remove_elements/')
def test_elements_should_be_greater_than(py: Pylenium):
py.visit(f'{THE_INTERNET}/add_remove_elements/')
py.contains('Add Element').click()
py.contains('Add Element').click()
assert py.find('.added-manually').should().be_greater_than(1)


def test_elements_should_be_less_than(py):
py.visit('https://the-internet.herokuapp.com/add_remove_elements/')
def test_elements_should_be_less_than(py: Pylenium):
py.visit(f'{THE_INTERNET}/add_remove_elements/')
py.contains('Add Element').click()
py.contains('Add Element').click()
assert py.find('.added-manually').should().be_less_than(3)


def test_element_attribute(py):
def test_element_attribute(py: Pylenium):
search_field = '[name="q"]'
py.visit('https://google.com')
assert py.get(search_field).get_attribute('title') == 'Search'
assert py.get(search_field).should().have_attr('title', 'Search')


def test_element_property(py):
def test_element_property(py: Pylenium):
search_field = '[name="q"]'
py.visit('https://google.com')
assert py.get(search_field).get_property('maxLength') == 2048
assert py.get(search_field).should().have_prop('maxLength', 2048)


def test_element_should_disappear(py):
def test_element_should_disappear(py: Pylenium):
spinner = '#serverSideDataTable_processing'
py.visit('https://www.copart.com/lotSearchResults/?free=true&query=nissan')
assert py.get(spinner).should().disappear()


def test_element_has_attribute(py):
py.visit('http://the-internet.herokuapp.com/checkboxes')
def test_element_has_attribute(py: Pylenium):
py.visit(f'{THE_INTERNET}/checkboxes')
py.find('[type="checkbox"]')[1].should().have_attr('checked')


def test_element_does_not_have_attribute(py):
py.visit('http://the-internet.herokuapp.com/checkboxes')
def test_element_does_not_have_attribute(py: Pylenium):
py.visit(f'{THE_INTERNET}/checkboxes')
py.get('[type="checkbox"]').should().not_have_attr('checked')


def test_element_has_attribute_with_value(py):
py.visit('http://the-internet.herokuapp.com/checkboxes')
def test_element_has_attribute_with_value(py: Pylenium):
py.visit(f'{THE_INTERNET}/checkboxes')
py.get('[type="checkbox"]').should().have_attr('type', 'checkbox')


def test_element_does_not_have_attribute_with_value(py):
py.visit('http://the-internet.herokuapp.com/checkboxes')
def test_element_does_not_have_attribute_with_value(py: Pylenium):
py.visit(f'{THE_INTERNET}/checkboxes')
py.should().contain_title('The Internet')
py.get('[type="checkbox"]').should().not_have_attr('type', 'box')


def test_element_css_value(py):
py.visit('https://demoqa.com/buttons')
def test_element_css_value(py: Pylenium):
py.visit(f'{DEMO_QA}/buttons')
element = py.contains('Click Me')
assert element.css_value('backgroundColor') == "rgba(0, 123, 255, 1)"
assert element.css_value('background-color') == "rgba(0, 123, 255, 1)"


def test_element_invalid_css_property_name(py):
py.visit('https://demoqa.com/buttons')
def test_element_invalid_css_property_name(py: Pylenium):
py.visit(f'{DEMO_QA}/buttons')
element = py.contains('Click Me')
assert element.css_value('bg-color') == ''
assert element.css_value('length') is None


def test_getx_nested_element(py):
py.visit('https://demoqa.com/automation-practice-form')
def test_getx_nested_element(py: Pylenium):
py.visit(f'{DEMO_QA}/automation-practice-form')
container = py.getx('//*[@id="subjectsContainer"]')
element = container.getx('.//input')
element_id = element.get_attribute('id')
assert element_id == 'subjectsInput'


def test_findx_nested_element(py):
py.visit('https://demoqa.com/automation-practice-form')

def test_findx_nested_element(py: Pylenium):
py.visit(f'{DEMO_QA}/automation-practice-form')
container = py.getx('//*[@id="hobbiesWrapper"]')
elements = container.findx('.//input')
assert len(elements) == 3
Expand Down
Loading

0 comments on commit ba2fafc

Please sign in to comment.